@juspay/neurolink 12.58.1 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/CHANGELOG.md +14 -3
  2. package/dist/auth/anthropicOAuth.js +3 -3
  3. package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
  4. package/dist/auth/sessionManager.js +4 -4
  5. package/dist/auth/tokenStore.js +4 -4
  6. package/dist/browser/neurolink.min.js +474 -473
  7. package/dist/cli/commands/observability.d.ts +1 -6
  8. package/dist/cli/commands/observability.js +0 -106
  9. package/dist/cli/commands/proxy.js +9 -18
  10. package/dist/cli/commands/telemetry.d.ts +3 -13
  11. package/dist/cli/commands/telemetry.js +7 -354
  12. package/dist/cli/loop/session.js +1 -1
  13. package/dist/client/httpClient.js +1 -1
  14. package/dist/client/sseClient.js +1 -1
  15. package/dist/client/streamingClient.js +2 -2
  16. package/dist/client/wsClient.js +1 -1
  17. package/dist/constants/langfuse.d.ts +25 -0
  18. package/dist/constants/langfuse.js +38 -0
  19. package/dist/constants/telemetry.d.ts +20 -0
  20. package/dist/constants/telemetry.js +34 -0
  21. package/dist/core/baseProvider.d.ts +2 -1
  22. package/dist/core/baseProvider.js +4 -11
  23. package/dist/core/conversationMemoryManager.js +5 -8
  24. package/dist/core/factory.js +1 -1
  25. package/dist/core/geminiLoopAdapter.d.ts +8 -1
  26. package/dist/core/geminiLoopAdapter.js +25 -1
  27. package/dist/core/loopEngine.js +69 -40
  28. package/dist/core/modules/MessageBuilder.js +2 -2
  29. package/dist/core/modules/StreamHandler.js +2 -2
  30. package/dist/core/modules/TelemetryHandler.d.ts +2 -18
  31. package/dist/core/modules/TelemetryHandler.js +1 -66
  32. package/dist/core/modules/ToolsManager.js +40 -31
  33. package/dist/core/nativeGenerateLoop.js +78 -8
  34. package/dist/core/redisConversationMemoryManager.js +8 -15
  35. package/dist/core/toolExecutionGuards.js +1 -13
  36. package/dist/index.d.ts +5 -12
  37. package/dist/index.js +5 -37
  38. package/dist/mcp/batching/requestBatcher.js +1 -1
  39. package/dist/mcp/externalServerManager.js +3 -21
  40. package/dist/mcp/toolDiscoveryService.js +4 -16
  41. package/dist/mcp/toolRegistry.js +2 -5
  42. package/dist/memory/memoryRetrievalTools.js +1 -1
  43. package/dist/neurolink.d.ts +16 -27
  44. package/dist/neurolink.js +788 -792
  45. package/dist/observability/exporterSpanProcessor.d.ts +50 -0
  46. package/dist/observability/exporterSpanProcessor.js +181 -0
  47. package/dist/observability/exporters/langfuseExporter.d.ts +13 -34
  48. package/dist/observability/exporters/langfuseExporter.js +101 -154
  49. package/dist/observability/index.d.ts +1 -0
  50. package/dist/observability/index.js +1 -0
  51. package/dist/observability/langfuseMasking.d.ts +8 -0
  52. package/dist/observability/langfuseMasking.js +47 -0
  53. package/dist/observability/otlpEncoding.d.ts +20 -0
  54. package/dist/observability/otlpEncoding.js +85 -0
  55. package/dist/providers/amazonBedrock/client.js +142 -176
  56. package/dist/providers/amazonBedrock/loopAdapter.js +14 -1
  57. package/dist/providers/amazonSagemaker.js +118 -80
  58. package/dist/providers/anthropic/client.js +3 -52
  59. package/dist/providers/anthropic/loopAdapter.js +24 -1
  60. package/dist/providers/anthropic/rateLimitCapture.js +9 -12
  61. package/dist/providers/googleAiStudio/client.d.ts +4 -5
  62. package/dist/providers/googleAiStudio/client.js +38 -40
  63. package/dist/providers/googleVertex/client.d.ts +2 -7
  64. package/dist/providers/googleVertex/client.js +282 -378
  65. package/dist/providers/googleVertex/constants.js +2 -2
  66. package/dist/providers/litellm/client.d.ts +2 -9
  67. package/dist/providers/litellm/client.js +1 -63
  68. package/dist/providers/openAI/client.d.ts +1 -8
  69. package/dist/providers/openAI/client.js +0 -65
  70. package/dist/providers/openaiChatCompletionsBase.d.ts +1 -0
  71. package/dist/providers/openaiChatCompletionsBase.js +61 -4
  72. package/dist/providers/replicate.js +22 -4
  73. package/dist/proxy/codexUsage.js +7 -0
  74. package/dist/proxy/proxyFetch.js +19 -25
  75. package/dist/proxy/proxyTracer.d.ts +14 -7
  76. package/dist/proxy/proxyTracer.js +129 -83
  77. package/dist/proxy/proxyTranslationEngine.js +0 -1
  78. package/dist/proxy/requestLogger.d.ts +1 -1
  79. package/dist/proxy/requestLogger.js +39 -45
  80. package/dist/server/middleware/common.js +1 -1
  81. package/dist/server/routes/agentRoutes.js +4 -4
  82. package/dist/server/routes/claudeProxyRoutes.js +99 -196
  83. package/dist/server/routes/codexProxyRoutes.js +621 -591
  84. package/dist/server/routes/healthRoutes.js +6 -6
  85. package/dist/server/routes/mcpRoutes.js +7 -7
  86. package/dist/server/routes/memoryRoutes.js +7 -7
  87. package/dist/server/routes/openApiRoutes.js +3 -3
  88. package/dist/server/routes/toolRoutes.js +5 -5
  89. package/dist/server/routes/transcribeRoutes.js +1 -1
  90. package/dist/server/utils/validation.d.ts +3 -3
  91. package/dist/services/server/ai/observability/instrumentation.d.ts +34 -201
  92. package/dist/services/server/ai/observability/instrumentation.js +220 -1267
  93. package/dist/services/server/ai/observability/langfuseSetup.d.ts +14 -0
  94. package/dist/services/server/ai/observability/langfuseSetup.js +55 -0
  95. package/dist/services/server/ai/observability/otlpSetup.d.ts +16 -0
  96. package/dist/services/server/ai/observability/otlpSetup.js +58 -0
  97. package/dist/session/globalSessionState.js +0 -11
  98. package/dist/telemetry/attributes.d.ts +23 -46
  99. package/dist/telemetry/attributes.js +76 -162
  100. package/dist/telemetry/chatMessages.d.ts +13 -0
  101. package/dist/telemetry/chatMessages.js +59 -0
  102. package/dist/telemetry/index.d.ts +5 -19
  103. package/dist/telemetry/index.js +5 -26
  104. package/dist/telemetry/observation.d.ts +37 -0
  105. package/dist/telemetry/observation.js +112 -0
  106. package/dist/telemetry/observationNames.d.ts +18 -0
  107. package/dist/telemetry/observationNames.js +24 -0
  108. package/dist/telemetry/spanSanitizer.d.ts +39 -0
  109. package/dist/telemetry/spanSanitizer.js +92 -0
  110. package/dist/telemetry/spanSerialization.d.ts +13 -0
  111. package/dist/telemetry/spanSerialization.js +46 -0
  112. package/dist/telemetry/tracers.d.ts +37 -18
  113. package/dist/telemetry/tracers.js +97 -19
  114. package/dist/telemetry/withSpan.d.ts +47 -25
  115. package/dist/telemetry/withSpan.js +158 -71
  116. package/dist/types/cli.d.ts +0 -11
  117. package/dist/types/decision.d.ts +3 -0
  118. package/dist/types/exporter.d.ts +54 -0
  119. package/dist/types/exporter.js +0 -4
  120. package/dist/types/generate.d.ts +4 -1
  121. package/dist/types/isolatedAgent.d.ts +5 -4
  122. package/dist/types/loopEngine.d.ts +18 -28
  123. package/dist/types/observability.d.ts +127 -160
  124. package/dist/types/providers.d.ts +15 -0
  125. package/dist/types/proxy.d.ts +41 -2
  126. package/dist/utils/anthropicTraceSanitizer.d.ts +2 -2
  127. package/dist/utils/anthropicTraceSanitizer.js +3 -1
  128. package/dist/utils/conversationMemory.js +4 -4
  129. package/dist/utils/fileDetector.js +1 -1
  130. package/dist/utils/messageBuilder.js +1 -1
  131. package/dist/utils/noOutputSentinel.d.ts +4 -16
  132. package/dist/utils/noOutputSentinel.js +12 -28
  133. package/dist/utils/providerRetry.js +4 -4
  134. package/dist/voice/livekit/brain.js +1 -1
  135. package/dist/voice/livekit/realtimeMemory.d.ts +1 -1
  136. package/dist/voice/livekit/realtimeMemory.js +66 -1
  137. package/dist/voice/livekit/realtimeVoiceAgent.js +1 -1
  138. package/docs-site/static/search-index.json +42 -63
  139. package/package.json +10 -4
  140. package/dist/telemetry/telemetryService.d.ts +0 -79
  141. package/dist/telemetry/telemetryService.js +0 -572
  142. package/dist/utils/observabilityHelpers.d.ts +0 -27
  143. package/dist/utils/observabilityHelpers.js +0 -47
