UNPKG

route-claudecode

Version:

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

336 lines 13.7 kB
"use strict"; /** * Max Tokens错误处理模块 - 集中处理token限制问题 * Project Owner: Jason Zhang * * 当收到max_tokens/length stop_reason时的智能处理方案 * Option 1: 滚动截断处理机制 (当前实现) * Option 2: LongContext模型压缩 (预留接口) */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.MaxTokensErrorHandlingModule = void 0; const logger_1 = require("./logger"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); class MaxTokensErrorHandlingModule { config; configPath; constructor(configPath) { this.configPath = configPath || path.join(process.cwd(), 'config', 'max-tokens-handling.json'); this.loadConfiguration(); } /** * 加载配置文件 */ loadConfiguration() { try { if (fs.existsSync(this.configPath)) { const configData = fs.readFileSync(this.configPath, 'utf8'); this.config = JSON.parse(configData); logger_1.logger.debug('Max tokens handling configuration loaded', { configPath: this.configPath, strategy: this.config.strategy }); } else { // 创建默认配置 this.config = this.getDefaultConfig(); this.saveConfiguration(); logger_1.logger.info('Created default max tokens handling configuration', { configPath: this.configPath }); } } catch (error) { logger_1.logger.error('Failed to load max tokens handling configuration', error); this.config = this.getDefaultConfig(); } } /** * 获取默认配置 */ getDefaultConfig() { return { strategy: 'rolling_truncation', rollingTruncation: { historyRetentionPercent: 80, useSimplifiedPrompt: true, simplifiedPromptPath: path.join(process.cwd(), 'config', 'simplified-system-prompt.json') }, longcontextCompression: { enabled: false, recentHistoryPercent: 20, compressionModel: 'claude-3-haiku', // 用于压缩的高效模型 compressionEndpoint: '/v1/chat/completions' } }; } /** * 保存配置文件 */ saveConfiguration() { try { // 确保配置目录存在 const configDir = path.dirname(this.configPath); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf8'); logger_1.logger.debug('Max tokens handling configuration saved', { configPath: this.configPath }); } catch (error) { logger_1.logger.error('Failed to save max tokens handling configuration', error); } } /** * 处理max tokens错误 - 主入口 */ async handleMaxTokensError(originalRequest, errorDetails, requestId) { logger_1.logger.info('🔧 [MAX-TOKENS] Starting max tokens error handling', { strategy: this.config.strategy, originalModel: originalRequest.model, requestId }); try { switch (this.config.strategy) { case 'rolling_truncation': return await this.handleRollingTruncation(originalRequest, requestId); case 'longcontext_compression': if (this.config.longcontextCompression?.enabled) { return await this.handleLongcontextCompression(originalRequest, requestId); } else { // 降级到滚动截断 logger_1.logger.warn('LongContext compression disabled, falling back to rolling truncation'); return await this.handleRollingTruncation(originalRequest, requestId); } default: throw new Error(`Unknown max tokens handling strategy: ${this.config.strategy}`); } } catch (error) { logger_1.logger.error('Max tokens error handling failed', error, requestId, 'max-tokens-handler'); throw error; } } /** * Option 1: 滚动截断处理 */ async handleRollingTruncation(originalRequest, requestId) { const config = this.config.rollingTruncation; let truncatedRequest = JSON.parse(JSON.stringify(originalRequest)); // 深拷贝 const originalTokens = this.estimateTokens(originalRequest); let systemPromptReduced = false; let historyMessagesRemoved = 0; logger_1.logger.debug('🔧 [ROLLING-TRUNCATION] Starting truncation process', { originalTokens, historyRetentionPercent: config.historyRetentionPercent, useSimplifiedPrompt: config.useSimplifiedPrompt, requestId }); // 1. 简化系统提示词 (如果启用) if (config.useSimplifiedPrompt) { const simplifiedSystemPrompt = await this.getSimplifiedSystemPrompt(); if (simplifiedSystemPrompt && truncatedRequest.metadata?.system) { const originalSystemLength = JSON.stringify(truncatedRequest.metadata.system).length; truncatedRequest.metadata.system = simplifiedSystemPrompt; const newSystemLength = JSON.stringify(simplifiedSystemPrompt).length; systemPromptReduced = newSystemLength < originalSystemLength; logger_1.logger.info('🔧 [ROLLING-TRUNCATION] System prompt simplified', { originalLength: originalSystemLength, newLength: newSystemLength, reductionPercent: Math.round((1 - newSystemLength / originalSystemLength) * 100), requestId }); } } // 2. 历史记录截断 if (truncatedRequest.messages && truncatedRequest.messages.length > 1) { const totalMessages = truncatedRequest.messages.length; const messagesToKeep = Math.max(1, Math.ceil(totalMessages * (config.historyRetentionPercent / 100))); // 保留最新的消息(通常最后一个是用户的当前请求) const messagesToRemove = totalMessages - messagesToKeep; if (messagesToRemove > 0) { // 从最旧的消息开始移除,但保留第一条(通常是系统消息或重要上下文) const startIndex = Math.max(1, Math.min(messagesToRemove, totalMessages - messagesToKeep)); truncatedRequest.messages = [ ...truncatedRequest.messages.slice(0, 1), // 保留第一条消息 ...truncatedRequest.messages.slice(startIndex + messagesToRemove) // 保留最新的消息 ]; historyMessagesRemoved = messagesToRemove; logger_1.logger.info('🔧 [ROLLING-TRUNCATION] History messages truncated', { originalMessages: totalMessages, messagesRemoved: historyMessagesRemoved, remainingMessages: truncatedRequest.messages.length, requestId }); } } const reducedTokens = this.estimateTokens(truncatedRequest); const reductionPercent = Math.round((1 - reducedTokens / originalTokens) * 100); logger_1.logger.info('🔧 [ROLLING-TRUNCATION] Truncation completed', { originalTokens, reducedTokens, reductionPercent, systemPromptReduced, historyMessagesRemoved, requestId }); return { success: true, originalTokens, reducedTokens, truncatedRequest, strategy: 'rolling_truncation', details: { systemPromptReduced, historyMessagesRemoved, totalMessagesRemaining: truncatedRequest.messages?.length || 0 } }; } /** * Option 2: LongContext模型压缩 (预留实现) */ async handleLongcontextCompression(originalRequest, requestId) { // TODO: 实现LongContext模型压缩逻辑 logger_1.logger.warn('🔧 [LONGCONTEXT-COMPRESSION] Not implemented yet, falling back to rolling truncation'); return await this.handleRollingTruncation(originalRequest, requestId); } /** * 获取简化版系统提示词 */ async getSimplifiedSystemPrompt() { const config = this.config.rollingTruncation; try { if (fs.existsSync(config.simplifiedPromptPath)) { const promptData = fs.readFileSync(config.simplifiedPromptPath, 'utf8'); return JSON.parse(promptData); } else { // 创建默认简化提示词文件 const defaultPrompt = this.createDefaultSimplifiedPrompt(); await this.saveSimplifiedPrompt(defaultPrompt); return defaultPrompt; } } catch (error) { logger_1.logger.error('Failed to load simplified system prompt', error); return null; } } /** * 创建默认简化系统提示词 */ createDefaultSimplifiedPrompt() { return { type: "text", text: "You are Claude, an AI assistant. Be helpful, harmless, and honest. Use available tools when needed." }; } /** * 保存简化版系统提示词 */ async saveSimplifiedPrompt(prompt) { const config = this.config.rollingTruncation; try { const promptDir = path.dirname(config.simplifiedPromptPath); if (!fs.existsSync(promptDir)) { fs.mkdirSync(promptDir, { recursive: true }); } fs.writeFileSync(config.simplifiedPromptPath, JSON.stringify(prompt, null, 2), 'utf8'); logger_1.logger.info('Default simplified system prompt created', { path: config.simplifiedPromptPath }); } catch (error) { logger_1.logger.error('Failed to save simplified system prompt', error); } } /** * 估算请求的token数量 */ estimateTokens(request) { let totalChars = 0; // 计算消息内容 if (request.messages) { request.messages.forEach(msg => { if (typeof msg.content === 'string') { totalChars += msg.content.length; } else if (Array.isArray(msg.content)) { msg.content.forEach((block) => { if (block.text) totalChars += block.text.length; if (block.content) totalChars += JSON.stringify(block.content).length; }); } }); } // 计算系统提示词 if (request.metadata?.system) { totalChars += JSON.stringify(request.metadata.system).length; } // 计算工具定义 if (request.metadata?.tools) { totalChars += JSON.stringify(request.metadata.tools).length; } // 估算:~4个字符等于1个token return Math.ceil(totalChars / 4); } /** * 获取当前配置 */ getConfig() { return { ...this.config }; } /** * 更新配置 */ updateConfig(updates) { this.config = { ...this.config, ...updates }; this.saveConfiguration(); logger_1.logger.info('Max tokens handling configuration updated', { strategy: this.config.strategy }); } } exports.MaxTokensErrorHandlingModule = MaxTokensErrorHandlingModule; exports.default = MaxTokensErrorHandlingModule; //# sourceMappingURL=max-tokens-error-handling-module.js.map