* external errors (pre-checks/config/hooks) will threw; * agent errors will be caught and added to history, and return a failed result
(task: string)
| 208 | * agent errors will be caught and added to history, and return a failed result |
| 209 | */ |
| 210 | async execute(task: string): Promise<ExecutionResult> { |
| 211 | // pre-checks |
| 212 | if (this.disposed) throw new Error('PageAgent has been disposed. Create a new instance.') |
| 213 | if (this.#status === 'running') throw new Error('A task is already running.') |
| 214 | if (!task) throw new Error('Task is required') |
| 215 | |
| 216 | this.task = task |
| 217 | this.taskId = uid() |
| 218 | |
| 219 | this.history = [] |
| 220 | this.#observations = [] |
| 221 | this.#states = { totalWaitTime: 0, lastURL: '', browserState: null } |
| 222 | this.#abortController = new AbortController() |
| 223 | const signal = this.#abortController.signal |
| 224 | |
| 225 | let resolveRunning!: () => void |
| 226 | this.#running = new Promise<void>((r) => (resolveRunning = r)) |
| 227 | |
| 228 | this.#setStatus('running') |
| 229 | this.#emitHistoryChange() |
| 230 | |
| 231 | // Disable ask_user tool if onAskUser is not set |
| 232 | if (!this.onAskUser) this.tools.delete('ask_user') |
| 233 | |
| 234 | const onBeforeStep = this.config.onBeforeStep |
| 235 | const onAfterStep = this.config.onAfterStep |
| 236 | const onBeforeTask = this.config.onBeforeTask |
| 237 | const onAfterTask = this.config.onAfterTask |
| 238 | const stepDelay = this.config.stepDelay ?? 0.4 |
| 239 | const maxSteps = this.config.maxSteps |
| 240 | |
| 241 | let step = 0 |
| 242 | let taskResult: ExecutionResult |
| 243 | let finalStatus: AgentStatus = 'error' |
| 244 | |
| 245 | await suppress(() => this.pageController.showMask()) |
| 246 | |
| 247 | // graceful exit |
| 248 | try { |
| 249 | await onBeforeTask?.(this) |
| 250 | |
| 251 | while (true) { |
| 252 | await onBeforeStep?.(this, step) |
| 253 | |
| 254 | // handle internal agent errors |
| 255 | try { |
| 256 | console.group(`step: ${step}`) |
| 257 | |
| 258 | // @note It's convenient to treat stepDelay as part of the next step. |
| 259 | // Maybe move it to a dedicated try block for better semantics? |
| 260 | if (step > 0) await waitFor(stepDelay, signal) |
| 261 | |
| 262 | signal.throwIfAborted() |
| 263 | |
| 264 | // observe |
| 265 | |
| 266 | console.log(chalk.blue.bold('👀 Observing...')) |
| 267 |
nothing calls this directly
no test coverage detected