Metadata-Version: 2.4
Name: shalfa
Version: 4.0.0rc53
Summary: Python SDK for Stagehand
Project-URL: Repository, https://github.com/pirate/stagehand-v4
Requires-Python: >=3.11
Requires-Dist: abxbus==2.5.18
Requires-Dist: browserbase>=1.8.0
Requires-Dist: pydantic>=2.0
Requires-Dist: rich-click>=1.8
Requires-Dist: rich>=13.9
Requires-Dist: websocket-client>=1.8.0
Requires-Dist: websockets>=14.0
Description-Content-Type: text/markdown

# Stagehand SDK Client (Python)

Python SDK for controlling the Stagehand extension through ModCDP.

## Run

From the repository root:

```bash
pnpm run build:artifacts
pnpm --filter @browserbasehq/stagehand-docs test:examples:python
```

For the CI smoke flow that exercises raw CDP, ModCDP, and GitHub summary output:

```bash
uv run python tests/integration/test_basic.py
```

## Usage

```python
import asyncio
import os

from stagehand import StagehandClient


async def main() -> None:
    client = StagehandClient(
        # Pass at most one launch source:
        # cdp_url="http://127.0.0.1:9222",
        # cdp_url="ws://127.0.0.1:9222/devtools/browser/<id>",
        # local_browser_launch_options={
        #     "executable_path": "/Applications/Chromium.app/Contents/MacOS/Chromium",
        # },
        # browserbase_session_create_params={
        #     "browserbase_api_key": os.environ["BROWSERBASE_API_KEY"],
        # },
    )

    await client.connect()

    client.on("Target.targetInfoChanged", print)

    print(await client.Browser.getVersion())
    print(await client.Target.getTargets())
    print(await client.Mod.evaluate(expression="chrome.runtime.id"))

    browser = client.browser
    page = await browser.new_page(url="https://example.com")
    page2 = await page.goto(url="https://browserbase.com")
    print(page2.url)
    print(await browser.pages(url=page2.url))

    body = await page.locate(css="body")
    print(await body.info())

    await client.close()


asyncio.run(main())
```

`StagehandClient.connect()` and `StagehandClient.close()` are async. Stagehand browser/page/locator methods are async. The compact `client.*` CDP command surface is synchronous because the Python ModCDP client owns a background websocket reader thread.

## Launch Sources

`connect()` accepts exactly one effective launch source:

- `cdp_url`: an existing browser CDP endpoint. `http://...` URLs are resolved through `/json/version`; `ws://...` and `wss://...` URLs are used directly.
- `local_browser_launch_options`: launches local Chromium or Chrome Canary with CDP enabled. `CHROME_PATH` can provide the executable path. `STAGEHAND_SDK_CDP_PORT` fixes the debugging port for editor attach workflows.
- `browserbase_session_create_params["browserbase_api_key"]`: asks ModCDP to create a Browserbase session. The SDK uploads or reuses the packaged versioned extension artifact automatically; no extension ID configuration is required.

If no launch source is passed, `connect()` reads `os.environ`; it uses `BROWSERBASE_API_KEY` when present, otherwise it launches local Chromium/Canary.

## Extension Paths

The default unpacked extension directory is the WXT output:

```text
stagehand-extension/.output/chrome-mv3
```

The same directory contains the single reusable extension zip:

```text
stagehand-extension/.output/chrome-mv3/stagehand-extension.zip
```

The prepared extension manifest uses the canonical `stagehand-modcdp/background.js` service worker path. The client trusts and waits for that service worker with `globalThis.__stagehand_modcdp_ready === true`.

## Routing

Default client routes:

```python
{
    "Mod.*": "service_worker",
    "Stagehand.*": "service_worker",
    "*.*": "service_worker",
}
```

Default extension service-worker routes:

```python
{
    "Mod.*": "service_worker",
    "Stagehand.*": "service_worker",
    "*.*": "loopback_cdp",
}
```

Stagehand SDK routes are fixed: Stagehand and ModCDP commands go through the extension service worker, and native CDP commands go from the service worker to loopback CDP.

## Debugging

The checked-in VS Code tasks set:

```text
STAGEHAND_DEBUG_WAIT_FOR_ENTER=1
STAGEHAND_SDK_CDP_PORT=9231
```

The smoke test at `tests/integration/test_basic.py` prints `[debug] Browser ready. Press Enter to continue.` after the extension is connected, so DevTools can inspect `chrome-extension://*/stagehand-modcdp/background.js` before the flow continues.
