mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +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.List;
|
||||
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.
|
||||
- click: Click an element. Requires selector (CSS selector).
|
||||
- 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").
|
||||
- list_cdp_targets: Scan local ports (9000-10000) for CDP endpoints. Optional cdpPort for single port.
|
||||
- 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 = "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 = "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 = "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,
|
||||
@ -642,6 +643,9 @@ public class BrowserUseTool {
|
||||
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) {
|
||||
if (code == null || code.isBlank()) {
|
||||
return error("code is required for action=eval");
|
||||
@ -655,7 +659,13 @@ public class BrowserUseTool {
|
||||
session.touch();
|
||||
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";
|
||||
|
||||
if (resultStr.length() > 10_000) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user