UNPKG

route-claudecode

Version:

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

350 lines 13.5 kB
"use strict"; /** * OpenAI Client Factory - 统一客户端管理器 * 基于项目记忆中的成功重构经验,消除重复实现 * 项目所有者: Jason Zhang * * 设计目标: * 1. 统一的客户端创建接口 * 2. 消除Pure Client和SDK Client的重复代码 * 3. 遵循零硬编码、零Fallback、零跨节点耦合原则 * 4. 向后兼容性保证 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIClientFactory = exports.ClientType = void 0; exports.createOpenAIClient = createOpenAIClient; const logger_1 = require("@/utils/logger"); const unified_client_1 = require("./unified-client"); // 保留legacy clients用于向后兼容,但标记为废弃 const sdk_client_1 = require("./sdk-client"); const pure_client_1 = require("./pure-client"); /** * 客户端类型枚举 - 推荐使用UNIFIED */ var ClientType; (function (ClientType) { ClientType["UNIFIED"] = "unified"; ClientType["PURE"] = "pure"; ClientType["SDK"] = "sdk"; // 废弃:保留向后兼容 })(ClientType || (exports.ClientType = ClientType = {})); /** * OpenAI客户端工厂 */ class OpenAIClientFactory { static clientStats = new Map(); static activeClients = new Map(); /** * 创建OpenAI客户端 - 优先使用统一实现 */ static createClient(config, providerId, globalConfig) { const clientType = this.determineClientType(config, providerId); const client = this.instantiateClient(clientType, config, providerId, globalConfig); // 记录活跃客户端 this.activeClients.set(providerId, { client, type: clientType }); // 初始化统计 if (!this.clientStats.has(providerId)) { this.clientStats.set(providerId, { requestCount: 0, errorCount: 0, consecutiveErrors: 0, averageResponseTime: 0 }); } logger_1.logger.info('OpenAI client created', { providerId, clientType, autoSwitch: config.switchingStrategy?.autoSwitch || false, hasSDKOptions: !!config.sdkOptions }); return this.wrapClientWithMonitoring(client, clientType, config, providerId); } /** * 确定客户端类型 - 优先使用统一客户端 * 基于项目记忆中的成功重构经验 */ static determineClientType(config, providerId) { const clientType = config.clientType || 'unified'; if (clientType === 'unified' || clientType === 'auto') { logger_1.logger.info('Selected Unified OpenAI client (recommended)', { providerId, clientType: 'unified', reason: 'eliminate-duplicate-code-architecture' }); return ClientType.UNIFIED; } else if (clientType === 'pure') { logger_1.logger.warn('Selected Pure OpenAI client (deprecated)', { providerId, clientType: 'pure', reason: 'backward-compatibility', recommendation: 'migrate-to-unified' }); return ClientType.PURE; } else if (clientType === 'sdk') { logger_1.logger.warn('Selected SDK OpenAI client (deprecated)', { providerId, clientType: 'sdk', reason: 'backward-compatibility', recommendation: 'migrate-to-unified' }); return ClientType.SDK; } else { // 默认使用统一客户端 logger_1.logger.info('Auto-selected Unified client (default)', { providerId, originalClientType: clientType, selectedClientType: 'unified', reason: 'zero-duplicate-code-principle' }); return ClientType.UNIFIED; } } /** * 实例化客户端 - 优先使用统一实现 */ static instantiateClient(clientType, config, providerId, globalConfig) { switch (clientType) { case ClientType.UNIFIED: logger_1.logger.debug('Creating Unified OpenAI client', { providerId, clientType: 'unified', architecture: 'six-layer-clean-zero-duplicate-code' }); return new unified_client_1.UnifiedOpenAIClient(config, providerId); case ClientType.PURE: logger_1.logger.debug('Creating Pure OpenAI client (deprecated)', { providerId, clientType: 'pure', architecture: 'legacy-transformer-based', warning: 'consider-migrating-to-unified' }); return new pure_client_1.PureOpenAIClient(config, providerId); case ClientType.SDK: logger_1.logger.debug('Creating SDK OpenAI client (deprecated)', { providerId, clientType: 'sdk', architecture: 'legacy-sdk-based', warning: 'consider-migrating-to-unified' }); return new sdk_client_1.OpenAISDKClient(config, providerId); default: throw new Error(`Unsupported client type: ${clientType} - violates zero fallback principle`); } } /** * 包装客户端以添加监控和自动切换功能 */ static wrapClientWithMonitoring(client, clientType, config, providerId) { const originalSendRequest = client.sendRequest.bind(client); const originalSendStreamRequest = client.sendStreamRequest.bind(client); // 包装非流式请求 client.sendRequest = async (request) => { const startTime = Date.now(); const stats = this.clientStats.get(providerId); try { const response = await originalSendRequest(request); // 更新成功统计 OpenAIClientFactory.updateSuccessStats(providerId, Date.now() - startTime); return response; } catch (error) { // 更新错误统计 OpenAIClientFactory.updateErrorStats(providerId, error); // 检查是否需要切换客户端 if (config.switchingStrategy?.autoSwitch) { await OpenAIClientFactory.checkAndSwitchClient(config, providerId, error); } throw error; } }; // 包装流式请求 client.sendStreamRequest = async function* (request) { const startTime = Date.now(); try { for await (const chunk of originalSendStreamRequest(request)) { yield chunk; } // 更新成功统计 OpenAIClientFactory.updateSuccessStats(providerId, Date.now() - startTime); } catch (error) { // 更新错误统计 OpenAIClientFactory.updateErrorStats(providerId, error); // 检查是否需要切换客户端 if (config.switchingStrategy?.autoSwitch) { await OpenAIClientFactory.checkAndSwitchClient(config, providerId, error); } throw error; } }.bind(this); return client; } /** * 更新成功统计 */ static updateSuccessStats(providerId, responseTime) { const stats = this.clientStats.get(providerId); if (!stats) return; stats.requestCount++; stats.consecutiveErrors = 0; // 更新平均响应时间 stats.averageResponseTime = ((stats.averageResponseTime * (stats.requestCount - 1)) + responseTime) / stats.requestCount; } /** * 更新错误统计 */ static updateErrorStats(providerId, error) { const stats = this.clientStats.get(providerId); if (!stats) return; stats.requestCount++; stats.errorCount++; stats.consecutiveErrors++; stats.lastErrorTime = new Date(); logger_1.logger.warn('Client error recorded', { providerId, errorCount: stats.errorCount, consecutiveErrors: stats.consecutiveErrors, error: error instanceof Error ? error.message : String(error) }); } /** * 检查并切换客户端 */ static async checkAndSwitchClient(config, providerId, error) { const stats = this.clientStats.get(providerId); const activeClient = this.activeClients.get(providerId); if (!stats || !activeClient) return; const strategy = config.switchingStrategy; const errorThreshold = strategy.errorThreshold || 3; const switchCooldown = strategy.switchCooldown || 60000; // 1分钟 // 检查冷却时间 if (stats.lastSwitchTime) { const timeSinceLastSwitch = Date.now() - stats.lastSwitchTime.getTime(); if (timeSinceLastSwitch < switchCooldown) { return; } } // 检查是否达到切换条件 const shouldSwitch = stats.consecutiveErrors >= errorThreshold; if (shouldSwitch) { const currentType = activeClient.type; const newType = currentType === ClientType.PURE ? ClientType.SDK : ClientType.PURE; logger_1.logger.warn('Switching OpenAI client due to consecutive errors', { providerId, fromType: currentType, toType: newType, consecutiveErrors: stats.consecutiveErrors, errorThreshold }); try { // 创建新客户端 const newClient = this.instantiateClient(newType, config, providerId); // 更新活跃客户端 this.activeClients.set(providerId, { client: newClient, type: newType }); // 重置统计 stats.consecutiveErrors = 0; stats.lastSwitchTime = new Date(); logger_1.logger.info('OpenAI client switched successfully', { providerId, newType, resetStats: true }); } catch (switchError) { logger_1.logger.error('Failed to switch OpenAI client', { providerId, targetType: newType, error: switchError instanceof Error ? switchError.message : String(switchError) }); } } } /** * 获取客户端统计信息 */ static getClientStats(providerId) { return this.clientStats.get(providerId); } /** * 获取活跃客户端信息 */ static getActiveClientInfo(providerId) { const activeClient = this.activeClients.get(providerId); const stats = this.clientStats.get(providerId); if (!activeClient || !stats) return undefined; return { type: activeClient.type, stats }; } /** * 手动切换客户端 */ static async switchClient(providerId, targetType, config) { const activeClient = this.activeClients.get(providerId); if (!activeClient) { logger_1.logger.error('Cannot switch client: provider not found', { providerId }); return false; } if (activeClient.type === targetType) { logger_1.logger.info('Client already using target type', { providerId, targetType }); return true; } try { // 创建新客户端 const newClient = this.instantiateClient(targetType, config, providerId); // 更新活跃客户端 this.activeClients.set(providerId, { client: newClient, type: targetType }); // 更新统计 const stats = this.clientStats.get(providerId); if (stats) { stats.lastSwitchTime = new Date(); stats.consecutiveErrors = 0; } logger_1.logger.info('OpenAI client manually switched', { providerId, fromType: activeClient.type, toType: targetType }); return true; } catch (error) { logger_1.logger.error('Failed to manually switch OpenAI client', { providerId, targetType, error: error instanceof Error ? error.message : String(error) }); return false; } } /** * 获取所有客户端状态 */ static getAllClientStatus() { const status = {}; for (const [providerId, activeClient] of this.activeClients.entries()) { const stats = this.clientStats.get(providerId); if (stats) { status[providerId] = { type: activeClient.type, stats }; } } return status; } } exports.OpenAIClientFactory = OpenAIClientFactory; /** * 便捷函数:创建OpenAI客户端 */ function createOpenAIClient(config, providerId, globalConfig) { return OpenAIClientFactory.createClient(config, providerId, globalConfig); } //# sourceMappingURL=client-factory.js.map