UNPKG

route-claudecode

Version:

Advanced routing and transformation system for Claude Code outputs to multiple AI providers

160 lines 5.83 kB
"use strict"; /** * OpenAI专用Finish Reason修正器 * 专门处理OpenAI工具调用的finish_reason映射问题 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.openaiFinishReasonCorrector = exports.OpenAIFinishReasonCorrector = void 0; exports.correctOpenAIFinishReason = correctOpenAIFinishReason; exports.correctOpenAIStreamingFinishReason = correctOpenAIStreamingFinishReason; const logging_1 = require("../logging"); class OpenAIFinishReasonCorrector { logger; constructor(port) { this.logger = (0, logging_1.getLogger)(port); } /** * 修正OpenAI响应的finish_reason */ correctOpenAIFinishReason(response, requestId) { const choice = response.choices?.[0]; if (!choice) { return { originalReason: 'unknown', correctedReason: 'unknown', wasCorreted: false, hasToolCalls: false, toolCallsCount: 0 }; } const originalReason = choice.finish_reason; const hasToolCalls = this.detectToolCallsInChoice(choice); const toolCallsCount = this.countToolCalls(choice); let correctedReason = originalReason; let wasCorreted = false; // 核心修正逻辑:如果有工具调用但finish_reason不是tool_calls,进行修正 if (hasToolCalls && originalReason !== 'tool_calls') { correctedReason = 'tool_calls'; wasCorreted = true; // 应用修正 choice.finish_reason = correctedReason; this.logger.warn('OpenAI finish_reason corrected for tool calls', { originalReason, correctedReason, hasToolCalls, toolCallsCount, requestId }, requestId, 'openai-finish-reason-correction'); } return { originalReason, correctedReason, wasCorreted, hasToolCalls, toolCallsCount }; } /** * 修正流式响应的finish_reason */ correctStreamingFinishReason(chunk, hasToolCallsInStream, requestId) { const choice = chunk.choices?.[0]; if (!choice || !choice.finish_reason) { return { originalReason: 'none', correctedReason: 'none', wasCorreted: false, hasToolCalls: hasToolCallsInStream, toolCallsCount: 0 }; } const originalReason = choice.finish_reason; const hasToolCallsInChunk = choice.delta?.tool_calls?.length > 0; const hasToolCalls = hasToolCallsInStream || hasToolCallsInChunk; let correctedReason = originalReason; let wasCorreted = false; // 流式修正逻辑 if (hasToolCalls && originalReason === 'stop') { correctedReason = 'tool_calls'; wasCorreted = true; // 应用修正 choice.finish_reason = correctedReason; this.logger.debug('OpenAI streaming finish_reason corrected', { originalReason, correctedReason, hasToolCallsInStream, hasToolCallsInChunk, requestId }, requestId, 'openai-streaming-finish-reason-correction'); } return { originalReason, correctedReason, wasCorreted, hasToolCalls, toolCallsCount: hasToolCallsInChunk ? choice.delta.tool_calls.length : 0 }; } /** * 检测choice中是否包含工具调用 */ detectToolCallsInChoice(choice) { // 检查message.tool_calls if (choice.message?.tool_calls?.length > 0) { return true; } // 检查delta.tool_calls(流式响应) if (choice.delta?.tool_calls?.length > 0) { return true; } // 检查文本内容中的工具调用模式 const content = choice.message?.content || choice.delta?.content; if (content && typeof content === 'string') { return this.detectToolCallsInText(content); } return false; } /** * 检测文本中的工具调用模式 */ detectToolCallsInText(text) { const toolCallPatterns = [ /Tool\s+call:\s*\w+\s*\(/i, /\{\s*"type"\s*:\s*"tool_use"/i, /\{\s*"name"\s*:\s*"[^"]+",\s*"input"\s*:/i, /function_call/i, /\{\s*"id"\s*:\s*"call_[^"]+"/i ]; return toolCallPatterns.some(pattern => pattern.test(text)); } /** * 计算工具调用数量 */ countToolCalls(choice) { let count = 0; if (choice.message?.tool_calls?.length > 0) { count += choice.message.tool_calls.length; } if (choice.delta?.tool_calls?.length > 0) { count += choice.delta.tool_calls.length; } return count; } /** * 批量修正多个响应 */ batchCorrectFinishReasons(responses, requestId) { return responses.map(response => this.correctOpenAIFinishReason(response, requestId)); } } exports.OpenAIFinishReasonCorrector = OpenAIFinishReasonCorrector; // 导出单例 exports.openaiFinishReasonCorrector = new OpenAIFinishReasonCorrector(); // 便捷函数 function correctOpenAIFinishReason(response, requestId) { return exports.openaiFinishReasonCorrector.correctOpenAIFinishReason(response, requestId); } function correctOpenAIStreamingFinishReason(chunk, hasToolCallsInStream, requestId) { return exports.openaiFinishReasonCorrector.correctStreamingFinishReason(chunk, hasToolCallsInStream, requestId); } //# sourceMappingURL=openai-finish-reason-corrector.js.map