@juspay/neurolink 9.41.0 → 9.42.1

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 (212) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +7 -1
  3. package/dist/auth/anthropicOAuth.d.ts +18 -3
  4. package/dist/auth/anthropicOAuth.js +149 -4
  5. package/dist/auth/providers/firebase.js +5 -1
  6. package/dist/auth/providers/jwt.js +5 -1
  7. package/dist/auth/providers/workos.js +5 -1
  8. package/dist/auth/sessionManager.d.ts +1 -1
  9. package/dist/auth/sessionManager.js +58 -27
  10. package/dist/browser/neurolink.min.js +354 -334
  11. package/dist/cli/commands/mcp.d.ts +6 -0
  12. package/dist/cli/commands/mcp.js +188 -181
  13. package/dist/cli/commands/proxy.d.ts +2 -1
  14. package/dist/cli/commands/proxy.js +713 -431
  15. package/dist/cli/commands/task.js +3 -0
  16. package/dist/cli/factories/commandFactory.d.ts +2 -0
  17. package/dist/cli/factories/commandFactory.js +38 -0
  18. package/dist/cli/parser.js +4 -3
  19. package/dist/client/aiSdkAdapter.js +3 -0
  20. package/dist/client/streamingClient.js +30 -10
  21. package/dist/core/baseProvider.d.ts +6 -1
  22. package/dist/core/baseProvider.js +208 -230
  23. package/dist/core/factory.d.ts +3 -0
  24. package/dist/core/factory.js +138 -188
  25. package/dist/core/modules/GenerationHandler.js +3 -2
  26. package/dist/core/redisConversationMemoryManager.js +7 -3
  27. package/dist/evaluation/BatchEvaluator.js +4 -1
  28. package/dist/evaluation/hooks/observabilityHooks.js +5 -3
  29. package/dist/evaluation/pipeline/evaluationPipeline.d.ts +3 -2
  30. package/dist/evaluation/pipeline/evaluationPipeline.js +24 -9
  31. package/dist/evaluation/pipeline/strategies/batchStrategy.js +6 -3
  32. package/dist/evaluation/pipeline/strategies/samplingStrategy.js +18 -10
  33. package/dist/evaluation/scorers/scorerRegistry.d.ts +3 -0
  34. package/dist/evaluation/scorers/scorerRegistry.js +353 -282
  35. package/dist/lib/auth/anthropicOAuth.d.ts +18 -3
  36. package/dist/lib/auth/anthropicOAuth.js +149 -4
  37. package/dist/lib/auth/providers/firebase.js +5 -1
  38. package/dist/lib/auth/providers/jwt.js +5 -1
  39. package/dist/lib/auth/providers/workos.js +5 -1
  40. package/dist/lib/auth/sessionManager.d.ts +1 -1
  41. package/dist/lib/auth/sessionManager.js +58 -27
  42. package/dist/lib/client/aiSdkAdapter.js +3 -0
  43. package/dist/lib/client/streamingClient.js +30 -10
  44. package/dist/lib/core/baseProvider.d.ts +6 -1
  45. package/dist/lib/core/baseProvider.js +208 -230
  46. package/dist/lib/core/factory.d.ts +3 -0
  47. package/dist/lib/core/factory.js +138 -188
  48. package/dist/lib/core/modules/GenerationHandler.js +3 -2
  49. package/dist/lib/core/redisConversationMemoryManager.js +7 -3
  50. package/dist/lib/evaluation/BatchEvaluator.js +4 -1
  51. package/dist/lib/evaluation/hooks/observabilityHooks.js +5 -3
  52. package/dist/lib/evaluation/pipeline/evaluationPipeline.d.ts +3 -2
  53. package/dist/lib/evaluation/pipeline/evaluationPipeline.js +24 -9
  54. package/dist/lib/evaluation/pipeline/strategies/batchStrategy.js +6 -3
  55. package/dist/lib/evaluation/pipeline/strategies/samplingStrategy.js +18 -10
  56. package/dist/lib/evaluation/scorers/scorerRegistry.d.ts +3 -0
  57. package/dist/lib/evaluation/scorers/scorerRegistry.js +353 -282
  58. package/dist/lib/mcp/toolRegistry.d.ts +2 -0
  59. package/dist/lib/mcp/toolRegistry.js +32 -31
  60. package/dist/lib/neurolink.d.ts +41 -2
  61. package/dist/lib/neurolink.js +1616 -1681
  62. package/dist/lib/observability/otelBridge.d.ts +2 -2
  63. package/dist/lib/observability/otelBridge.js +12 -3
  64. package/dist/lib/providers/amazonBedrock.js +2 -4
  65. package/dist/lib/providers/anthropic.d.ts +9 -5
  66. package/dist/lib/providers/anthropic.js +19 -14
  67. package/dist/lib/providers/anthropicBaseProvider.d.ts +3 -3
  68. package/dist/lib/providers/anthropicBaseProvider.js +5 -4
  69. package/dist/lib/providers/azureOpenai.d.ts +1 -1
  70. package/dist/lib/providers/azureOpenai.js +5 -4
  71. package/dist/lib/providers/googleAiStudio.js +30 -6
  72. package/dist/lib/providers/googleVertex.d.ts +10 -0
  73. package/dist/lib/providers/googleVertex.js +437 -423
  74. package/dist/lib/providers/huggingFace.d.ts +3 -3
  75. package/dist/lib/providers/huggingFace.js +6 -8
  76. package/dist/lib/providers/litellm.d.ts +1 -0
  77. package/dist/lib/providers/litellm.js +76 -55
  78. package/dist/lib/providers/mistral.js +2 -1
  79. package/dist/lib/providers/ollama.js +93 -23
  80. package/dist/lib/providers/openAI.d.ts +2 -0
  81. package/dist/lib/providers/openAI.js +141 -141
  82. package/dist/lib/providers/openRouter.js +2 -1
  83. package/dist/lib/providers/openaiCompatible.d.ts +4 -4
  84. package/dist/lib/providers/openaiCompatible.js +4 -4
  85. package/dist/lib/proxy/claudeFormat.d.ts +3 -2
  86. package/dist/lib/proxy/claudeFormat.js +27 -14
  87. package/dist/lib/proxy/cloaking/plugins/sessionIdentity.d.ts +2 -6
  88. package/dist/lib/proxy/cloaking/plugins/sessionIdentity.js +9 -33
  89. package/dist/lib/proxy/modelRouter.js +3 -0
  90. package/dist/lib/proxy/oauthFetch.d.ts +1 -1
  91. package/dist/lib/proxy/oauthFetch.js +289 -316
  92. package/dist/lib/proxy/proxyConfig.js +46 -24
  93. package/dist/lib/proxy/proxyEnv.d.ts +19 -0
  94. package/dist/lib/proxy/proxyEnv.js +73 -0
  95. package/dist/lib/proxy/proxyFetch.js +291 -217
  96. package/dist/lib/proxy/proxyTracer.d.ts +133 -0
  97. package/dist/lib/proxy/proxyTracer.js +645 -0
  98. package/dist/lib/proxy/rawStreamCapture.d.ts +10 -0
  99. package/dist/lib/proxy/rawStreamCapture.js +83 -0
  100. package/dist/lib/proxy/requestLogger.d.ts +32 -5
  101. package/dist/lib/proxy/requestLogger.js +503 -47
  102. package/dist/lib/proxy/sseInterceptor.d.ts +97 -0
  103. package/dist/lib/proxy/sseInterceptor.js +427 -0
  104. package/dist/lib/proxy/usageStats.d.ts +4 -3
  105. package/dist/lib/proxy/usageStats.js +25 -12
  106. package/dist/lib/rag/chunkers/MarkdownChunker.js +13 -5
  107. package/dist/lib/rag/chunking/markdownChunker.js +15 -6
  108. package/dist/lib/server/routes/claudeProxyRoutes.d.ts +17 -3
  109. package/dist/lib/server/routes/claudeProxyRoutes.js +3032 -1349
  110. package/dist/lib/services/server/ai/observability/instrumentation.d.ts +7 -1
  111. package/dist/lib/services/server/ai/observability/instrumentation.js +337 -161
  112. package/dist/lib/tasks/backends/bullmqBackend.d.ts +1 -0
  113. package/dist/lib/tasks/backends/bullmqBackend.js +35 -22
  114. package/dist/lib/tasks/store/redisTaskStore.d.ts +1 -0
  115. package/dist/lib/tasks/store/redisTaskStore.js +54 -39
  116. package/dist/lib/tasks/taskManager.d.ts +5 -0
  117. package/dist/lib/tasks/taskManager.js +158 -30
  118. package/dist/lib/telemetry/index.d.ts +2 -1
  119. package/dist/lib/telemetry/index.js +2 -1
  120. package/dist/lib/telemetry/telemetryService.d.ts +3 -0
  121. package/dist/lib/telemetry/telemetryService.js +69 -5
  122. package/dist/lib/types/cli.d.ts +10 -0
  123. package/dist/lib/types/proxyTypes.d.ts +160 -5
  124. package/dist/lib/types/streamTypes.d.ts +25 -3
  125. package/dist/lib/utils/messageBuilder.js +3 -2
  126. package/dist/lib/utils/providerHealth.d.ts +19 -0
  127. package/dist/lib/utils/providerHealth.js +279 -33
  128. package/dist/lib/utils/providerUtils.js +17 -22
  129. package/dist/lib/utils/toolChoice.d.ts +4 -0
  130. package/dist/lib/utils/toolChoice.js +7 -0
  131. package/dist/mcp/toolRegistry.d.ts +2 -0
  132. package/dist/mcp/toolRegistry.js +32 -31
  133. package/dist/neurolink.d.ts +41 -2
  134. package/dist/neurolink.js +1616 -1681
  135. package/dist/observability/otelBridge.d.ts +2 -2
  136. package/dist/observability/otelBridge.js +12 -3
  137. package/dist/providers/amazonBedrock.js +2 -4
  138. package/dist/providers/anthropic.d.ts +9 -5
  139. package/dist/providers/anthropic.js +19 -14
  140. package/dist/providers/anthropicBaseProvider.d.ts +3 -3
  141. package/dist/providers/anthropicBaseProvider.js +5 -4
  142. package/dist/providers/azureOpenai.d.ts +1 -1
  143. package/dist/providers/azureOpenai.js +5 -4
  144. package/dist/providers/googleAiStudio.js +30 -6
  145. package/dist/providers/googleVertex.d.ts +10 -0
  146. package/dist/providers/googleVertex.js +437 -423
  147. package/dist/providers/huggingFace.d.ts +3 -3
  148. package/dist/providers/huggingFace.js +6 -7
  149. package/dist/providers/litellm.d.ts +1 -0
  150. package/dist/providers/litellm.js +76 -55
  151. package/dist/providers/mistral.js +2 -1
  152. package/dist/providers/ollama.js +93 -23
  153. package/dist/providers/openAI.d.ts +2 -0
  154. package/dist/providers/openAI.js +141 -141
  155. package/dist/providers/openRouter.js +2 -1
  156. package/dist/providers/openaiCompatible.d.ts +4 -4
  157. package/dist/providers/openaiCompatible.js +4 -3
  158. package/dist/proxy/claudeFormat.d.ts +3 -2
  159. package/dist/proxy/claudeFormat.js +27 -14
  160. package/dist/proxy/cloaking/plugins/sessionIdentity.d.ts +2 -6
  161. package/dist/proxy/cloaking/plugins/sessionIdentity.js +9 -33
  162. package/dist/proxy/modelRouter.js +3 -0
  163. package/dist/proxy/oauthFetch.d.ts +1 -1
  164. package/dist/proxy/oauthFetch.js +289 -316
  165. package/dist/proxy/proxyConfig.js +46 -24
  166. package/dist/proxy/proxyEnv.d.ts +19 -0
  167. package/dist/proxy/proxyEnv.js +72 -0
  168. package/dist/proxy/proxyFetch.js +291 -217
  169. package/dist/proxy/proxyTracer.d.ts +133 -0
  170. package/dist/proxy/proxyTracer.js +644 -0
  171. package/dist/proxy/rawStreamCapture.d.ts +10 -0
  172. package/dist/proxy/rawStreamCapture.js +82 -0
  173. package/dist/proxy/requestLogger.d.ts +32 -5
  174. package/dist/proxy/requestLogger.js +503 -47
  175. package/dist/proxy/sseInterceptor.d.ts +97 -0
  176. package/dist/proxy/sseInterceptor.js +426 -0
  177. package/dist/proxy/usageStats.d.ts +4 -3
  178. package/dist/proxy/usageStats.js +25 -12
  179. package/dist/rag/chunkers/MarkdownChunker.js +13 -5
  180. package/dist/rag/chunking/markdownChunker.js +15 -6
  181. package/dist/server/routes/claudeProxyRoutes.d.ts +17 -3
  182. package/dist/server/routes/claudeProxyRoutes.js +3032 -1349
  183. package/dist/services/server/ai/observability/instrumentation.d.ts +7 -1
  184. package/dist/services/server/ai/observability/instrumentation.js +337 -161
  185. package/dist/tasks/backends/bullmqBackend.d.ts +1 -0
  186. package/dist/tasks/backends/bullmqBackend.js +35 -22
  187. package/dist/tasks/store/redisTaskStore.d.ts +1 -0
  188. package/dist/tasks/store/redisTaskStore.js +54 -39
  189. package/dist/tasks/taskManager.d.ts +5 -0
  190. package/dist/tasks/taskManager.js +158 -30
  191. package/dist/telemetry/index.d.ts +2 -1
  192. package/dist/telemetry/index.js +2 -1
  193. package/dist/telemetry/telemetryService.d.ts +3 -0
  194. package/dist/telemetry/telemetryService.js +69 -5
  195. package/dist/types/cli.d.ts +10 -0
  196. package/dist/types/proxyTypes.d.ts +160 -5
  197. package/dist/types/streamTypes.d.ts +25 -3
  198. package/dist/utils/messageBuilder.js +3 -2
  199. package/dist/utils/providerHealth.d.ts +19 -0
  200. package/dist/utils/providerHealth.js +279 -33
  201. package/dist/utils/providerUtils.js +18 -22
  202. package/dist/utils/toolChoice.d.ts +4 -0
  203. package/dist/utils/toolChoice.js +6 -0
  204. package/docs/assets/dashboards/neurolink-proxy-observability-dashboard.json +6609 -0
  205. package/docs/changelog.md +252 -0
  206. package/package.json +19 -2
  207. package/scripts/observability/check-proxy-telemetry.mjs +235 -0
  208. package/scripts/observability/docker-compose.proxy-observability.yaml +55 -0
  209. package/scripts/observability/import-openobserve-dashboard.mjs +240 -0
  210. package/scripts/observability/manage-local-openobserve.sh +215 -0
  211. package/scripts/observability/otel-collector.proxy-observability.yaml +78 -0
  212. package/scripts/observability/proxy-observability.env.example +23 -0
