@juspay/neurolink 9.15.0 → 9.16.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 (193) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/adapters/video/videoAnalyzer.d.ts +1 -1
  3. package/dist/adapters/video/videoAnalyzer.js +10 -8
  4. package/dist/cli/commands/setup-anthropic.js +1 -14
  5. package/dist/cli/commands/setup-azure.js +1 -12
  6. package/dist/cli/commands/setup-bedrock.js +1 -9
  7. package/dist/cli/commands/setup-google-ai.js +1 -12
  8. package/dist/cli/commands/setup-openai.js +1 -14
  9. package/dist/cli/commands/workflow.d.ts +27 -0
  10. package/dist/cli/commands/workflow.js +216 -0
  11. package/dist/cli/factories/commandFactory.js +79 -20
  12. package/dist/cli/index.js +0 -1
  13. package/dist/cli/parser.js +4 -1
  14. package/dist/cli/utils/maskCredential.d.ts +11 -0
  15. package/dist/cli/utils/maskCredential.js +23 -0
  16. package/dist/constants/contextWindows.js +107 -16
  17. package/dist/constants/enums.d.ts +99 -15
  18. package/dist/constants/enums.js +152 -22
  19. package/dist/context/budgetChecker.js +1 -1
  20. package/dist/context/contextCompactor.js +31 -4
  21. package/dist/context/emergencyTruncation.d.ts +21 -0
  22. package/dist/context/emergencyTruncation.js +88 -0
  23. package/dist/context/errorDetection.d.ts +16 -0
  24. package/dist/context/errorDetection.js +48 -1
  25. package/dist/context/errors.d.ts +19 -0
  26. package/dist/context/errors.js +21 -0
  27. package/dist/context/stages/slidingWindowTruncator.d.ts +6 -0
  28. package/dist/context/stages/slidingWindowTruncator.js +159 -24
  29. package/dist/core/baseProvider.js +306 -200
  30. package/dist/core/conversationMemoryManager.js +104 -61
  31. package/dist/core/evaluationProviders.js +16 -33
  32. package/dist/core/factory.js +237 -164
  33. package/dist/core/modules/GenerationHandler.js +175 -116
  34. package/dist/core/modules/MessageBuilder.js +222 -170
  35. package/dist/core/modules/StreamHandler.d.ts +1 -0
  36. package/dist/core/modules/StreamHandler.js +95 -27
  37. package/dist/core/modules/TelemetryHandler.d.ts +10 -1
  38. package/dist/core/modules/TelemetryHandler.js +25 -7
  39. package/dist/core/modules/ToolsManager.js +115 -191
  40. package/dist/core/redisConversationMemoryManager.js +418 -282
  41. package/dist/factories/providerRegistry.d.ts +5 -0
  42. package/dist/factories/providerRegistry.js +20 -2
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.js +4 -2
  45. package/dist/lib/adapters/video/videoAnalyzer.d.ts +1 -1
  46. package/dist/lib/adapters/video/videoAnalyzer.js +10 -8
  47. package/dist/lib/constants/contextWindows.js +107 -16
  48. package/dist/lib/constants/enums.d.ts +99 -15
  49. package/dist/lib/constants/enums.js +152 -22
  50. package/dist/lib/context/budgetChecker.js +1 -1
  51. package/dist/lib/context/contextCompactor.js +31 -4
  52. package/dist/lib/context/emergencyTruncation.d.ts +21 -0
  53. package/dist/lib/context/emergencyTruncation.js +89 -0
  54. package/dist/lib/context/errorDetection.d.ts +16 -0
  55. package/dist/lib/context/errorDetection.js +48 -1
  56. package/dist/lib/context/errors.d.ts +19 -0
  57. package/dist/lib/context/errors.js +22 -0
  58. package/dist/lib/context/stages/slidingWindowTruncator.d.ts +6 -0
  59. package/dist/lib/context/stages/slidingWindowTruncator.js +159 -24
  60. package/dist/lib/core/baseProvider.js +306 -200
  61. package/dist/lib/core/conversationMemoryManager.js +104 -61
  62. package/dist/lib/core/evaluationProviders.js +16 -33
  63. package/dist/lib/core/factory.js +237 -164
  64. package/dist/lib/core/modules/GenerationHandler.js +175 -116
  65. package/dist/lib/core/modules/MessageBuilder.js +222 -170
  66. package/dist/lib/core/modules/StreamHandler.d.ts +1 -0
  67. package/dist/lib/core/modules/StreamHandler.js +95 -27
  68. package/dist/lib/core/modules/TelemetryHandler.d.ts +10 -1
  69. package/dist/lib/core/modules/TelemetryHandler.js +25 -7
  70. package/dist/lib/core/modules/ToolsManager.js +115 -191
  71. package/dist/lib/core/redisConversationMemoryManager.js +418 -282
  72. package/dist/lib/factories/providerRegistry.d.ts +5 -0
  73. package/dist/lib/factories/providerRegistry.js +20 -2
  74. package/dist/lib/index.d.ts +2 -2
  75. package/dist/lib/index.js +4 -2
  76. package/dist/lib/mcp/externalServerManager.js +66 -0
  77. package/dist/lib/mcp/mcpCircuitBreaker.js +24 -0
  78. package/dist/lib/mcp/mcpClientFactory.js +16 -0
  79. package/dist/lib/mcp/toolDiscoveryService.js +32 -6
  80. package/dist/lib/mcp/toolRegistry.js +193 -123
  81. package/dist/lib/neurolink.d.ts +6 -0
  82. package/dist/lib/neurolink.js +1162 -646
  83. package/dist/lib/providers/amazonBedrock.d.ts +1 -1
  84. package/dist/lib/providers/amazonBedrock.js +521 -319
  85. package/dist/lib/providers/anthropic.js +73 -17
  86. package/dist/lib/providers/anthropicBaseProvider.js +77 -17
  87. package/dist/lib/providers/googleAiStudio.d.ts +1 -1
  88. package/dist/lib/providers/googleAiStudio.js +292 -227
  89. package/dist/lib/providers/googleVertex.d.ts +36 -1
  90. package/dist/lib/providers/googleVertex.js +553 -260
  91. package/dist/lib/providers/ollama.js +329 -278
  92. package/dist/lib/providers/openAI.js +77 -19
  93. package/dist/lib/providers/sagemaker/parsers.js +3 -3
  94. package/dist/lib/providers/sagemaker/streaming.js +3 -3
  95. package/dist/lib/proxy/proxyFetch.js +81 -48
  96. package/dist/lib/rag/ChunkerFactory.js +1 -1
  97. package/dist/lib/rag/chunkers/MarkdownChunker.d.ts +22 -0
  98. package/dist/lib/rag/chunkers/MarkdownChunker.js +213 -9
  99. package/dist/lib/rag/chunking/markdownChunker.d.ts +16 -0
  100. package/dist/lib/rag/chunking/markdownChunker.js +174 -2
  101. package/dist/lib/rag/pipeline/contextAssembly.js +2 -1
  102. package/dist/lib/rag/ragIntegration.d.ts +18 -1
  103. package/dist/lib/rag/ragIntegration.js +94 -14
  104. package/dist/lib/rag/retrieval/vectorQueryTool.js +21 -4
  105. package/dist/lib/server/abstract/baseServerAdapter.js +4 -1
  106. package/dist/lib/server/adapters/fastifyAdapter.js +35 -30
  107. package/dist/lib/services/server/ai/observability/instrumentation.d.ts +32 -0
  108. package/dist/lib/services/server/ai/observability/instrumentation.js +39 -0
  109. package/dist/lib/telemetry/attributes.d.ts +52 -0
  110. package/dist/lib/telemetry/attributes.js +61 -0
  111. package/dist/lib/telemetry/index.d.ts +3 -0
  112. package/dist/lib/telemetry/index.js +3 -0
  113. package/dist/lib/telemetry/telemetryService.d.ts +6 -0
  114. package/dist/lib/telemetry/telemetryService.js +6 -0
  115. package/dist/lib/telemetry/tracers.d.ts +15 -0
  116. package/dist/lib/telemetry/tracers.js +17 -0
  117. package/dist/lib/telemetry/withSpan.d.ts +9 -0
  118. package/dist/lib/telemetry/withSpan.js +35 -0
  119. package/dist/lib/types/contextTypes.d.ts +10 -0
  120. package/dist/lib/types/streamTypes.d.ts +14 -0
  121. package/dist/lib/utils/conversationMemory.js +121 -82
  122. package/dist/lib/utils/logger.d.ts +5 -0
  123. package/dist/lib/utils/logger.js +50 -2
  124. package/dist/lib/utils/messageBuilder.js +22 -42
  125. package/dist/lib/utils/modelDetection.js +3 -3
  126. package/dist/lib/utils/providerRetry.d.ts +41 -0
  127. package/dist/lib/utils/providerRetry.js +114 -0
  128. package/dist/lib/utils/retryability.d.ts +14 -0
  129. package/dist/lib/utils/retryability.js +23 -0
  130. package/dist/lib/utils/sanitizers/svg.js +4 -5
  131. package/dist/lib/utils/tokenEstimation.d.ts +11 -1
  132. package/dist/lib/utils/tokenEstimation.js +19 -4
  133. package/dist/lib/utils/videoAnalysisProcessor.js +7 -3
  134. package/dist/mcp/externalServerManager.js +66 -0
  135. package/dist/mcp/mcpCircuitBreaker.js +24 -0
  136. package/dist/mcp/mcpClientFactory.js +16 -0
  137. package/dist/mcp/toolDiscoveryService.js +32 -6
  138. package/dist/mcp/toolRegistry.js +193 -123
  139. package/dist/neurolink.d.ts +6 -0
  140. package/dist/neurolink.js +1162 -646
  141. package/dist/providers/amazonBedrock.d.ts +1 -1
  142. package/dist/providers/amazonBedrock.js +521 -319
  143. package/dist/providers/anthropic.js +73 -17
  144. package/dist/providers/anthropicBaseProvider.js +77 -17
  145. package/dist/providers/googleAiStudio.d.ts +1 -1
  146. package/dist/providers/googleAiStudio.js +292 -227
  147. package/dist/providers/googleVertex.d.ts +36 -1
  148. package/dist/providers/googleVertex.js +553 -260
  149. package/dist/providers/ollama.js +329 -278
  150. package/dist/providers/openAI.js +77 -19
  151. package/dist/providers/sagemaker/parsers.js +3 -3
  152. package/dist/providers/sagemaker/streaming.js +3 -3
  153. package/dist/proxy/proxyFetch.js +81 -48
  154. package/dist/rag/ChunkerFactory.js +1 -1
  155. package/dist/rag/chunkers/MarkdownChunker.d.ts +22 -0
  156. package/dist/rag/chunkers/MarkdownChunker.js +213 -9
  157. package/dist/rag/chunking/markdownChunker.d.ts +16 -0
  158. package/dist/rag/chunking/markdownChunker.js +174 -2
  159. package/dist/rag/pipeline/contextAssembly.js +2 -1
  160. package/dist/rag/ragIntegration.d.ts +18 -1
  161. package/dist/rag/ragIntegration.js +94 -14
  162. package/dist/rag/retrieval/vectorQueryTool.js +21 -4
  163. package/dist/server/abstract/baseServerAdapter.js +4 -1
  164. package/dist/server/adapters/fastifyAdapter.js +35 -30
  165. package/dist/services/server/ai/observability/instrumentation.d.ts +32 -0
  166. package/dist/services/server/ai/observability/instrumentation.js +39 -0
  167. package/dist/telemetry/attributes.d.ts +52 -0
  168. package/dist/telemetry/attributes.js +60 -0
  169. package/dist/telemetry/index.d.ts +3 -0
  170. package/dist/telemetry/index.js +3 -0
  171. package/dist/telemetry/telemetryService.d.ts +6 -0
  172. package/dist/telemetry/telemetryService.js +6 -0
  173. package/dist/telemetry/tracers.d.ts +15 -0
  174. package/dist/telemetry/tracers.js +16 -0
  175. package/dist/telemetry/withSpan.d.ts +9 -0
  176. package/dist/telemetry/withSpan.js +34 -0
  177. package/dist/types/contextTypes.d.ts +10 -0
  178. package/dist/types/streamTypes.d.ts +14 -0
  179. package/dist/utils/conversationMemory.js +121 -82
  180. package/dist/utils/logger.d.ts +5 -0
  181. package/dist/utils/logger.js +50 -2
  182. package/dist/utils/messageBuilder.js +22 -42
  183. package/dist/utils/modelDetection.js +3 -3
  184. package/dist/utils/providerRetry.d.ts +41 -0
  185. package/dist/utils/providerRetry.js +113 -0
  186. package/dist/utils/retryability.d.ts +14 -0
  187. package/dist/utils/retryability.js +22 -0
  188. package/dist/utils/sanitizers/svg.js +4 -5
  189. package/dist/utils/tokenEstimation.d.ts +11 -1
  190. package/dist/utils/tokenEstimation.js +19 -4
  191. package/dist/utils/videoAnalysisProcessor.js +7 -3
  192. package/dist/workflow/config.d.ts +26 -26
  193. package/package.json +1 -1
