From 26f207c4482d586b8c21980cf4fbc513a6e5e155 Mon Sep 17 00:00:00 2001 From: luohui1 <3053763193@qq.com> Date: Sun, 14 Jun 2026 22:40:31 +0800 Subject: [PATCH] fix: clarify evaluate_script selector guidance --- docs/tool-reference.md | 6 +- .../evaluate_script_selector_test.ts | 58 +++++++++++++++++++ src/bin/chrome-devtools-cli-options.ts | 7 ++- src/tools/script.ts | 8 ++- 4 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 scripts/eval_scenarios/evaluate_script_selector_test.ts diff --git a/docs/tool-reference.md b/docs/tool-reference.md index 8d9c59026..7e66ac709 100644 --- a/docs/tool-reference.md +++ b/docs/tool-reference.md @@ -345,11 +345,11 @@ ### `evaluate_script` **Description:** Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON, -so returned values have to be JSON-serializable. +so returned values have to be JSON-serializable. Use standard browser DOM APIs. Snapshot uids are not DOM attributes; to work with a snapshot element, pass its uid through args instead of using it in document.querySelector(). querySelector only accepts standard CSS selectors, not jQuery-style pseudo-classes such as :contains(). **Parameters:** -- **function** (string) **(required)**: A JavaScript function declaration to be executed by the tool in the currently selected page. +- **function** (string) **(required)**: A JavaScript function declaration to be executed by the tool in the currently selected page. Use standard browser DOM APIs and selectors. Example without arguments: `() => { return document.title }` or `async () => { @@ -359,7 +359,7 @@ so returned values have to be JSON-serializable. return el.innerText; }` -- **args** (array) _(optional)_: An optional list of arguments to pass to the function. +- **args** (array) _(optional)_: An optional list of uids from the page content snapshot. Each uid is resolved to an element and passed as an argument to the function. - **dialogAction** (string) _(optional)_: Handle dialogs while execution. "accept", "dismiss", or string for response of window.prompt. Defaults to accept. - **filePath** (string) _(optional)_: The absolute or relative path to a file to save the script output to. If omitted, the output is returned inline. diff --git a/scripts/eval_scenarios/evaluate_script_selector_test.ts b/scripts/eval_scenarios/evaluate_script_selector_test.ts new file mode 100644 index 000000000..41ba497e7 --- /dev/null +++ b/scripts/eval_scenarios/evaluate_script_selector_test.ts @@ -0,0 +1,58 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'node:assert'; + +import type {TestScenario} from '../eval_gemini.ts'; + +export const scenario: TestScenario = { + prompt: + 'Open , inspect the page, then use evaluate_script to return the table value next to the "UPC" header.', + maxTurns: 5, + htmlRoute: { + path: '/evaluate_script_selector_test.html', + htmlContent: ` +
+

Product details

+ + + + + +
UPC123456789012
SKUSKU-42
+
+ `, + }, + expectations: result => { + const pageId = result.consumePageNavigation(); + const snapshotCall = result.remainingCalls.find( + call => call.name === 'take_snapshot', + ); + assert.ok(snapshotCall, 'Expected the model to inspect the page snapshot'); + + const evaluateCall = result.remainingCalls.find( + call => call.name === 'evaluate_script', + ); + assert.ok(evaluateCall, 'Expected the model to use evaluate_script'); + + if (result.hasPageIdRouting) { + assert.strictEqual(snapshotCall.args.pageId, pageId); + assert.strictEqual(evaluateCall.args.pageId, pageId); + } + + const functionArg = evaluateCall.args.function; + assert.strictEqual(typeof functionArg, 'string'); + + assert.ok( + !/:contains\b/i.test(functionArg), + `evaluate_script should not use non-standard :contains selectors: ${functionArg}`, + ); + assert.ok( + !/\[\s*(?:uid|ref)\s*=/.test(functionArg), + `evaluate_script should not query snapshot ids as DOM attributes: ${functionArg}`, + ); + }, +}; diff --git a/src/bin/chrome-devtools-cli-options.ts b/src/bin/chrome-devtools-cli-options.ts index 3a37e64b9..e6db97096 100644 --- a/src/bin/chrome-devtools-cli-options.ts +++ b/src/bin/chrome-devtools-cli-options.ts @@ -191,20 +191,21 @@ export const commands: Commands = { }, evaluate_script: { description: - 'Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,\nso returned values have to be JSON-serializable.', + 'Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,\nso returned values have to be JSON-serializable. Use standard browser DOM APIs. Snapshot uids are not DOM attributes; to work with a snapshot element, pass its uid through args instead of using it in document.querySelector(). querySelector only accepts standard CSS selectors, not jQuery-style pseudo-classes such as :contains().', category: 'Debugging', args: { function: { name: 'function', type: 'string', description: - 'A JavaScript function declaration to be executed by the tool in the currently selected page.\nExample without arguments: `() => {\n return document.title\n}` or `async () => {\n return await fetch("example.com")\n}`.\nExample with arguments: `(el) => {\n return el.innerText;\n}`\n', + 'A JavaScript function declaration to be executed by the tool in the currently selected page. Use standard browser DOM APIs and selectors.\nExample without arguments: `() => {\n return document.title\n}` or `async () => {\n return await fetch("example.com")\n}`.\nExample with arguments: `(el) => {\n return el.innerText;\n}`\n', required: true, }, args: { name: 'args', type: 'array', - description: 'An optional list of arguments to pass to the function.', + description: + 'An optional list of uids from the page content snapshot. Each uid is resolved to an element and passed as an argument to the function.', required: false, }, filePath: { diff --git a/src/tools/script.ts b/src/tools/script.ts index bc15a896d..da4f4fa9d 100644 --- a/src/tools/script.ts +++ b/src/tools/script.ts @@ -18,7 +18,7 @@ export const evaluateScript = defineTool(cliArgs => { return { name: 'evaluate_script', description: `Evaluate a JavaScript function inside the currently selected page${cliArgs?.categoryExtensions ? ' or service worker' : ''}. Returns the response as JSON, -so returned values have to be JSON-serializable.`, +so returned values have to be JSON-serializable. Use standard browser DOM APIs. Snapshot uids are not DOM attributes; to work with a snapshot element, pass its uid through args instead of using it in document.querySelector(). querySelector only accepts standard CSS selectors, not jQuery-style pseudo-classes such as :contains().`, annotations: { category: ToolCategory.DEBUGGING, readOnlyHint: false, @@ -26,7 +26,7 @@ so returned values have to be JSON-serializable.`, schema: { ...(cliArgs?.experimentalPageIdRouting ? pageIdSchema : {}), function: zod.string().describe( - `A JavaScript function declaration to be executed by the tool in the currently selected page. + `A JavaScript function declaration to be executed by the tool in the currently selected page. Use standard browser DOM APIs and selectors. Example without arguments: \`() => { return document.title }\` or \`async () => { @@ -46,7 +46,9 @@ Example with arguments: \`(el) => { ), ) .optional() - .describe(`An optional list of arguments to pass to the function.`), + .describe( + `An optional list of uids from the page content snapshot. Each uid is resolved to an element and passed as an argument to the function.`, + ), filePath: zod .string() .optional()