2025-09-29 16:33:15 +08:00
/**
* Internal tools for PageAgent.
* @note Adapted from browser-use
*/
2025-10-17 18:43:41 +08:00
import zod , { type z } from 'zod'
2025-09-29 16:33:15 +08:00
2026-01-19 16:06:07 +08:00
import type { PageAgentCore } from '../PageAgentCore'
2025-12-05 16:18:01 +08:00
import { waitFor } from '../utils'
2025-09-29 16:33:15 +08:00
2025-10-17 18:43:41 +08:00
/**
* Internal tool definition that has access to PageAgent `this` context
*/
export interface PageAgentTool < TParams = any > {
// name: string
description : string
inputSchema : z.ZodType < TParams >
2026-01-19 16:06:07 +08:00
execute : ( this : PageAgentCore , args : TParams ) => Promise < string >
2025-10-17 18:43:41 +08:00
}
export function tool < TParams >( options : PageAgentTool < TParams >) : PageAgentTool < TParams > {
return options
}
2025-09-29 16:33:15 +08:00
/**
* Internal tools for PageAgent.
2025-10-17 18:43:41 +08:00
* Note: Using any to allow different parameter types for each tool
2025-09-29 16:33:15 +08:00
*/
2025-10-17 18:43:41 +08:00
export const tools = new Map < string , PageAgentTool >()
2025-09-29 16:33:15 +08:00
tools . set (
'done' ,
tool ({
description :
'Complete task - provide a summary of results for the user. Set success=True if task completed successfully, false otherwise. Text should be your response to the user summarizing results.' ,
inputSchema : zod.object ({
text : zod.string (),
success : zod.boolean (). default ( true ),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-09-29 16:33:15 +08:00
// @note main loop will handle this one
// this.onDone(input.text, input.success)
2025-10-17 18:43:41 +08:00
return Promise . resolve ( 'Task completed' )
2025-09-29 16:33:15 +08:00
},
})
)
tools . set (
'wait' ,
tool ({
description :
'Wait for x seconds. default 1s (max 10 seconds, min 1 second). This can be used to wait until the page or data is fully loaded.' ,
inputSchema : zod.object ({
seconds : zod.number (). min ( 1 ). max ( 10 ). default ( 1 ),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const lastTimeUpdate = await this . pageController . getLastUpdateTime ()
2025-09-29 16:33:15 +08:00
const actualWaitTime = Math . max ( 0 , input . seconds - ( Date . now () - lastTimeUpdate ) / 1000 )
console . log ( `actualWaitTime: ${ actualWaitTime } seconds` )
await waitFor ( actualWaitTime )
2026-01-15 20:17:50 +08:00
2026-01-15 20:28:39 +08:00
this . states . totalWaitTime += input . seconds
2026-01-15 20:17:50 +08:00
2026-01-15 20:28:39 +08:00
if ( this . states . totalWaitTime >= 3 ) {
2026-01-15 20:17:50 +08:00
this . pushObservation (
2026-01-15 20:28:39 +08:00
`You have waited ${ this . states . totalWaitTime } seconds accumulatively. Do NOT wait any longer unless you have a good reason.`
2026-01-15 20:17:50 +08:00
)
}
2025-12-05 16:18:01 +08:00
return `✅ Waited for ${ input . seconds } seconds.`
2025-09-29 16:33:15 +08:00
},
})
)
tools . set (
'ask_user' ,
tool ({
description :
'Ask the user a question and wait for their answer. Use this if you need more information or clarification.' ,
inputSchema : zod.object ({
question : zod.string (),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2026-01-17 23:14:26 +08:00
if ( ! this . onAskUser ) {
throw new Error ( 'ask_user tool requires onAskUser callback to be set' )
2026-01-17 17:24:17 +08:00
}
2026-01-17 23:14:26 +08:00
const answer = await this . onAskUser ( input . question )
return `User answered: ${ answer } `
2025-09-29 16:33:15 +08:00
},
})
)
tools . set (
'click_element_by_index' ,
tool ({
description : 'Click element by index' ,
inputSchema : zod.object ({
index : zod.int (). min ( 0 ),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const result = await this . pageController . clickElement ( input . index )
return result . message
2025-09-29 16:33:15 +08:00
},
})
)
tools . set (
'input_text' ,
tool ({
description : 'Click and input text into a input interactive element' ,
inputSchema : zod.object ({
index : zod.int (). min ( 0 ),
text : zod.string (),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const result = await this . pageController . inputText ( input . index , input . text )
return result . message
2025-09-29 16:33:15 +08:00
},
})
)
tools . set (
'select_dropdown_option' ,
tool ({
description :
'Select dropdown option for interactive element index by the text of the option you want to select' ,
inputSchema : zod.object ({
index : zod.int (). min ( 0 ),
text : zod.string (),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const result = await this . pageController . selectOption ( input . index , input . text )
return result . message
2025-09-29 16:33:15 +08:00
},
})
)
/**
* @note Reference from browser-use
*/
tools . set (
'scroll' ,
tool ({
description :
'Scroll the page by specified number of pages (set down=True to scroll down, down=False to scroll up, num_pages=number of pages to scroll like 0.5 for half page, 1.0 for one page, etc.). Optional index parameter to scroll within a specific element or its scroll container (works well for dropdowns and custom UI components). Optional pixels parameter to scroll by a specific number of pixels instead of pages.' ,
inputSchema : zod.object ({
down : zod.boolean (). default ( true ),
num_pages : zod.number (). min ( 0 ). max ( 10 ). optional (). default ( 0.1 ),
pixels : zod.number (). int (). min ( 0 ). optional (),
index : zod.number (). int (). min ( 0 ). optional (),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const result = await this . pageController . scroll ({
... input ,
numPages : input.num_pages ,
})
return result . message
2025-09-29 16:33:15 +08:00
},
})
)
tools . set (
'scroll_horizontally' ,
tool ({
description :
'Scroll the page or element horizontally (set right=True to scroll right, right=False to scroll left, pixels=number of pixels to scroll). Optional index parameter to scroll within a specific element or its scroll container (works well for wide tables).' ,
inputSchema : zod.object ({
right : zod.boolean (). default ( true ),
pixels : zod.number (). int (). min ( 0 ),
index : zod.number (). int (). min ( 0 ). optional (),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const result = await this . pageController . scrollHorizontally ( input )
return result . message
2025-09-29 16:33:15 +08:00
},
})
)
2025-10-23 19:59:17 +08:00
tools . set (
'execute_javascript' ,
tool ({
description :
'Execute JavaScript code on the current page. Supports async/await syntax. Use with caution!' ,
inputSchema : zod.object ({
script : zod.string (),
}),
2026-01-19 16:06:07 +08:00
execute : async function ( this : PageAgentCore , input ) {
2025-12-05 16:18:01 +08:00
const result = await this . pageController . executeJavascript ( input . script )
return result . message
2025-10-23 19:59:17 +08:00
},
})
)
2025-09-29 16:33:15 +08:00
// @todo get_dropdown_options
// @todo select_dropdown_option
// @todo send_keys
// @todo upload_file
// @todo go_back
// @todo extract_structured_data