{"version":3,"file":"agent/runner/tool-processor.mjs","sources":["webpack://@multimodal/agent/./src/agent/runner/tool-processor.ts"],"sourcesContent":["/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Agent } from '../agent';\nimport { ToolManager } from '../tool-manager';\nimport {\n  AgentEventStream,\n  Tool,\n  ToolCallResult,\n  JSONSchema7,\n  ChatCompletionMessageToolCall,\n} from '@multimodal/agent-interface';\nimport { getLogger } from '../../utils/logger';\nimport { zodToJsonSchema } from '../../utils';\n\n/**\n * ToolProcessor - Responsible for tool calls and processing\n *\n * This class handles the execution of tools, processing of tool results,\n * and managing tool-related state.\n */\nexport class ToolProcessor {\n  private logger = getLogger('ToolProcessor');\n\n  constructor(\n    private agent: Agent,\n    private toolManager: ToolManager,\n    private eventStream: AgentEventStream.Processor,\n  ) {}\n\n  /**\n   * Get all available tools\n   */\n  getTools(): Tool[] {\n    return this.toolManager.getTools();\n  }\n\n  /**\n   * Process a collection of tool calls\n   *\n   * @param toolCalls Array of tool calls to execute\n   * @param sessionId Session identifier\n   * @param abortSignal Optional signal to abort the execution\n   * @returns Array of tool call results\n   */\n  async processToolCalls(\n    toolCalls: ChatCompletionMessageToolCall[],\n    sessionId: string,\n    abortSignal?: AbortSignal,\n  ): Promise<ToolCallResult[]> {\n    // Check if operation was already aborted\n    if (abortSignal?.aborted) {\n      this.logger.info(`[Tool] Tool call processing aborted before starting`);\n      return this.createAbortedToolCallResults(toolCalls);\n    }\n\n    // Allow agent to intercept and potentially replace tool call execution\n    // This is essential for test mocking to avoid executing real tools\n    try {\n      const interceptedResults = await this.agent.onProcessToolCalls(sessionId, toolCalls);\n\n      // If the hook returned results, use them instead of executing tools\n      if (interceptedResults) {\n        this.logger.info(\n          `[Tool] Using intercepted tool call results for ${interceptedResults.length} tools`,\n        );\n\n        // Still create events for the intercepted results to maintain event stream consistency\n        for (let i = 0; i < interceptedResults.length; i++) {\n          const result = interceptedResults[i];\n          const toolCall = toolCalls[i];\n          const toolName = toolCall.function.name;\n          const toolCallId = toolCall.id;\n\n          // Parse arguments\n          let args = JSON.parse(toolCall.function.arguments || '{}');\n\n          // Trigger onBeforeToolCall hook\n          try {\n            args = await this.agent.onBeforeToolCall(\n              sessionId,\n              { toolCallId, name: toolName },\n              args,\n            );\n          } catch (hookError) {\n            this.logger.error(`[Hook] Error in onBeforeToolCall during interception: ${hookError}`);\n          }\n\n          // Create tool call event\n          const toolCallEvent = this.eventStream.createEvent('tool_call', {\n            toolCallId: toolCall.id,\n            name: toolName,\n            arguments: args,\n            startTime: Date.now(),\n            tool: {\n              name: toolName,\n              description: this.toolManager.getTool(toolName)?.description || 'Unknown tool',\n              schema: this.getToolSchema(this.toolManager.getTool(toolName)),\n            },\n          });\n          this.eventStream.sendEvent(toolCallEvent);\n\n          // Trigger onAfterToolCall hook\n          let content = result.content;\n          try {\n            content = await this.agent.onAfterToolCall(\n              sessionId,\n              { toolCallId, name: toolName },\n              content,\n            );\n            // Update the result content with possibly modified content from the hook\n            result.content = content;\n          } catch (hookError) {\n            this.logger.error(`[Hook] Error in onAfterToolCall during interception: ${hookError}`);\n          }\n\n          // Create tool result event\n          const toolResultEvent = this.eventStream.createEvent('tool_result', {\n            toolCallId: result.toolCallId,\n            name: result.toolName,\n            content: result.content,\n            elapsedMs: 0, // For intercepted calls, we don't track execution time\n            error: undefined,\n          });\n          this.eventStream.sendEvent(toolResultEvent);\n        }\n\n        return interceptedResults;\n      }\n    } catch (error) {\n      this.logger.error(`[Tool] Error in onProcessToolCalls hook: ${error}`);\n      // Continue with normal execution if hook fails\n    }\n\n    // If no interception, proceed with normal tool execution\n    // Collect results from all tool calls\n    const toolCallResults: ToolCallResult[] = [];\n\n    for (const toolCall of toolCalls) {\n      // Check if operation was aborted\n      if (abortSignal?.aborted) {\n        this.logger.info(`[Tool] Tool call processing aborted`);\n        break;\n      }\n\n      const toolName = toolCall.function.name;\n      const toolCallId = toolCall.id;\n\n      try {\n        // Parse arguments\n        let args = JSON.parse(toolCall.function.arguments || '{}');\n\n        try {\n          args = await this.agent.onBeforeToolCall(sessionId, { toolCallId, name: toolName }, args);\n        } catch (hookError) {\n          this.logger.error(`[Hook] Error in onBeforeToolCall: ${hookError}`);\n        }\n\n        // Create tool call event\n        const toolCallEvent = this.eventStream.createEvent('tool_call', {\n          toolCallId: toolCall.id,\n          name: toolName,\n          arguments: args,\n          startTime: Date.now(),\n          tool: {\n            name: toolName,\n            description: this.toolManager.getTool(toolName)?.description || 'Unknown tool',\n            schema: this.getToolSchema(this.toolManager.getTool(toolName)),\n          },\n        });\n        this.eventStream.sendEvent(toolCallEvent);\n\n        // Check again for abort before executing the tool\n        if (abortSignal?.aborted) {\n          this.logger.info(`[Tool] Tool execution aborted before execution: ${toolName}`);\n\n          // Create abort result event\n          const abortResultEvent = this.eventStream.createEvent('tool_result', {\n            toolCallId: toolCall.id,\n            name: toolName,\n            content: `Tool execution aborted`,\n            elapsedMs: 0,\n            error: 'aborted',\n          });\n          this.eventStream.sendEvent(abortResultEvent);\n\n          toolCallResults.push({\n            toolCallId: toolCall.id,\n            toolName,\n            content: `Tool execution aborted`,\n          });\n\n          continue;\n        }\n\n        // Execute the tool\n        // eslint-disable-next-line prefer-const\n        let { result, executionTime, error } = await this.toolManager.executeTool(\n          toolName,\n          toolCall.id,\n          args,\n        );\n\n        if (!error) {\n          try {\n            result = await this.agent.onAfterToolCall(\n              sessionId,\n              { toolCallId, name: toolName },\n              result,\n            );\n          } catch (hookError) {\n            this.logger.error(`[Hook] Error in onAfterToolCall: ${hookError}`);\n          }\n        }\n\n        // Create tool result event\n        const toolResultEvent = this.eventStream.createEvent('tool_result', {\n          toolCallId: toolCall.id,\n          name: toolName,\n          content: result,\n          elapsedMs: executionTime,\n          error,\n        });\n        this.eventStream.sendEvent(toolResultEvent);\n\n        // Add to results collection\n        toolCallResults.push({\n          toolCallId: toolCall.id,\n          toolName,\n          content: result,\n        });\n      } catch (error) {\n        // Don't log aborted requests as errors\n        if (abortSignal?.aborted) {\n          this.logger.info(`[Tool] Tool execution aborted: ${toolName}`);\n        } else {\n          this.logger.error(`[Tool] Error processing tool call: ${toolName} | ${error}`);\n        }\n\n        let errorResult;\n        try {\n          errorResult = await this.agent.onToolCallError(\n            sessionId,\n            { toolCallId, name: toolName },\n            error,\n          );\n        } catch (hookError) {\n          this.logger.error(`[Hook] Error in onToolCallError: ${hookError}`);\n          errorResult = `Error: ${error}`;\n        }\n\n        // Create error result event\n        const toolResultEvent = this.eventStream.createEvent('tool_result', {\n          toolCallId: toolCall.id,\n          name: toolName,\n          content: `Error: ${error}`,\n          elapsedMs: 0,\n          error: String(error),\n        });\n        this.eventStream.sendEvent(toolResultEvent);\n\n        toolCallResults.push({\n          toolCallId: toolCall.id,\n          toolName,\n          content: `Error: ${error}`,\n        });\n      }\n    }\n\n    return toolCallResults;\n  }\n\n  /**\n   * Create aborted tool call results for all tool calls\n   * Helper method to handle the abort case\n   */\n  private createAbortedToolCallResults(\n    toolCalls: ChatCompletionMessageToolCall[],\n  ): ToolCallResult[] {\n    return toolCalls.map((toolCall) => ({\n      toolCallId: toolCall.id,\n      toolName: toolCall.function.name,\n      content: `Tool execution aborted`,\n    }));\n  }\n\n  /**\n   * Get JSON schema for a tool\n   * @param tool The tool definition\n   * @returns JSON schema representation of the tool\n   */\n  private getToolSchema(tool?: Tool): JSONSchema7 {\n    if (!tool) return { type: 'object', properties: {} };\n    return tool.hasJsonSchema?.() ? (tool.schema as JSONSchema7) : zodToJsonSchema(tool.schema);\n  }\n}\n"],"names":["ToolProcessor","toolCalls","sessionId","abortSignal","interceptedResults","i","_this_toolManager_getTool","result","toolCall","toolName","toolCallId","args","JSON","hookError","toolCallEvent","Date","content","toolResultEvent","undefined","error","toolCallResults","_this_toolManager_getTool1","abortResultEvent","executionTime","String","tool","zodToJsonSchema","agent","toolManager","eventStream","getLogger"],"mappings":"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"}