Merge pull request #545 from alibaba/feat/execute-js-abort-signal
feat(core): make execute_javascript honor AbortSignal
This commit is contained in:
@@ -181,12 +181,15 @@ tools.set(
|
|||||||
'execute_javascript',
|
'execute_javascript',
|
||||||
tool({
|
tool({
|
||||||
description:
|
description:
|
||||||
'Execute JavaScript code on the current page. Supports async/await syntax. Use with caution!',
|
'Execute JavaScript code on the current page. Supports async/await syntax. Use with caution! ' +
|
||||||
|
'An `AbortSignal` named `signal` is available in scope: long-running async code MUST honor it ' +
|
||||||
|
'(e.g. `await fetch(url, { signal })`, or `signal.throwIfAborted()` in loops)',
|
||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
script: z.string(),
|
script: z.string(),
|
||||||
}),
|
}),
|
||||||
execute: async function (this: PageAgentCore, input) {
|
execute: async function (this: PageAgentCore, input, { signal }) {
|
||||||
const result = await this.pageController.executeJavascript(input.script)
|
const result = await this.pageController.executeJavascript(input.script, signal)
|
||||||
|
signal.throwIfAborted()
|
||||||
return result.message
|
return result.message
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ export class MultiPageAgent extends PageAgentCore {
|
|||||||
|
|
||||||
super({
|
super({
|
||||||
...config,
|
...config,
|
||||||
|
// Disabled: AbortSignal cannot cross contexts
|
||||||
|
experimentalScriptExecutionTool: false,
|
||||||
pageController: pageController as any,
|
pageController: pageController as any,
|
||||||
customTools: customTools,
|
customTools: customTools,
|
||||||
customSystemPrompt: systemPrompt,
|
customSystemPrompt: systemPrompt,
|
||||||
|
|||||||
@@ -133,9 +133,7 @@ export class RemotePageController {
|
|||||||
return this.remoteCallDomAction('scroll_horizontally', args)
|
return this.remoteCallDomAction('scroll_horizontally', args)
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeJavascript(...args: any[]): Promise<DomActionReturn> {
|
// `execute_javascript` is intentionally not implemented: AbortSignal cannot cross context
|
||||||
return this.remoteCallDomAction('execute_javascript', args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @note Managed by content script via storage polling. */
|
/** @note Managed by content script via storage polling. */
|
||||||
async showMask(): Promise<void> {}
|
async showMask(): Promise<void> {}
|
||||||
|
|||||||
@@ -376,13 +376,15 @@ export class PageController extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute arbitrary JavaScript on the page
|
* Execute arbitrary JavaScript on the page.
|
||||||
|
* The optional `signal` is exposed to the script scope so cooperative code
|
||||||
|
* can abort promptly when the task is stopped.
|
||||||
*/
|
*/
|
||||||
async executeJavascript(script: string): Promise<ActionResult> {
|
async executeJavascript(script: string, signal?: AbortSignal): Promise<ActionResult> {
|
||||||
try {
|
try {
|
||||||
// Wrap script in async function to support await
|
// Wrap script in async function to support await, exposing `signal`.
|
||||||
const asyncFunction = eval(`(async () => { ${script} })`)
|
const asyncFunction = eval(`(async (signal) => { ${script} })`)
|
||||||
const result = await asyncFunction()
|
const result = await asyncFunction(signal)
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `✅ Executed JavaScript. Result: ${result}`,
|
message: `✅ Executed JavaScript. Result: ${result}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user