validator.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { BaseAgent, type BaseAgentOptions, type ExtraAgentOptions } from './base';
  2. import { createLogger } from '@src/background/log';
  3. import { z } from 'zod';
  4. import { ActionResult, type AgentOutput } from '../types';
  5. import { Actors, ExecutionState } from '../event/types';
  6. import { HumanMessage } from '@langchain/core/messages';
  7. import {
  8. ChatModelAuthError,
  9. ChatModelForbiddenError,
  10. isAuthenticationError,
  11. isForbiddenError,
  12. LLM_FORBIDDEN_ERROR_MESSAGE,
  13. } from './errors';
  14. const logger = createLogger('ValidatorAgent');
  15. // Define Zod schema for validator output
  16. export const validatorOutputSchema = z.object({
  17. is_valid: z.union([
  18. z.boolean(),
  19. z.string().transform(val => {
  20. if (val.toLowerCase() === 'true') return true;
  21. if (val.toLowerCase() === 'false') return false;
  22. throw new Error('无效的布尔字符串');
  23. }),
  24. ]), // indicates if the output is correct
  25. reason: z.string(), // explains why it is valid or not
  26. answer: z.string(), // the final answer to the task if it is valid
  27. });
  28. export type ValidatorOutput = z.infer<typeof validatorOutputSchema>;
  29. export class ValidatorAgent extends BaseAgent<typeof validatorOutputSchema, ValidatorOutput> {
  30. // sometimes we need to validate the output against both the current browser state and the plan
  31. private plan: string | null = null;
  32. constructor(options: BaseAgentOptions, extraOptions?: Partial<ExtraAgentOptions>) {
  33. super(validatorOutputSchema, options, { ...extraOptions, id: 'validator' });
  34. }
  35. /**
  36. * Set the plan for the validator agent
  37. * @param plan - The plan to set
  38. */
  39. setPlan(plan: string | null): void {
  40. this.plan = plan;
  41. }
  42. /**
  43. * Executes the validator agent
  44. * @returns AgentOutput<ValidatorOutput>
  45. */
  46. async execute(): Promise<AgentOutput<ValidatorOutput>> {
  47. try {
  48. this.context.emitEvent(Actors.VALIDATOR, ExecutionState.STEP_START, 'Validating...');
  49. let stateMessage = await this.prompt.getUserMessage(this.context);
  50. if (this.plan) {
  51. // merge the plan and the state message
  52. const mergedMessage = new HumanMessage(`${stateMessage.content}\n\nThe current plan is: \n${this.plan}`);
  53. stateMessage = mergedMessage;
  54. }
  55. // logger.info('validator input', stateMessage);
  56. const systemMessage = this.prompt.getSystemMessage();
  57. const inputMessages = [systemMessage, stateMessage];
  58. const modelOutput = await this.invoke(inputMessages);
  59. if (!modelOutput) {
  60. throw new Error('验证任务结果失败');
  61. }
  62. logger.info('validator output', JSON.stringify(modelOutput, null, 2));
  63. if (!modelOutput.is_valid) {
  64. // need to update the action results so that other agents can see the error
  65. const msg = `答案还不正确。 ${modelOutput.reason}`;
  66. this.context.emitEvent(Actors.VALIDATOR, ExecutionState.STEP_FAIL, msg);
  67. this.context.actionResults = [new ActionResult({ extractedContent: msg, includeInMemory: true })];
  68. } else {
  69. this.context.emitEvent(Actors.VALIDATOR, ExecutionState.STEP_OK, modelOutput.answer);
  70. }
  71. return {
  72. id: this.id,
  73. result: modelOutput,
  74. };
  75. } catch (error) {
  76. // Check if this is an authentication error
  77. if (isAuthenticationError(error)) {
  78. throw new ChatModelAuthError('验证器API身份验证失败。请验证您的API密钥', error);
  79. }
  80. if (isForbiddenError(error)) {
  81. throw new ChatModelForbiddenError(LLM_FORBIDDEN_ERROR_MESSAGE, error);
  82. }
  83. const errorMessage = error instanceof Error ? error.message : String(error);
  84. logger.error(`验证失败: ${errorMessage}`);
  85. this.context.emitEvent(Actors.VALIDATOR, ExecutionState.STEP_FAIL, `验证失败: ${errorMessage}`);
  86. return {
  87. id: this.id,
  88. error: `验证失败: ${errorMessage}`,
  89. };
  90. }
  91. }
  92. }