* fix(tabs): initialize tab_id on missing PageInfo sites PR #892 added a required `tab_id: u32` field to `PageInfo` but missed two initializer sites, which broke the build on the PR branch. CI never caught this because the external-contributor workflow status was `action_required` and never ran. - `cli/src/native/browser.rs:395` — the `direct_page` branch of `connect_cdp_inner` used by the cloud providers (Browserbase, Browserless, Browser Use, Kernel, AgentCore). Use `assign_tab_id()` to get a fresh id. - `cli/src/native/browser.rs:1580` — a unit test initializer. Use `tab_id: 1` since the test doesn't exercise id assignment. * feat(tabs): restore active tab and clear per-tab state for scoped --tab Follow-up on PR #892's `--tab <id>` flag. The original implementation called `tab_switch_by_id` directly from the pre-dispatch block in `execute_command` but didn't touch the daemon's per-tab state, and never restored the previously-active tab. Two concrete issues this fixes: 1. `state.ref_map`, `state.iframe_sessions`, and `state.active_frame_id` were left intact across the pre-dispatch switch, so `--tab N click @e1` would try to resolve `@e1` against the scoped tab's DOM using a backend-node id from the outer tab. In practice the click handler's role+name fallback hid this as "element not found" errors, but on pages where both tabs have similarly-labelled elements it could click the wrong one. 2. The PR description promised scoped routing would "restore the previous active tab", but the implementation permanently switched. `--tab 3 snapshot` would leave tab 3 as the active tab even after the command returned, surprising subsequent non-scoped commands. This change: - Saves the current tab's stable `tab_id` (not its array index, which would shift if the scoped command closed other tabs) before switching. - Clears per-tab daemon state before the switch so refs/iframes/frame context can't leak between tabs. - After the action runs, restores the original active tab (also via stable id) unless that tab was closed during the scoped command, in which case we leave the scoped tab active. - Adds `BrowserManager::active_tab_id()` and `has_tab_id()` accessors to support the above without exposing the internal `pages` vector. * test(tabs): regression tests for scoped --tab state clearing and restoration Three new `#[ignore]` e2e tests pinning the fixed behavior: - `e2e_tab_scoped_command_clears_state_on_switch` — populates `ref_map` on tab 1, runs a `tabId: 2`-scoped command, asserts `ref_map`, `iframe_sessions`, and `active_frame_id` are all cleared. - `e2e_tab_scoped_command_restores_active_tab` — sets up two tabs, runs a scoped command against the non-active one, asserts a subsequent unscoped command reflects the originally-active tab. - `e2e_tab_scoped_command_handles_outer_tab_closed` — runs a scoped `tab_close` that kills the outer tab itself, asserts no error and the scoped tab becomes active. Also updates two misleading comments in the PR's existing `e2e_tab_global_targeting*` tests to reflect restoration semantics; the assertions themselves were already consistent with restoration. * docs(tabs): document stable tab IDs and --tab scoped-command flag Per AGENTS.md, changes that users or agents would need to know about must land in every doc surface. Fills the gaps PR #892 left: - `README.md` — new `--tab <id>` row in the Options table, rewrite the tab command examples to use `<id>` instead of `<n>`, add a paragraph explaining stable tab IDs and `--tab` peek semantics. - `docs/src/app/commands/page.mdx` — same command-example rewrite plus a new "Stable tab IDs and `--tab`" subsection. - `docs/src/app/configuration/page.mdx` — add `tab` row to the config options table so JSON config users can discover it. - `agent-browser.schema.json` — add `tab` property with description, matching the config schema. - `skills/agent-browser/references/commands.md` — same command-example rewrite plus a short paragraph for agents on when to use `--tab`.
172 lines
5.1 KiB
JSON
172 lines
5.1 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"title": "Agent Browser Configuration",
|
|
"description": "Configuration file for agent-browser (e.g., agent-browser.json or ~/.agent-browser/config.json)",
|
|
"type": "object",
|
|
"properties": {
|
|
"headed": {
|
|
"type": "boolean",
|
|
"description": "Show browser window instead of running headless."
|
|
},
|
|
"json": {
|
|
"type": "boolean",
|
|
"description": "Output in JSON format."
|
|
},
|
|
"debug": {
|
|
"type": "boolean",
|
|
"description": "Enable debug output."
|
|
},
|
|
"session": {
|
|
"type": "string",
|
|
"description": "Session identifier."
|
|
},
|
|
"sessionName": {
|
|
"type": "string",
|
|
"description": "Auto-save/load state persistence name."
|
|
},
|
|
"tab": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"description": "Target a specific tab by stable tabId for this command only. The active tab is restored afterward."
|
|
},
|
|
"executablePath": {
|
|
"type": "string",
|
|
"description": "Path to a custom browser executable."
|
|
},
|
|
"extensions": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "Paths to browser extensions. Extensions from user-level and project-level configs are concatenated."
|
|
},
|
|
"profile": {
|
|
"type": "string",
|
|
"description": "Path to the browser profile data directory."
|
|
},
|
|
"state": {
|
|
"type": "string",
|
|
"description": "Path to load/save browser state."
|
|
},
|
|
"proxy": {
|
|
"type": "string",
|
|
"description": "Proxy server URL (e.g., http://localhost:8080)."
|
|
},
|
|
"proxyBypass": {
|
|
"type": "string",
|
|
"description": "Comma-separated domains to bypass the proxy (e.g., localhost,*.internal.com)."
|
|
},
|
|
"args": {
|
|
"type": "string",
|
|
"description": "Additional comma-separated launch arguments for the browser."
|
|
},
|
|
"userAgent": {
|
|
"type": "string",
|
|
"description": "Custom User-Agent string."
|
|
},
|
|
"provider": {
|
|
"type": "string",
|
|
"description": "Provider to use, such as 'ios'."
|
|
},
|
|
"device": {
|
|
"type": "string",
|
|
"description": "Device name or identifier for emulation or providers (e.g., 'iPhone 16 Pro')."
|
|
},
|
|
"ignoreHttpsErrors": {
|
|
"type": "boolean",
|
|
"description": "Ignore HTTPS errors during navigation."
|
|
},
|
|
"allowFileAccess": {
|
|
"type": "boolean",
|
|
"description": "Allow file:// URLs to access local files."
|
|
},
|
|
"cdp": {
|
|
"type": "string",
|
|
"description": "Chrome DevTools Protocol endpoint URL."
|
|
},
|
|
"autoConnect": {
|
|
"type": "boolean",
|
|
"description": "Auto-discover and connect to a running Chrome instance."
|
|
},
|
|
"annotate": {
|
|
"type": "boolean",
|
|
"description": "Annotated screenshot with numbered element labels."
|
|
},
|
|
"colorScheme": {
|
|
"type": "string",
|
|
"enum": ["dark", "light", "no-preference"],
|
|
"description": "Color scheme preference."
|
|
},
|
|
"downloadPath": {
|
|
"type": "string",
|
|
"description": "Default directory for browser downloads."
|
|
},
|
|
"contentBoundaries": {
|
|
"type": "boolean",
|
|
"description": "Wrap page output in boundary markers for LLM safety."
|
|
},
|
|
"maxOutput": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"description": "Max characters for page output (truncates beyond limit)."
|
|
},
|
|
"allowedDomains": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "Allowed domain patterns (e.g., ['example.com', '*.example.com'])."
|
|
},
|
|
"actionPolicy": {
|
|
"type": "string",
|
|
"description": "Path to action policy JSON file."
|
|
},
|
|
"confirmActions": {
|
|
"type": "string",
|
|
"description": "Comma-separated action categories requiring confirmation."
|
|
},
|
|
"confirmInteractive": {
|
|
"type": "boolean",
|
|
"description": "Enable interactive confirmation prompts (auto-denies if stdin is not a TTY)."
|
|
},
|
|
"engine": {
|
|
"type": "string",
|
|
"enum": ["chrome", "lightpanda"],
|
|
"default": "chrome",
|
|
"description": "Browser engine to use."
|
|
},
|
|
"screenshotDir": {
|
|
"type": "string",
|
|
"description": "Default screenshot output directory."
|
|
},
|
|
"screenshotQuality": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"maximum": 100,
|
|
"description": "JPEG quality for screenshots (0-100)."
|
|
},
|
|
"screenshotFormat": {
|
|
"type": "string",
|
|
"enum": ["png", "jpeg"],
|
|
"description": "Screenshot format."
|
|
},
|
|
"idleTimeout": {
|
|
"type": "string",
|
|
"description": "Auto-shutdown the daemon after inactivity (e.g., '30s', '5m', '1h', or raw milliseconds like '60000')."
|
|
},
|
|
"model": {
|
|
"type": "string",
|
|
"description": "AI model for chat command (e.g., 'openai/gpt-4o')."
|
|
},
|
|
"noAutoDialog": {
|
|
"type": "boolean",
|
|
"description": "Disable automatic dismissal of alert/beforeunload dialogs."
|
|
},
|
|
"headers": {
|
|
"type": "string",
|
|
"description": "Custom HTTP headers supplied as a JSON-formatted string."
|
|
}
|
|
},
|
|
"additionalProperties": true
|
|
}
|