fix(browser): remove hardcoded profile="user" suggestion from tool description (#102582)

* fix(browser): remove hardcoded profile="user" suggestion from browser tool description

The browser tool description hardcoded a suggestion to use profile="user"
for logged-in sessions, even when the operator has configured a different
default profile (e.g. browser.defaultProfile: "openclaw").

Replace with profile-agnostic guidance that references the configured
browser.defaultProfile setting instead of prescribing a specific value.

Fixes #102566

* test: update browser tool description assertion for profile-agnostic wording

* refactor(browser): unify tool profile guidance

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Gary 2026-07-09 19:32:56 +08:00 committed by GitHub
parent 3ada371449
commit 981d67a703
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 29 additions and 28 deletions

View file

@ -150,6 +150,8 @@ describe("browser plugin", () => {
}
expect(tool.name).toBe("browser");
expect(tool.description).toContain("action=profiles");
expect(tool.description).not.toContain('profile="user"');
expect(runtimeApiMocks.createBrowserTool).not.toHaveBeenCalled();
await tool.execute("call-1", { action: "status" });
expect(runtimeApiMocks.createBrowserTool).toHaveBeenCalledWith({

View file

@ -18,6 +18,7 @@ import {
BROWSER_REQUEST_GATEWAY_METHOD,
BROWSER_REQUEST_GATEWAY_SCOPE,
} from "./src/browser-gateway-contract.js";
import { describeBrowserTool } from "./src/browser-tool-description.js";
import { BrowserToolSchema } from "./src/browser-tool.schema.js";
const EAGER_BROWSER_CONTROL_SERVICE_ENV = "OPENCLAW_EAGER_BROWSER_CONTROL_SERVER";
@ -74,19 +75,7 @@ function createLazyBrowserTool(opts?: {
return {
label: "Browser",
name: "browser",
description: [
"Control the browser via OpenClaw's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/download/actions).",
"Browser choice: omit profile by default for the isolated OpenClaw-managed browser (`openclaw`).",
'For the logged-in user browser, use profile="user". A supported Chromium-based browser (v144+) must be running on the selected host or browser node. Use only when existing logins/cookies matter and the user is present.',
'For profile="user" or other existing-session profiles, omit timeoutMs on act:type, evaluate, hover, scrollIntoView, drag, select, and fill; that driver rejects per-call timeout overrides for those actions.',
'When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target="node".',
"When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc). For tab operations, targetId also accepts tabId handles (t1) and labels from action=tabs.",
"For multi-step browser work, login checks, stale refs, duplicate tabs, or Google Meet flows, use the bundled browser-automation skill when it is available.",
'For stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
"Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
`target selects browser location (sandbox|host|node). Default: ${targetDefault}.`,
hostHint,
].join(" "),
description: describeBrowserTool({ targetDefault, hostHint }),
parameters: BrowserToolSchema,
execute: async (toolCallId, args, signal, onUpdate) => {
const { createBrowserTool } = await loadBrowserRegistrationRuntimeModule();

View file

@ -0,0 +1,20 @@
/** Build the Browser tool guidance shared by lazy registration and runtime execution. */
export function describeBrowserTool(opts: {
targetDefault: "sandbox" | "host";
hostHint: string;
}): string {
return [
"Control the browser via OpenClaw's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/download/actions).",
"Browser choice: omit profile to use the configured default (normally the isolated OpenClaw-managed `openclaw` browser).",
"When existing logins/cookies matter, use action=profiles to inspect available profiles, then select the appropriate profile by name. Do not assume a profile name. Use only when the task requires an existing session and the user has authorized it.",
"For Chrome MCP existing-session profiles, omit timeoutMs on act:type, evaluate, hover, scrollIntoView, drag, select, and fill; that driver rejects per-call timeout overrides for those actions.",
'When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target="node".',
"When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc). For tab operations, targetId also accepts tabId handles (t1) and labels from action=tabs.",
"For multi-step browser work, login checks, stale refs, duplicate tabs, or Google Meet flows, use the bundled browser-automation skill when it is available.",
'For stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
"Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
"For file chooser uploads, pass the trigger ref with paths in the same upload call when available; use paths-only arming only when a later trigger is intentional. Use inputRef or element to set a file input directly.",
`target selects browser location (sandbox|host|node). Default: ${opts.targetDefault}.`,
opts.hostHint,
].join(" ");
}

View file

@ -503,7 +503,9 @@ describe("browser tool description", () => {
it("warns agents about existing-session act timeout limits", () => {
const tool = createBrowserTool();
expect(tool.description).toContain('profile="user"');
expect(tool.description).toContain("action=profiles");
expect(tool.description).toContain("Do not assume a profile name");
expect(tool.description).not.toContain('profile="user"');
expect(tool.description).toContain("omit timeoutMs on act:type");
expect(tool.description).toContain("existing-session profiles");
expect(tool.description).toContain("browser-automation skill");

View file

@ -5,6 +5,7 @@
* maps high-level actions onto browser control client calls.
*/
import crypto from "node:crypto";
import { describeBrowserTool } from "./browser-tool-description.js";
import {
executeActAction,
executeConsoleAction,
@ -514,20 +515,7 @@ export function createBrowserTool(opts?: {
return {
label: "Browser",
name: "browser",
description: [
"Control the browser via OpenClaw's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions).",
"Browser choice: omit profile by default for the isolated OpenClaw-managed browser (`openclaw`).",
'For the logged-in user browser, use profile="user". A supported Chromium-based browser (v144+) must be running on the selected host or browser node. Use only when existing logins/cookies matter and the user is present.',
'For profile="user" or other existing-session profiles, omit timeoutMs on act:type, evaluate, hover, scrollIntoView, drag, select, and fill; that driver rejects per-call timeout overrides for those actions.',
'When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target="node".',
"When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc). For tab operations, targetId also accepts tabId handles (t1) and labels from action=tabs.",
"For multi-step browser work, login checks, stale refs, duplicate tabs, or Google Meet flows, use the bundled browser-automation skill when it is available.",
'For stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
"Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
"For file chooser uploads, pass the trigger ref with paths in the same upload call when available; use paths-only arming only when a later trigger is intentional. Use inputRef or element to set a file input directly.",
`target selects browser location (sandbox|host|node). Default: ${targetDefault}.`,
hostHint,
].join(" "),
description: describeBrowserTool({ targetDefault, hostHint }),
parameters: BrowserToolSchema,
execute: async (_toolCallId, args) => {
const params = args as Record<string, unknown>;