feat: improve lifecycle hooks API; wait a little after url change
This commit is contained in:
@@ -21,7 +21,7 @@ import {
|
||||
MacroToolInput,
|
||||
MacroToolResult,
|
||||
} from './types'
|
||||
import { normalizeResponse, trimLines, uid } from './utils'
|
||||
import { normalizeResponse, trimLines, uid, waitFor } from './utils'
|
||||
import { assert } from './utils/assert'
|
||||
|
||||
export { type PageAgentConfig }
|
||||
@@ -184,12 +184,12 @@ export class PageAgentCore extends EventTarget {
|
||||
this.tools.delete('ask_user')
|
||||
}
|
||||
|
||||
const onBeforeStep = this.config.onBeforeStep || (() => void 0)
|
||||
const onAfterStep = this.config.onAfterStep || (() => void 0)
|
||||
const onBeforeTask = this.config.onBeforeTask || (() => void 0)
|
||||
const onAfterTask = this.config.onAfterTask || (() => void 0)
|
||||
const onBeforeStep = this.config.onBeforeStep
|
||||
const onAfterStep = this.config.onAfterStep
|
||||
const onBeforeTask = this.config.onBeforeTask
|
||||
const onAfterTask = this.config.onAfterTask
|
||||
|
||||
await onBeforeTask.call(this)
|
||||
await onBeforeTask?.(this)
|
||||
|
||||
// Show mask
|
||||
await this.pageController.showMask()
|
||||
@@ -215,7 +215,7 @@ export class PageAgentCore extends EventTarget {
|
||||
while (true) {
|
||||
await this.#generateObservations(step)
|
||||
|
||||
await onBeforeStep.call(this, step)
|
||||
await onBeforeStep?.(this, step)
|
||||
|
||||
console.group(`step: ${step}`)
|
||||
|
||||
@@ -271,7 +271,7 @@ export class PageAgentCore extends EventTarget {
|
||||
console.log(chalk.green('Step finished:'), actionName)
|
||||
console.groupEnd()
|
||||
|
||||
await onAfterStep.call(this, this.history)
|
||||
await onAfterStep?.(this, this.history)
|
||||
|
||||
step++
|
||||
if (step > this.config.maxSteps) {
|
||||
@@ -281,7 +281,7 @@ export class PageAgentCore extends EventTarget {
|
||||
data: 'Step count exceeded maximum limit',
|
||||
history: this.history,
|
||||
}
|
||||
await onAfterTask.call(this, result)
|
||||
await onAfterTask?.(this, result)
|
||||
return result
|
||||
}
|
||||
if (actionName === 'done') {
|
||||
@@ -294,7 +294,7 @@ export class PageAgentCore extends EventTarget {
|
||||
data: text,
|
||||
history: this.history,
|
||||
}
|
||||
await onAfterTask.call(this, result)
|
||||
await onAfterTask?.(this, result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -308,7 +308,7 @@ export class PageAgentCore extends EventTarget {
|
||||
data: errorMessage,
|
||||
history: this.history,
|
||||
}
|
||||
await onAfterTask.call(this, result)
|
||||
await onAfterTask?.(this, result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -473,6 +473,7 @@ export class PageAgentCore extends EventTarget {
|
||||
if (currentURL !== this.states.lastURL) {
|
||||
this.pushObservation(`Page navigated to → ${currentURL}`)
|
||||
this.states.lastURL = currentURL
|
||||
await waitFor(500) // wait for page to stabilize
|
||||
}
|
||||
|
||||
// Warn about remaining steps
|
||||
@@ -584,6 +585,6 @@ export class PageAgentCore extends EventTarget {
|
||||
// Emit dispose event for UI cleanup
|
||||
this.dispatchEvent(new Event('dispose'))
|
||||
|
||||
this.config.onDispose?.call(this, reason)
|
||||
this.config.onDispose?.(this, reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,20 +69,52 @@ export interface AgentConfig {
|
||||
getPageInstructions?: (url: string) => string | undefined | null
|
||||
}
|
||||
|
||||
// lifecycle hooks
|
||||
// @todo: use event instead of hooks
|
||||
// @todo: remove `this` binding, pass agent as explicit parameter instead
|
||||
|
||||
onBeforeStep?: (this: PageAgentCore, stepCnt: number) => Promise<void> | void
|
||||
onAfterStep?: (this: PageAgentCore, history: HistoricalEvent[]) => Promise<void> | void
|
||||
onBeforeTask?: (this: PageAgentCore) => Promise<void> | void
|
||||
onAfterTask?: (this: PageAgentCore, result: ExecutionResult) => Promise<void> | void
|
||||
/**
|
||||
* Lifecycle hooks for task execution.
|
||||
* @experimental API may change in future versions.
|
||||
*
|
||||
* All hooks receive the agent instance as first parameter.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @note this hook can block the disposal process
|
||||
* @todo remove `this` binding, pass agent as explicit parameter instead
|
||||
* Called before each step execution.
|
||||
* @experimental
|
||||
* @param agent - The PageAgentCore instance
|
||||
* @param stepCount - Current step number (0-indexed)
|
||||
*/
|
||||
onDispose?: (this: PageAgentCore, reason?: string) => void
|
||||
onBeforeStep?: (agent: PageAgentCore, stepCount: number) => Promise<void> | void
|
||||
|
||||
/**
|
||||
* Called after each step execution.
|
||||
* @experimental
|
||||
* @param agent - The PageAgentCore instance
|
||||
* @param history - Current history of events
|
||||
*/
|
||||
onAfterStep?: (agent: PageAgentCore, history: HistoricalEvent[]) => Promise<void> | void
|
||||
|
||||
/**
|
||||
* Called before task execution starts.
|
||||
* @experimental
|
||||
* @param agent - The PageAgentCore instance
|
||||
*/
|
||||
onBeforeTask?: (agent: PageAgentCore) => Promise<void> | void
|
||||
|
||||
/**
|
||||
* Called after task execution completes (success or failure).
|
||||
* @experimental
|
||||
* @param agent - The PageAgentCore instance
|
||||
* @param result - The execution result
|
||||
*/
|
||||
onAfterTask?: (agent: PageAgentCore, result: ExecutionResult) => Promise<void> | void
|
||||
|
||||
/**
|
||||
* Called when the agent is disposed.
|
||||
* @experimental
|
||||
* @note This hook can block the disposal process if it's async.
|
||||
* @param agent - The PageAgentCore instance
|
||||
* @param reason - Optional reason for disposal
|
||||
*/
|
||||
onDispose?: (agent: PageAgentCore, reason?: string) => void
|
||||
|
||||
// page behavior hooks
|
||||
|
||||
@@ -109,21 +141,6 @@ export interface AgentConfig {
|
||||
* }
|
||||
*/
|
||||
transformPageContent?: (content: string) => Promise<string> | string
|
||||
|
||||
/**
|
||||
* TODO: @unimplemented
|
||||
* hook when action causes a new page to be opened
|
||||
* @note PageAgent will try to detect new pages and decide if it's caused by an action. But not very reliable.
|
||||
* @todo remove `this` binding, pass agent as explicit parameter instead
|
||||
*/
|
||||
// onNewPageOpen?: (this: PageAgent, url: string) => Promise<void> | void
|
||||
|
||||
/**
|
||||
* TODO: @unimplemented
|
||||
* try to navigate to a new page instead of opening a new tab/window.
|
||||
* @note will unload the current page when a action tries to open a new page. so that things keep in the same tab/window.
|
||||
*/
|
||||
// experimentalPreventNewPage?: boolean
|
||||
}
|
||||
|
||||
export type PageAgentConfig = LLMConfig & AgentConfig & PageControllerConfig
|
||||
|
||||
Reference in New Issue
Block a user