123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- import { BaseAgent, type BaseAgentOptions, type ExtraAgentOptions } from './base';
- import { createLogger } from '@src/background/log';
- import { z } from 'zod';
- import type { AgentOutput } from '../types';
- import { HumanMessage } from '@langchain/core/messages';
- import { Actors, ExecutionState } from '../event/types';
- import {
- ChatModelAuthError,
- ChatModelForbiddenError,
- isAuthenticationError,
- isForbiddenError,
- LLM_FORBIDDEN_ERROR_MESSAGE,
- } from './errors';
- const logger = createLogger('PlannerAgent');
- // Define Zod schema for planner output
- export const plannerOutputSchema = z.object({
- observation: z.string(),
- challenges: z.string(),
- done: z.union([
- z.boolean(),
- z.string().transform(val => {
- if (val.toLowerCase() === 'true') return true;
- if (val.toLowerCase() === 'false') return false;
- throw new Error('Invalid boolean string');
- }),
- ]),
- next_steps: z.string(),
- reasoning: z.string(),
- web_task: z.union([
- z.boolean(),
- z.string().transform(val => {
- if (val.toLowerCase() === 'true') return true;
- if (val.toLowerCase() === 'false') return false;
- throw new Error('Invalid boolean string');
- }),
- ]),
- });
- export type PlannerOutput = z.infer<typeof plannerOutputSchema>;
- export class PlannerAgent extends BaseAgent<typeof plannerOutputSchema, PlannerOutput> {
- constructor(options: BaseAgentOptions, extraOptions?: Partial<ExtraAgentOptions>) {
- super(plannerOutputSchema, options, { ...extraOptions, id: 'planner' });
- }
- async execute(): Promise<AgentOutput<PlannerOutput>> {
- try {
- this.context.emitEvent(Actors.PLANNER, ExecutionState.STEP_START, 'Planning...');
- // get all messages from the message manager, state message should be the last one
- const messages = this.context.messageManager.getMessages();
- // Use full message history except the first one
- const plannerMessages = [this.prompt.getSystemMessage(), ...messages.slice(1)];
- // Remove images from last message if vision is not enabled for planner but vision is enabled
- if (!this.context.options.useVisionForPlanner && this.context.options.useVision) {
- const lastStateMessage = plannerMessages[plannerMessages.length - 1];
- let newMsg = '';
- if (Array.isArray(lastStateMessage.content)) {
- for (const msg of lastStateMessage.content) {
- if (msg.type === 'text') {
- newMsg += msg.text;
- }
- // Skip image_url messages
- }
- } else {
- newMsg = lastStateMessage.content;
- }
- plannerMessages[plannerMessages.length - 1] = new HumanMessage(newMsg);
- }
- const modelOutput = await this.invoke(plannerMessages);
- if (!modelOutput) {
- throw new Error('未能验证规划器输出');
- }
- this.context.emitEvent(Actors.PLANNER, ExecutionState.STEP_OK, modelOutput.next_steps);
- return {
- id: this.id,
- result: modelOutput,
- };
- } catch (error) {
- // Check if this is an authentication error
- if (isAuthenticationError(error)) {
- throw new ChatModelAuthError('Planner API鉴权失败。请验证您的API密钥', error);
- }
- if (isForbiddenError(error)) {
- throw new ChatModelForbiddenError(LLM_FORBIDDEN_ERROR_MESSAGE, error);
- }
- const errorMessage = error instanceof Error ? error.message : String(error);
- this.context.emitEvent(Actors.PLANNER, ExecutionState.STEP_FAIL, `策划失败: ${errorMessage}`);
- return {
- id: this.id,
- error: errorMessage,
- };
- }
- }
- }
|