route-claudecode
Version:
Advanced routing and transformation system for Claude Code outputs to multiple AI providers
160 lines • 5.83 kB
JavaScript
;
/**
* 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