Skip to main content

Sentience Python SDK

A verification & control layer for AI agents that operate browsers

Sentience is built for AI agent developers who already use Playwright / CDP / browser-use / LangGraph and care about flakiness, cost, determinism, evals, and debugging.

Often described as Jest for Browser AI Agents - but applied to end-to-end agent runs (not unit tests).

The core loop is:

Agent → Snapshot → Action → Verification → Artifact

What Sentience is

  • A verification-first runtime (AgentRuntime) for browser agents
  • Treats the browser as an adapter (Playwright / CDP / browser-use); AgentRuntime is the product
  • A controlled perception layer (semantic snapshots; pruning/limits; lowers token usage by filtering noise from what models see)
  • A debugging layer (structured traces + failure artifacts)
  • Enables local LLM small models (3B-7B) for browser automation (privacy, compliance, and cost control)
  • Keeps vision models optional (use as a fallback when DOM/snapshot structure falls short, e.g. <canvas>)

What Sentience is not

  • Not a browser driver
  • Not a Playwright replacement
  • Not a vision-first agent framework

Install

pip install sentienceapi
playwright install chromium

Conceptual example (why this exists)

In Sentience, agents don’t “hope” an action worked.

  • Every step is gated by verifiable UI assertions
  • If progress can’t be proven, the run fails with evidence (trace + artifacts)
  • This is how you make runs reproducible and debuggable, and how you run evals reliably

Quickstart: a verification-first loop

This is the smallest useful pattern: snapshot → assert → act → assert-done.

import asyncio

from sentience import AgentRuntime, AsyncSentienceBrowser
from sentience.tracing import JsonlTraceSink, Tracer
from sentience.verification import exists, url_contains


async def main() -> None:
    tracer = Tracer(run_id="demo", sink=JsonlTraceSink("trace.jsonl"))

    async with AsyncSentienceBrowser() as browser:
        page = await browser.new_page()
        await page.goto("https://example.com")

        runtime = await AgentRuntime.from_sentience_browser(
            browser=browser,
            page=page,
            tracer=tracer,
        )

        runtime.begin_step("Verify homepage")
        await runtime.snapshot()

        runtime.assert_(url_contains("example.com"), label="on_domain", required=True)
        runtime.assert_(exists("role=heading"), label="has_heading")

        runtime.assert_done(exists("text~'Example'"), label="task_complete")


if __name__ == "__main__":
    asyncio.run(main())

SentienceDebugger: attach to your existing agent framework (sidecar mode)

If you already have an agent loop (LangGraph, browser-use, custom planner/executor), you can keep it and attach Sentience as a verifier + trace layer.

Key idea: your agent still decides and executes actions — Sentience snapshots and verifies outcomes.

from sentience import SentienceDebugger, create_tracer
from sentience.verification import exists, url_contains


async def run_existing_agent(page) -> None:
    # page: playwright.async_api.Page (owned by your agent/framework)
    tracer = create_tracer(run_id="run-123")  # local JSONL by default
    dbg = SentienceDebugger.attach(page, tracer=tracer)

    async with dbg.step("agent_step: navigate + verify"):
        # 1) Let your framework do whatever it does
        await your_agent.step()

        # 2) Snapshot what the agent produced
        await dbg.snapshot()

        # 3) Verify outcomes (with bounded retries)
        await dbg.check(url_contains("example.com"), label="on_domain", required=True).eventually(timeout_s=10)
        await dbg.check(exists("role=heading"), label="has_heading").eventually(timeout_s=10)

SDK-driven full loop (snapshots + actions)

If you want Sentience to drive the loop end-to-end, you can use the SDK primitives directly: take a snapshot, select elements, act, then verify.

from sentience import SentienceBrowser, snapshot, find, click, type_text, wait_for


def login_example() -> None:
    with SentienceBrowser() as browser:
        browser.page.goto("https://example.com/login")

        snap = snapshot(browser)
        email = find(snap, "role=textbox text~'email'")
        password = find(snap, "role=textbox text~'password'")
        submit = find(snap, "role=button text~'sign in'")

        if not (email and password and submit):
            raise RuntimeError("login form not found")

        type_text(browser, email.id, "user@example.com")
        type_text(browser, password.id, "password123")
        click(browser, submit.id)

        # Verify success
        ok = wait_for(browser, "role=heading text~'Dashboard'", timeout=10.0)
        if not ok.found:
            raise RuntimeError("login failed")

