{"version":3,"file":"reflection/reflection-service.mjs","sources":["webpack://@multimodal/agent/./src/reflection/reflection-service.ts"],"sourcesContent":["/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { getLogger } from '../utils/logger';\nimport { Agent } from '../agent/agent';\nimport { ReflectionRequest, ReflectionResult } from './types';\nimport { ChatCompletionCreateParams } from '@multimodal/agent-interface';\n\n/**\n * ReflectionService - Provides self-reflection capabilities for agents\n *\n * This service evaluates whether an agent's response actually resolves the user's query\n * or indicates more work to be done. It helps prevent premature loop termination when\n * the agent itself indicates that additional steps are needed.\n */\nexport class ReflectionService {\n  private logger = getLogger('ReflectionService');\n\n  /**\n   * Perform reflection on an assistant message to determine if it should\n   * be the final response or if the agent loop should continue\n   *\n   * @param agent The agent instance that will perform the reflection\n   * @param request The reflection request parameters\n   * @returns Promise resolving to a reflection result with termination decision\n   */\n  async reflect(agent: Agent, request: ReflectionRequest): Promise<ReflectionResult> {\n    try {\n      // Get LLM client from agent\n      const llmClient = agent.getLLMClient();\n      if (!llmClient) {\n        this.logger.warn('No LLM client available for reflection, allowing termination');\n        return { finished: true };\n      }\n\n      const resolvedModel = agent.getCurrentResolvedModel();\n      if (!resolvedModel) {\n        this.logger.warn('No resolved model available for reflection, allowing termination');\n        return { finished: true };\n      }\n\n      // Extract the most recent user message content\n      const lastUserMessage = request.userMessages[request.userMessages.length - 1];\n      if (!lastUserMessage) {\n        this.logger.warn('No user message found for reflection, allowing termination');\n        return { finished: true };\n      }\n\n      const userContent =\n        typeof lastUserMessage.content === 'string'\n          ? lastUserMessage.content\n          : 'Complex multimodal query'; // Simplified handling for multimodal content\n\n      const assistantContent = request.assistantMessage.content || '';\n\n      // Create prompt for reflection\n      const messages = [\n        {\n          role: 'system' as const,\n          content: `You are a reflection engine that evaluates whether an assistant's response properly addresses the user's query. Your task is to analyze:\n1. If the assistant's message clearly indicates that MORE WORK NEEDS TO BE DONE but the conversation is about to end\n2. If the assistant mentions \"I'll\", \"I will\", \"I need to\", \"Let me\", followed by a task that wasn't completed\n3. If the assistant mentions using tools or performing actions that weren't executed\n\nRespond ONLY with a JSON object with these fields:\n- \"shouldContinue\": boolean (true if the loop should continue, false if it can terminate)\n- \"reason\": brief explanation of your decision\n- \"analysis\": detailed analysis of why the response is incomplete or complete\n\nFocus specifically on whether the assistant indicates pending tasks in its LAST response.`,\n        },\n        {\n          role: 'user' as const,\n          content: `USER QUERY:\n${userContent}\n\nASSISTANT'S FINAL RESPONSE:\n${assistantContent}\n\nShould the agent conversation continue or is this a complete response?`,\n        },\n      ];\n\n      // Call LLM with JSON response format\n      const params: ChatCompletionCreateParams = {\n        messages,\n        model: resolvedModel.id,\n        temperature: 0.2, // Lower temperature for more consistent reasoning\n        response_format: { type: 'json_object' },\n        max_tokens: 500,\n      };\n\n      this.logger.info(`[SessionId: ${request.sessionId}] Performing reflection check`);\n\n      // Make the LLM call with abort signal\n      const response = await llmClient.chat.completions.create(params, {\n        signal: request.abortSignal,\n      });\n\n      // Parse JSON response\n      try {\n        const content = response.choices[0]?.message?.content || '{\"shouldContinue\": false}';\n        const reflectionData = JSON.parse(content);\n\n        const result: ReflectionResult = {\n          finished: !reflectionData.shouldContinue,\n          message: reflectionData.reason,\n          analysis: reflectionData.analysis,\n        };\n\n        this.logger.info(\n          `[SessionId: ${request.sessionId}] Reflection result: ${result.finished ? 'Should terminate' : 'Should continue'}, reason: ${result.message || 'No reason provided'}`,\n        );\n\n        return result;\n      } catch (parseError) {\n        this.logger.error(`Failed to parse reflection response: ${parseError}`, response);\n        return { finished: true, message: 'Error in reflection process' };\n      }\n    } catch (error) {\n      // Handle errors gracefully\n      this.logger.error(`Reflection error: ${error}`);\n      if (request.abortSignal?.aborted) {\n        this.logger.info('Reflection aborted');\n      }\n\n      // Default to allowing termination on error\n      return {\n        finished: true,\n        message: `Error during reflection: ${error instanceof Error ? error.message : String(error)}`,\n      };\n    }\n  }\n}\n"],"names":["ReflectionService","agent","request","llmClient","resolvedModel","lastUserMessage","userContent","assistantContent","messages","params","response","_response_choices__message","content","reflectionData","JSON","result","parseError","error","_request_abortSignal","Error","String","getLogger"],"mappings":"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"}