feat: add lifecycle hooks for task and step events
This commit is contained in:
@@ -17,8 +17,9 @@ The development progress and future plans for PageAgent.
|
|||||||
- [x] **Free evaluation plan?**
|
- [x] **Free evaluation plan?**
|
||||||
- [x] **Custom actions and HITL**
|
- [x] **Custom actions and HITL**
|
||||||
- [ ] **Hooks and Events**
|
- [ ] **Hooks and Events**
|
||||||
- [x] **Step lifecycle**
|
- [x] **lifecycle**
|
||||||
- [ ] **Hijacking `page_open` event**
|
- [ ] **Pause and intervene**
|
||||||
|
- [ ] **Hijacking `page_open/page_change/page_unload` event**
|
||||||
- [ ] **Custom knowledge base and instructions**
|
- [ ] **Custom knowledge base and instructions**
|
||||||
- [ ] **Black/white-list safeguard**
|
- [ ] **Black/white-list safeguard**
|
||||||
- [ ] **Data-masking**
|
- [ ] **Data-masking**
|
||||||
|
|||||||
@@ -134,6 +134,13 @@ export class PageAgent extends EventTarget {
|
|||||||
if (!task) throw new Error('Task is required')
|
if (!task) throw new Error('Task is required')
|
||||||
this.task = task
|
this.task = task
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
await onBeforeTask.call(this, task)
|
||||||
|
|
||||||
// Show mask and panel
|
// Show mask and panel
|
||||||
this.mask.show()
|
this.mask.show()
|
||||||
|
|
||||||
@@ -142,7 +149,7 @@ export class PageAgent extends EventTarget {
|
|||||||
|
|
||||||
this.bus.emit('panel:update', {
|
this.bus.emit('panel:update', {
|
||||||
type: 'input',
|
type: 'input',
|
||||||
displayText: task,
|
displayText: this.task,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.#abortController) {
|
if (this.#abortController) {
|
||||||
@@ -156,7 +163,7 @@ export class PageAgent extends EventTarget {
|
|||||||
let step = 0
|
let step = 0
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.config.onBeforeStep) await this.config.onBeforeStep.call(this, step)
|
await onBeforeStep.call(this, step)
|
||||||
|
|
||||||
console.group(`step: ${step + 1}`)
|
console.group(`step: ${step + 1}`)
|
||||||
|
|
||||||
@@ -211,37 +218,43 @@ export class PageAgent extends EventTarget {
|
|||||||
console.log(chalk.green('Step finished:'), actionName)
|
console.log(chalk.green('Step finished:'), actionName)
|
||||||
console.groupEnd()
|
console.groupEnd()
|
||||||
|
|
||||||
if (this.config.onAfterStep) await this.config.onAfterStep.call(this, step, this.history)
|
await onAfterStep.call(this, step, this.history)
|
||||||
|
|
||||||
step++
|
step++
|
||||||
if (step > MAX_STEPS) {
|
if (step > MAX_STEPS) {
|
||||||
this.#onDone('Step count exceeded maximum limit', false)
|
this.#onDone('Step count exceeded maximum limit', false)
|
||||||
return {
|
const result: ExecutionResult = {
|
||||||
success: false,
|
success: false,
|
||||||
data: 'Step count exceeded maximum limit',
|
data: 'Step count exceeded maximum limit',
|
||||||
history: this.history,
|
history: this.history,
|
||||||
}
|
}
|
||||||
|
await onAfterTask.call(this, task, result)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
if (actionName === 'done') {
|
if (actionName === 'done') {
|
||||||
const success = action.input?.success ?? false
|
const success = action.input?.success ?? false
|
||||||
const text = action.input?.text || 'no text provided'
|
const text = action.input?.text || 'no text provided'
|
||||||
console.log(chalk.green.bold('Task completed'), success, text)
|
console.log(chalk.green.bold('Task completed'), success, text)
|
||||||
this.#onDone(text, success)
|
this.#onDone(text, success)
|
||||||
return {
|
const result: ExecutionResult = {
|
||||||
success,
|
success,
|
||||||
data: text,
|
data: text,
|
||||||
history: this.history,
|
history: this.history,
|
||||||
}
|
}
|
||||||
|
await onAfterTask.call(this, task, result)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error('Task failed', error)
|
console.error('Task failed', error)
|
||||||
this.#onDone(String(error), false)
|
this.#onDone(String(error), false)
|
||||||
return {
|
const result: ExecutionResult = {
|
||||||
success: false,
|
success: false,
|
||||||
data: String(error),
|
data: String(error),
|
||||||
history: this.history,
|
history: this.history,
|
||||||
}
|
}
|
||||||
|
await onAfterTask.call(this, task, result)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { AgentHistory, PageAgent } from '@/PageAgent'
|
import type { AgentHistory, ExecutionResult, PageAgent } from '@/PageAgent'
|
||||||
import type { DomConfig } from '@/dom'
|
import type { DomConfig } from '@/dom'
|
||||||
import type { SupportedLanguage } from '@/i18n'
|
import type { SupportedLanguage } from '@/i18n'
|
||||||
import type { PageAgentTool } from '@/tools'
|
import type { PageAgentTool } from '@/tools'
|
||||||
@@ -32,6 +32,7 @@ export interface UIConfig {
|
|||||||
* @see [tools](../tools/index.ts)
|
* @see [tools](../tools/index.ts)
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
* // override internal tool
|
||||||
* import { tool } from 'page-agent'
|
* import { tool } from 'page-agent'
|
||||||
* const customTools = {
|
* const customTools = {
|
||||||
* ask_user: tool({
|
* ask_user: tool({
|
||||||
@@ -46,13 +47,25 @@ export interface UIConfig {
|
|||||||
* },
|
* },
|
||||||
* })
|
* })
|
||||||
* }
|
* }
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // remove internal tool
|
||||||
|
* const customTools = {
|
||||||
|
* ask_user: null // never ask user questions
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
customTools?: Record<string, PageAgentTool | null>
|
customTools?: Record<string, PageAgentTool | null>
|
||||||
|
|
||||||
// hooks
|
// lifecycle hooks
|
||||||
|
|
||||||
onBeforeStep?: (this: PageAgent, stepCnt: number) => Promise<void> | void
|
onBeforeStep?: (this: PageAgent, stepCnt: number) => Promise<void> | void
|
||||||
onAfterStep?: (this: PageAgent, stepCnt: number, history: AgentHistory[]) => Promise<void> | void
|
onAfterStep?: (this: PageAgent, stepCnt: number, history: AgentHistory[]) => Promise<void> | void
|
||||||
|
onBeforeTask?: (this: PageAgent, task: string) => Promise<void> | void
|
||||||
|
onAfterTask?: (this: PageAgent, task: string, result: ExecutionResult) => Promise<void> | void
|
||||||
|
|
||||||
|
// page behavior hooks
|
||||||
|
|
||||||
|
onPageUnload?: (this: PageAgent) => Promise<void> | void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PageAgentConfig = LLMConfig & DomConfig & UIConfig
|
export type PageAgentConfig = LLMConfig & DomConfig & UIConfig
|
||||||
|
|||||||
Reference in New Issue
Block a user