mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-05-01 06:36:23 +08:00
fix(browser): reject existing-session type timeouts
This commit is contained in:
@@ -30,7 +30,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Browser/tool: tell agents not to pass per-call `timeoutMs` on existing-session evaluate and other Chrome MCP actions that reject timeout overrides.
|
||||
- Browser/tool: tell agents not to pass per-call `timeoutMs` on existing-session type, evaluate, and other Chrome MCP actions that reject timeout overrides.
|
||||
- Voice-call/Telnyx: preserve inbound/outbound callback metadata and read transcription text from Telnyx's current `transcription_data` payload.
|
||||
- Codex harness: send verbose tool progress to chat channels for native app-server runs, matching the Pi harness `/verbose on` and `/verbose full` behavior. (#70966) Thanks @jalehman.
|
||||
- Codex models: fetch paginated Codex app-server model catalogs, mark truncated `/codex models` output, and keep ChatGPT OAuth defaults on the `openai-codex/gpt-5.5` route instead of the OpenAI API-key route.
|
||||
|
||||
@@ -482,6 +482,7 @@ Common signatures:
|
||||
- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP upload hooks need snapshot refs, not CSS selectors.
|
||||
- `existing-session file uploads currently support one file at a time.` → send one upload per call on Chrome MCP profiles.
|
||||
- `existing-session dialog handling does not support timeoutMs.` → dialog hooks on Chrome MCP profiles do not support timeout overrides.
|
||||
- `existing-session type does not support timeoutMs overrides.` → omit `timeoutMs` for `act:type` on `profile="user"` / Chrome MCP existing-session profiles, or use a managed/CDP browser profile when a custom timeout is required.
|
||||
- `existing-session evaluate does not support timeoutMs overrides.` → omit `timeoutMs` for `act:evaluate` on `profile="user"` / Chrome MCP existing-session profiles, or use a managed/CDP browser profile when a custom timeout is required.
|
||||
- `response body is not supported for existing-session profiles yet.` → `responsebody` still requires a managed browser or raw CDP profile.
|
||||
- stale viewport / dark-mode / locale / offline overrides on attach-only or remote CDP profiles → run `openclaw browser stop --browser-profile <name>` to close the active control session and release Playwright/CDP emulation state without restarting the whole gateway.
|
||||
|
||||
@@ -484,7 +484,7 @@ Notes:
|
||||
Compared to the managed `openclaw` profile, existing-session drivers are more constrained:
|
||||
|
||||
- **Screenshots** — page captures and `--ref` element captures work; CSS `--element` selectors do not. `--full-page` cannot combine with `--ref` or `--element`. Playwright is not required for page or ref-based element screenshots.
|
||||
- **Actions** — `click`, `type`, `hover`, `scrollIntoView`, `drag`, and `select` require snapshot refs (no CSS selectors). `click` is left-button only. `type` does not support `slowly=true`; use `fill` or `press`. `press` does not support `delayMs`. `hover`, `scrollIntoView`, `drag`, `select`, `fill`, and `evaluate` do not support per-call timeouts. `select` accepts a single value.
|
||||
- **Actions** — `click`, `type`, `hover`, `scrollIntoView`, `drag`, and `select` require snapshot refs (no CSS selectors). `click` is left-button only. `type` does not support `slowly=true`; use `fill` or `press`. `press` does not support `delayMs`. `type`, `hover`, `scrollIntoView`, `drag`, `select`, `fill`, and `evaluate` do not support per-call timeouts. `select` accepts a single value.
|
||||
- **Wait / upload / dialog** — `wait --url` supports exact, substring, and glob patterns; `wait --load networkidle` is not supported. Upload hooks require `ref` or `inputRef`, one file at a time, no CSS `element`. Dialog hooks do not support timeout overrides.
|
||||
- **Managed-only features** — batch actions, PDF export, download interception, and `responsebody` still require the managed browser path.
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ describe("browser tool description", () => {
|
||||
const tool = createBrowserTool();
|
||||
|
||||
expect(tool.description).toContain('profile="user"');
|
||||
expect(tool.description).toContain("omit timeoutMs on act:evaluate");
|
||||
expect(tool.description).toContain("omit timeoutMs on act:type");
|
||||
expect(tool.description).toContain("existing-session profiles");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -382,7 +382,7 @@ export function createBrowserTool(opts?: {
|
||||
"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:evaluate, hover, scrollIntoView, drag, select, and fill; that driver rejects per-call timeout overrides for those actions.',
|
||||
'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 stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
|
||||
|
||||
@@ -286,7 +286,7 @@ function getExistingSessionUnsupportedMessage(action: BrowserActRequest): string
|
||||
if (action.slowly) {
|
||||
return EXISTING_SESSION_LIMITS.act.typeSlowly;
|
||||
}
|
||||
return null;
|
||||
return action.timeoutMs ? EXISTING_SESSION_LIMITS.act.typeTimeout : null;
|
||||
case "press":
|
||||
return action.delayMs ? EXISTING_SESSION_LIMITS.act.pressDelay : null;
|
||||
case "hover":
|
||||
|
||||
@@ -12,6 +12,7 @@ const chromeMcpMocks = vi.hoisted(() => ({
|
||||
evaluateChromeMcpScript: vi.fn(
|
||||
async (_params: { profileName: string; targetId: string; fn: string }) => true,
|
||||
),
|
||||
fillChromeMcpElement: vi.fn(async () => {}),
|
||||
navigateChromeMcpPage: vi.fn(async ({ url }: { url: string }) => ({ url })),
|
||||
takeChromeMcpScreenshot: vi.fn(async () => Buffer.from("png")),
|
||||
takeChromeMcpSnapshot: vi.fn(async () => ({
|
||||
@@ -33,7 +34,7 @@ vi.mock("../chrome-mcp.js", () => ({
|
||||
closeChromeMcpTab: vi.fn(async () => {}),
|
||||
dragChromeMcpElement: vi.fn(async () => {}),
|
||||
evaluateChromeMcpScript: chromeMcpMocks.evaluateChromeMcpScript,
|
||||
fillChromeMcpElement: vi.fn(async () => {}),
|
||||
fillChromeMcpElement: chromeMcpMocks.fillChromeMcpElement,
|
||||
fillChromeMcpForm: vi.fn(async () => {}),
|
||||
hoverChromeMcpElement: vi.fn(async () => {}),
|
||||
navigateChromeMcpPage: chromeMcpMocks.navigateChromeMcpPage,
|
||||
@@ -109,6 +110,7 @@ describe("existing-session browser routes", () => {
|
||||
routeState.profileCtx.listTabs.mockClear();
|
||||
chromeMcpMocks.clickChromeMcpElement.mockClear();
|
||||
chromeMcpMocks.evaluateChromeMcpScript.mockReset();
|
||||
chromeMcpMocks.fillChromeMcpElement.mockClear();
|
||||
chromeMcpMocks.navigateChromeMcpPage.mockClear();
|
||||
chromeMcpMocks.takeChromeMcpScreenshot.mockClear();
|
||||
chromeMcpMocks.takeChromeMcpSnapshot.mockClear();
|
||||
@@ -238,6 +240,25 @@ describe("existing-session browser routes", () => {
|
||||
expect(chromeMcpMocks.evaluateChromeMcpScript).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("fails closed for existing-session type timeout overrides", async () => {
|
||||
const handler = getActPostHandler();
|
||||
const response = createBrowserRouteResponse();
|
||||
await handler?.(
|
||||
{
|
||||
params: {},
|
||||
query: {},
|
||||
body: { kind: "type", ref: "input-1", text: "hello", timeoutMs: 1234 },
|
||||
},
|
||||
response.res,
|
||||
);
|
||||
|
||||
expect(response.statusCode).toBe(501);
|
||||
expect(response.body).toMatchObject({
|
||||
error: expect.stringContaining("type does not support timeoutMs"),
|
||||
});
|
||||
expect(chromeMcpMocks.fillChromeMcpElement).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("supports glob URL waits for existing-session profiles", async () => {
|
||||
chromeMcpMocks.evaluateChromeMcpScript.mockReset();
|
||||
chromeMcpMocks.evaluateChromeMcpScript.mockImplementation(
|
||||
|
||||
@@ -5,6 +5,7 @@ export const EXISTING_SESSION_LIMITS = {
|
||||
"existing-session click currently supports left-click only (no button overrides/modifiers).",
|
||||
typeSelector: "existing-session type does not support selector targeting yet; use ref.",
|
||||
typeSlowly: "existing-session type does not support slowly=true; use fill/press instead.",
|
||||
typeTimeout: "existing-session type does not support timeoutMs overrides.",
|
||||
pressDelay: "existing-session press does not support delayMs.",
|
||||
hoverSelector: "existing-session hover does not support selector targeting yet; use ref.",
|
||||
hoverTimeout: "existing-session hover does not support timeoutMs overrides.",
|
||||
|
||||
Reference in New Issue
Block a user