@@ -2306,7 +2306,10 @@ function extractResponseInfo(responseJson) {
2306
2306
  * streaming path records the same gen_ai.response.* attributes as non-streaming.
2307
2307
  */
2308
2308
  function responseInfoFromStream(data) {
2309
- const info = {};
2309
+ const info = {
2310
+ output: data.contentBlocks,
2311
+ firstOutputAt: data.firstUsefulOutputAt,
2312
+ };
2310
2313
  if (data.model) {
2311
2314
  info.responseModel = data.model;
2312
2315
  }
@@ -2736,6 +2739,64 @@ function trackUpstreamReadableStream(source) {
2736
2739
  });
2737
2740
  return { stream, outcome: tracker.outcome };
2738
2741
  }
2742
+ function settleStreamSpend(account, model, usage) {
2743
+ settleBorrowedRequest(account.key, model, usage);
2744
+ recordLeasedAccountSpend(account.label, model, usage);
2745
+ }
2746
+ function logStreamFinal(logFinalRequest, failure, accountLabel, accountType, usage) {
2747
+ logFinalRequest(failure?.status ?? 200, accountLabel, accountType, failure?.errorType, failure?.message, usage);
2748
+ }
2749
+ function streamUsageFields(usage) {
2750
+ return {
2751
+ inputTokens: usage.inputTokens,
2752
+ outputTokens: usage.outputTokens,
2753
+ cacheCreationTokens: usage.cacheCreationInputTokens,
2754
+ ...oneHourCacheWriteFields(usage.cacheCreation1hInputTokens),
2755
+ cacheReadTokens: usage.cacheReadInputTokens,
2756
+ };
2757
+ }
2758
+ function setRateLimitUsage(tracer, response, usage) {
2759
+ const rateLimit5h = parseFloat(response.headers.get("anthropic-ratelimit-unified-5h-utilization") ?? "");
2760
+ const rateLimit7d = parseFloat(response.headers.get("anthropic-ratelimit-unified-7d-utilization") ?? "");
2761
+ if (isNaN(rateLimit5h) && isNaN(rateLimit7d)) {
2762
+ return;
2763
+ }
2764
+ const usageUpdate = streamUsageFields(usage);
2765
+ if (!isNaN(rateLimit5h)) {
2766
+ usageUpdate.rateLimitAfter5h = rateLimit5h;
2767
+ }
2768
+ if (!isNaN(rateLimit7d)) {
2769
+ usageUpdate.rateLimitAfter7d = rateLimit7d;
2770
+ }
2771
+ tracer.setUsage(usageUpdate);
2772
+ }
2773
+ function logStreamBodies(args) {
2774
+ const { logProxyBody, headers, data, clientBody, requestStartTime } = args;
2775
+ const common = {
2776
+ headers,
2777
+ contentType: headers["content-type"] ?? "text/event-stream",
2778
+ account: args.account,
2779
+ accountType: args.accountType,
2780
+ attempt: args.attempt,
2781
+ responseStatus: args.responseStatus,
2782
+ };
2783
+ logProxyBody({
2784
+ ...common,
2785
+ phase: "upstream_response",
2786
+ body: data.rawText ?? "",
2787
+ sourceTruncated: data.rawTextTruncated,
2788
+ bodySize: data.totalBytesReceived,
2789
+ durationMs: Date.now() - requestStartTime,
2790
+ });
2791
+ logProxyBody({
2792
+ ...common,
2793
+ phase: "client_response",
2794
+ body: clientBody.text,
2795
+ sourceTruncated: clientBody.truncated,
2796
+ bodySize: clientBody.totalBytes,
2797
+ durationMs: Date.now() - requestStartTime,
2798
+ });
2799
+ }
2739
2800
  async function handleClaudePassthroughStreamResponse(args) {
2740
2801
  const { ctx, bodyStr, response, tracer, requestStartTime, upstreamSpan, upstreamResponseHeaders, logProxyBody, logFinalRequest, } = args;
2741
2802
  const responseHeaders = { ...upstreamResponseHeaders };
@@ -2779,73 +2840,28 @@ async function handleClaudePassthroughStreamResponse(args) {
2779
2840
  const terminalOutcome = mergeStreamTerminalOutcome(rawOutcome, data.streamErrorMessage, data.messageStopReceived);
2780
2841
  observeClaudeStreamOutput(ctx.metadata, data);
2781
2842
  const failure = getStreamFailureDetails(terminalOutcome);
2782
- capturedTracer.setUsage({
2783
- inputTokens: data.usage.inputTokens,
2784
- outputTokens: data.usage.outputTokens,
2785
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
2786
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
2787
- cacheReadTokens: data.usage.cacheReadInputTokens,
2788
- });
2843
+ capturedTracer.setUsage(streamUsageFields(data.usage));
2789
2844
  capturedTracer.logStreamEvents(data.events);
2790
2845
  capturedTracer.setResponseInfo(responseInfoFromStream(data));
2791
- const rateLimit5h = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-5h-utilization") ?? "");
2792
- const rateLimit7d = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-7d-utilization") ?? "");
2793
- const usageUpdate = {
2794
- inputTokens: data.usage.inputTokens,
2795
- outputTokens: data.usage.outputTokens,
2796
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
2797
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
2798
- cacheReadTokens: data.usage.cacheReadInputTokens,
2799
- };
2800
- if (!isNaN(rateLimit5h)) {
2801
- usageUpdate.rateLimitAfter5h = rateLimit5h;
2802
- }
2803
- if (!isNaN(rateLimit7d)) {
2804
- usageUpdate.rateLimitAfter7d = rateLimit7d;
2805
- }
2806
- if (!isNaN(rateLimit5h) || !isNaN(rateLimit7d)) {
2807
- capturedTracer.setUsage(usageUpdate);
2808
- }
2846
+ setRateLimitUsage(capturedTracer, capturedResponse, data.usage);
2809
2847
  capturedTracer.logUpstreamResponseBody(data.rawText ?? "");
2810
- capturedTracer.recordMetrics();
2811
2848
  capturedTracer.recordBodySizes(capturedRequestBytes, data.totalBytesReceived);
2812
2849
  capturedUpstreamSpan?.end();
2813
2850
  if (failure) {
2814
2851
  capturedTracer.setError(failure.errorType, failure.message);
2815
2852
  }
2816
2853
  capturedTracer.end(failure?.status ?? response.status, Date.now() - requestStartTime);
2817
- finalizeStream(failure?.status ?? response.status, failure?.errorType, failure?.message, {
2818
- inputTokens: data.usage.inputTokens,
2819
- outputTokens: data.usage.outputTokens,
2820
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
2821
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
2822
- cacheReadTokens: data.usage.cacheReadInputTokens,
2823
- });
2824
- logProxyBody({
2825
- phase: "upstream_response",
2826
- headers: responseHeaders,
2827
- body: data.rawText ?? "",
2828
- sourceTruncated: data.rawTextTruncated,
2829
- bodySize: data.totalBytesReceived,
2830
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
2831
- account: "passthrough",
2832
- accountType: "passthrough",
2833
- attempt: 1,
2834
- responseStatus: 200,
2835
- durationMs: Date.now() - requestStartTime,
2836
- });
2837
- logProxyBody({
2838
- phase: "client_response",
2854
+ finalizeStream(failure?.status ?? response.status, failure?.errorType, failure?.message, streamUsageFields(data.usage));
2855
+ logStreamBodies({
2856
+ logProxyBody,
2839
2857
  headers: responseHeaders,
2840
- body: clientBody.text,
2841
- sourceTruncated: clientBody.truncated,
2842
- bodySize: clientBody.totalBytes,
2843
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
2858
+ data,
2859
+ clientBody,
2844
2860
  account: "passthrough",
2845
2861
  accountType: "passthrough",
2846
2862
  attempt: 1,
2847
2863
  responseStatus: 200,
2848
- durationMs: Date.now() - requestStartTime,
2864
+ requestStartTime,
2849
2865
  });
2850
2866
  })
2851
2867
  .catch((error) => {
@@ -2886,38 +2902,17 @@ async function handleClaudePassthroughStreamResponse(args) {
2886
2902
  const terminalOutcome = mergeStreamTerminalOutcome(rawOutcome, data.streamErrorMessage, data.messageStopReceived);
2887
2903
  observeClaudeStreamOutput(ctx.metadata, data);
2888
2904
  const failure = getStreamFailureDetails(terminalOutcome);
2889
- finalizeStream(failure?.status ?? response.status, failure?.errorType, failure?.message, {
2890
- inputTokens: data.usage.inputTokens,
2891
- outputTokens: data.usage.outputTokens,
2892
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
2893
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
2894
- cacheReadTokens: data.usage.cacheReadInputTokens,
2895
- });
2896
- logProxyBody({
2897
- phase: "upstream_response",
2898
- headers: responseHeaders,
2899
- body: data.rawText ?? "",
2900
- sourceTruncated: data.rawTextTruncated,
2901
- bodySize: data.totalBytesReceived,
2902
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
2903
- account: "passthrough",
2904
- accountType: "passthrough",
2905
- attempt: 1,
2906
- responseStatus: response.status,
2907
- durationMs: Date.now() - requestStartTime,
2908
- });
2909
- logProxyBody({
2910
- phase: "client_response",
2905
+ finalizeStream(failure?.status ?? response.status, failure?.errorType, failure?.message, streamUsageFields(data.usage));
2906
+ logStreamBodies({
2907
+ logProxyBody,
2911
2908
  headers: responseHeaders,
2912
- body: clientBody.text,
2913
- sourceTruncated: clientBody.truncated,
2914
- bodySize: clientBody.totalBytes,
2915
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
2909
+ data,
2910
+ clientBody,
2916
2911
  account: "passthrough",
2917
2912
  accountType: "passthrough",
2918
2913
  attempt: 1,
2919
2914
  responseStatus: response.status,
2920
- durationMs: Date.now() - requestStartTime,
2915
+ requestStartTime,
2921
2916
  });
2922
2917
  })
2923
2918
  .catch((error) => {
@@ -3012,7 +3007,6 @@ async function handleClaudePassthroughJsonResponse(args) {
3012
3007
  }
3013
3008
  }
3014
3009
  tracer.setResponseInfo(extractResponseInfo(responseJson));
3015
- tracer.recordMetrics();
3016
3010
  const responseJsonStr = JSON.stringify(responseJson);
3017
3011
  tracer.recordBodySizes(bodyStr.length, responseJsonStr.length);
3018
3012
  upstreamSpan?.end();
@@ -5251,99 +5245,38 @@ function attachAnthropicSuccessStreamTelemetry(args) {
5251
5245
  const capturedResponse = response;
5252
5246
  const capturedRequestBytes = finalBodyStr.length;
5253
5247
  const capturedAccountLabel = account.label;
5254
- const capturedAccountKey = account.key;
5255
5248
  telemetryDone = Promise.all([telemetry, clientCapture, streamOutcome])
5256
5249
  .then(([data, clientBody, rawOutcome]) => {
5257
5250
  const terminalOutcome = mergeStreamTerminalOutcome(rawOutcome, data.streamErrorMessage, data.messageStopReceived);
5258
5251
  observeClaudeStreamOutput(ctx.metadata, data);
5259
5252
  recordCommittedAnthropicStreamAttemptFailure(terminalOutcome, account, logAttempt);
5260
- capturedTracer.setUsage({
5261
- inputTokens: data.usage.inputTokens,
5262
- outputTokens: data.usage.outputTokens,
5263
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
5264
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
5265
- cacheReadTokens: data.usage.cacheReadInputTokens,
5266
- });
5253
+ const usage = streamUsageFields(data.usage);
5254
+ capturedTracer.setUsage(usage);
5267
5255
  // Bill the borrowing grant from the same totals. A stream's usage is
5268
5256
  // only final at message_delta, which is exactly here.
5269
- settleBorrowedRequest(capturedAccountKey, data.model, {
5270
- inputTokens: data.usage.inputTokens,
5271
- outputTokens: data.usage.outputTokens,
5272
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
5273
- cacheReadTokens: data.usage.cacheReadInputTokens,
5274
- });
5275
- recordLeasedAccountSpend(capturedAccountLabel, data.model, {
5276
- inputTokens: data.usage.inputTokens,
5277
- outputTokens: data.usage.outputTokens,
5278
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
5279
- cacheReadTokens: data.usage.cacheReadInputTokens,
5280
- });
5257
+ settleStreamSpend(account, data.model, usage);
5281
5258
  capturedTracer.logStreamEvents(data.events);
5282
5259
  capturedTracer.setResponseInfo(responseInfoFromStream(data));
5283
- const rateLimit5h = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-5h-utilization") ?? "");
5284
- const rateLimit7d = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-7d-utilization") ?? "");
5285
- const usageUpdate = {
5286
- inputTokens: data.usage.inputTokens,
5287
- outputTokens: data.usage.outputTokens,
5288
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
5289
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
5290
- cacheReadTokens: data.usage.cacheReadInputTokens,
5291
- };
5292
- if (!isNaN(rateLimit5h)) {
5293
- usageUpdate.rateLimitAfter5h = rateLimit5h;
5294
- }
5295
- if (!isNaN(rateLimit7d)) {
5296
- usageUpdate.rateLimitAfter7d = rateLimit7d;
5297
- }
5298
- if (!isNaN(rateLimit5h) || !isNaN(rateLimit7d)) {
5299
- capturedTracer.setUsage(usageUpdate);
5300
- }
5260
+ setRateLimitUsage(capturedTracer, capturedResponse, data.usage);
5301
5261
  capturedTracer.logUpstreamResponseBody(data.rawText ?? "");
5302
- capturedTracer.recordMetrics();
5303
5262
  capturedTracer.recordBodySizes(capturedRequestBytes, data.totalBytesReceived);
5304
5263
  capturedUpstreamSpan?.end();
5305
5264
  const failure = getStreamFailureDetails(terminalOutcome);
5306
- const usage = {
5307
- inputTokens: data.usage.inputTokens,
5308
- outputTokens: data.usage.outputTokens,
5309
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
5310
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
5311
- cacheReadTokens: data.usage.cacheReadInputTokens,
5312
- };
5313
5265
  if (failure) {
5314
5266
  capturedTracer.setError(failure.errorType, failure.message);
5315
- capturedTracer.end(failure.status, Date.now() - requestStartTime);
5316
- logFinalRequest(failure.status, capturedAccountLabel, account.type, failure.errorType, failure.message, usage);
5317
- }
5318
- else {
5319
- capturedTracer.end(200, Date.now() - requestStartTime);
5320
- logFinalRequest(200, capturedAccountLabel, account.type, undefined, undefined, usage);
5321
5267
  }
5322
- logProxyBody({
5323
- phase: "upstream_response",
5324
- headers: responseHeaders,
5325
- body: data.rawText ?? "",
5326
- sourceTruncated: data.rawTextTruncated,
5327
- bodySize: data.totalBytesReceived,
5328
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
5329
- account: capturedAccountLabel,
5330
- accountType: account.type,
5331
- attempt: attemptNumber,
5332
- responseStatus: 200,
5333
- durationMs: Date.now() - requestStartTime,
5334
- });
5335
- logProxyBody({
5336
- phase: "client_response",
5268
+ capturedTracer.end(failure?.status ?? 200, Date.now() - requestStartTime);
5269
+ logStreamFinal(logFinalRequest, failure, capturedAccountLabel, account.type, usage);
5270
+ logStreamBodies({
5271
+ logProxyBody,
5337
5272
  headers: responseHeaders,
5338
- body: clientBody.text,
5339
- sourceTruncated: clientBody.truncated,
5340
- bodySize: clientBody.totalBytes,
5341
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
5273
+ data,
5274
+ clientBody,
5342
5275
  account: capturedAccountLabel,
5343
5276
  accountType: account.type,
5344
5277
  attempt: attemptNumber,
5345
5278
  responseStatus: 200,
5346
- durationMs: Date.now() - requestStartTime,
5279
+ requestStartTime,
5347
5280
  });
5348
5281
  })
5349
5282
  .catch((error) => {
@@ -5382,7 +5315,6 @@ function attachAnthropicSuccessStreamTelemetry(args) {
5382
5315
  });
5383
5316
  streamSource = streamSource.pipeThrough(noTracerInterceptor);
5384
5317
  const capturedAccountLabel = account.label;
5385
- const capturedAccountKey = account.key;
5386
5318
  telemetryDone = Promise.all([
5387
5319
  noTracerTelemetry,
5388
5320
  clientCapture,
@@ -5393,48 +5325,21 @@ function attachAnthropicSuccessStreamTelemetry(args) {
5393
5325
  observeClaudeStreamOutput(ctx.metadata, data);
5394
5326
  recordCommittedAnthropicStreamAttemptFailure(terminalOutcome, account, logAttempt);
5395
5327
  const failure = getStreamFailureDetails(terminalOutcome);
5396
- const usage = {
5397
- inputTokens: data.usage.inputTokens,
5398
- outputTokens: data.usage.outputTokens,
5399
- cacheCreationTokens: data.usage.cacheCreationInputTokens,
5400
- ...oneHourCacheWriteFields(data.usage.cacheCreation1hInputTokens),
5401
- cacheReadTokens: data.usage.cacheReadInputTokens,
5402
- };
5328
+ const usage = streamUsageFields(data.usage);
5403
5329
  // Settled on the untraced path too: whether telemetry is exported has
5404
5330
  // nothing to do with whether a borrower should be charged.
5405
- settleBorrowedRequest(capturedAccountKey, data.model, usage);
5406
- recordLeasedAccountSpend(capturedAccountLabel, data.model, usage);
5407
- if (failure) {
5408
- logFinalRequest(failure.status, capturedAccountLabel, account.type, failure.errorType, failure.message, usage);
5409
- }
5410
- else {
5411
- logFinalRequest(200, capturedAccountLabel, account.type, undefined, undefined, usage);
5412
- }
5413
- logProxyBody({
5414
- phase: "upstream_response",
5415
- headers: responseHeaders,
5416
- body: data.rawText ?? "",
5417
- sourceTruncated: data.rawTextTruncated,
5418
- bodySize: data.totalBytesReceived,
5419
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
5420
- account: capturedAccountLabel,
5421
- accountType: account.type,
5422
- attempt: attemptNumber,
5423
- responseStatus: 200,
5424
- durationMs: Date.now() - requestStartTime,
5425
- });
5426
- logProxyBody({
5427
- phase: "client_response",
5331
+ settleStreamSpend(account, data.model, usage);
5332
+ logStreamFinal(logFinalRequest, failure, capturedAccountLabel, account.type, usage);
5333
+ logStreamBodies({
5334
+ logProxyBody,
5428
5335
  headers: responseHeaders,
5429
- body: clientBody.text,
5430
- sourceTruncated: clientBody.truncated,
5431
- bodySize: clientBody.totalBytes,
5432
- contentType: responseHeaders["content-type"] ?? "text/event-stream",
5336
+ data,
5337
+ clientBody,
5433
5338
  account: capturedAccountLabel,
5434
5339
  accountType: account.type,
5435
5340
  attempt: attemptNumber,
5436
5341
  responseStatus: 200,
5437
- durationMs: Date.now() - requestStartTime,
5342
+ requestStartTime,
5438
5343
  });
5439
5344
  })
5440
5345
  .catch((error) => {
@@ -5569,7 +5474,6 @@ async function handleAnthropicJsonSuccessResponse(args) {
5569
5474
  }
5570
5475
  }
5571
5476
  tracer.setResponseInfo(extractResponseInfo(responseJson));
5572
- tracer.recordMetrics();
5573
5477
  const responseJsonStr = JSON.stringify(responseJson);
5574
5478
  tracer.recordBodySizes(finalBodyStr.length, responseJsonStr.length);
5575
5479
  upstreamSpan?.end();
@@ -5672,7 +5576,6 @@ async function handleAnthropicSuccessfulNonStreamRetryResponse(args) {
5672
5576
  });
5673
5577
  }
5674
5578
  tracer.setResponseInfo(extractResponseInfo(retryJson));
5675
- tracer.recordMetrics();
5676
5579
  const retryJsonStr = JSON.stringify(retryJson);
5677
5580
  tracer.recordBodySizes(finalBodyStr.length, retryJsonStr.length);
5678
5581
  upstreamSpan?.end();
@@ -8518,7 +8421,7 @@ export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrat
8518
8421
  ? runtimeConfigProvider().modelRouter
8519
8422
  : modelRouter;
8520
8423
  return withSpan({
8521
- name: "neurolink.http.claudeProxy.listModels",
8424
+ name: "http.claudeProxy.listModels",
8522
8425
  tracer: tracers.http,
8523
8426
  attributes: { "http.route": `${basePath}/v1/models` },
8524
8427
  }, async () => buildAnthropicModelsListResponse(requestModelRouter));
@@ -8533,7 +8436,7 @@ export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrat
8533
8436
  method: "POST",
8534
8437
  path: `${basePath}/v1/messages/count_tokens`,
8535
8438
  handler: async (ctx) => withSpan({
8536
- name: "neurolink.http.claudeProxy.countTokens",
8439
+ name: "http.claudeProxy.countTokens",
8537
8440
  tracer: tracers.http,
8538
8441
  attributes: {
8539
8442
  "http.route": `${basePath}/v1/messages/count_tokens`,
@@ -8552,7 +8455,7 @@ export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrat
8552
8455
  .join(" ");
8553
8456
  const inputTokens = Math.ceil(text.length / 4);
8554
8457
  span.setAttribute("ai.model", body.model);
8555
- span.setAttribute("gen_ai.usage.input_tokens", inputTokens);
8458
+ span.setAttribute("ai.tokens.input", inputTokens);
8556
8459
  return { input_tokens: inputTokens };
8557
8460
  }),
8558
8461
  description: "Count tokens for a messages request",
@@ -8587,7 +8490,7 @@ export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrat
8587
8490
  const snapshotOnly = ctx.query?.snapshot === "true" || ctx.query?.snapshot === "1";
8588
8491
  const accountFilter = ctx.query?.account;
8589
8492
  return withSpan({
8590
- name: "neurolink.http.claudeProxy.limits",
8493
+ name: "http.claudeProxy.limits",
8591
8494
  tracer: tracers.http,
8592
8495
  attributes: { "http.route": `${basePath}/limits` },
8593
8496
  }, async () => {