UNPKG

route-claudecode

Version:

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

391 lines 15.2 kB
"use strict"; /** * CodeWhisperer Request Converter - 重构优化版本 * 基于demo2兼容性设计,消除硬编码和优化性能 * 项目所有者: Jason Zhang */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CodeWhispererConverter = void 0; const uuid_1 = require("uuid"); const logger_1 = require("@/utils/logger"); const types_1 = require("./types"); class CodeWhispererConverter { config; fallbackContent = 'answer for user qeustion'; // 保持demo2原始拼写错误 constructor(config) { this.config = config || (0, types_1.createCodeWhispererConfig)(); if (!(0, types_1.validateConfig)(this.config)) { throw new Error('无效的CodeWhisperer配置'); } logger_1.logger.debug('CodeWhispererConverter初始化完成', { endpoint: this.config.endpoint, origin: this.config.origin, }); } /** * 提取消息文本内容 - 优化版本 */ extractMessageContent(content) { // 快速路径:字符串类型 if (typeof content === 'string') { return content.length === 0 ? this.fallbackContent : content; } // 数组类型处理 if (Array.isArray(content)) { return this.processContentBlocks(content); } // 其他类型处理 return this.handleUnknownContent(content); } /** * 处理内容块数组 */ processContentBlocks(content) { const texts = []; for (const block of content) { if (typeof block === 'string') { texts.push(block); continue; } if (this.isValidContentBlock(block)) { const text = this.extractTextFromBlock(block); if (text) texts.push(text); } } return texts.length > 0 ? texts.join('\n') : this.fallbackContent; } /** * 验证内容块有效性 */ isValidContentBlock(block) { return block && typeof block === 'object' && 'type' in block; } /** * 从内容块提取文本 */ extractTextFromBlock(block) { switch (block.type) { case 'tool_result': return block.content || null; case 'text': return block.text || null; default: return null; } } /** * 处理未知内容类型 */ handleUnknownContent(content) { try { const jsonStr = JSON.stringify(content); logger_1.logger.debug('未知消息内容格式', { contentType: typeof content, content: jsonStr.substring(0, 200) // 只记录前200字符 }); return this.fallbackContent; } catch (error) { logger_1.logger.warn('内容序列化失败', { error: error instanceof Error ? error.message : String(error) }); return this.fallbackContent; } } /** * 构建CodeWhisperer请求 - 重构优化版本 */ async buildCodeWhispererRequest(anthropicReq, profileArn, authMethod) { const debugInfo = this.createDebugInfo(anthropicReq); logger_1.logger.debug('开始构建CodeWhisperer请求', debugInfo); // 获取最后一条消息内容 const lastMessage = anthropicReq.messages[anthropicReq.messages.length - 1]; const messageContent = this.extractMessageContent(lastMessage.content); // 构建基础请求结构 const cwReq = { conversationState: { chatTriggerType: this.config.chatTriggerType, conversationId: (0, uuid_1.v4)(), currentMessage: { userInputMessage: { content: messageContent, modelId: anthropicReq.model, // 路由引擎已完成模型映射 origin: this.config.origin, userInputMessageContext: { // 🔑 关键:demo2兼容性 - 必须为空对象 }, }, }, history: [], }, // ✅ 修复:初始化时设置空字符串,后面根据authMethod条件更新 profileArn: '', }; // 🔧 关键修复:CodeWhisperer支持工具调用,正确转换工具定义 // 完全按照demo3的逻辑:toolsContext包装 + 条件检查 let toolsContext = {}; if (anthropicReq.tools && Array.isArray(anthropicReq.tools) && anthropicReq.tools.length > 0) { const convertedTools = this.convertTools(anthropicReq.tools); toolsContext = { tools: convertedTools }; } // 🚨 关键修复:按照demo3的精确结构,只设置tools字段 // 根据对比测试发现,Demo3不包含toolResults字段,这是导致400错误的原因! const contextData = {}; if (Object.keys(toolsContext).length > 0 && toolsContext.tools) { contextData.tools = toolsContext.tools; } // 直接设置整个userInputMessageContext,完全匹配demo3结构 cwReq.conversationState.currentMessage.userInputMessage.userInputMessageContext = contextData; logger_1.logger.debug('工具字段设置完成 (demo3精确结构匹配)', { hasTools: !!(anthropicReq.tools && anthropicReq.tools.length > 0), toolsContextKeys: Object.keys(toolsContext), contextDataKeys: Object.keys(contextData), toolsFieldValue: contextData.tools, strategy: 'demo3-exact-structure-no-toolResults' }); // 构建历史消息 - 优化版本 const hasHistory = this.shouldBuildHistory(anthropicReq); if (hasHistory) { cwReq.conversationState.history = this.buildMessageHistory(anthropicReq); } // 🚨 关键修复:按照demo3的逻辑,只有当authMethod为'social'时才添加profileArn // 这是导致400错误的根本原因! if (authMethod === 'social') { cwReq.profileArn = profileArn; logger_1.logger.debug('添加profileArn到请求根级别 (authMethod=social)', { authMethod, profileArn: profileArn ? profileArn.substring(0, 50) + '...' : 'undefined', strategy: 'demo3-conditional-logic' }); } else { // ✅ 修复:明确设置profileArn为undefined,与demo3逻辑完全一致 cwReq.profileArn = undefined; logger_1.logger.debug('设置profileArn为undefined (authMethod!=social)', { authMethod, strategy: 'demo3-exact-match' }); } const buildResult = this.createBuildResult(cwReq); logger_1.logger.debug('CodeWhisperer请求构建完成', buildResult); return cwReq; } /** * 转换工具定义到 CodeWhisperer 格式 * 基于 demo3 的工具转换策略,添加默认值处理 */ convertTools(anthropicTools) { const cwTools = anthropicTools.map(tool => ({ toolSpecification: { name: tool.name, description: tool.description || "", // ✅ 修复:添加默认空字符串 inputSchema: { json: tool.input_schema || {} // ✅ 修复:添加默认空对象 } } })); logger_1.logger.debug('工具转换完成', { inputToolCount: anthropicTools.length, outputToolCount: cwTools.length, toolNames: cwTools.map(t => t.toolSpecification.name) }); return cwTools; } /** * 创建调试信息 */ createDebugInfo(anthropicReq) { return { model: anthropicReq.model, messageCount: anthropicReq.messages.length, hasTools: !!(anthropicReq.tools && anthropicReq.tools.length > 0), hasSystem: !!(anthropicReq.system && anthropicReq.system.length > 0), }; } /** * 判断是否需要构建历史消息 */ shouldBuildHistory(anthropicReq) { return (anthropicReq.system && anthropicReq.system.length > 0) || anthropicReq.messages.length > 1; } /** * 构建消息历史 */ buildMessageHistory(anthropicReq) { const history = []; // 处理系统消息 this.processSystemMessages(anthropicReq, history); // 处理常规消息历史 this.processRegularMessages(anthropicReq, history); logger_1.logger.debug('已构建历史消息', { historyLength: history.length, systemMessageCount: anthropicReq.system?.length || 0, regularMessageCount: anthropicReq.messages.length - 1, }); return history; } /** * 处理系统消息 */ processSystemMessages(anthropicReq, history) { if (!anthropicReq.system || anthropicReq.system.length === 0) return; const defaultAssistantMsg = { assistantResponseMessage: { content: 'I will follow these instructions', toolUses: [], }, }; for (const sysMsg of anthropicReq.system) { const userMsg = { userInputMessage: { content: sysMsg.text, modelId: anthropicReq.model, origin: this.config.origin, }, }; history.push(userMsg, defaultAssistantMsg); } } /** * 处理常规消息历史 */ processRegularMessages(anthropicReq, history) { for (let i = 0; i < anthropicReq.messages.length - 1; i++) { const message = anthropicReq.messages[i]; if (message.role === 'user') { const userMsg = { userInputMessage: { content: this.extractMessageContent(message.content), modelId: anthropicReq.model, origin: this.config.origin, }, }; history.push(userMsg); // 检查是否有对应的助手回复 const nextMessage = anthropicReq.messages[i + 1]; if (i + 1 < anthropicReq.messages.length - 1 && nextMessage?.role === 'assistant') { const assistantMsg = { assistantResponseMessage: { content: this.extractMessageContent(nextMessage.content), toolUses: [], }, }; history.push(assistantMsg); i++; // 跳过已处理的助手消息 } } } } /** * 创建构建结果信息 */ createBuildResult(cwReq) { return { conversationId: cwReq.conversationState.conversationId, contentLength: cwReq.conversationState.currentMessage.userInputMessage.content.length, historyLength: cwReq.conversationState.history.length, modelId: cwReq.conversationState.currentMessage.userInputMessage.modelId, // 🚨 关键修复:防止profileArn为undefined时调用substring导致错误 profileArn: cwReq.profileArn ? cwReq.profileArn.substring(0, 50) + '...' : 'N/A (authMethod!=social)', }; } /** * 验证请求格式 - 重构优化版本 */ validateRequest(cwReq) { const errors = []; const warnings = []; try { // 分层验证 this.validateBasicFields(cwReq, errors); this.validateConversationState(cwReq, errors); this.validateUserInputMessage(cwReq, errors, warnings); const isValid = errors.length === 0; if (isValid) { logger_1.logger.debug('请求格式验证通过', { conversationId: cwReq.conversationState.conversationId, modelId: cwReq.conversationState.currentMessage.userInputMessage.modelId, contentLength: cwReq.conversationState.currentMessage.userInputMessage.content.length, warningCount: warnings.length }); } else { logger_1.logger.error('请求格式验证失败', { errors, warnings }); } return { isValid, errors, warnings }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger_1.logger.error('验证过程异常', { error: errorMessage }); return { isValid: false, errors: [`验证过程异常: ${errorMessage}`], warnings }; } } /** * 验证基本字段 */ validateBasicFields(cwReq, errors) { // 🚨 关键修复:profileArn只在authMethod='social'时才需要,undefined是合法的 // 根据demo3逻辑,当authMethod != 'social'时,profileArn为undefined是正常状态 // 这里不再验证profileArn存在性,因为它是条件性字段 if (!cwReq.conversationState) { errors.push('缺少conversationState'); } } /** * 验证对话状态 */ validateConversationState(cwReq, errors) { if (!cwReq.conversationState) return; const state = cwReq.conversationState; if (!state.conversationId) { errors.push('缺少conversationId'); } if (!state.currentMessage) { errors.push('缺少currentMessage'); } if (!state.chatTriggerType) { errors.push('缺少chatTriggerType'); } } /** * 验证用户输入消息 */ validateUserInputMessage(cwReq, errors, warnings) { const userInput = cwReq.conversationState?.currentMessage?.userInputMessage; if (!userInput) { errors.push('缺少userInputMessage'); return; } if (!userInput.content) { errors.push('缺少userInputMessage.content'); } else if (userInput.content.length > 50000) { warnings.push('消息内容过长,可能影响性能'); } if (!userInput.modelId) { errors.push('缺少userInputMessage.modelId'); } if (!userInput.origin) { errors.push('缺少userInputMessage.origin'); } if (!userInput.userInputMessageContext) { errors.push('缺少userInputMessageContext'); } } /** * 简化的验证方法(向后兼容) */ validateRequestLegacy(cwReq) { const result = this.validateRequest(cwReq); return result.isValid; } } exports.CodeWhispererConverter = CodeWhispererConverter; //# sourceMappingURL=converter.js.map