Capabilities (lifecycle guarantees)

Controlled perception

  • Semantic snapshots instead of raw DOM dumps
  • Pruning knobs via SnapshotOptions (limit/filter)
  • Snapshot diagnostics that help decide when “structure is insufficient”

Constrained action space

  • Action primitives operate on stable IDs / rects derived from snapshots
  • Optional helpers for ordinality (“click the 3rd result”)

Verified progress

  • Predicates like exists(...), url_matches(...), is_enabled(...), value_equals(...)
  • Fluent assertion DSL via expect(...)
  • Retrying verification via runtime.check(...).eventually(...)

Explained failure

  • JSONL trace events (Tracer + JsonlTraceSink)
  • Optional failure artifact bundles (snapshots, diagnostics, step timelines, frames/clip)
  • Deterministic failure semantics: when required assertions can’t be proven, the run fails with artifacts you can replay

Framework interoperability

  • Bring your own LLM and orchestration (LangGraph, AutoGen, custom loops)
  • Register explicit LLM-callable tools with ToolRegistry

ToolRegistry (LLM-callable tools)

Sentience can expose a typed tool surface for agents (with tool-call tracing).

from sentience.tools import ToolRegistry, register_default_tools

registry = ToolRegistry()
register_default_tools(registry, runtime)  # or pass a ToolContext

# LLM-ready tool specs
tools_for_llm = registry.llm_tools()

Permissions (avoid Chrome permission bubbles)

Chrome permission prompts are outside the DOM and can be invisible to snapshots. Prefer setting a policy before navigation.

from sentience import AsyncSentienceBrowser, PermissionPolicy

policy = PermissionPolicy(
    default="clear",
    auto_grant=["geolocation"],
    geolocation={"latitude": 37.77, "longitude": -122.41, "accuracy": 50},
    origin="https://example.com",
)

async with AsyncSentienceBrowser(permission_policy=policy) as browser:
    ...

If your backend supports it, you can also use ToolRegistry permission tools (grant_permissions, clear_permissions, set_geolocation) mid-run.

Downloads (verification predicate)

If a flow is expected to download a file, assert it explicitly:

from sentience.verification import download_completed

runtime.assert_(download_completed("report.csv"), label="download_ok", required=True)

Debugging (fast)

  • Manual driver CLI (inspect clickables, click/type/press quickly):
sentience driver --url https://example.com
  • Verification + artifacts + debugging with time-travel traces (Sentience Studio demo):

If the video tag doesn’t render in your GitHub README view, use this link: sentience-studio-demo.mp4

Integrations (examples)

Metadata

Release files for sentienceapi 0.99.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sentienceapi 0.99.7
File Size Uploaded Provenance Actions
sentienceapi-0.99.7.tar.gz 386.4 kB Without provenance Details for sentienceapi-0.99.7.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sentienceapi 0.99.7
File Interpreter ABI Platform Actions
sentienceapi-0.99.7-py3-none-any.whl Python 3 none any Details for sentienceapi-0.99.7-py3-none-any.whl

Total release size: 726.1 kB

Release files / sentienceapi-0.99.7.tar.gz

Download URL sentienceapi-0.99.7.tar.gz
Size 386.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8531cb84478d9f3fc60c70c21a2b9ee7ee0376cef6b405d7dcc2c2a8c67d3de8
BLAKE2b-256 checksum
How to use checksums
6a47d765330672d31430c0cbf53d6479816e67ed6636578bc70cbe812a27f840
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release files / sentienceapi-0.99.7-py3-none-any.whl

Download URL sentienceapi-0.99.7-py3-none-any.whl
Size 339.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b528ed26ab3bfc0c94469f68d242dfdf69f1daa4c80c541351b94a378f9cc56b
BLAKE2b-256 checksum
How to use checksums
1ed9a85cc4355b3662cd5b9d31573139f3a4f2e50ae87eb7ced629e7e5a71e75
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Security for sentienceapi 0.99.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.99.7 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page