UNPKG

route-claudecode

Version:

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

343 lines 13.6 kB
"use strict"; /** * OpenAI格式解析器 * 处理OpenAI API格式和兼容格式 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIFormatParser = void 0; const base_parser_1 = require("./base-parser"); class OpenAIFormatParser extends base_parser_1.BaseFormatParser { constructor() { super('openai'); } /** * 检测是否为OpenAI格式 */ canParse(data, context) { if (!data || typeof data !== 'object') { return false; } // OpenAI格式特征: // 1. 有choices数组 // 2. 有finish_reason字段 // 3. 没有content数组(Anthropic特征) // 4. 没有candidates数组(Gemini特征) const hasOpenAIChoices = data.choices && Array.isArray(data.choices); const hasAnthropicContent = data.content && Array.isArray(data.content); const hasGeminiCandidates = data.candidates && Array.isArray(data.candidates); const isOpenAI = hasOpenAIChoices && !hasAnthropicContent && !hasGeminiCandidates; console.log(`🔍 [OPENAI] Format detection:`, { hasOpenAIChoices, hasAnthropicContent, hasGeminiCandidates, isOpenAI, requestId: context.requestId }); return isOpenAI; } /** * 解析OpenAI格式的工具调用 */ parseToolCalls(data, context) { const toolCalls = []; let toolCount = 0; let confidence = 0.9; // OpenAI格式置信度较高 if (!data.choices || !Array.isArray(data.choices) || data.choices.length === 0) { const result = { hasTools: false, toolCount: 0, toolCalls: [], confidence: 1.0 }; this.validateParseResult(result, context); this.logParseResult(result, context); return result; } // 解析choices数组中的工具调用 for (const choice of data.choices) { if (!choice || typeof choice !== 'object') { continue; } // 检查message中的工具调用 if (choice.message) { // 新格式:tool_calls数组 if (choice.message.tool_calls && Array.isArray(choice.message.tool_calls)) { for (const toolCall of choice.message.tool_calls) { const parsedToolCall = this.parseOpenAIToolCall(toolCall, context); if (parsedToolCall) { toolCalls.push(parsedToolCall); toolCount++; } } } // 旧格式:function_call对象 if (choice.message.function_call) { const parsedToolCall = this.parseOpenAIFunctionCall(choice.message.function_call, context); if (parsedToolCall) { toolCalls.push(parsedToolCall); toolCount++; } } // 检查content中的文本工具调用 if (choice.message.content && typeof choice.message.content === 'string') { const textToolCalls = this.parseTextToolCalls(choice.message.content, context); toolCalls.push(...textToolCalls); toolCount += textToolCalls.length; if (textToolCalls.length > 0) { confidence = Math.min(confidence, 0.6); // 文本解析置信度更低 } } } // 检查delta中的工具调用(流式响应) if (choice.delta) { if (choice.delta.tool_calls && Array.isArray(choice.delta.tool_calls)) { for (const toolCall of choice.delta.tool_calls) { const parsedToolCall = this.parseOpenAIToolCall(toolCall, context); if (parsedToolCall) { toolCalls.push(parsedToolCall); toolCount++; } } } if (choice.delta.function_call) { const parsedToolCall = this.parseOpenAIFunctionCall(choice.delta.function_call, context); if (parsedToolCall) { toolCalls.push(parsedToolCall); toolCount++; } } } } const result = { hasTools: toolCount > 0, toolCount, toolCalls, finishReason: this.getFinishReason(data, context), confidence }; this.validateParseResult(result, context); this.logParseResult(result, context); return result; } /** * 解析OpenAI tool_call对象 */ parseOpenAIToolCall(toolCall, context) { if (!toolCall || typeof toolCall !== 'object') { return null; } if (!toolCall.id) { console.warn(`🚨 [OPENAI] Tool call missing id`, { requestId: context.requestId }); return null; } if (!toolCall.function || !toolCall.function.name) { console.warn(`🚨 [OPENAI] Tool call missing function name`, { id: toolCall.id, requestId: context.requestId }); return null; } let input = {}; if (toolCall.function.arguments) { try { input = typeof toolCall.function.arguments === 'string' ? JSON.parse(toolCall.function.arguments) : toolCall.function.arguments; } catch (error) { console.warn(`🚨 [OPENAI] Failed to parse tool call arguments`, { id: toolCall.id, arguments: toolCall.function.arguments, error: error instanceof Error ? error.message : String(error), requestId: context.requestId }); input = {}; // 不使用fallback,使用空对象 } } const result = { id: toolCall.id, name: toolCall.function.name, input, type: 'function_call' }; try { this.validateToolCall(result, context); return result; } catch (error) { console.warn(`🚨 [OPENAI] Tool call validation failed`, { toolCall: result, error: error instanceof Error ? error.message : String(error), requestId: context.requestId }); return null; } } /** * 解析OpenAI function_call对象(旧格式) */ parseOpenAIFunctionCall(functionCall, context) { if (!functionCall || typeof functionCall !== 'object') { return null; } if (!functionCall.name) { console.warn(`🚨 [OPENAI] Function call missing name`, { requestId: context.requestId }); return null; } let input = {}; if (functionCall.arguments) { try { input = typeof functionCall.arguments === 'string' ? JSON.parse(functionCall.arguments) : functionCall.arguments; } catch (error) { console.warn(`🚨 [OPENAI] Failed to parse function call arguments`, { name: functionCall.name, arguments: functionCall.arguments, error: error instanceof Error ? error.message : String(error), requestId: context.requestId }); input = {}; // 不使用fallback,使用空对象 } } const result = { id: `func_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, name: functionCall.name, input, type: 'function_call' }; try { this.validateToolCall(result, context); return result; } catch (error) { console.warn(`🚨 [OPENAI] Function call validation failed`, { functionCall: result, error: error instanceof Error ? error.message : String(error), requestId: context.requestId }); return null; } } /** * 从文本中解析工具调用(处理不规范格式) */ parseTextToolCalls(text, context) { const toolCalls = []; if (!text || typeof text !== 'string') { return toolCalls; } // 匹配各种工具调用模式 const patterns = [ // Tool call: FunctionName({...}) 格式 /Tool\s+call:\s*(\w+)\s*\((\{[^}]*\})\)/gi, // 函数调用格式 functionName({...}) /(\w+)\s*\(\s*(\{[^}]*\})\s*\)/gi, // JSON格式的函数调用 /\{\s*"function"\s*:\s*\{\s*"name"\s*:\s*"([^"]+)"\s*,\s*"arguments"\s*:\s*"([^"]+)"\s*\}\s*\}/gi ]; for (const pattern of patterns) { let match; while ((match = pattern.exec(text)) !== null) { try { let name; let input; if (pattern.source.includes('Tool\\s+call')) { // Tool call格式 name = match[1]; input = JSON.parse(match[2]); } else if (pattern.source.includes('"function"')) { // JSON格式 name = match[1]; input = JSON.parse(match[2]); } else { // 函数调用格式 name = match[1]; // 排除常见的非工具调用 if (['console', 'json', 'object', 'array', 'string', 'math', 'date'].includes(name.toLowerCase())) { continue; } input = JSON.parse(match[2]); } const toolCall = { id: `text_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, name, input, type: 'function_call' }; this.validateToolCall(toolCall, context); toolCalls.push(toolCall); } catch (error) { console.warn(`🚨 [OPENAI] Failed to parse text tool call: ${match[0]}`, { error: error instanceof Error ? error.message : String(error), requestId: context.requestId }); // 不抛出错误,继续解析其他工具调用 } } } return toolCalls; } /** * 获取OpenAI格式的finish reason */ getFinishReason(data, context) { if (!data || typeof data !== 'object') { return undefined; } if (!data.choices || !Array.isArray(data.choices) || data.choices.length === 0) { return undefined; } const choice = data.choices[0]; const finishReason = choice.finish_reason; if (finishReason === undefined || finishReason === null) { return undefined; } if (typeof finishReason !== 'string') { throw new Error(`OpenAI finish_reason must be string, got ${typeof finishReason}`); } // 检查fallback值 if (finishReason === 'unknown' || finishReason === 'default') { throw new Error(`OpenAI finish_reason has fallback value: ${finishReason} - violates zero fallback principle`); } console.log(`🎯 [OPENAI] Finish reason: ${finishReason}`, { requestId: context.requestId }); return finishReason; } /** * 修复OpenAI格式的finish reason */ fixFinishReason(data, targetReason, context) { if (!data || typeof data !== 'object') { throw new Error('OpenAI data is null or not object - cannot fix finish reason'); } if (!targetReason) { throw new Error('Target reason is required - violates zero fallback principle'); } // 检查目标值是否为fallback if (targetReason === 'unknown' || targetReason === 'default') { throw new Error(`Target reason is fallback value: ${targetReason} - violates zero fallback principle`); } if (!data.choices || !Array.isArray(data.choices)) { throw new Error('OpenAI data missing choices array - cannot fix finish reason'); } // 修复所有choices中的finish_reason for (const choice of data.choices) { if (choice && typeof choice === 'object') { const originalReason = choice.finish_reason; choice.finish_reason = targetReason; console.log(`🔧 [OPENAI] Fixed finish reason: ${originalReason} -> ${targetReason}`, { requestId: context.requestId }); } } return data; } } exports.OpenAIFormatParser = OpenAIFormatParser; //# sourceMappingURL=openai-parser.js.map