Metadata-Version: 2.4
Name: vercel-agent-browser
Version: 0.1.2
Summary: Type-safe Pydantic wrapper around Vercel's agent-browser CLI
Keywords: agent-browser,browser-automation,pydantic,subprocess,type-safe
Author: John Ades
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Typing :: Typed
Requires-Dist: pydantic>=2.7,<3
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# agent-browser

A type-safe Python wrapper around Vercel's
[`agent-browser`](https://github.com/vercel-labs/agent-browser) CLI.

The convenience API is mapped against the complete 151-tool MCP inventory in
`agent-browser 0.31.1`, with one additional documented CLI extension for
runtime init scripts.

## Install

Install `agent-browser` and its browser once:

```bash
npm install -g agent-browser
agent-browser install
```

Then install this package:

```bash
pip install vercel-agent-browser
```

Python 3.10+ and Pydantic 2 are supported.

## Quick start

```python
from agent_browser import AgentBrowser, Direction, LoadState

browser = AgentBrowser()

browser.open("https://example.com")
browser.wait_for_load(LoadState.NETWORK_IDLE)

snapshot = browser.snapshot(interactive=True).data
print(snapshot.snapshot)
print(snapshot.refs["e1"].role)

browser.click("@e1")
browser.scroll(Direction.DOWN, 500)

title: str = browser.get_title().data.value
url: str = browser.get_url().data.value

browser.close()
```

The browser remains stateful between calls because `agent-browser` manages a
persistent daemon. A context manager closes the current session on exit:

```python
from agent_browser import AgentBrowser, ClientConfig, GlobalOptions

config = ClientConfig(
    timeout=60,
    options=GlobalOptions(
        session="research",
        headed=True,
        allowed_domains=("example.com", "*.example.com"),
    ),
)

with AgentBrowser(config) as browser:
    browser.open("https://example.com")
    print(browser.read().data.value)
```

Clone a configured client when one process needs to address multiple isolated
browser sessions explicitly:

```python
research = browser.for_session("research", namespace="my-application")
checkout = browser.for_session("checkout", namespace="my-application")

research.open("https://example.com/docs")
checkout.open("https://example.com/store")
```

## Complete 0.31.1 surface

The wrapper includes authentication vaults, persisted state, cookie-file
imports, tracing and recording, page diffs, React diagnostics, mobile gestures,
streaming, session discovery, confirmations, and trusted CLI administration.
For example:

```python
from agent_browser import ColorScheme, Direction, ReducedMotion

# Passwords are sent over stdin and never placed in argv.
browser.auth_save(
    "example",
    url="https://example.com/login",
    username="person@example.com",
    password="secret",
)
browser.auth_login("example")

browser.state_save("state.json")
browser.trace_start()
browser.swipe(Direction.UP, 400)
trace = browser.trace_stop("trace.json").data.path

browser.set_media(
    ColorScheme.NO_PREFERENCE,
    reduced_motion=ReducedMotion.NO_PREFERENCE,
)
```

Administrative methods such as `plugin_add()`, `doctor()`, `install()`,
`upgrade()`, and `chat()` are available to trusted Python callers. They are
deliberately absent from the agent-facing registry described below.

The versioned inventory and exposure tier for every MCP tool are available from
`agent_browser.inventory`. `AgentBrowser.tools_profiles()` returns typed local
metadata for the MCP-only startup-profile tool without inventing a nonexistent
CLI command.

## Safe tools for browser subagents

`agent_browser.agent` provides a provider-neutral tool registry for the newly
added browser features and all file-boundary operations. Every call requires an
explicit session owned by `SessionManager`. Agent-visible files use opaque
artifact IDs; outputs are accepted only after existence, containment, regular
file, quota, size, and SHA-256 checks.

```python
from pathlib import Path

from agent_browser.agent import (
    AgentBrowserTools,
    ArtifactStore,
    SessionManager,
    ToolPolicy,
)

root = Path(".browser-artifacts")
policy = ToolPolicy.full_access()
sessions = SessionManager(root)
sessions.create("research")
artifacts = ArtifactStore(root, policy)
tools = AgentBrowserTools(sessions, artifacts, policy)

result = tools.call(
    "agent_browser_screenshot",
    {"session_id": "research", "output_name": "page.png"},
)
if result.ok:
    screenshot = result.artifacts[0]
    print(screenshot.id, screenshot.sha256, screenshot.size_bytes)
```

The default `ToolPolicy` is conservative. Credentials, persisted state,
scripting, network interception, streaming, and low-level browser control must
be enabled deliberately. Host paths, raw session overrides, MCP `extraArgs`,
and the 14 metadata/administration tools are not accepted by this registry.

## Typed results

Every JSON-mode call returns `CommandResult[T]`. Its `data` is a Pydantic model
specific to that operation, while its other fields preserve useful process
metadata:

```python
result = browser.get_box("@e1")

print(result.data.x, result.data.y)
print(result.command)
print(result.stderr)
print(result.duration_seconds)
```

Common typed payloads include:

- `SnapshotData` and `SnapshotRef`
- `StringData`, `BooleanData`, and `IntegerData`
- `BoundingBox` and `PathData`
- `JsonData` for successful commands whose payload is command-specific

Pydantic validates both outgoing configuration and incoming structured data.

## Errors

CLI failures raise `AgentBrowserCommandError`. The exception retains the
subprocess exit code, arguments, stdout/stderr, warning, and normalized Pydantic
error model:

```python
from agent_browser import AgentBrowserCommandError

try:
    browser.click("@missing")
except AgentBrowserCommandError as exc:
    print(exc.error.message)
    print(exc.error.code)
    print(exc.returncode)
```

The package also distinguishes an unavailable executable, subprocess timeout,
and invalid CLI response with `AgentBrowserNotFoundError`,
`AgentBrowserTimeoutError`, and `AgentBrowserResponseError`.

## Custom and future commands

Use `run()` for CLI commands not yet represented by a convenience method. Pass
an argument sequence—not a shell string:

```python
result = browser.run(["console", "--clear"])
print(result.data.root)
```

You can supply your own Pydantic model for a command's `data` payload:

```python
from pydantic import BaseModel

class StreamStatus(BaseModel):
    enabled: bool
    port: int | None = None

status = browser.run(["stream", "status"], StreamStatus).data
```

For compact human-readable CLI output, use `run_text()`:

```python
text = browser.run_text(["snapshot", "-i"]).stdout
```

`run()` always requests JSON output and parses the standard
`{"success": ..., "data": ...}` envelope. It also accepts raw JSON payloads for
commands such as `batch` that emit an array directly.

## Compatibility note

The encoded inventory and argument contract target `agent-browser 0.31.1`.
That release's version-matched documentation advertises a runtime
`addinitscript` command, so this package exposes `add_init_script()` alongside
`remove_init_script()`. The installed 0.31.1 native binary currently rejects
`addinitscript` as `unknown_command`; the wrapper preserves that structured CLI
error rather than silently substituting the different launch-time
`--init-script <file>` option.

## Executable and environment configuration

If `agent-browser` is not on `PATH`, point to it explicitly:

```python
from pathlib import Path
from agent_browser import AgentBrowser, ClientConfig

browser = AgentBrowser(
    ClientConfig(
        executable=Path("/opt/homebrew/bin/agent-browser"),
        env={"AGENT_BROWSER_ENCRYPTION_KEY": "..."},
    )
)
```

Environment values are merged onto the current process environment. Arguments
are passed directly to `subprocess.run(..., shell=False)`; no selector, URL,
JavaScript, password, or other input is interpreted by a shell.