@@ -11,6 +11,7 @@ export declare class TelemetryService {
11
11
  private tracerProvider?;
12
12
  private enabled;
13
13
  private initialized;
14
+ private usingExternalTracerProvider;
14
15
  private meter?;
15
16
  private tracer?;
16
17
  private aiRequestCounter?;
@@ -29,6 +30,8 @@ export declare class TelemetryService {
29
30
  private constructor();
30
31
  static getInstance(): TelemetryService;
31
32
  private isTelemetryEnabled;
33
+ private hasExternalTracerProvider;
34
+ private adoptExternalTracerProvider;
32
35
  private initializeTelemetry;
33
36
  private initializeMetrics;
34
37
  initialize(): Promise<void>;
@@ -9,6 +9,7 @@ export class TelemetryService {
9
9
  tracerProvider;
10
10
  enabled = false;
11
11
  initialized = false;
12
+ usingExternalTracerProvider = false;
12
13
  meter;
13
14
  tracer;
14
15
  // Optional Metrics (only created when enabled)
@@ -43,11 +44,52 @@ export class TelemetryService {
43
44
  return TelemetryService.instance;
44
45
  }
45
46
  isTelemetryEnabled() {
46
- return (process.env.NEUROLINK_TELEMETRY_ENABLED === "true" ||
47
+ return (this.hasExternalTracerProvider() ||
48
+ process.env.NEUROLINK_TELEMETRY_ENABLED === "true" ||
47
49
  process.env.OTEL_EXPORTER_OTLP_ENDPOINT !== undefined);
48
50
  }
51
+ hasExternalTracerProvider() {
52
+ try {
53
+ const provider = trace.getTracerProvider();
54
+ if (!provider) {
55
+ return false;
56
+ }
57
+ const providerName = provider.constructor?.name || "";
58
+ if (providerName &&
59
+ providerName !== "ProxyTracerProvider" &&
60
+ providerName !== "NoopTracerProvider") {
61
+ return true;
62
+ }
63
+ const delegate = typeof provider.getDelegate === "function"
64
+ ? provider.getDelegate()
65
+ : provider._delegate;
66
+ const delegateName = delegate?.constructor?.name || "";
67
+ return Boolean(delegateName && delegateName !== "NoopTracerProvider");
68
+ }
69
+ catch (error) {
70
+ logger.warn("[Telemetry] Failed checking for external TracerProvider", {
71
+ error: error instanceof Error ? error.message : String(error),
72
+ });
73
+ return false;
74
+ }
75
+ }
76
+ adoptExternalTracerProvider(reason) {
77
+ this.usingExternalTracerProvider = true;
78
+ this.tracerProvider = undefined;
79
+ this.meter = metrics.getMeter("neurolink-ai");
80
+ this.tracer = trace.getTracer("neurolink-ai");
81
+ this.initializeMetrics();
82
+ logger.debug("[Telemetry] Reusing externally managed TracerProvider", {
83
+ reason,
84
+ endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
85
+ });
86
+ }
49
87
  initializeTelemetry() {
50
88
  try {
89
+ if (this.hasExternalTracerProvider()) {
90
+ this.adoptExternalTracerProvider("global tracer provider already registered");
91
+ return;
92
+ }
51
93
  const resource = resourceFromAttributes({
52
94
  [ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || "neurolink-ai",
53
95
  [ATTR_SERVICE_VERSION]: process.env.OTEL_SERVICE_VERSION || "3.0.1",
@@ -61,13 +103,23 @@ export class TelemetryService {
61
103
  resource,
62
104
  spanProcessors: [new BatchSpanProcessor(exporter)],
63
105
  });
64
- trace.setGlobalTracerProvider(this.tracerProvider);
65
106
  this.meter = metrics.getMeter("neurolink-ai");
66
- this.tracer = trace.getTracer("neurolink-ai");
107
+ this.tracer = this.tracerProvider.getTracer("neurolink-ai");
67
108
  this.initializeMetrics();
68
- logger.debug("[Telemetry] Initialized with endpoint:", process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
109
+ logger.debug("[Telemetry] Initialized local telemetry exporter", {
110
+ endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
111
+ globalTracerProviderOwnedBy: "observability/instrumentation",
112
+ });
69
113
  }
70
114
  catch (error) {
115
+ const errorMessage = error instanceof Error ? error.message : String(error);
116
+ const isDuplicateRegistration = errorMessage.includes("duplicate registration") ||
117
+ errorMessage.includes("already registered") ||
118
+ errorMessage.includes("already set");
119
+ if (isDuplicateRegistration && this.hasExternalTracerProvider()) {
120
+ this.adoptExternalTracerProvider("duplicate global tracer registration detected");
121
+ return;
122
+ }
71
123
  logger.error("[Telemetry] Failed to initialize:", error);
72
124
  this.enabled = false;
73
125
  }
@@ -105,6 +157,16 @@ export class TelemetryService {
105
157
  if (!this.enabled) {
106
158
  return;
107
159
  }
160
+ if (this.usingExternalTracerProvider) {
161
+ this.initialized = true;
162
+ logger.debug("[Telemetry] External TracerProvider already initialized by host");
163
+ return;
164
+ }
165
+ if (!this.tracerProvider) {
166
+ this.initialized = true;
167
+ logger.debug("[Telemetry] Tracer provider already prepared during constructor");
168
+ return;
169
+ }
108
170
  try {
109
171
  // Register AsyncLocalStorage context manager for proper parent-child
110
172
  // span relationships across async boundaries (required for startActiveSpan)
@@ -308,7 +370,9 @@ export class TelemetryService {
308
370
  }
309
371
  // Cleanup
310
372
  async shutdown() {
311
- if (this.enabled && this.tracerProvider) {
373
+ if (this.enabled &&
374
+ this.tracerProvider &&
375
+ !this.usingExternalTracerProvider) {
312
376
  try {
313
377
  await this.tracerProvider.shutdown();
314
378
  this.initialized = false;
@@ -763,6 +763,8 @@ export type ProxyStartArgs = {
763
763
  quiet?: boolean;
764
764
  debug?: boolean;
765
765
  config?: string;
766
+ envFile?: string;
767
+ passthrough?: boolean;
766
768
  };
767
769
  /** Arguments accepted by `neurolink proxy status` */
768
770
  export type ProxyStatusArgs = {
@@ -779,6 +781,11 @@ export type ProxyGuardArgs = {
779
781
  pollIntervalMs?: number;
780
782
  quiet?: boolean;
781
783
  };
784
+ /** Arguments accepted by `neurolink proxy telemetry <subcommand>` */
785
+ export type ProxyTelemetryArgs = {
786
+ action?: "setup" | "start" | "stop" | "status" | "logs" | "import-dashboard";
787
+ quiet?: boolean;
788
+ };
782
789
  /** A fallback chain entry (serialisable subset of FallbackEntry) */
783
790
  export type FallbackInfo = {
784
791
  provider: string;
@@ -791,12 +798,15 @@ export type ProxyState = {
791
798
  host: string;
792
799
  strategy: string;
793
800
  startTime: string;
801
+ envFile?: string;
794
802
  /** Fallback chain from proxy config (persisted at start time) */
795
803
  fallbackChain?: FallbackInfo[];
796
804
  /** Optional fail-open guard PID that reverts Claude settings if proxy dies */
797
805
  guardPid?: number;
798
806
  /** How the proxy was launched — "launchd" if installed as service, "manual" otherwise */
799
807
  managedBy?: "launchd" | "manual";
808
+ /** Whether the proxy is running in transparent passthrough mode */
809
+ passthrough?: boolean;
800
810
  };
801
811
  /** Stored credentials for an authenticated provider. */
802
812
  export type StoredCredentials = {
@@ -13,6 +13,8 @@
13
13
  * - src/lib/proxy/accountQuota.ts (quota type)
14
14
  * - src/lib/server/routes/claudeProxyRoutes.ts (runtime state, deps)
15
15
  */
16
+ import type { Span } from "@opentelemetry/api";
17
+ import type { ProxyTracer } from "../proxy/proxyTracer.js";
16
18
  /**
17
19
  * Type describing the ModelRouter contract.
18
20
  * Defined here to avoid a circular dependency between types and implementation.
@@ -239,10 +241,11 @@ export type ParsedClaudeRequest = {
239
241
  role: string;
240
242
  content: string;
241
243
  }>;
242
- /** Tools in NeuroLink-compatible shape (name -> { description, parameters }). */
244
+ /** Tools translated to AI SDK-compatible shape for provider fallback. */
243
245
  tools: Record<string, {
244
- description: string;
245
- parameters: Record<string, unknown>;
246
+ description?: string;
247
+ inputSchema: unknown;
248
+ execute?: (...args: unknown[]) => unknown;
246
249
  }>;
247
250
  /**
248
251
  * Tool choice mapping from Claude format.
@@ -360,6 +363,14 @@ export type TlsFingerprintOptions = {
360
363
  /** Whether the stub should log a warning that it is a no-op. */
361
364
  warnOnUse?: boolean;
362
365
  };
366
+ /**
367
+ * Proxy operating mode:
368
+ * - "full" — managed accounts, retry, rotation, polyfill (default)
369
+ * - "passthrough" — no polyfill/retry/rotation, but body is still parsed and re-serialized
370
+ * - "transparent" — zero-mutation byte relay: raw body forwarded as-is, minimal header filtering,
371
+ * SSE interceptor for cache metrics only (bytes pass through unmodified)
372
+ */
373
+ export type ProxyMode = "full" | "passthrough" | "transparent";
363
374
  export type RouteResult = {
364
375
  provider: string | null;
365
376
  model: string;
@@ -421,21 +432,165 @@ export type RequestLogEntry = {
421
432
  errorMessage?: string;
422
433
  inputTokens?: number;
423
434
  outputTokens?: number;
435
+ cacheCreationTokens?: number;
436
+ cacheReadTokens?: number;
437
+ /** OTel trace ID for correlation with distributed traces */
438
+ traceId?: string;
439
+ /** OTel span ID for correlation with distributed traces */
440
+ spanId?: string;
441
+ };
442
+ export type RequestAttemptLogEntry = {
443
+ timestamp: string;
444
+ requestId: string;
445
+ attempt: number;
446
+ method: string;
447
+ path: string;
448
+ model: string;
449
+ stream: boolean;
450
+ toolCount: number;
451
+ account: string;
452
+ accountType: string;
453
+ responseStatus: number;
454
+ responseTimeMs: number;
455
+ errorType?: string;
456
+ errorMessage?: string;
457
+ inputTokens?: number;
458
+ outputTokens?: number;
459
+ cacheCreationTokens?: number;
460
+ cacheReadTokens?: number;
461
+ /** OTel trace ID for correlation with distributed traces */
462
+ traceId?: string;
463
+ /** OTel span ID for correlation with distributed traces */
464
+ spanId?: string;
465
+ };
466
+ export type ProxyBodyCaptureInput = {
467
+ phase: string;
468
+ headers?: Record<string, string>;
469
+ body?: unknown;
470
+ bodySize?: number;
471
+ contentType?: string;
472
+ responseStatus?: number;
473
+ durationMs?: number;
474
+ account?: string;
475
+ accountType?: string;
476
+ attempt?: number;
477
+ metadata?: Record<string, unknown>;
478
+ };
479
+ export type ProxyBodyCaptureLogger = (capture: ProxyBodyCaptureInput) => void;
480
+ export type ClaudeFinalRequestLogger = (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
481
+ inputTokens?: number;
482
+ outputTokens?: number;
483
+ cacheCreationTokens?: number;
484
+ cacheReadTokens?: number;
485
+ }) => void;
486
+ export type ClaudeLoggedErrorBuilder = (status: number, message: string, errorType?: string, extra?: {
487
+ account?: string;
488
+ accountType?: string;
489
+ attempt?: number;
490
+ }) => ClaudeErrorResponse;
491
+ export type ClaudeRequestRuntimeContext = {
492
+ tracer?: ProxyTracer;
493
+ requestStartTime: number;
494
+ logProxyBody: ProxyBodyCaptureLogger;
495
+ logFinalRequest: ClaudeFinalRequestLogger;
496
+ buildLoggedClaudeError: ClaudeLoggedErrorBuilder;
497
+ };
498
+ export type AnthropicAttemptLogger = (status: number, errorType?: string, errorMessage?: string, extra?: {
499
+ inputTokens?: number;
500
+ outputTokens?: number;
501
+ cacheCreationTokens?: number;
502
+ cacheReadTokens?: number;
503
+ }) => void;
504
+ export type AnthropicLoopState = {
505
+ lastError: unknown;
506
+ sawRateLimit: boolean;
507
+ sawNetworkError: boolean;
508
+ sawTransientFailure: boolean;
509
+ invalidRequestFailure: {
510
+ status: number;
511
+ body: string;
512
+ contentType?: string;
513
+ } | null;
514
+ authFailureMessage: string | null;
515
+ attemptNumber: number;
516
+ };
517
+ export type AnthropicUpstreamBody = {
518
+ bodyStr: string;
519
+ sessionId?: string;
520
+ };
521
+ export type AnthropicUpstreamBodyBuilder = (token: string) => AnthropicUpstreamBody;
522
+ export type LoadedClaudeAccountContext = {
523
+ accounts: ProxyPassthroughAccount[];
524
+ enabledAccounts: ProxyPassthroughAccount[];
525
+ orderedAccounts: ProxyPassthroughAccount[];
526
+ bodyStr: string;
527
+ requestStart: number;
528
+ toolCount: number;
529
+ url: string;
530
+ clientHeaders: Record<string, string | undefined>;
531
+ isClaudeClientRequest: boolean;
532
+ };
533
+ export type AnthropicSuccessResult = {
534
+ retryNextAccount: true;
535
+ } | {
536
+ response: Response | unknown;
537
+ };
538
+ export type AnthropicAuthRetryResult = {
539
+ response?: Response | unknown;
540
+ continueLoop: boolean;
541
+ lastError: unknown;
542
+ authFailureMessage: string | null;
543
+ sawRateLimit: boolean;
544
+ sawTransientFailure: boolean;
545
+ sawNetworkError: boolean;
546
+ upstreamSpan?: Span;
547
+ };
548
+ export type AnthropicNonOkResult = {
549
+ response?: Response | unknown;
550
+ continueLoop: boolean;
551
+ lastError: unknown;
552
+ authFailureMessage: string | null;
553
+ sawTransientFailure: boolean;
554
+ invalidRequestFailure: {
555
+ status: number;
556
+ body: string;
557
+ contentType?: string;
558
+ } | null;
559
+ upstreamSpan?: Span;
560
+ };
561
+ export type PreparedAnthropicAccountAttempt = {
562
+ continueLoop: boolean;
563
+ lastError: unknown;
564
+ authFailureMessage: string | null;
565
+ headers?: Record<string, string>;
566
+ buildUpstreamBody?: AnthropicUpstreamBodyBuilder;
567
+ finalBodyStr?: string;
568
+ fetchStartMs?: number;
569
+ upstreamSpan?: Span;
570
+ };
571
+ export type AnthropicUpstreamFetchResult = {
572
+ continueLoop: boolean;
573
+ response?: Response;
574
+ lastError: unknown;
575
+ sawRateLimit: boolean;
576
+ sawNetworkError: boolean;
577
+ upstreamSpan?: Span;
424
578
  };
425
579
  export type AccountStats = {
426
580
  label: string;
427
581
  type: string;
428
- requestCount: number;
582
+ attemptCount: number;
429
583
  successCount: number;
430
584
  errorCount: number;
431
585
  rateLimitCount: number;
432
- lastRequestAt: number;
586
+ lastAttemptAt: number;
433
587
  lastErrorAt?: number;
434
588
  currentBackoffLevel: number;
435
589
  coolingUntil?: number;
436
590
  };
437
591
  export type ProxyStats = {
438
592
  startedAt: number;
593
+ totalAttempts: number;
439
594
  totalRequests: number;
440
595
  totalSuccess: number;
441
596
  totalErrors: number;
@@ -1,16 +1,16 @@
1
- import type { Tool } from "ai";
1
+ import type { LanguageModel, StepResult, Tool, ToolChoice } from "ai";
2
2
  import type { AIProviderName } from "../constants/enums.js";
3
3
  import type { EvaluationData } from "../index.js";
4
4
  import type { RAGConfig } from "../rag/types.js";
5
5
  import type { AnalyticsData, ToolExecutionEvent, ToolExecutionSummary } from "../types/index.js";
6
- import type { MiddlewareFactoryOptions, OnFinishCallback, OnErrorCallback, OnChunkCallback } from "../types/middlewareTypes.js";
6
+ import type { MiddlewareFactoryOptions, OnChunkCallback, OnErrorCallback, OnFinishCallback } from "../types/middlewareTypes.js";
7
7
  import type { TokenUsage } from "./analytics.js";
8
8
  import type { JsonValue, UnknownRecord } from "./common.js";
9
9
  import type { Content, ImageWithAltText } from "./content.js";
10
10
  import type { ChatMessage } from "./conversation.js";
11
+ import type { AdditionalMemoryUser } from "./generateTypes.js";
11
12
  import type { AIModelProviderConfig } from "./providers.js";
12
13
  import type { TTSChunk, TTSOptions } from "./ttsTypes.js";
13
- import type { AdditionalMemoryUser } from "./generateTypes.js";
14
14
  import type { StandardRecord, ValidationSchema } from "./typeAliases.js";
15
15
  /**
16
16
  * Progress tracking and metadata for streaming operations
@@ -326,12 +326,34 @@ export type StreamOptions = {
326
326
  abortSignal?: AbortSignal;
327
327
  disableTools?: boolean;
328
328
  maxSteps?: number;
329
+ /**
330
+ * Tool choice configuration for streaming generation.
331
+ * Mirrors generate() so translated/fallback requests can preserve forced tool use.
332
+ */
333
+ toolChoice?: ToolChoice<Record<string, Tool>>;
334
+ /**
335
+ * Optional callback that runs before each stream step in a multi-step generation.
336
+ */
337
+ prepareStep?: (options: {
338
+ steps: StepResult<Record<string, Tool>>[];
339
+ stepNumber: number;
340
+ maxSteps: number;
341
+ model: LanguageModel;
342
+ }) => PromiseLike<{
343
+ toolChoice?: ToolChoice<Record<string, Tool>>;
344
+ activeTools?: Record<string, Tool>;
345
+ } | undefined>;
329
346
  /** Include only these tools by name (whitelist). If set, only matching tools are available. */
330
347
  toolFilter?: string[];
331
348
  /** Exclude these tools by name (blacklist). Applied after toolFilter. */
332
349
  excludeTools?: string[];
333
350
  /** Disable tool result caching for this request (overrides global mcp.cache.enabled) */
334
351
  disableToolCache?: boolean;
352
+ /**
353
+ * Disable NeuroLink's internal provider fallback for this request.
354
+ * Used by the Claude proxy so the proxy itself can own fallback order.
355
+ */
356
+ disableInternalFallback?: boolean;
335
357
  /**
336
358
  * Skip injecting tool schemas into the system prompt.
337
359
  * When true, tools are ONLY passed natively via the provider's `tools` parameter,
@@ -775,6 +775,7 @@ async function processUnifiedFilesArray(options, maxSize, provider) {
775
775
  return;
776
776
  }
777
777
  const totalFiles = options.input.files.length;
778
+ const files = options.input.files;
778
779
  return withSpan({
779
780
  name: "neurolink.file.process_all",
780
781
  tracer: tracers.file,
@@ -787,8 +788,8 @@ async function processUnifiedFilesArray(options, maxSize, provider) {
787
788
  options.input.text = options.input.text || "";
788
789
  let includedCount = 0;
789
790
  const fileRegistry = options.fileRegistry;
790
- for (let fileIdx = 0; fileIdx < options.input.files.length; fileIdx++) {
791
- const file = options.input.files[fileIdx];
791
+ for (let fileIdx = 0; fileIdx < files.length; fileIdx++) {
792
+ const file = files[fileIdx];
792
793
  const filename = extractFilename(file, fileIdx);
793
794
  try {
794
795
  // ─── Lazy file registration path ──────────────────────────────
@@ -30,6 +30,7 @@ export declare class ProviderHealthChecker {
30
30
  * Check connectivity to provider endpoints
31
31
  */
32
32
  private static checkConnectivity;
33
+ private static getConnectivityHeaders;
33
34
  /**
34
35
  * Check model availability (if possible without making API calls)
35
36
  */
@@ -98,6 +99,20 @@ export declare class ProviderHealthChecker {
98
99
  * Check Azure OpenAI configuration
99
100
  */
100
101
  private static checkAzureConfig;
102
+ private static getLiteLLMBaseUrl;
103
+ private static getLiteLLMModelsUrl;
104
+ private static getConfiguredLiteLLMModel;
105
+ private static getOllamaBaseUrl;
106
+ private static getOllamaTagsUrl;
107
+ private static getConfiguredOllamaModel;
108
+ private static fetchJsonWithTimeout;
109
+ private static normalizeModelList;
110
+ private static hasRequestedModel;
111
+ private static getOllamaAvailableModels;
112
+ private static getLiteLLMAvailableModels;
113
+ private static checkOllamaAvailability;
114
+ private static checkLiteLLMAvailability;
115
+ private static checkLiteLLMConfig;
101
116
  /**
102
117
  * Check Ollama configuration
103
118
  */
@@ -169,6 +184,10 @@ export declare class ProviderHealthChecker {
169
184
  * Clear health cache for a provider or all providers
170
185
  */
171
186
  static clearHealthCache(providerName?: AIProviderName): void;
187
+ static checkFallbackProviderAvailability(providerName: string, model: string): Promise<{
188
+ available: boolean;
189
+ reason?: string;
190
+ }>;
172
191
  /**
173
192
  * Get the best healthy provider from a list of options (NON-BLOCKING)
174
193
  * Prioritizes healthy providers over configured but unhealthy ones