Files
zeekay a1022c257e hanzo-tools-browser 0.5.6: three orthogonal tools (browser / cdp / playwright)
Decomplects the browser surface. Previously: BrowserTool with three
braided transports (ZAP, CDP bridge, Playwright) plus a CdpTool alias
that was just a name change. Now: three peer tools, one transport
strategy each, env-gated registration.

Tools (each default-on, each disable-able):
- `browser`    — high-level action surface, auto-routes transport.
                 Disable: HANZO_BROWSER_TOOL_DISABLED=1
- `cdp`        — raw Chrome DevTools Protocol method dispatch
                 (`method=`, `params=`). No Playwright fallback.
                 Disable: HANZO_CDP_TOOL_DISABLED=1
- `playwright` — same action surface as `browser` but pinned to
                 backend=playwright (no extension / CDP-bridge).
                 Disable: HANZO_PLAYWRIGHT_TOOL_DISABLED=1

Transport knobs stay orthogonal to tool selection:
- HANZO_ZAP_DISABLED=1        — don't auto-start the in-process ZAP server
- HANZO_CDP_BRIDGE_ENABLED=1  — opt back into the legacy HTTP bridge
- BROWSER_TRANSPORT=zap|http|auto
- BROWSER_BACKEND=firefox|chrome|extension|playwright|auto

Lifecycle (ZAP server + CDP bridge background threads) moved out of
__init__.py into lifecycle.py. __init__.py is now a pure re-export
surface that resolves TOOLS at import time based on env flags.

CdpTool is now a genuine peer of BrowserTool — method-oriented, not
action-oriented — replacing the alias-subclass from 0.5.5.
2026-06-10 08:41:13 -07:00

62 lines
2.1 KiB
Python

"""Playwright-pinned browser tool.
Same action surface as ``BrowserTool`` but with ``backend="playwright"``
forced — never dispatches through the extension or CDP bridge. Use this
when you want deterministic headless automation regardless of whether a
browser extension is connected to this MCP.
The high-level ``browser`` tool auto-detects transport. Calling
``playwright`` is the explicit "I want Playwright, period" path.
"""
from __future__ import annotations
import logging
from typing import Optional
from hanzo_tools.browser.browser_tool import BrowserTool
logger = logging.getLogger(__name__)
class PlaywrightTool(BrowserTool):
"""Browser automation pinned to the Playwright backend.
Skips the in-process ZAP server (extension dispatch) and the legacy
CDP HTTP bridge entirely — every action goes through Playwright's
Chromium driver. Suitable for headless test runs, CI pipelines, and
any context where attaching to a user-controlled browser is wrong.
The action surface (navigate, click, fill, screenshot, expect_*, ...)
is identical to ``BrowserTool`` — only the transport pin differs.
"""
name = "playwright"
def __init__(
self,
headless: bool = True,
cdp_endpoint: Optional[str] = None,
):
# Force backend="playwright" — overrides BROWSER_BACKEND env, ignores
# extension config, skips ZAP/CDP-bridge lifecycle bootstrap.
super().__init__(
headless=headless,
cdp_endpoint=cdp_endpoint,
backend="playwright",
)
@property
def description(self) -> str:
return """Playwright-pinned browser automation — peer of `browser` and `cdp`.
Same action surface as `browser` but forces backend="playwright":
- No extension dispatch (does not talk to Hanzo browser extension).
- No legacy CDP HTTP bridge.
- Pure async-playwright, headless by default.
Use `browser` for auto-routing (extension > CDP-bridge > Playwright).
Use `cdp` for raw Chrome DevTools Protocol method dispatch.
Use `playwright` for deterministic headless automation.
""" + BrowserTool.description.fget(self).split("CATEGORIES:", 1)[-1].rstrip()