Refresh BYOB browser inventory
Poll connected A0 CLI host-browser metadata while Browser Settings is open so newly authorized endpoints appear without saving or reopening. Extend Browser Settings labels and remote-debugging guidance for Brave, Opera, Vivaldi, and Chromium-family host browsers with regression coverage.
Alessandro committed
Jul 4, 2026 at 19:22 UTC
7168f0984e78c51d2d3d86d2be48ffee77215064
8 files changed
+34
-4
plugins/_browser/AGENTS.md
+1
@@ -25,6 +25,7 @@
25
- Keep WebUI Browser tabs scoped to the active chat context by default; aggregate tabs from other AgentContext runtimes only when the Browser settings tab scope is `shared`.
26
- Keep narrow WebUI Browser controls usable by grouping navigation with Annotate/settings above a full-width address bar.
27
- For Bring Your Own Browser with an existing host profile, `host_browser_selection` may target automatic CLI selection, a browser family/id, or an explicit CDP endpoint and must be forwarded to the connector runtime as `browser_selection`.
28
+- Browser Settings must refresh connected A0 CLI host-browser inventory while the settings view is open so newly authorized endpoints appear without saving or reopening.
29
- Browser URL-intent handling must only claim web URL schemes and leave custom Agent Zero schemes to their owning surfaces.
30
- Prefer DOM/CDP browser actions with refs, selectors, frame-chain refs, and screenshots over viewport coordinate input. Coordinates remain a visual fallback.
31
- Do not hardcode user-specific browser paths or secrets.
plugins/_browser/helpers/connector_runtime.py
+6
-2
@@ -83,7 +83,8 @@ _REQUIRED_API_NAMES_RE = re.compile(
83
re.S,
84
)
85
_HOST_BROWSER_REMOTE_DEBUGGING_HELP = (
86
- 'For an already-open Chrome-family browser, open `chrome://inspect/#remote-debugging`, '
86
+ "For an already-open Chromium-family browser, open its inspect page, such as "
87
+ "`chrome://inspect/#remote-debugging` or `opera://inspect/#remote-debugging`, "
88
'enable "Allow remote debugging for this browser instance", run `/browser host on`, '
89
"and retry."
90
)
@@ -519,7 +520,10 @@ class ConnectorBrowserRuntime:
520
if not message:
521
message = "Host browser operation failed"
522
normalized = message.lower()
522
- if "chrome://inspect/#remote-debugging" in normalized:
523
+ if (
524
+ "chrome://inspect/#remote-debugging" in normalized
525
+ or "opera://inspect/#remote-debugging" in normalized
526
+ ):
527
return _append_docker_browser_recovery(message)
528
if any(token in normalized for token in _REMOTE_DEBUGGING_ERROR_TOKENS):
529
return _append_docker_browser_recovery(
plugins/_browser/prompts/agent.system.tool.browser.md
+1
-1
@@ -3,7 +3,7 @@ Rendered browser automation for pages that need interaction, JavaScript, forms,
3
4
Prefer `search_engine` or `document_query` for plain text research. The tool must not open a Browser surface automatically. Use the tool headlessly unless the user opens the Browser surface or asks for the optional visible WebUI viewer.
5
6
-When the user asks for "my browser", "host browser", "local browser", local Chrome, or opening a URL in their host browser, use this `browser` tool. Do not substitute `computer_use_remote`, `code_execution_remote`, `xdg-open`, `sensible-browser`, or Python `webbrowser.open`. If setup fails and mentions remote debugging, tell the user to open `chrome://inspect/#remote-debugging`, enable "Allow remote debugging for this browser instance", run `/browser host on`, and retry.
6
+When the user asks for "my browser", "host browser", "local browser", a local Chromium browser, or opening a URL in their host browser, use this `browser` tool. Do not substitute `computer_use_remote`, `code_execution_remote`, `xdg-open`, `sensible-browser`, or Python `webbrowser.open`. If setup fails and mentions remote debugging, tell the user to open the browser inspect page, such as `chrome://inspect/#remote-debugging` or `opera://inspect/#remote-debugging`, enable "Allow remote debugging for this browser instance", run `/browser host on`, and retry.
7
8
For rendered browsing workflows, multi-step interaction, screenshots, downloads, uploads, forms, or host/container mode decisions, first load `browser-automation` with `skills_tool:load`, then call this tool using the loaded instructions. For fragile forms, `browser-automation` links to `browser-form-workflows`; load it when selects, checkboxes, radios, uploads, contenteditable fields, validation, or submission state are central.
9
plugins/_browser/webui/browser-config-store.js
+21
@@ -10,6 +10,7 @@ const HOST_PROFILE_MODES = new Set(["existing", "agent"]);
10
const DEFAULT_MAX_OPEN_TABS = 32;
11
const MIN_MAX_OPEN_TABS = 1;
12
const HARD_MAX_OPEN_TABS = 50;
13
+const HOST_BROWSER_STATUS_REFRESH_MS = 3000;
14
15
function normalizePathList(value) {
16
const source = Array.isArray(value)
@@ -91,6 +92,9 @@ function hostBrowserFamilyLabel(value) {
92
chromium: "Chromium",
93
edge: "Edge",
94
"edge-dev": "Edge Dev",
95
+ brave: "Brave",
96
+ opera: "Opera",
97
+ vivaldi: "Vivaldi",
98
};
99
const label = labels[base] || "Host browser";
100
if (remoteDebugging) return `${label} (allowed)`;
@@ -116,13 +120,16 @@ export const store = createStore("browserConfig", {
120
extensionDeleteLoadingPath: "",
121
hostBrowserStatus: null,
122
hostBrowserStatusLoading: false,
123
+ hostBrowserStatusRefreshTimer: null,
124
125
async init(config) {
126
this.bindConfig(config);
127
await Promise.all([this.loadExtensionsList(), this.loadHostBrowserStatus()]);
128
+ this.startHostBrowserStatusRefresh();
129
},
130
131
cleanup() {
132
+ this.stopHostBrowserStatusRefresh();
133
this.config = null;
134
this.extensionsList = [];
135
this.extensionsError = "";
@@ -132,6 +139,20 @@ export const store = createStore("browserConfig", {
139
this.hostBrowserStatusLoading = false;
140
},
141
142
+ startHostBrowserStatusRefresh() {
143
+ this.stopHostBrowserStatusRefresh();
144
+ this.hostBrowserStatusRefreshTimer = window.setInterval(
145
+ () => this.loadHostBrowserStatus(),
146
+ HOST_BROWSER_STATUS_REFRESH_MS,
147
+ );
148
+ },
149
+
150
+ stopHostBrowserStatusRefresh() {
151
+ if (!this.hostBrowserStatusRefreshTimer) return;
152
+ window.clearInterval(this.hostBrowserStatusRefreshTimer);
153
+ this.hostBrowserStatusRefreshTimer = null;
154
+ },
155
+
156
bindConfig(config) {
157
const safeConfig = ensureConfig(config);
158
if (!safeConfig) return;
plugins/_browser/webui/config.html
+1
-1
@@ -37,7 +37,7 @@
37
class="browser-config-field-help"
38
x-show="$store.browserConfig.config.runtime_backend === 'host_required'"
39
>
40
- Uses Chrome, Edge, or Chromium on the A0 CLI host. Keep A0 CLI connected; the browser opens when the agent first needs it. For an already-open browser, use chrome://inspect/#remote-debugging and enable "Allow remote debugging for this browser instance".
40
+ Uses Chrome, Edge, Brave, Opera, Vivaldi, or Chromium on the A0 CLI host. Keep A0 CLI connected; the browser opens when the agent first needs it. For an already-open browser, use its inspect page, such as chrome://inspect/#remote-debugging or opera://inspect/#remote-debugging, and enable "Allow remote debugging for this browser instance".
41
</span>
42
</label>
43
tests/test_a0_connector_prompt_gating.py
+1
@@ -624,6 +624,7 @@ def test_host_browser_requests_route_to_browser_tool_not_desktop_or_shell_fallba
624
assert "code_execution_remote" in browser_prompt
625
assert "Python `webbrowser.open`" in browser_prompt
626
assert "chrome://inspect/#remote-debugging" in browser_prompt
627
+ assert "opera://inspect/#remote-debugging" in browser_prompt
628
assert "Do not start `computer_use_remote` for web-page navigation" in computer_skill
629
assert (
630
"Do not fall back to `code_execution_remote`, `xdg-open`, `sensible-browser`, "
tests/test_browser_agent_regressions.py
+2
@@ -995,10 +995,12 @@ def test_browser_tool_does_not_auto_open_canvas_policy_is_documented():
995
assert "`browser-automation` links to `browser-form-workflows`" in prompt
996
assert "does not automatically load screenshots" in prompt
997
assert "chrome://inspect/#remote-debugging" in prompt
998
+ assert "opera://inspect/#remote-debugging" in prompt
999
assert tokens.approximate_tokens(prompt) <= 650
1000
assert "already open" in config
1001
assert "already-open Browser surface" in config_html
1002
assert "chrome://inspect/#remote-debugging" in config_html
1003
+ assert "opera://inspect/#remote-debugging" in config_html
1004
1005
1006
def test_browser_skills_are_plugin_owned_and_progressively_linked():
tests/test_host_browser_connector.py
+1
@@ -308,6 +308,7 @@ def test_connector_runtime_adds_remote_debugging_help_to_cdp_errors():
308
)
309
310
assert "chrome://inspect/#remote-debugging" in message
311
+ assert "opera://inspect/#remote-debugging" in message
312
assert "Allow remote debugging for this browser instance" in message
313
assert "/browser host on" in message
314
assert "Internal Docker browser" in message