{"version":3,"file":"agent/agents/base.mjs","sources":["webpack://@agent-infra/browser-use/./src/agent/agents/base.ts"],"sourcesContent":["/**\n * The following code is modified based on\n * https://github.com/nanobrowser/nanobrowser/blob/master/chrome-extension/src/background/agent/agents/base.ts\n *\n * Apache-2.0 License\n * Copyright (c) 2024 alexchenzl\n * https://github.com/nanobrowser/nanobrowser/blob/master/LICENSE\n */\nimport type { z } from 'zod';\nimport { jsonrepair } from 'jsonrepair';\nimport type {\n  BaseChatModel,\n  BaseChatModelCallOptions,\n} from '@langchain/core/language_models/chat_models';\nimport type { AgentContext, AgentOutput } from '../types';\nimport type { BasePrompt } from '../prompts/base';\nimport {\n  type BaseMessage,\n  AIMessage,\n  ToolMessage,\n} from '@langchain/core/messages';\nimport { createLogger } from '../../utils';\nimport type { Action } from '../actions/builder';\n\nconst logger = createLogger('agent');\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type CallOptions = BaseChatModelCallOptions;\n\n// Update options to use Zod schema\nexport interface BaseAgentOptions {\n  chatLLM: BaseChatModel;\n  context: AgentContext;\n  prompt: BasePrompt;\n}\nexport interface ExtraAgentOptions {\n  id?: string;\n  toolCallingMethod?: string;\n  callOptions?: Partial<CallOptions>;\n}\n\nconst THINK_TAGS = /<think>[\\s\\S]*?<\\/think>/;\n\n/**\n * Base class for all agents\n * @param T - The Zod schema for the model output\n * @param M - The type of the result field of the agent output\n */\nexport abstract class BaseAgent<T extends z.ZodType, M = unknown> {\n  protected id: string;\n  protected chatLLM: BaseChatModel;\n  protected prompt: BasePrompt;\n  protected context: AgentContext;\n  protected actions: Record<string, Action> = {};\n  protected modelOutputSchema: T;\n  protected toolCallingMethod: string | null;\n  protected chatModelLibrary: string;\n  protected modelName: string;\n  protected withStructuredOutput: boolean;\n  protected callOptions?: CallOptions;\n  protected modelOutputToolName: string;\n  declare ModelOutput: z.infer<T>;\n\n  constructor(\n    modelOutputSchema: T,\n    options: BaseAgentOptions,\n    extraOptions?: Partial<ExtraAgentOptions>,\n  ) {\n    // base options\n    this.modelOutputSchema = modelOutputSchema;\n    this.chatLLM = options.chatLLM;\n    this.prompt = options.prompt;\n    this.context = options.context;\n    this.chatModelLibrary = this.chatLLM.constructor.name;\n    this.modelName = this.setModelNames();\n    this.withStructuredOutput = this.setWithStructuredOutput();\n    // extra options\n    this.id = extraOptions?.id || 'agent';\n    this.toolCallingMethod = this.setToolCallingMethod(\n      extraOptions?.toolCallingMethod,\n    );\n    this.callOptions = extraOptions?.callOptions;\n    this.modelOutputToolName = `${this.id}_output`;\n  }\n\n  // Set the model name\n  private setModelNames(): string {\n    if ('model_name' in this.chatLLM) {\n      return this.chatLLM.model_name as string;\n    }\n    if ('model' in this.chatLLM) {\n      return this.chatLLM.model as string;\n    }\n    return 'Unknown';\n  }\n\n  // Set the tool calling method\n  private setToolCallingMethod(toolCallingMethod?: string): string | null {\n    if (toolCallingMethod === 'auto') {\n      switch (this.chatModelLibrary) {\n        case 'ChatGoogleGenerativeAI':\n          return null;\n        case 'ChatOpenAI':\n        case 'AzureChatOpenAI':\n          return 'function_calling';\n        default:\n          return null;\n      }\n    }\n    return toolCallingMethod || null;\n  }\n\n  // Set whether to use structured output based on the model name\n  private setWithStructuredOutput(): boolean {\n    if (\n      this.modelName === 'deepseek-reasoner' ||\n      this.modelName === 'deepseek-r1' ||\n      this.modelName.includes('claude')\n    ) {\n      return false;\n    }\n    return true;\n  }\n\n  // Remove think tags from the model output\n  protected removeThinkTags(text: string): string {\n    return text.replace(THINK_TAGS, '');\n  }\n\n  async invoke(inputMessages: BaseMessage[]): Promise<this['ModelOutput']> {\n    // Use structured output\n    if (this.withStructuredOutput) {\n      const structuredLlm = this.chatLLM.withStructuredOutput(\n        this.modelOutputSchema,\n        {\n          includeRaw: true,\n          name: this.modelOutputToolName,\n          strict: true,\n        },\n      );\n\n      const response = await structuredLlm.invoke(inputMessages, {\n        ...this.callOptions,\n      });\n      if (response.parsed) {\n        // @ts-ignore\n        return response.parsed;\n      }\n      throw new Error('Could not parse response');\n    }\n\n    // Without structured output support, need to extract JSON from model output manually\n    const response = await this.chatLLM.invoke(inputMessages, {\n      ...this.callOptions,\n    });\n    if (typeof response.content === 'string') {\n      response.content = this.removeThinkTags(response.content);\n      try {\n        const extractedJson = this.extractJsonFromModelOutput(response.content);\n        const parsed = this.validateModelOutput(extractedJson);\n        if (parsed) {\n          return parsed;\n        }\n      } catch (error) {\n        logger.error('Could not parse response', response);\n        throw new Error('Could not parse response');\n      }\n    }\n    throw new Error('Could not parse response');\n  }\n\n  // Execute the agent and return the result\n  abstract execute(): Promise<AgentOutput<M>>;\n\n  // Helper method to validate metadata\n  protected validateModelOutput(\n    data: unknown,\n  ): this['ModelOutput'] | undefined {\n    if (!this.modelOutputSchema || !data) return undefined;\n    return this.modelOutputSchema.parse(data);\n  }\n\n  // Add the model output to the memory\n  protected addModelOutputToMemory(modelOutput: this['ModelOutput']): void {\n    const messageManager = this.context.messageManager;\n    const toolCallId = String(messageManager.nextToolId());\n    const toolCalls = [\n      {\n        name: this.modelOutputToolName,\n        args: modelOutput,\n        id: toolCallId,\n        type: 'tool_call' as const,\n      },\n    ];\n\n    const toolCallMessage = new AIMessage({\n      content: 'tool call',\n      // @ts-ignore\n      tool_calls: toolCalls,\n    });\n    messageManager.addMessageWithTokens(toolCallMessage);\n\n    const toolMessage = new ToolMessage({\n      content: 'tool call response placeholder',\n      tool_call_id: toolCallId,\n    });\n    messageManager.addMessageWithTokens(toolMessage);\n  }\n\n  /**\n   * Extract JSON from raw string model output, handling both plain JSON and code-block-wrapped JSON.\n   *\n   * some models not supporting tool calls well like deepseek-reasoner, so we need to extract the JSON from the output\n   * @param content - The content of the model output\n   * @returns The JSON object\n   */\n  protected extractJsonFromModelOutput(content: string): unknown {\n    try {\n      let cleanedContent = content;\n      // If content is wrapped in code blocks, extract just the JSON part\n      if (content.includes('```')) {\n        // Find the JSON content between code blocks\n        cleanedContent = cleanedContent.split('```')[1];\n        // Remove language identifier if present (e.g., 'json\\n')\n        if (cleanedContent.includes('\\n')) {\n          cleanedContent = cleanedContent.split('\\n', 2)[1];\n        }\n      } else {\n        const jsonRegex = /(\\{(?:[^{}]|(?:\\{(?:[^{}]|(?:\\{[^{}]*\\}))*\\}))*\\})/;\n        const match = cleanedContent.match(jsonRegex);\n        if (match && match[1]) {\n          cleanedContent = match[1];\n        }\n      }\n\n      cleanedContent = jsonrepair(cleanedContent);\n\n      // Parse the cleaned content\n      return JSON.parse(cleanedContent);\n    } catch (e) {\n      logger.warning(`Failed to parse model output: ${content} ${e}`);\n      throw new Error('Could not parse response.');\n    }\n  }\n}\n"],"names":["logger","createLogger","THINK_TAGS","BaseAgent","toolCallingMethod","text","inputMessages","structuredLlm","response","Error","extractedJson","parsed","error","data","modelOutput","messageManager","toolCallId","String","toolCalls","toolCallMessage","AIMessage","toolMessage","ToolMessage","content","cleanedContent","jsonRegex","match","jsonrepair","JSON","e","modelOutputSchema","options","extraOptions"],"mappings":"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"}