route-claudecode
Version:
Advanced routing and transformation system for Claude Code outputs to multiple AI providers
586 lines • 23.7 kB
JavaScript
"use strict";
/**
* CodeWhisperer 实时流式客户端
* 基于demo2的Go实现移植,实现零延迟流式处理
* 项目所有者: Jason Zhang
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodeWhispererRealtimeClient = void 0;
const axios_1 = __importDefault(require("axios"));
const logger_1 = require("@/utils/logger");
const auth_1 = require("./auth");
const converter_1 = require("./converter");
const parser_realtime_1 = require("./parser-realtime");
const performance_metrics_1 = require("./config/performance-metrics");
class CodeWhispererRealtimeClient {
auth;
converter;
parser;
metrics;
config;
options;
httpTimeout;
maxRetries;
tokenBlacklisted = false;
consecutiveRefreshFailures = 0;
maxRefreshFailures = 3;
activeStreams = new Set();
constructor(config) {
this.config = config;
this.options = config.realtimeOptions;
this.auth = auth_1.CodeWhispererAuth.getInstance();
this.converter = new converter_1.CodeWhispererConverter();
this.parser = new parser_realtime_1.CodeWhispererRealtimeParser({
maxFrameSize: this.options.binaryFrameSize,
enableCompression: this.options.enableCompression,
});
this.metrics = new performance_metrics_1.CodeWhispererPerformanceMetrics(config);
this.httpTimeout = 60000; // 60秒超时
this.maxRetries = 3; // Token刷新重试次数
logger_1.logger.info('CodeWhispererRealtimeClient初始化完成', {
implementation: 'realtime',
options: this.options,
timeout: this.httpTimeout,
maxRetries: this.maxRetries,
});
}
/**
* 处理流式请求 - 实时流式实现
*/
async handleStreamRequest(anthropicReq, writeSSE, onError) {
const requestId = `realtime_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
try {
// 检查并发流限制
if (this.activeStreams.size >= this.options.maxConcurrentStreams) {
throw new Error(`超过最大并发流数限制: ${this.options.maxConcurrentStreams}`);
}
this.activeStreams.add(requestId);
const requestInfo = this.createRequestInfo(anthropicReq, requestId);
logger_1.logger.info('开始处理实时流式请求', requestInfo);
// 开始性能跟踪
this.metrics.startTracking(requestId, 'realtime');
// 使用重试机制执行流式请求
await this.executeWithRetry(async () => {
// 获取认证信息
const { accessToken, profileArn, authMethod } = await this.getAuthInfo();
// 构建和验证请求
const cwReq = await this.buildAndValidateRequest(anthropicReq, profileArn, authMethod);
const cwReqBody = JSON.stringify(cwReq);
// 发送HTTP请求
const responseBuffer = await this.sendHttpRequest(accessToken, cwReqBody, requestId);
// 实时处理响应流(零延迟转发)
await this.processRealtimeStream(responseBuffer, anthropicReq, writeSSE, requestId);
}, 'realtime-stream', requestId);
// 结束性能跟踪
this.metrics.endTracking(requestId, true);
}
catch (error) {
// 结束性能跟踪(失败)
this.metrics.endTracking(requestId, false, error instanceof Error ? error.message : String(error));
await this.handleStreamError(error, onError);
}
finally {
this.activeStreams.delete(requestId);
}
}
/**
* 实时处理响应流 - 核心实时特性
*/
async processRealtimeStream(responseBuffer, anthropicReq, writeSSE, requestId) {
logger_1.logger.debug('开始实时流式响应处理', {
requestId,
bufferSize: responseBuffer.length,
enableZeroDelay: this.options.enableZeroDelay,
});
// 生成消息ID
const messageId = `msg_${Date.now()}`;
// 发送初始事件序列
await this.sendInitialEvents(messageId, anthropicReq, writeSSE);
// 实时解析和转发事件(零延迟)
let outputTokens = 0;
let eventsCount = 0;
if (this.options.toolCallStrategy === 'immediate') {
// 立即处理策略 - 基于demo2的实时转发
for await (const event of this.parser.parseRealtimeStream(this.bufferToStream(responseBuffer), (progress) => {
logger_1.logger.debug('实时解析进度', {
requestId,
progress,
});
})) {
// 零延迟转发事件
writeSSE(event.event, event.data);
// 记录性能指标
if (this.config.performanceMetrics.collectLatencyData) {
this.metrics.recordLatency(requestId, event);
}
// 计算输出token数量
if (event.event === 'content_block_delta' && event.data?.delta?.text) {
outputTokens += Math.floor(event.data.delta.text.length / 4);
}
eventsCount++;
// 仅在不启用零延迟时添加微小延时
if (!this.options.enableZeroDelay) {
await this.sleep(Math.random() * 10); // 最多10ms延时
}
}
}
else {
// 缓冲处理策略(兼容现有逻辑)
const events = this.parser.parseEvents(responseBuffer);
for (const event of events) {
writeSSE(event.event, event.data);
if (this.config.performanceMetrics.collectLatencyData) {
this.metrics.recordLatency(requestId, event);
}
if (event.event === 'content_block_delta' && event.data?.delta?.text) {
outputTokens += Math.floor(event.data.delta.text.length / 4);
}
eventsCount++;
await this.sleep(Math.random() * 50); // 缓冲式延时
}
}
// 发送结束事件序列
await this.sendFinalEvents(outputTokens, writeSSE);
logger_1.logger.info('实时流式请求处理完成', {
requestId,
eventCount: eventsCount,
outputTokens,
processingTime: Date.now() - parseInt(requestId.split('_')[1]),
});
}
/**
* 发送初始事件
*/
async sendInitialEvents(messageId, anthropicReq, writeSSE) {
// 发送开始事件
const messageStart = {
type: 'message_start',
message: {
id: messageId,
type: 'message',
role: 'assistant',
content: [],
model: anthropicReq.model,
stop_reason: null,
stop_sequence: null,
usage: {
input_tokens: Math.max(1, Math.floor(this.calculateMessageLength(anthropicReq) / 4)),
output_tokens: 1,
},
},
};
writeSSE('message_start', messageStart);
// 发送ping事件
writeSSE('ping', { type: 'ping' });
// 发送content_block_start事件
const contentBlockStart = {
content_block: {
text: '',
type: 'text',
},
index: 0,
type: 'content_block_start',
};
writeSSE('content_block_start', contentBlockStart);
}
/**
* 发送结束事件
*/
async sendFinalEvents(outputTokens, writeSSE) {
writeSSE('content_block_stop', {
index: 0,
type: 'content_block_stop',
});
writeSSE('message_delta', {
type: 'message_delta',
delta: {
stop_reason: 'end_turn',
stop_sequence: null,
},
usage: {
output_tokens: Math.max(1, outputTokens),
},
});
writeSSE('message_stop', {
type: 'message_stop',
});
}
/**
* 处理非流式请求 - 实时优化版本
*/
async handleNonStreamRequest(anthropicReq) {
const requestId = `nonstream_realtime_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
try {
const requestInfo = this.createRequestInfo(anthropicReq, requestId);
logger_1.logger.info('开始处理实时非流式请求', requestInfo);
// 开始性能跟踪
this.metrics.startTracking(requestId, 'realtime');
// 使用重试机制执行非流式请求
const result = await this.executeWithRetry(async () => {
// 获取认证信息
const { accessToken, profileArn, authMethod } = await this.getAuthInfo();
// 构建和验证请求
const cwReq = await this.buildAndValidateRequest(anthropicReq, profileArn, authMethod);
const cwReqBody = JSON.stringify(cwReq);
// 发送HTTP请求
const responseBuffer = await this.sendNonStreamHttpRequest(accessToken, cwReqBody, requestId);
// 实时处理响应
return await this.processRealtimeNonStreamResponse(responseBuffer, anthropicReq, requestId);
}, 'realtime-nonstream', requestId);
// 结束性能跟踪
this.metrics.endTracking(requestId, true);
return result;
}
catch (error) {
// 结束性能跟踪(失败)
this.metrics.endTracking(requestId, false, error instanceof Error ? error.message : String(error));
throw error;
}
}
/**
* 实时处理非流式响应
*/
async processRealtimeNonStreamResponse(responseBuffer, anthropicReq, requestId) {
logger_1.logger.debug('开始实时非流式响应处理', {
requestId,
bufferSize: responseBuffer.length,
});
// 实时解析事件
const events = this.parser.parseEvents(responseBuffer);
if (events.length === 0) {
throw new Error('没有解析到任何事件');
}
// 构建非流式响应
const anthropicResp = this.parser.buildNonStreamResponse(events, anthropicReq.model);
logger_1.logger.info('实时非流式请求处理完成', {
requestId,
eventCount: events.length,
contentBlocks: anthropicResp.content?.length || 0,
});
return anthropicResp;
}
/**
* 获取客户端类型
*/
getClientType() {
return 'realtime';
}
/**
* 健康检查
*/
async healthCheck() {
try {
// 检查认证状态
const tokenAvailable = await this.auth.getToken().then(() => true).catch(() => false);
// 检查并发流状态
const streamsHealthy = this.activeStreams.size < this.options.maxConcurrentStreams;
const healthy = tokenAvailable && streamsHealthy && !this.tokenBlacklisted;
return {
healthy,
type: 'realtime',
message: healthy
? 'Realtime client is healthy'
: `Issues: ${!tokenAvailable ? 'auth ' : ''}${!streamsHealthy ? 'streams ' : ''}${this.tokenBlacklisted ? 'blacklisted' : ''}`,
};
}
catch (error) {
return {
healthy: false,
type: 'realtime',
message: error instanceof Error ? error.message : String(error),
};
}
}
/**
* Token可用性检查
*/
isTokenAvailable() {
if (this.tokenBlacklisted) {
logger_1.logger.warn('Token已被拉黑,不可用', {
consecutiveRefreshFailures: this.consecutiveRefreshFailures,
maxRefreshFailures: this.maxRefreshFailures
});
return false;
}
return true;
}
/**
* 标记token为不可用
*/
markTokenUnavailable(reason, requestId) {
this.tokenBlacklisted = true;
logger_1.logger.error(`CodeWhisperer token已拉黑`, {
reason,
consecutiveRefreshFailures: this.consecutiveRefreshFailures,
maxRefreshFailures: this.maxRefreshFailures,
requestId
});
}
/**
* 报告token刷新失败
*/
reportRefreshFailure(error, requestId) {
this.consecutiveRefreshFailures++;
if (this.consecutiveRefreshFailures >= this.maxRefreshFailures) {
this.markTokenUnavailable(`连续${this.consecutiveRefreshFailures}次刷新失败`, requestId);
}
logger_1.logger.warn('Token刷新失败计数', {
consecutiveRefreshFailures: this.consecutiveRefreshFailures,
maxRefreshFailures: this.maxRefreshFailures,
tokenBlacklisted: this.tokenBlacklisted,
requestId,
error: error instanceof Error ? error.message : error
});
}
/**
* 报告token刷新成功
*/
reportRefreshSuccess(requestId) {
if (this.consecutiveRefreshFailures > 0) {
logger_1.logger.info('Token刷新成功,重置失败计数', {
previousFailures: this.consecutiveRefreshFailures,
requestId
});
this.consecutiveRefreshFailures = 0;
}
}
/**
* 执行带重试机制的操作
*/
async executeWithRetry(requestFn, operation, requestId) {
// 首先检查token是否可用
if (!this.isTokenAvailable()) {
throw new Error('CodeWhisperer token不可用: token已被拉黑,无法执行请求');
}
let lastError;
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
try {
// 清除auth缓存以确保获取最新token
if (attempt > 0) {
this.auth.clearCache();
logger_1.logger.info(`Token重试第${attempt}次`, { requestId, operation });
}
return await requestFn();
}
catch (error) {
lastError = error;
// 检查是否是403 token过期错误
if (axios_1.default.isAxiosError(error) && error.response?.status === 403) {
logger_1.logger.warn(`检测到403错误,尝试刷新token (尝试 ${attempt + 1}/${this.maxRetries})`, {
requestId,
operation,
errorMessage: error.message
});
try {
// 尝试刷新token
await this.auth.refreshToken();
this.reportRefreshSuccess(requestId);
logger_1.logger.info('Token刷新成功,准备重试', { requestId, operation, attempt: attempt + 1 });
// 如果不是最后一次尝试,继续循环重试
if (attempt < this.maxRetries - 1) {
continue;
}
}
catch (refreshError) {
this.reportRefreshFailure(refreshError, requestId);
logger_1.logger.error('Token刷新失败', {
requestId,
operation,
attempt: attempt + 1,
refreshError: refreshError instanceof Error ? refreshError.message : refreshError,
tokenBlacklisted: this.tokenBlacklisted
});
// 如果token已被拉黑,立即抛出错误
if (this.tokenBlacklisted) {
throw new Error(`CodeWhisperer token已拉黑: 连续刷新失败${this.consecutiveRefreshFailures}次`);
}
// 如果token刷新失败,抛出刷新错误
throw new Error(`Token刷新失败: ${refreshError instanceof Error ? refreshError.message : refreshError}`);
}
}
else {
// 非403错误,不需要重试,直接抛出
logger_1.logger.error(`非token错误,不进行重试`, {
requestId,
operation,
statusCode: axios_1.default.isAxiosError(error) ? error.response?.status : 'unknown',
errorMessage: error instanceof Error ? error.message : error
});
throw error;
}
}
}
// 如果所有重试都失败,抛出最后一个错误
logger_1.logger.error(`所有重试尝试都失败`, {
requestId,
operation,
maxRetries: this.maxRetries,
tokenBlacklisted: this.tokenBlacklisted,
lastError: lastError instanceof Error ? lastError.message : lastError
});
throw lastError;
}
/**
* 获取认证信息 - 修复支持authMethod
*/
async getAuthInfo() {
// 🚨 关键修复:使用auth的新getAuthInfo方法获取完整认证信息
const authInfo = await this.auth.getAuthInfo();
logger_1.logger.debug('获取认证信息成功', {
tokenLength: authInfo.token.length,
profileArnLength: authInfo.profileArn.length,
authMethod: authInfo.authMethod,
strategy: 'enhanced-auth-info-realtime'
});
return {
accessToken: authInfo.token,
profileArn: authInfo.profileArn,
authMethod: authInfo.authMethod
};
}
/**
* 构建和验证请求 - 修复支持authMethod条件判断
*/
async buildAndValidateRequest(anthropicReq, profileArn, authMethod) {
// 🚨 关键修复:传递authMethod给converter,支持demo3的条件判断逻辑
const cwReq = await this.converter.buildCodeWhispererRequest(anthropicReq, profileArn, authMethod);
logger_1.logger.debug('构建CodeWhisperer请求完成 (realtime)', {
conversationId: cwReq.conversationState.conversationId,
authMethod,
hasProfileArn: !!cwReq.profileArn,
strategy: 'demo3-conditional-logic-realtime'
});
const validation = this.converter.validateRequest(cwReq);
if (!validation.isValid) {
throw new Error(`请求格式验证失败: ${validation.errors.join(', ')}`);
}
if (validation.warnings.length > 0) {
logger_1.logger.warn('请求验证警告', { warnings: validation.warnings });
}
return cwReq;
}
/**
* 发送HTTP请求
*/
async sendHttpRequest(accessToken, requestBody, requestId) {
logger_1.logger.debug('发送CodeWhisperer实时请求', {
requestId,
requestSize: requestBody.length,
endpoint: 'https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse',
});
const response = await axios_1.default.post('https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse', requestBody, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'Accept': 'text/event-stream',
},
responseType: 'arraybuffer',
timeout: this.httpTimeout,
});
if (response.status !== 200) {
throw new Error(`HTTP请求失败,状态码: ${response.status}`);
}
const responseBuffer = Buffer.from(response.data);
logger_1.logger.debug('收到CodeWhisperer实时响应', {
requestId,
responseSize: responseBuffer.length,
});
return responseBuffer;
}
/**
* 发送非流式HTTP请求
*/
async sendNonStreamHttpRequest(accessToken, requestBody, requestId) {
logger_1.logger.debug('发送CodeWhisperer实时非流式请求', {
requestId,
requestSize: requestBody.length,
});
const response = await axios_1.default.post('https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse', requestBody, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
responseType: 'arraybuffer',
timeout: this.httpTimeout,
});
if (response.status !== 200) {
throw new Error(`HTTP请求失败,状态码: ${response.status}`);
}
return Buffer.from(response.data);
}
/**
* 处理流式请求错误
*/
async handleStreamError(error, onError) {
logger_1.logger.error('实时流式请求处理失败', error);
const errorMessage = error instanceof Error ? error.message : String(error);
onError(`CodeWhisperer实时请求失败: ${errorMessage}`, error);
}
/**
* 创建请求信息
*/
createRequestInfo(anthropicReq, requestId) {
return {
requestId,
model: anthropicReq.model,
messageCount: anthropicReq.messages.length,
hasTools: !!(anthropicReq.tools && anthropicReq.tools.length > 0),
hasSystem: !!(anthropicReq.system && anthropicReq.system.length > 0),
contentLength: this.calculateMessageLength(anthropicReq),
activeStreams: this.activeStreams.size,
};
}
/**
* 计算消息长度
*/
calculateMessageLength(anthropicReq) {
let totalLength = 0;
if (anthropicReq.system) {
for (const sysMsg of anthropicReq.system) {
totalLength += sysMsg.text.length;
}
}
for (const message of anthropicReq.messages) {
totalLength += this.calculateContentLength(message.content);
}
return totalLength;
}
/**
* 计算内容长度
*/
calculateContentLength(content) {
if (typeof content === 'string') {
return content.length;
}
if (Array.isArray(content)) {
return content.reduce((total, block) => {
if (typeof block === 'string') {
return total + block.length;
}
if (block && typeof block === 'object' && 'text' in block) {
return total + (block.text?.length || 0);
}
return total;
}, 0);
}
return 0;
}
/**
* 睡眠函数
*/
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 将Buffer转换为Readable流
*/
bufferToStream(buffer) {
const { Readable } = require('stream');
return Readable.from([buffer]);
}
}
exports.CodeWhispererRealtimeClient = CodeWhispererRealtimeClient;
//# sourceMappingURL=client-realtime.js.map