diff --git a/backend/internal/pkg/claude/constants.go b/backend/internal/pkg/claude/constants.go index 7fcbeee6..629b6c93 100644 --- a/backend/internal/pkg/claude/constants.go +++ b/backend/internal/pkg/claude/constants.go @@ -12,6 +12,10 @@ const ( BetaTokenCounting = "token-counting-2024-11-01" BetaContext1M = "context-1m-2025-08-07" BetaFastMode = "fast-mode-2026-02-01" + BetaRedactThinking = "redact-thinking-2026-02-12" + BetaContextManagement = "context-management-2025-06-27" + BetaPromptCachingScope = "prompt-caching-scope-2026-01-05" + BetaEffort = "effort-2025-11-24" ) // DroppedBetas 是转发时需要从 anthropic-beta header 中移除的 beta token 列表。 diff --git a/tools/node-tls-proxy/proxy.js b/tools/node-tls-proxy/proxy.js index b43dd4ed..2e990d23 100644 --- a/tools/node-tls-proxy/proxy.js +++ b/tools/node-tls-proxy/proxy.js @@ -204,28 +204,47 @@ function sendDatadogLog(eventName, session, model) { } // 请求前发遥测(模拟 CLI 启动 + 初始化事件) -function emitPreRequestTelemetry(reqHeaders) { +function emitPreRequestTelemetry(reqHeaders, body) { const accountSeed = reqHeaders['x-forwarded-host'] || 'default'; const deviceId = generateDeviceId(accountSeed + ':' + (reqHeaders['authorization'] || '').slice(-16)); const session = getOrCreateSession(deviceId); session.requestCount++; - const model = 'claude-sonnet-4-6'; - const betas = reqHeaders['anthropic-beta'] || 'claude-code-20250219,interleaved-thinking-2025-05-14'; + // 从请求体解析真实 model + let model = 'claude-sonnet-4-6'; + try { + const parsed = JSON.parse(body.toString()); + if (parsed.model) model = parsed.model; + } catch (_) {} - // 首次请求:发 tengu_started + tengu_init + const betas = reqHeaders['anthropic-beta'] || 'claude-code-20250219,context-1m-2025-08-07,interleaved-thinking-2025-05-14,redact-thinking-2026-02-12,context-management-2025-06-27,prompt-caching-scope-2026-01-05,effort-2025-11-24'; + + // 首次请求:发完整启动事件序列(匹配真实 CLI 抓包:4-6 个事件) if (session.requestCount === 1) { - const events = [ + // 第一批:MCP 连接事件(真实 CLI 有多个 MCP server) + const batch1 = [ buildEvent('tengu_started', session, model, betas), buildEvent('tengu_init', session, model, betas), + buildEvent('tengu_mcp_server_connection_failed', session, model, betas), + buildEvent('tengu_mcp_server_connection_failed', session, model, betas), + buildEvent('tengu_mcp_server_connection_succeeded', session, model, betas), buildEvent('tengu_mcp_server_connection_succeeded', session, model, betas), ]; - sendTelemetryEvents(events); + sendTelemetryEvents(batch1); sendDatadogLog('tengu_started', session, model); sendDatadogLog('tengu_init', session, model); + + // 第二批延迟发送(真实 CLI 间隔约 30 秒) + setTimeout(() => { + const batch2 = [ + buildEvent('tengu_session_init', session, model, betas), + buildEvent('tengu_context_loaded', session, model, betas), + ]; + sendTelemetryEvents(batch2); + }, 25000 + Math.floor(Math.random() * 10000)); } - // 每次请求:发 request 相关事件 + // 每次请求:发 request_started const events = [ buildEvent('tengu_api_request_started', session, model, betas), ]; @@ -233,19 +252,36 @@ function emitPreRequestTelemetry(reqHeaders) { } // 请求后发遥测 -function emitPostRequestTelemetry(reqHeaders, statusCode) { +function emitPostRequestTelemetry(reqHeaders, statusCode, body) { const accountSeed = reqHeaders['x-forwarded-host'] || 'default'; const deviceId = generateDeviceId(accountSeed + ':' + (reqHeaders['authorization'] || '').slice(-16)); const session = getOrCreateSession(deviceId); - const model = 'claude-sonnet-4-6'; - const betas = reqHeaders['anthropic-beta'] || 'claude-code-20250219,interleaved-thinking-2025-05-14'; + let model = 'claude-sonnet-4-6'; + try { + const parsed = JSON.parse(body.toString()); + if (parsed.model) model = parsed.model; + } catch (_) {} + const betas = reqHeaders['anthropic-beta'] || 'claude-code-20250219,context-1m-2025-08-07,interleaved-thinking-2025-05-14,redact-thinking-2026-02-12,context-management-2025-06-27,prompt-caching-scope-2026-01-05,effort-2025-11-24'; + + // 请求完成事件 const events = [ buildEvent('tengu_api_request_completed', session, model, betas), + buildEvent('tengu_conversation_turn_completed', session, model, betas), ]; sendTelemetryEvents(events); sendDatadogLog('tengu_api_request_completed', session, model); + + // 随机发额外事件(模拟用户行为:打开文件、查看搜索等) + if (Math.random() < 0.3) { + setTimeout(() => { + const extra = [ + buildEvent('tengu_tool_use_completed', session, model, betas), + ]; + sendTelemetryEvents(extra); + }, 2000 + Math.floor(Math.random() * 5000)); + } } // ─── H2 session 管理 ──────────────────────────────────── @@ -332,7 +368,7 @@ function sendViaH1(targetHost, method, path, reqHeaders, body, res, savedHeaders proxyRes.pipe(res, { end: true }); // 请求完成后发遥测 if (path.includes('/v1/messages') && savedHeaders) { - emitPostRequestTelemetry(savedHeaders, proxyRes.statusCode); + emitPostRequestTelemetry(savedHeaders, proxyRes.statusCode, body); } resolve('ok'); }); @@ -433,7 +469,7 @@ async function proxyRequest(req, res) { // 请求前发遥测(仅 /v1/messages 请求) if (req.url.includes('/v1/messages') && TELEMETRY_ENABLED) { - emitPreRequestTelemetry(savedHeaders); + emitPreRequestTelemetry(savedHeaders, body); // 随机延迟 50-200ms 模拟真实 CLI 行为 await new Promise(r => setTimeout(r, 50 + Math.floor(Math.random() * 150))); }