mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 11:58:34 +08:00
fix(tool): support top-level await in the browser eval action
This commit is contained in:
parent
c6d51f8ced
commit
d1b7e76f5b
@ -26,6 +26,7 @@ import java.nio.file.Paths;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 浏览器自动化工具
|
* 浏览器自动化工具
|
||||||
@ -98,7 +99,7 @@ public class BrowserUseTool {
|
|||||||
- screenshot: Take a screenshot. Optional path to save file; returns base64 if no path.
|
- screenshot: Take a screenshot. Optional path to save file; returns base64 if no path.
|
||||||
- click: Click an element. Requires selector (CSS selector).
|
- click: Click an element. Requires selector (CSS selector).
|
||||||
- type: Type text into an element. Requires selector and text.
|
- type: Type text into an element. Requires selector and text.
|
||||||
- eval: Execute JavaScript on the page. Requires code parameter.
|
- eval: Execute JavaScript on the page. Requires code parameter. Top-level await is supported; use `return` to surface a value.
|
||||||
- connect_cdp: Connect to an existing Chrome via CDP. Requires url (e.g. "http://localhost:9222").
|
- connect_cdp: Connect to an existing Chrome via CDP. Requires url (e.g. "http://localhost:9222").
|
||||||
- list_cdp_targets: Scan local ports (9000-10000) for CDP endpoints. Optional cdpPort for single port.
|
- list_cdp_targets: Scan local ports (9000-10000) for CDP endpoints. Optional cdpPort for single port.
|
||||||
- navigate_back: Go back in browser history.
|
- navigate_back: Go back in browser history.
|
||||||
@ -109,7 +110,7 @@ public class BrowserUseTool {
|
|||||||
@ToolParam(description = "URL to navigate to (for open), or CDP base URL (for connect_cdp, e.g. http://localhost:9222)", required = false) String url,
|
@ToolParam(description = "URL to navigate to (for open), or CDP base URL (for connect_cdp, e.g. http://localhost:9222)", required = false) String url,
|
||||||
@ToolParam(description = "CSS selector for target element (for click/type)", required = false) String selector,
|
@ToolParam(description = "CSS selector for target element (for click/type)", required = false) String selector,
|
||||||
@ToolParam(description = "Text to type (for action=type)", required = false) String text,
|
@ToolParam(description = "Text to type (for action=type)", required = false) String text,
|
||||||
@ToolParam(description = "JavaScript code to execute (for action=eval)", required = false) String code,
|
@ToolParam(description = "JavaScript code to execute (for action=eval). Top-level await is allowed; add `return` to return a value when the snippet uses await.", required = false) String code,
|
||||||
@ToolParam(description = "File path to save screenshot (for action=screenshot)", required = false) String path,
|
@ToolParam(description = "File path to save screenshot (for action=screenshot)", required = false) String path,
|
||||||
@ToolParam(description = "Launch visible browser window (for action=start, default false)", required = false) Boolean headed,
|
@ToolParam(description = "Launch visible browser window (for action=start, default false)", required = false) Boolean headed,
|
||||||
@ToolParam(description = "Single CDP port to scan (for action=list_cdp_targets)", required = false) Integer cdpPort,
|
@ToolParam(description = "Single CDP port to scan (for action=list_cdp_targets)", required = false) Integer cdpPort,
|
||||||
@ -642,6 +643,9 @@ public class BrowserUseTool {
|
|||||||
return JSONUtil.toJsonPrettyStr(result);
|
return JSONUtil.toJsonPrettyStr(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Detects the {@code await} keyword as a whole word to decide whether eval code needs an async wrapper. */
|
||||||
|
private static final Pattern TOP_LEVEL_AWAIT = Pattern.compile("\\bawait\\b");
|
||||||
|
|
||||||
private String doEval(String sessionKey, String code) {
|
private String doEval(String sessionKey, String code) {
|
||||||
if (code == null || code.isBlank()) {
|
if (code == null || code.isBlank()) {
|
||||||
return error("code is required for action=eval");
|
return error("code is required for action=eval");
|
||||||
@ -655,7 +659,13 @@ public class BrowserUseTool {
|
|||||||
session.touch();
|
session.touch();
|
||||||
Page page = session.page;
|
Page page = session.page;
|
||||||
|
|
||||||
Object evalResult = page.evaluate(code);
|
// Playwright evaluates the supplied string as a plain expression, which
|
||||||
|
// rejects top-level `await`. Wrap such snippets in an async IIFE so the
|
||||||
|
// agent can await promises; Playwright auto-resolves the returned one.
|
||||||
|
String script = TOP_LEVEL_AWAIT.matcher(code).find()
|
||||||
|
? "(async () => {" + code + "})()"
|
||||||
|
: code;
|
||||||
|
Object evalResult = page.evaluate(script);
|
||||||
String resultStr = evalResult != null ? evalResult.toString() : "null";
|
String resultStr = evalResult != null ? evalResult.toString() : "null";
|
||||||
|
|
||||||
if (resultStr.length() > 10_000) {
|
if (resultStr.length() > 10_000) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user