{"version":3,"file":"agent/runner/llm-processor.mjs","sources":["webpack://@multimodal/agent/./src/agent/runner/llm-processor.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Agent } from '../agent';\nimport { getLLMClient } from '../llm-client';\nimport { MessageHistory } from '../message-history';\nimport {\n  AgentEventStream,\n  PrepareRequestContext,\n  ChatCompletionChunk,\n  ChatCompletionCreateParams,\n  ToolCallEngine,\n  ChatCompletion,\n  AgentContextAwarenessOptions,\n  Tool,\n} from '@multimodal/agent-interface';\nimport {\n  ResolvedModel,\n  LLMReasoningOptions,\n  OpenAI,\n  ChatCompletionMessageToolCall,\n} from '@multimodal/model-provider';\nimport { getLogger } from '../../utils/logger';\nimport { ToolProcessor } from './tool-processor';\n\n/**\n * LLMProcessor - Responsible for LLM interaction\n *\n * This class handles preparing requests to the LLM, processing responses,\n * and managing streaming vs. non-streaming interactions.\n */\nexport class LLMProcessor {\n  private logger = getLogger('LLMProcessor');\n  private messageHistory: MessageHistory;\n  private llmClient?: OpenAI;\n\n  constructor(\n    private agent: Agent,\n    private eventStream: AgentEventStream.Processor,\n    private toolProcessor: ToolProcessor,\n    private reasoningOptions: LLMReasoningOptions,\n    private maxTokens?: number,\n    private temperature: number = 0.7,\n    private contextAwarenessOptions?: AgentContextAwarenessOptions,\n  ) {\n    this.messageHistory = new MessageHistory(\n      this.eventStream,\n      this.contextAwarenessOptions?.maxImagesCount,\n    );\n  }\n\n  /**\n   * Custom LLM client for testing or custom implementations\n   *\n   * @param llmClient - OpenAI-compatible llm client\n   */\n  public setCustomLLMClient(client: OpenAI): void {\n    this.llmClient = client;\n  }\n\n  /**\n   * Get the current LLM client (custom or created on demand)\n   *\n   * @returns The current OpenAI-compatible LLM client\n   */\n  public getCurrentLLMClient(): OpenAI | undefined {\n    return this.llmClient;\n  }\n\n  /**\n   * Process an LLM request for a single iteration\n   *\n   * @param resolvedModel The resolved model configuration\n   * @param systemPrompt The configured base system prompt\n   * @param toolCallEngine The tool call engine to use\n   * @param sessionId Session identifier\n   * @param streamingMode Whether to operate in streaming mode\n   * @param iteration Current iteration number for logging\n   * @param abortSignal Optional signal to abort the execution\n   */\n  async processRequest(\n    resolvedModel: ResolvedModel,\n    systemPrompt: string,\n    toolCallEngine: ToolCallEngine,\n    sessionId: string,\n    streamingMode: boolean,\n    iteration: number,\n    abortSignal?: AbortSignal,\n  ): Promise<void> {\n    // Check if operation was aborted\n    if (abortSignal?.aborted) {\n      this.logger.info(`[LLM] Request processing aborted`);\n      return;\n    }\n\n    // Create or reuse llm client\n    if (!this.llmClient) {\n      this.llmClient = getLLMClient(\n        resolvedModel,\n        this.reasoningOptions,\n        // Pass session ID to request interceptor hook\n        (provider, request, baseURL) => {\n          this.agent.onLLMRequest(sessionId, {\n            provider,\n            request,\n            baseURL,\n          });\n          // Currently we ignore any modifications to the request\n          return request;\n        },\n      );\n    }\n\n    // Allow the agent to perform any pre-iteration setup\n    try {\n      await this.agent.onEachAgentLoopStart(sessionId);\n      this.logger.debug(`[Agent] Pre-iteration hook executed for iteration ${iteration}`);\n    } catch (error) {\n      this.logger.error(`[Agent] Error in pre-iteration hook: ${error}`);\n    }\n\n    // Get available tools through the hook\n    let tools: Tool[];\n    try {\n      tools = await this.agent.getAvailableTools();\n      if (tools.length) {\n        this.logger.info(\n          `[Tools] Available: ${tools.length} | Names: ${tools.map((t) => t.name).join(', ')}`,\n        );\n      }\n    } catch (error) {\n      this.logger.error(`[Agent] Error getting available tools: ${error}`);\n      tools = [];\n    }\n\n    // Build messages for current iteration including enhanced system message\n    const messages = this.messageHistory.toMessageHistory(toolCallEngine, systemPrompt, tools);\n\n    this.logger.info(`[LLM] Requesting ${resolvedModel.provider}/${resolvedModel.id}`);\n\n    // Prepare request context\n    const prepareRequestContext: PrepareRequestContext = {\n      model: resolvedModel.id,\n      messages,\n      tools: tools,\n      temperature: this.temperature,\n    };\n\n    // Process the request\n    const startTime = Date.now();\n\n    await this.sendRequest(\n      resolvedModel,\n      prepareRequestContext,\n      sessionId,\n      toolCallEngine,\n      streamingMode,\n      abortSignal,\n    );\n\n    const duration = Date.now() - startTime;\n    this.logger.info(`[LLM] Response received | Duration: ${duration}ms`);\n  }\n\n  /**\n   * Send the actual request to the LLM and process the response\n   */\n  private async sendRequest(\n    resolvedModel: ResolvedModel,\n    context: PrepareRequestContext,\n    sessionId: string,\n    toolCallEngine: ToolCallEngine,\n    streamingMode: boolean,\n    abortSignal?: AbortSignal,\n  ): Promise<void> {\n    // Check if operation was aborted\n    if (abortSignal?.aborted) {\n      this.logger.info(`[LLM] Request sending aborted`);\n      return;\n    }\n\n    // Prepare the request using the tool call engine\n    const requestOptions = toolCallEngine.prepareRequest(context);\n\n    // Set max tokens limit\n    requestOptions.max_tokens = this.maxTokens;\n    // Always enable streaming internally for performance\n    requestOptions.stream = true;\n\n    // Use either the custom LLM client or create one using model resolver\n    this.logger.info(\n      `[LLM] Sending streaming request to ${resolvedModel.provider} | SessionId: ${sessionId}`,\n    );\n\n    // Make the streaming request with abort signal if available\n    const options: ChatCompletionCreateParams = { ...requestOptions };\n    const stream = (await this.llmClient!.chat.completions.create(options, {\n      signal: abortSignal,\n    })) as unknown as AsyncIterable<ChatCompletionChunk>;\n\n    await this.handleStreamingResponse(\n      stream,\n      resolvedModel,\n      sessionId,\n      toolCallEngine,\n      streamingMode,\n      abortSignal,\n    );\n  }\n\n  /**\n   * Handle streaming response from LLM\n   * Processes chunks, accumulates content, and handles tool calls\n   */\n  private async handleStreamingResponse(\n    stream: AsyncIterable<ChatCompletionChunk>,\n    resolvedModel: ResolvedModel,\n    sessionId: string,\n    toolCallEngine: ToolCallEngine,\n    streamingMode: boolean,\n    abortSignal?: AbortSignal,\n  ): Promise<void> {\n    // Collect all chunks for final onLLMResponse call\n    const allChunks: ChatCompletionChunk[] = [];\n\n    // Initialize stream processing state\n    const processingState = toolCallEngine.initStreamProcessingState();\n\n    // Generate a unique message ID to correlate streaming messages with final message\n    const messageId = `msg_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;\n\n    this.logger.info(`llm stream start`);\n\n    // Process each incoming chunk\n    for await (const chunk of stream) {\n      // Check if operation was aborted\n      if (abortSignal?.aborted) {\n        this.logger.info(`[LLM] Streaming response processing aborted`);\n        break;\n      }\n\n      allChunks.push(chunk);\n\n      // Process the chunk using the tool call engine\n      const chunkResult = toolCallEngine.processStreamingChunk(chunk, processingState);\n\n      // Only send streaming events in streaming mode\n      if (streamingMode) {\n        // Send reasoning content if any\n        if (chunkResult.reasoningContent) {\n          // Create thinking streaming event\n          const thinkingEvent = this.eventStream.createEvent(\n            'assistant_streaming_thinking_message',\n            {\n              content: chunkResult.reasoningContent,\n              isComplete: Boolean(processingState.finishReason),\n            },\n          );\n          this.eventStream.sendEvent(thinkingEvent);\n        }\n\n        // Only send content chunk if it contains actual content\n        if (chunkResult.content) {\n          // Create content streaming event with only the incremental content\n          const messageEvent = this.eventStream.createEvent('assistant_streaming_message', {\n            content: chunkResult.content, // Only send the incremental content, not accumulated\n            isComplete: Boolean(processingState.finishReason),\n            messageId: messageId, // Add the message ID to correlate with final message\n          });\n          this.eventStream.sendEvent(messageEvent);\n        }\n\n        // Tool call updates are handled separately and will be sent in the final assistant message\n        // We don't send partial tool calls in streaming events\n      }\n    }\n\n    // Check if operation was aborted after processing chunks\n    if (abortSignal?.aborted) {\n      this.logger.info(`[LLM] Streaming response processing aborted after chunks`);\n      return;\n    }\n\n    // Finalize the stream processing\n    const parsedResponse = toolCallEngine.finalizeStreamProcessing(processingState);\n\n    this.logger.infoWithData('Finalized Response', parsedResponse, JSON.stringify);\n\n    // Create the final events based on processed content\n    this.createFinalEvents(\n      parsedResponse.content || '',\n      parsedResponse.toolCalls || [],\n      parsedResponse.reasoningContent || '',\n      parsedResponse.finishReason || 'stop',\n      messageId, // Pass the message ID to final events\n    );\n\n    // Call response hooks with session ID\n    this.agent.onLLMResponse(sessionId, {\n      provider: resolvedModel.provider,\n      response: {\n        id: allChunks[0]?.id || '',\n        choices: [\n          {\n            index: 0,\n            message: {\n              role: 'assistant',\n              content: parsedResponse.content || '',\n              tool_calls: parsedResponse.toolCalls,\n              refusal: null,\n            },\n            finish_reason: parsedResponse.finishReason || 'stop',\n          },\n        ],\n        created: Date.now(),\n        model: resolvedModel.id,\n        object: 'chat.completion',\n      } as ChatCompletion,\n    });\n\n    this.agent.onLLMStreamingResponse(sessionId, {\n      provider: resolvedModel.provider,\n      chunks: allChunks,\n    });\n\n    this.logger.info(\n      `[LLM] Streaming response completed from ${resolvedModel.provider} | SessionId: ${sessionId}`,\n    );\n\n    // Process any tool calls\n    if (parsedResponse.toolCalls && parsedResponse.toolCalls.length > 0 && !abortSignal?.aborted) {\n      const toolNames = parsedResponse.toolCalls.map((tc) => tc.function?.name).join(', ');\n      this.logger.info(\n        `[Tools] LLM requested ${parsedResponse.toolCalls.length} tool executions: ${toolNames}`,\n      );\n\n      // Process each tool call\n      await this.toolProcessor.processToolCalls(parsedResponse.toolCalls, sessionId, abortSignal);\n    }\n  }\n\n  /**\n   * Create the final events from accumulated content\n   */\n  private createFinalEvents(\n    contentBuffer: string,\n    currentToolCalls: ChatCompletionMessageToolCall[],\n    reasoningBuffer: string,\n    finishReason: string,\n    messageId?: string,\n  ): void {\n    // If we have complete content, create a consolidated assistant message event\n    if (contentBuffer || currentToolCalls.length > 0) {\n      const assistantEvent = this.eventStream.createEvent('assistant_message', {\n        content: contentBuffer,\n        toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,\n        finishReason: finishReason,\n        messageId: messageId, // Include the message ID in the final message\n      });\n\n      this.eventStream.sendEvent(assistantEvent);\n    }\n\n    // If we have complete reasoning content, create a consolidated thinking message event\n    if (reasoningBuffer) {\n      const thinkingEvent = this.eventStream.createEvent('assistant_thinking_message', {\n        content: reasoningBuffer,\n        isComplete: true,\n      });\n\n      this.eventStream.sendEvent(thinkingEvent);\n    }\n  }\n}\n"],"names":["LLMProcessor","client","resolvedModel","systemPrompt","toolCallEngine","sessionId","streamingMode","iteration","abortSignal","getLLMClient","provider","request","baseURL","error","tools","t","messages","prepareRequestContext","startTime","Date","duration","context","requestOptions","options","stream","_allChunks_","allChunks","processingState","messageId","Math","chunk","chunkResult","thinkingEvent","Boolean","messageEvent","parsedResponse","JSON","toolNames","tc","_tc_function","contentBuffer","currentToolCalls","reasoningBuffer","finishReason","assistantEvent","undefined","agent","eventStream","toolProcessor","reasoningOptions","maxTokens","temperature","contextAwarenessOptions","_this_contextAwarenessOptions","getLogger","MessageHistory"],"mappings":"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"}