Metadata-Version: 2.4
Name: vercel-agent-browser
Version: 0.1.0
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.

## Install

Install `agent-browser` and its browser once:

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

Then install this package:

```bash
pip install -e .
```

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)
```

## 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.

## 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.