@@ -1,11 +1,13 @@
1
1
  import { createAnthropic } from "@ai-sdk/anthropic";
2
2
  import { streamText } from "ai";
3
+ import { trace, SpanKind, SpanStatusCode } from "@opentelemetry/api";
3
4
  import { AnthropicModels } from "../constants/enums.js";
4
5
  import { BaseProvider } from "../core/baseProvider.js";
5
6
  import { DEFAULT_MAX_STEPS } from "../core/constants.js";
6
7
  import { createProxyFetch } from "../proxy/proxyFetch.js";
7
8
  import { AuthenticationError, NetworkError, ProviderError, RateLimitError, } from "../types/errors.js";
8
9
  import { logger } from "../utils/logger.js";
10
+ import { calculateCost } from "../utils/pricing.js";
9
11
  import { createAnthropicConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
10
12
  import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../utils/timeout.js";
11
13
  import { isModelAvailableForTier, getRecommendedModelForTier, getModelCapabilities, } from "../models/anthropicModels.js";
@@ -213,6 +215,7 @@ const getAnthropicApiKey = () => {
213
215
  const getDefaultAnthropicModel = () => {
214
216
  return getProviderModel("ANTHROPIC_MODEL", AnthropicModels.CLAUDE_3_5_SONNET);
215
217
  };
218
+ const streamTracer = trace.getTracer("neurolink.provider.anthropic");
216
219
  /**
217
220
  * Get OAuth token from stored credentials file or environment.
218
221
  * Priority:
@@ -878,25 +881,78 @@ export class AnthropicProvider extends BaseProvider {
878
881
  // Using protected helper from BaseProvider to eliminate code duplication
879
882
  const messages = await this.buildMessagesForStream(options);
880
883
  const model = await this.getAISDKModelWithMiddleware(options);
881
- const result = await streamText({
882
- model: model,
883
- messages: messages,
884
- temperature: options.temperature,
885
- maxTokens: options.maxTokens, // No default limit - unlimited unless specified
886
- tools,
887
- maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
888
- toolChoice: shouldUseTools ? "auto" : "none",
889
- abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
890
- experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
891
- onStepFinish: ({ toolCalls, toolResults }) => {
892
- this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
893
- logger.warn("[AnthropicProvider] Failed to store tool executions", {
894
- provider: this.providerName,
895
- error: error instanceof Error ? error.message : String(error),
896
- });
897
- });
884
+ // Wrap streamText in an OTel span to capture provider-level latency and token usage
885
+ const streamSpan = streamTracer.startSpan("neurolink.provider.streamText", {
886
+ kind: SpanKind.CLIENT,
887
+ attributes: {
888
+ "gen_ai.system": "anthropic",
889
+ "gen_ai.request.model": model.modelId || this.modelName || "unknown",
898
890
  },
899
891
  });
892
+ let result;
893
+ try {
894
+ result = streamText({
895
+ model: model,
896
+ messages: messages,
897
+ temperature: options.temperature,
898
+ maxTokens: options.maxTokens, // No default limit - unlimited unless specified
899
+ maxRetries: 0, // NL11: Disable AI SDK's invisible internal retries; we handle retries with OTel instrumentation
900
+ tools,
901
+ maxSteps: options.maxSteps || DEFAULT_MAX_STEPS,
902
+ toolChoice: shouldUseTools ? "auto" : "none",
903
+ abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
904
+ experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
905
+ onStepFinish: ({ toolCalls, toolResults }) => {
906
+ this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
907
+ logger.warn("[AnthropicProvider] Failed to store tool executions", {
908
+ provider: this.providerName,
909
+ error: error instanceof Error ? error.message : String(error),
910
+ });
911
+ });
912
+ },
913
+ });
914
+ }
915
+ catch (streamError) {
916
+ streamSpan.end();
917
+ throw streamError;
918
+ }
919
+ // Collect token usage and finish reason asynchronously when the stream completes,
920
+ // then end the span. This avoids blocking the stream consumer.
921
+ result.usage
922
+ .then((usage) => {
923
+ streamSpan.setAttribute("gen_ai.usage.input_tokens", usage.promptTokens || 0);
924
+ streamSpan.setAttribute("gen_ai.usage.output_tokens", usage.completionTokens || 0);
925
+ const cost = calculateCost(this.providerName, this.modelName, {
926
+ input: usage.promptTokens || 0,
927
+ output: usage.completionTokens || 0,
928
+ total: (usage.promptTokens || 0) + (usage.completionTokens || 0),
929
+ });
930
+ if (cost && cost > 0) {
931
+ streamSpan.setAttribute("neurolink.cost", cost);
932
+ }
933
+ })
934
+ .catch(() => {
935
+ // Usage may not be available if the stream is aborted
936
+ });
937
+ result.finishReason
938
+ .then((reason) => {
939
+ streamSpan.setAttribute("gen_ai.response.finish_reason", reason || "unknown");
940
+ })
941
+ .catch(() => {
942
+ // Finish reason may not be available if the stream is aborted
943
+ });
944
+ // End the span when the stream text resolves (stream fully consumed)
945
+ result.text
946
+ .then(() => {
947
+ streamSpan.end();
948
+ })
949
+ .catch((err) => {
950
+ streamSpan.setStatus({
951
+ code: SpanStatusCode.ERROR,
952
+ message: err instanceof Error ? err.message : String(err),
953
+ });
954
+ streamSpan.end();
955
+ });
900
956
  timeoutController?.cleanup();
901
957
  const transformedStream = this.createTextStream(result);
902
958
  // ✅ Note: Vercel AI SDK's streamText() method limitations with tools
@@ -1,11 +1,14 @@
1
1
  import { createAnthropic } from "@ai-sdk/anthropic";
2
2
  import { streamText } from "ai";
3
+ import { trace, SpanKind, SpanStatusCode } from "@opentelemetry/api";
3
4
  import { AIProviderName, AnthropicModels } from "../constants/enums.js";
4
5
  import { BaseProvider } from "../core/baseProvider.js";
5
6
  import { AuthenticationError, NetworkError, ProviderError, RateLimitError, } from "../types/errors.js";
6
7
  import { logger } from "../utils/logger.js";
8
+ import { calculateCost } from "../utils/pricing.js";
7
9
  import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../utils/timeout.js";
8
10
  import { validateApiKey, createAnthropicBaseConfig, } from "../utils/providerConfig.js";
11
+ const streamTracer = trace.getTracer("neurolink.provider.anthropic");
9
12
  /**
10
13
  * Anthropic provider implementation using BaseProvider pattern
11
14
  * Migrated from direct API calls to Vercel AI SDK (@ai-sdk/anthropic)
@@ -68,25 +71,82 @@ export class AnthropicProviderV2 extends BaseProvider {
68
71
  const tools = shouldUseTools
69
72
  ? options.tools || (await this.getAllTools())
70
73
  : {};
71
- const result = await streamText({
72
- model,
73
- prompt: options.input.text,
74
- system: options.systemPrompt,
75
- temperature: options.temperature,
76
- maxTokens: options.maxTokens, // No default limit - unlimited unless specified
77
- tools,
78
- toolChoice: shouldUseTools ? "auto" : "none",
79
- abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
80
- experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
81
- onStepFinish: ({ toolCalls, toolResults }) => {
82
- this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
83
- logger.warn("[AnthropicBaseProvider] Failed to store tool executions", {
84
- provider: this.providerName,
85
- error: error instanceof Error ? error.message : String(error),
86
- });
87
- });
74
+ // Wrap streamText in an OTel span to capture provider-level latency and token usage
75
+ const streamSpan = streamTracer.startSpan("neurolink.provider.streamText", {
76
+ kind: SpanKind.CLIENT,
77
+ attributes: {
78
+ "gen_ai.system": "anthropic",
79
+ "gen_ai.request.model": model.modelId || this.modelName || "unknown",
88
80
  },
89
81
  });
82
+ let result;
83
+ try {
84
+ result = streamText({
85
+ model,
86
+ prompt: options.input.text,
87
+ system: options.systemPrompt,
88
+ temperature: options.temperature,
89
+ maxTokens: options.maxTokens, // No default limit - unlimited unless specified
90
+ maxRetries: 0, // NL11: Disable AI SDK's invisible internal retries; we handle retries with OTel instrumentation
91
+ tools,
92
+ toolChoice: shouldUseTools ? "auto" : "none",
93
+ abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
94
+ experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
95
+ onStepFinish: ({ toolCalls, toolResults }) => {
96
+ this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
97
+ logger.warn("[AnthropicBaseProvider] Failed to store tool executions", {
98
+ provider: this.providerName,
99
+ error: error instanceof Error ? error.message : String(error),
100
+ });
101
+ });
102
+ },
103
+ });
104
+ }
105
+ catch (err) {
106
+ streamSpan.recordException(err instanceof Error ? err : new Error(String(err)));
107
+ streamSpan.setStatus({
108
+ code: SpanStatusCode.ERROR,
109
+ message: err instanceof Error ? err.message : String(err),
110
+ });
111
+ streamSpan.end();
112
+ throw err;
113
+ }
114
+ // Collect token usage and finish reason asynchronously when the stream completes,
115
+ // then end the span. This avoids blocking the stream consumer.
116
+ result.usage
117
+ .then((usage) => {
118
+ streamSpan.setAttribute("gen_ai.usage.input_tokens", usage.promptTokens || 0);
119
+ streamSpan.setAttribute("gen_ai.usage.output_tokens", usage.completionTokens || 0);
120
+ const cost = calculateCost(this.providerName, this.modelName, {
121
+ input: usage.promptTokens || 0,
122
+ output: usage.completionTokens || 0,
123
+ total: (usage.promptTokens || 0) + (usage.completionTokens || 0),
124
+ });
125
+ if (cost && cost > 0) {
126
+ streamSpan.setAttribute("neurolink.cost", cost);
127
+ }
128
+ })
129
+ .catch(() => {
130
+ // Usage may not be available if the stream is aborted
131
+ });
132
+ result.finishReason
133
+ .then((reason) => {
134
+ streamSpan.setAttribute("gen_ai.response.finish_reason", reason || "unknown");
135
+ })
136
+ .catch(() => {
137
+ // Finish reason may not be available if the stream is aborted
138
+ });
139
+ result.text
140
+ .then(() => {
141
+ streamSpan.end();
142
+ })
143
+ .catch((err) => {
144
+ streamSpan.setStatus({
145
+ code: SpanStatusCode.ERROR,
146
+ message: err instanceof Error ? err.message : String(err),
147
+ });
148
+ streamSpan.end();
149
+ });
90
150
  timeoutController?.cleanup();
91
151
  // Transform string stream to content object stream (match Google AI pattern)
92
152
  const transformedStream = async function* () {
@@ -56,7 +56,7 @@ export declare class GoogleAIStudioProvider extends BaseProvider {
56
56
  */
57
57
  private detectImageType;
58
58
  /**
59
- * Estimate token count from text (simple character-based estimation)
59
+ * Estimate token count from text using centralized estimation with provider multipliers
60
60
  */
61
61
  private estimateTokenCount;
62
62
  protected executeStream(options: StreamOptions, _analysisSchema?: ZodUnknownSchema | Schema<unknown>): Promise<StreamResult>;