UNPKG

route-claudecode

Version:

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

128 lines 5.62 kB
"use strict"; /** * Gemini Provider * Integration with Google's Gemini API via OpenAI-compatible interface * Project owner: Jason Zhang */ Object.defineProperty(exports, "__esModule", { value: true }); exports.GeminiProvider = void 0; const logger_1 = require("../../utils/logger"); const client_1 = require("./client"); class GeminiProvider { config; name; type; client; static PROVIDER_TYPE = 'gemini'; constructor(config, providerId) { this.config = config; if (!providerId) { throw new Error('GeminiProvider: providerId is required - no default fallback allowed'); } this.name = providerId; // Zero Hardcode Principle: type from config or static constant this.type = config.type || GeminiProvider.PROVIDER_TYPE; if (config.type !== GeminiProvider.PROVIDER_TYPE) { throw new Error(`Invalid provider type: ${config.type}, expected '${GeminiProvider.PROVIDER_TYPE}'`); } this.client = new client_1.GeminiClient(config, this.name); logger_1.logger.info(`Initialized Gemini provider: ${config.endpoint}`, { provider: this.name, endpoint: config.endpoint }); } async isHealthy() { try { return await this.client.healthCheck(); } catch (error) { logger_1.logger.error('Gemini provider health check failed', { provider: this.name, error: error instanceof Error ? error.message : String(error) }); return false; } } async sendRequest(request) { try { if (!request.metadata?.requestId) { throw new Error('GeminiProvider: request.metadata.requestId is required'); } logger_1.logger.trace(request.metadata.requestId, 'provider', 'Sending request to Gemini', { provider: this.name, model: request.model, endpoint: this.config.endpoint }); const response = await this.client.createCompletion(request); logger_1.logger.debug('Received response from Gemini', { provider: this.name, model: response.model, requestId: request.metadata?.requestId, inputTokens: response.usage?.input_tokens, outputTokens: response.usage?.output_tokens }); return response; } catch (error) { const isRateLimited = error?.status === 429 || error?.message?.includes('429') || error?.message?.includes('RESOURCE_EXHAUSTED') || error?.message?.includes('quota'); // 获取当前使用的key信息(如果可用) const currentKeyInfo = this.client?.getRotationStats?.() ?? {}; // 强制控制台输出429错误,包含详细的key和模型降级信息 if (isRateLimited) { console.error(`🚨 [429 RATE LIMIT] Gemini API quota exhausted:`); console.error(` Provider: ${this.name}`); console.error(` Requested Model: ${request.model}`); console.error(` Request ID: ${request.metadata?.requestId}`); console.error(` Current Key: ${currentKeyInfo.keyIndex !== undefined ? `key-${currentKeyInfo.keyIndex + 1}` : 'unknown'}`); console.error(` Key Suffix: ${currentKeyInfo.keySuffix ?? 'unknown'}`); console.error(` Total Keys: ${currentKeyInfo.totalKeys ?? 'unknown'}`); console.error(` Error Details: ${error instanceof Error ? error.message : String(error)}`); console.error(` Zero Fallback Principle: No model fallback - routing layer must handle alternatives`); console.error(` Next Key Available: ${currentKeyInfo.nextKeyIndex !== undefined ? `key-${currentKeyInfo.nextKeyIndex + 1}` : 'checking...'}`); } logger_1.logger.error('Gemini API request failed', { provider: this.name, model: request.model, requestId: request.metadata?.requestId, error: error instanceof Error ? error.message : String(error), isRateLimited, keyInfo: currentKeyInfo, httpStatus: error?.status, errorCode: error?.code }); throw error; } } async *sendStreamRequest(request) { try { logger_1.logger.debug('Starting streaming request to Gemini', { provider: this.name, model: request.model, requestId: request.metadata?.requestId }); const stream = this.client.streamCompletion(request); for await (const chunk of stream) { yield chunk; } logger_1.logger.debug('Completed streaming request to Gemini', { provider: this.name, model: request.model, requestId: request.metadata?.requestId }); } catch (error) { logger_1.logger.error('Gemini streaming request failed', { provider: this.name, model: request.model, requestId: request.metadata?.requestId, error: error instanceof Error ? error.message : String(error) }); throw error; } } } exports.GeminiProvider = GeminiProvider; //# sourceMappingURL=index.js.map