UNPKG

route-claudecode

Version:

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

189 lines 8.13 kB
"use strict"; /** * 统一响应验证模块 * 项目所有者: Jason Zhang * * 消除重复的静默失败检测逻辑,提供统一的响应验证接口 * 遵循零硬编码、零Fallback、零静默失败原则 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.StreamChunkValidationError = exports.ResponseValidationError = void 0; exports.validateNonStreamingResponse = validateNonStreamingResponse; exports.validateStreamingChunk = validateStreamingChunk; exports.validateStreamingCompletion = validateStreamingCompletion; exports.isValidContentChunk = isValidContentChunk; exports.extractFinishReasonFromChunk = extractFinishReasonFromChunk; exports.handleProviderError = handleProviderError; const logger_1 = require("@/utils/logger"); /** * 响应验证错误类型 */ class ResponseValidationError extends Error { requestId; provider; validationType; constructor(message, requestId, provider, validationType) { super(message); this.requestId = requestId; this.provider = provider; this.validationType = validationType; this.name = 'ResponseValidationError'; } } exports.ResponseValidationError = ResponseValidationError; /** * 流式块验证错误类型 */ class StreamChunkValidationError extends Error { requestId; provider; chunkIndex; constructor(message, requestId, provider, chunkIndex) { super(message); this.requestId = requestId; this.provider = provider; this.chunkIndex = chunkIndex; this.name = 'StreamChunkValidationError'; } } exports.StreamChunkValidationError = StreamChunkValidationError; /** * 🚨 Critical: 验证非流式响应,防止静默失败 * 统一的响应验证逻辑,消除重复代码 */ function validateNonStreamingResponse(response, requestId, providerName) { // 验证响应对象存在 if (!response) { const error = new ResponseValidationError('Response is null or undefined - silent failure detected', requestId, providerName, 'non-streaming'); console.error(`🚨 [${providerName}] SILENT FAILURE: Null response for ${requestId}`); throw error; } // 验证内容存在 if (!response.content || response.content.length === 0) { const error = new ResponseValidationError('Response has no content - potential silent failure', requestId, providerName, 'non-streaming'); console.error(`🚨 [${providerName}] SILENT FAILURE: Empty content for ${requestId}`); throw error; } // 验证stop_reason存在 if (!response.stop_reason) { const error = new ResponseValidationError('Response missing stop_reason - potential silent failure', requestId, providerName, 'non-streaming'); console.error(`🚨 [${providerName}] SILENT FAILURE: Missing stop_reason for ${requestId}`); throw error; } // 🚨 Critical: 检查fallback值(违反零fallback原则) if (response.stop_reason === 'unknown' || response.stop_reason === 'default') { const error = new ResponseValidationError(`Response has fallback stop_reason: ${response.stop_reason} - violates zero fallback principle`, requestId, providerName, 'non-streaming'); console.error(`🚨 [${providerName}] FALLBACK VIOLATION: ${response.stop_reason} for ${requestId}`); throw error; } // 验证使用信息 if (!response.usage) { logger_1.logger.warn('Response missing usage information', { requestId, provider: providerName }); } logger_1.logger.debug('Non-streaming response validation passed', { requestId, provider: providerName, contentLength: response.content.length, stopReason: response.stop_reason, hasUsage: !!response.usage }); } /** * 🚨 Critical: 验证流式chunk,防止静默失败 * 统一的流式验证逻辑,消除重复代码 */ function validateStreamingChunk(chunk, requestId, providerName, chunkIndex) { // 验证chunk存在 if (!chunk) { const error = new StreamChunkValidationError(`Streaming chunk ${chunkIndex} is null/undefined - silent failure detected`, requestId, providerName, chunkIndex); console.error(`🚨 [${providerName}] STREAMING SILENT FAILURE: Null chunk ${chunkIndex} for ${requestId}`); throw error; } // 验证event类型存在 if (!chunk.event) { const error = new StreamChunkValidationError(`Streaming chunk ${chunkIndex} missing event type - malformed chunk`, requestId, providerName, chunkIndex); console.error(`🚨 [${providerName}] STREAMING MALFORMED: Missing event in chunk ${chunkIndex} for ${requestId}`); throw error; } // 🚨 Critical: 检查fallback事件类型(违反零fallback原则) if (chunk.event === 'unknown' || chunk.event === 'default' || chunk.event === 'fallback') { const error = new StreamChunkValidationError(`Streaming chunk has fallback event: ${chunk.event} - violates zero fallback principle`, requestId, providerName, chunkIndex); console.error(`🚨 [${providerName}] STREAMING FALLBACK VIOLATION: ${chunk.event} in chunk ${chunkIndex} for ${requestId}`); throw error; } // 验证chunk数据结构(除了ping事件) if (chunk.event !== 'ping' && !chunk.data) { const error = new StreamChunkValidationError(`Streaming chunk ${chunkIndex} missing data - malformed chunk`, requestId, providerName, chunkIndex); console.error(`🚨 [${providerName}] STREAMING MALFORMED: Missing data in chunk ${chunkIndex} for ${requestId}`); throw error; } logger_1.logger.trace(requestId, 'validation', 'Streaming chunk validation passed', { chunkIndex, event: chunk.event, hasData: !!chunk.data, provider: providerName }); } /** * 验证流式请求是否产生了有效内容 */ function validateStreamingCompletion(chunkCount, hasValidContent, requestId, providerName) { if (chunkCount === 0) { const error = new StreamChunkValidationError('Streaming request produced no chunks - potential silent failure', requestId, providerName, 0); console.error(`🚨 [${providerName}] STREAMING SILENT FAILURE DETECTED:`); console.error(` Request ID: ${requestId}`); console.error(` Chunks: ${chunkCount}`); console.error(` Valid Content: ${hasValidContent}`); console.error(` RESULT: Throwing error to prevent silent failure`); throw error; } if (!hasValidContent) { logger_1.logger.warn('Streaming request completed without valid content', { requestId, provider: providerName, chunkCount }); } } /** * 检查是否为有效内容chunk */ function isValidContentChunk(chunk) { if (!chunk || !chunk.event) { return false; } const validContentEvents = [ 'content_block_delta', 'content_block_start', 'message_start' ]; return validContentEvents.includes(chunk.event); } /** * 提取finish reason从chunk */ function extractFinishReasonFromChunk(chunk) { if (chunk?.event === 'message_delta' && chunk?.data?.delta?.stop_reason) { return chunk.data.delta.stop_reason; } return undefined; } /** * 统一的错误处理函数 */ function handleProviderError(error, requestId, providerName, operationType) { const httpStatus = error?.response?.status || error?.status || 500; const errorMessage = error instanceof Error ? error.message : String(error); console.error(`🚨 [${providerName}] ${operationType.toUpperCase()} REQUEST FAILED - NO SILENT FAILURE:`); console.error(` Request ID: ${requestId}`); console.error(` Status: ${httpStatus}`); console.error(` Error: ${errorMessage}`); console.error(` Provider: ${providerName}`); console.error(` RESULT: Throwing error to client`); // 重新抛出原错误,确保错误类型和堆栈信息保持不变 throw error; } //# sourceMappingURL=response-validation.js.map