@juspay/neurolink 9.32.0 → 9.33.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 (475) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/auth/anthropicOAuth.js +1 -1
  3. package/dist/cli/commands/proxy.js +18 -5
  4. package/dist/client/aiSdkAdapter.js +1 -1
  5. package/dist/client/index.js +137 -501
  6. package/dist/core/factory.js +0 -1
  7. package/dist/core/redisConversationMemoryManager.js +1 -1
  8. package/dist/features/ppt/slideGenerator.js +0 -1
  9. package/dist/features/ppt/utils.js +0 -1
  10. package/dist/lib/neurolink.d.ts +10 -0
  11. package/dist/lib/neurolink.js +41 -7
  12. package/dist/lib/server/routes/claudeProxyRoutes.js +45 -9
  13. package/dist/lib/types/generateTypes.d.ts +16 -0
  14. package/dist/lib/types/streamTypes.d.ts +15 -0
  15. package/dist/mcp/elicitationProtocol.js +1 -1
  16. package/dist/mcp/servers/agent/directToolsServer.js +0 -1
  17. package/dist/neurolink.d.ts +10 -0
  18. package/dist/neurolink.js +41 -7
  19. package/dist/providers/azureOpenai.js +1 -1
  20. package/dist/providers/huggingFace.js +0 -1
  21. package/dist/providers/openaiCompatible.js +0 -1
  22. package/dist/sdk/toolRegistration.js +0 -1
  23. package/dist/server/openapi/generator.js +1 -1
  24. package/dist/server/routes/claudeProxyRoutes.js +45 -9
  25. package/dist/types/configTypes.js +0 -5
  26. package/dist/types/generateTypes.d.ts +16 -0
  27. package/dist/types/modelTypes.js +0 -1
  28. package/dist/types/streamTypes.d.ts +15 -0
  29. package/dist/types/tools.js +0 -1
  30. package/dist/types/typeAliases.js +0 -1
  31. package/dist/types/utilities.js +1 -1
  32. package/dist/types/workflowTypes.js +0 -1
  33. package/dist/utils/providerRetry.js +0 -1
  34. package/dist/utils/providerUtils.js +0 -1
  35. package/package.json +2 -2
  36. package/dist/client/adapters/providerImageAdapter.js +0 -588
  37. package/dist/client/adapters/tts/googleTTSHandler.js +0 -344
  38. package/dist/client/adapters/video/directorPipeline.js +0 -516
  39. package/dist/client/adapters/video/ffmpegAdapter.js +0 -206
  40. package/dist/client/adapters/video/frameExtractor.js +0 -143
  41. package/dist/client/adapters/video/vertexVideoHandler.js +0 -763
  42. package/dist/client/adapters/video/videoAnalyzer.js +0 -238
  43. package/dist/client/adapters/video/videoMerger.js +0 -171
  44. package/dist/client/agent/directTools.js +0 -840
  45. package/dist/client/auth/AuthProviderFactory.js +0 -111
  46. package/dist/client/auth/AuthProviderRegistry.js +0 -190
  47. package/dist/client/auth/RequestContext.js +0 -78
  48. package/dist/client/auth/accountPool.js +0 -178
  49. package/dist/client/auth/anthropicOAuth.js +0 -974
  50. package/dist/client/auth/authContext.js +0 -314
  51. package/dist/client/auth/errors.js +0 -39
  52. package/dist/client/auth/index.js +0 -61
  53. package/dist/client/auth/middleware/AuthMiddleware.js +0 -519
  54. package/dist/client/auth/middleware/rateLimitByUser.js +0 -554
  55. package/dist/client/auth/providers/BaseAuthProvider.js +0 -723
  56. package/dist/client/auth/providers/CognitoProvider.js +0 -304
  57. package/dist/client/auth/providers/KeycloakProvider.js +0 -393
  58. package/dist/client/auth/providers/auth0.js +0 -274
  59. package/dist/client/auth/providers/betterAuth.js +0 -182
  60. package/dist/client/auth/providers/clerk.js +0 -317
  61. package/dist/client/auth/providers/custom.js +0 -112
  62. package/dist/client/auth/providers/firebase.js +0 -226
  63. package/dist/client/auth/providers/jwt.js +0 -212
  64. package/dist/client/auth/providers/oauth2.js +0 -303
  65. package/dist/client/auth/providers/supabase.js +0 -259
  66. package/dist/client/auth/providers/workos.js +0 -284
  67. package/dist/client/auth/serverBridge.js +0 -25
  68. package/dist/client/auth/sessionManager.js +0 -437
  69. package/dist/client/auth/tokenStore.js +0 -799
  70. package/dist/client/client/aiSdkAdapter.js +0 -487
  71. package/dist/client/client/auth.js +0 -473
  72. package/dist/client/client/errors.js +0 -552
  73. package/dist/client/client/httpClient.js +0 -837
  74. package/dist/client/client/index.js +0 -172
  75. package/dist/client/client/interceptors.js +0 -601
  76. package/dist/client/client/sseClient.js +0 -545
  77. package/dist/client/client/streamingClient.js +0 -917
  78. package/dist/client/client/wsClient.js +0 -369
  79. package/dist/client/config/configManager.js +0 -303
  80. package/dist/client/config/conversationMemory.js +0 -86
  81. package/dist/client/config/taskClassificationConfig.js +0 -148
  82. package/dist/client/constants/contextWindows.js +0 -295
  83. package/dist/client/constants/enums.js +0 -853
  84. package/dist/client/constants/index.js +0 -207
  85. package/dist/client/constants/performance.js +0 -389
  86. package/dist/client/constants/retry.js +0 -266
  87. package/dist/client/constants/timeouts.js +0 -182
  88. package/dist/client/constants/tokens.js +0 -380
  89. package/dist/client/constants/videoErrors.js +0 -46
  90. package/dist/client/context/budgetChecker.js +0 -98
  91. package/dist/client/context/contextCompactor.js +0 -205
  92. package/dist/client/context/emergencyTruncation.js +0 -88
  93. package/dist/client/context/errorDetection.js +0 -171
  94. package/dist/client/context/errors.js +0 -21
  95. package/dist/client/context/fileTokenBudget.js +0 -127
  96. package/dist/client/context/prompts/summarizationPrompt.js +0 -117
  97. package/dist/client/context/stages/fileReadDeduplicator.js +0 -66
  98. package/dist/client/context/stages/slidingWindowTruncator.js +0 -190
  99. package/dist/client/context/stages/structuredSummarizer.js +0 -99
  100. package/dist/client/context/stages/toolOutputPruner.js +0 -52
  101. package/dist/client/context/summarizationEngine.js +0 -136
  102. package/dist/client/context/toolOutputLimits.js +0 -78
  103. package/dist/client/context/toolPairRepair.js +0 -66
  104. package/dist/client/core/analytics.js +0 -88
  105. package/dist/client/core/baseProvider.js +0 -1385
  106. package/dist/client/core/constants.js +0 -140
  107. package/dist/client/core/conversationMemoryFactory.js +0 -141
  108. package/dist/client/core/conversationMemoryInitializer.js +0 -128
  109. package/dist/client/core/conversationMemoryManager.js +0 -344
  110. package/dist/client/core/dynamicModels.js +0 -358
  111. package/dist/client/core/evaluation.js +0 -309
  112. package/dist/client/core/evaluationProviders.js +0 -248
  113. package/dist/client/core/factory.js +0 -412
  114. package/dist/client/core/infrastructure/baseError.js +0 -22
  115. package/dist/client/core/infrastructure/baseFactory.js +0 -54
  116. package/dist/client/core/infrastructure/baseRegistry.js +0 -53
  117. package/dist/client/core/infrastructure/index.js +0 -5
  118. package/dist/client/core/infrastructure/retry.js +0 -20
  119. package/dist/client/core/infrastructure/typedEventEmitter.js +0 -23
  120. package/dist/client/core/modelConfiguration.js +0 -851
  121. package/dist/client/core/modules/GenerationHandler.js +0 -588
  122. package/dist/client/core/modules/MessageBuilder.js +0 -273
  123. package/dist/client/core/modules/StreamHandler.js +0 -185
  124. package/dist/client/core/modules/TelemetryHandler.js +0 -203
  125. package/dist/client/core/modules/ToolsManager.js +0 -499
  126. package/dist/client/core/modules/Utilities.js +0 -331
  127. package/dist/client/core/redisConversationMemoryManager.js +0 -1435
  128. package/dist/client/core/streamAnalytics.js +0 -131
  129. package/dist/client/evaluation/contextBuilder.js +0 -134
  130. package/dist/client/evaluation/index.js +0 -61
  131. package/dist/client/evaluation/prompts.js +0 -73
  132. package/dist/client/evaluation/ragasEvaluator.js +0 -110
  133. package/dist/client/evaluation/retryManager.js +0 -78
  134. package/dist/client/evaluation/scoring.js +0 -61
  135. package/dist/client/factories/providerFactory.js +0 -166
  136. package/dist/client/factories/providerRegistry.js +0 -166
  137. package/dist/client/features/ppt/constants.js +0 -896
  138. package/dist/client/features/ppt/contentPlanner.js +0 -529
  139. package/dist/client/features/ppt/presentationOrchestrator.js +0 -236
  140. package/dist/client/features/ppt/slideGenerator.js +0 -532
  141. package/dist/client/features/ppt/slideRenderers.js +0 -2383
  142. package/dist/client/features/ppt/slideTypeInference.js +0 -405
  143. package/dist/client/features/ppt/types.js +0 -13
  144. package/dist/client/features/ppt/utils.js +0 -443
  145. package/dist/client/files/fileReferenceRegistry.js +0 -1543
  146. package/dist/client/files/fileTools.js +0 -450
  147. package/dist/client/files/streamingReader.js +0 -321
  148. package/dist/client/files/types.js +0 -23
  149. package/dist/client/hitl/hitlErrors.js +0 -54
  150. package/dist/client/hitl/hitlManager.js +0 -460
  151. package/dist/client/mcp/agentExposure.js +0 -356
  152. package/dist/client/mcp/auth/index.js +0 -11
  153. package/dist/client/mcp/auth/oauthClientProvider.js +0 -325
  154. package/dist/client/mcp/auth/tokenStorage.js +0 -134
  155. package/dist/client/mcp/batching/index.js +0 -10
  156. package/dist/client/mcp/batching/requestBatcher.js +0 -441
  157. package/dist/client/mcp/caching/index.js +0 -10
  158. package/dist/client/mcp/caching/toolCache.js +0 -433
  159. package/dist/client/mcp/elicitation/elicitationManager.js +0 -376
  160. package/dist/client/mcp/elicitation/index.js +0 -11
  161. package/dist/client/mcp/elicitation/types.js +0 -10
  162. package/dist/client/mcp/elicitationProtocol.js +0 -375
  163. package/dist/client/mcp/enhancedToolDiscovery.js +0 -481
  164. package/dist/client/mcp/externalServerManager.js +0 -1478
  165. package/dist/client/mcp/factory.js +0 -161
  166. package/dist/client/mcp/flexibleToolValidator.js +0 -161
  167. package/dist/client/mcp/httpRateLimiter.js +0 -391
  168. package/dist/client/mcp/httpRetryHandler.js +0 -178
  169. package/dist/client/mcp/index.js +0 -74
  170. package/dist/client/mcp/mcpCircuitBreaker.js +0 -427
  171. package/dist/client/mcp/mcpClientFactory.js +0 -708
  172. package/dist/client/mcp/mcpRegistryClient.js +0 -488
  173. package/dist/client/mcp/mcpServerBase.js +0 -373
  174. package/dist/client/mcp/multiServerManager.js +0 -579
  175. package/dist/client/mcp/registry.js +0 -158
  176. package/dist/client/mcp/routing/index.js +0 -10
  177. package/dist/client/mcp/routing/toolRouter.js +0 -416
  178. package/dist/client/mcp/serverCapabilities.js +0 -502
  179. package/dist/client/mcp/servers/agent/directToolsServer.js +0 -150
  180. package/dist/client/mcp/toolAnnotations.js +0 -239
  181. package/dist/client/mcp/toolConverter.js +0 -258
  182. package/dist/client/mcp/toolDiscoveryService.js +0 -798
  183. package/dist/client/mcp/toolIntegration.js +0 -334
  184. package/dist/client/mcp/toolRegistry.js +0 -729
  185. package/dist/client/memory/hippocampusInitializer.js +0 -19
  186. package/dist/client/memory/memoryRetrievalTools.js +0 -166
  187. package/dist/client/middleware/builtin/analytics.js +0 -132
  188. package/dist/client/middleware/builtin/autoEvaluation.js +0 -203
  189. package/dist/client/middleware/builtin/guardrails.js +0 -109
  190. package/dist/client/middleware/builtin/lifecycle.js +0 -168
  191. package/dist/client/middleware/factory.js +0 -327
  192. package/dist/client/middleware/registry.js +0 -295
  193. package/dist/client/middleware/utils/guardrailsUtils.js +0 -396
  194. package/dist/client/models/anthropicModels.js +0 -527
  195. package/dist/client/neurolink.js +0 -8233
  196. package/dist/client/observability/exporterRegistry.js +0 -413
  197. package/dist/client/observability/exporters/arizeExporter.js +0 -138
  198. package/dist/client/observability/exporters/baseExporter.js +0 -190
  199. package/dist/client/observability/exporters/braintrustExporter.js +0 -154
  200. package/dist/client/observability/exporters/datadogExporter.js +0 -196
  201. package/dist/client/observability/exporters/laminarExporter.js +0 -302
  202. package/dist/client/observability/exporters/langfuseExporter.js +0 -209
  203. package/dist/client/observability/exporters/langsmithExporter.js +0 -143
  204. package/dist/client/observability/exporters/otelExporter.js +0 -164
  205. package/dist/client/observability/exporters/posthogExporter.js +0 -287
  206. package/dist/client/observability/exporters/sentryExporter.js +0 -165
  207. package/dist/client/observability/index.js +0 -31
  208. package/dist/client/observability/metricsAggregator.js +0 -556
  209. package/dist/client/observability/otelBridge.js +0 -131
  210. package/dist/client/observability/retryPolicy.js +0 -383
  211. package/dist/client/observability/sampling/samplers.js +0 -216
  212. package/dist/client/observability/spanProcessor.js +0 -303
  213. package/dist/client/observability/tokenTracker.js +0 -413
  214. package/dist/client/observability/types/exporterTypes.js +0 -5
  215. package/dist/client/observability/types/index.js +0 -4
  216. package/dist/client/observability/types/spanTypes.js +0 -92
  217. package/dist/client/observability/utils/safeMetadata.js +0 -25
  218. package/dist/client/observability/utils/spanSerializer.js +0 -292
  219. package/dist/client/processors/archive/ArchiveProcessor.js +0 -1308
  220. package/dist/client/processors/base/BaseFileProcessor.js +0 -614
  221. package/dist/client/processors/base/types.js +0 -82
  222. package/dist/client/processors/config/fileTypes.js +0 -520
  223. package/dist/client/processors/config/index.js +0 -92
  224. package/dist/client/processors/config/languageMap.js +0 -410
  225. package/dist/client/processors/config/mimeTypes.js +0 -363
  226. package/dist/client/processors/config/sizeLimits.js +0 -258
  227. package/dist/client/processors/document/ExcelProcessor.js +0 -590
  228. package/dist/client/processors/document/OpenDocumentProcessor.js +0 -212
  229. package/dist/client/processors/document/PptxProcessor.js +0 -157
  230. package/dist/client/processors/document/RtfProcessor.js +0 -361
  231. package/dist/client/processors/document/WordProcessor.js +0 -353
  232. package/dist/client/processors/errors/FileErrorCode.js +0 -255
  233. package/dist/client/processors/errors/errorHelpers.js +0 -386
  234. package/dist/client/processors/errors/errorSerializer.js +0 -507
  235. package/dist/client/processors/errors/index.js +0 -49
  236. package/dist/client/processors/markup/SvgProcessor.js +0 -240
  237. package/dist/client/processors/media/AudioProcessor.js +0 -707
  238. package/dist/client/processors/media/VideoProcessor.js +0 -1045
  239. package/dist/client/providers/amazonBedrock.js +0 -1512
  240. package/dist/client/providers/amazonSagemaker.js +0 -162
  241. package/dist/client/providers/anthropic.js +0 -831
  242. package/dist/client/providers/azureOpenai.js +0 -143
  243. package/dist/client/providers/googleAiStudio.js +0 -1200
  244. package/dist/client/providers/googleNativeGemini3.js +0 -543
  245. package/dist/client/providers/googleVertex.js +0 -2936
  246. package/dist/client/providers/huggingFace.js +0 -315
  247. package/dist/client/providers/litellm.js +0 -488
  248. package/dist/client/providers/mistral.js +0 -157
  249. package/dist/client/providers/ollama.js +0 -1579
  250. package/dist/client/providers/openAI.js +0 -627
  251. package/dist/client/providers/openRouter.js +0 -543
  252. package/dist/client/providers/openaiCompatible.js +0 -290
  253. package/dist/client/providers/providerTypeUtils.js +0 -46
  254. package/dist/client/providers/sagemaker/adaptive-semaphore.js +0 -215
  255. package/dist/client/providers/sagemaker/client.js +0 -472
  256. package/dist/client/providers/sagemaker/config.js +0 -317
  257. package/dist/client/providers/sagemaker/detection.js +0 -606
  258. package/dist/client/providers/sagemaker/error-constants.js +0 -227
  259. package/dist/client/providers/sagemaker/errors.js +0 -299
  260. package/dist/client/providers/sagemaker/language-model.js +0 -775
  261. package/dist/client/providers/sagemaker/parsers.js +0 -634
  262. package/dist/client/providers/sagemaker/streaming.js +0 -331
  263. package/dist/client/providers/sagemaker/structured-parser.js +0 -625
  264. package/dist/client/proxy/accountQuota.js +0 -162
  265. package/dist/client/proxy/claudeFormat.js +0 -595
  266. package/dist/client/proxy/modelRouter.js +0 -29
  267. package/dist/client/proxy/oauthFetch.js +0 -367
  268. package/dist/client/proxy/proxyFetch.js +0 -586
  269. package/dist/client/proxy/requestLogger.js +0 -207
  270. package/dist/client/proxy/tokenRefresh.js +0 -124
  271. package/dist/client/proxy/usageStats.js +0 -74
  272. package/dist/client/proxy/utils/noProxyUtils.js +0 -149
  273. package/dist/client/rag/ChunkerFactory.js +0 -320
  274. package/dist/client/rag/ChunkerRegistry.js +0 -421
  275. package/dist/client/rag/chunkers/BaseChunker.js +0 -143
  276. package/dist/client/rag/chunkers/CharacterChunker.js +0 -28
  277. package/dist/client/rag/chunkers/HTMLChunker.js +0 -38
  278. package/dist/client/rag/chunkers/JSONChunker.js +0 -68
  279. package/dist/client/rag/chunkers/LaTeXChunker.js +0 -63
  280. package/dist/client/rag/chunkers/MarkdownChunker.js +0 -306
  281. package/dist/client/rag/chunkers/RecursiveChunker.js +0 -139
  282. package/dist/client/rag/chunkers/SemanticMarkdownChunker.js +0 -138
  283. package/dist/client/rag/chunkers/SentenceChunker.js +0 -66
  284. package/dist/client/rag/chunkers/TokenChunker.js +0 -61
  285. package/dist/client/rag/chunkers/index.js +0 -15
  286. package/dist/client/rag/chunking/characterChunker.js +0 -142
  287. package/dist/client/rag/chunking/chunkerRegistry.js +0 -194
  288. package/dist/client/rag/chunking/htmlChunker.js +0 -247
  289. package/dist/client/rag/chunking/index.js +0 -17
  290. package/dist/client/rag/chunking/jsonChunker.js +0 -281
  291. package/dist/client/rag/chunking/latexChunker.js +0 -251
  292. package/dist/client/rag/chunking/markdownChunker.js +0 -373
  293. package/dist/client/rag/chunking/recursiveChunker.js +0 -148
  294. package/dist/client/rag/chunking/semanticChunker.js +0 -306
  295. package/dist/client/rag/chunking/sentenceChunker.js +0 -230
  296. package/dist/client/rag/chunking/tokenChunker.js +0 -183
  297. package/dist/client/rag/document/MDocument.js +0 -392
  298. package/dist/client/rag/document/index.js +0 -5
  299. package/dist/client/rag/document/loaders.js +0 -500
  300. package/dist/client/rag/errors/RAGError.js +0 -274
  301. package/dist/client/rag/errors/index.js +0 -6
  302. package/dist/client/rag/graphRag/graphRAG.js +0 -401
  303. package/dist/client/rag/graphRag/index.js +0 -4
  304. package/dist/client/rag/index.js +0 -141
  305. package/dist/client/rag/metadata/MetadataExtractorFactory.js +0 -418
  306. package/dist/client/rag/metadata/MetadataExtractorRegistry.js +0 -362
  307. package/dist/client/rag/metadata/index.js +0 -9
  308. package/dist/client/rag/metadata/metadataExtractor.js +0 -280
  309. package/dist/client/rag/pipeline/RAGPipeline.js +0 -436
  310. package/dist/client/rag/pipeline/contextAssembly.js +0 -341
  311. package/dist/client/rag/pipeline/index.js +0 -5
  312. package/dist/client/rag/ragIntegration.js +0 -321
  313. package/dist/client/rag/reranker/RerankerFactory.js +0 -430
  314. package/dist/client/rag/reranker/RerankerRegistry.js +0 -402
  315. package/dist/client/rag/reranker/index.js +0 -9
  316. package/dist/client/rag/reranker/reranker.js +0 -277
  317. package/dist/client/rag/resilience/CircuitBreaker.js +0 -431
  318. package/dist/client/rag/resilience/RetryHandler.js +0 -304
  319. package/dist/client/rag/resilience/index.js +0 -7
  320. package/dist/client/rag/retrieval/hybridSearch.js +0 -335
  321. package/dist/client/rag/retrieval/index.js +0 -5
  322. package/dist/client/rag/retrieval/vectorQueryTool.js +0 -307
  323. package/dist/client/rag/types.js +0 -8
  324. package/dist/client/sdk/toolRegistration.js +0 -377
  325. package/dist/client/server/abstract/baseServerAdapter.js +0 -575
  326. package/dist/client/server/adapters/expressAdapter.js +0 -486
  327. package/dist/client/server/adapters/fastifyAdapter.js +0 -472
  328. package/dist/client/server/adapters/honoAdapter.js +0 -632
  329. package/dist/client/server/adapters/koaAdapter.js +0 -510
  330. package/dist/client/server/errors.js +0 -486
  331. package/dist/client/server/factory/serverAdapterFactory.js +0 -160
  332. package/dist/client/server/index.js +0 -108
  333. package/dist/client/server/middleware/abortSignal.js +0 -111
  334. package/dist/client/server/middleware/auth.js +0 -388
  335. package/dist/client/server/middleware/cache.js +0 -359
  336. package/dist/client/server/middleware/common.js +0 -281
  337. package/dist/client/server/middleware/deprecation.js +0 -190
  338. package/dist/client/server/middleware/mcpBodyAttachment.js +0 -63
  339. package/dist/client/server/middleware/rateLimit.js +0 -227
  340. package/dist/client/server/middleware/validation.js +0 -388
  341. package/dist/client/server/openapi/generator.js +0 -398
  342. package/dist/client/server/openapi/index.js +0 -36
  343. package/dist/client/server/openapi/schemas.js +0 -695
  344. package/dist/client/server/openapi/templates.js +0 -374
  345. package/dist/client/server/routes/agentRoutes.js +0 -189
  346. package/dist/client/server/routes/claudeProxyRoutes.js +0 -1600
  347. package/dist/client/server/routes/healthRoutes.js +0 -187
  348. package/dist/client/server/routes/index.js +0 -57
  349. package/dist/client/server/routes/mcpRoutes.js +0 -342
  350. package/dist/client/server/routes/memoryRoutes.js +0 -350
  351. package/dist/client/server/routes/openApiRoutes.js +0 -126
  352. package/dist/client/server/routes/toolRoutes.js +0 -199
  353. package/dist/client/server/streaming/dataStream.js +0 -486
  354. package/dist/client/server/streaming/index.js +0 -11
  355. package/dist/client/server/types.js +0 -67
  356. package/dist/client/server/utils/redaction.js +0 -334
  357. package/dist/client/server/utils/validation.js +0 -243
  358. package/dist/client/server/websocket/WebSocketHandler.js +0 -383
  359. package/dist/client/server/websocket/index.js +0 -4
  360. package/dist/client/services/server/ai/observability/instrumentation.js +0 -808
  361. package/dist/client/telemetry/attributes.js +0 -100
  362. package/dist/client/telemetry/index.js +0 -26
  363. package/dist/client/telemetry/telemetryService.js +0 -308
  364. package/dist/client/telemetry/tracers.js +0 -17
  365. package/dist/client/telemetry/withSpan.js +0 -34
  366. package/dist/client/types/actionTypes.js +0 -6
  367. package/dist/client/types/analytics.js +0 -5
  368. package/dist/client/types/authTypes.js +0 -9
  369. package/dist/client/types/circuitBreakerErrors.js +0 -34
  370. package/dist/client/types/cli.js +0 -21
  371. package/dist/client/types/clientTypes.js +0 -10
  372. package/dist/client/types/common.js +0 -51
  373. package/dist/client/types/configTypes.js +0 -49
  374. package/dist/client/types/content.js +0 -19
  375. package/dist/client/types/contextTypes.js +0 -400
  376. package/dist/client/types/conversation.js +0 -47
  377. package/dist/client/types/conversationMemoryInterface.js +0 -6
  378. package/dist/client/types/domainTypes.js +0 -5
  379. package/dist/client/types/errors.js +0 -167
  380. package/dist/client/types/evaluation.js +0 -5
  381. package/dist/client/types/evaluationProviders.js +0 -5
  382. package/dist/client/types/evaluationTypes.js +0 -1
  383. package/dist/client/types/externalMcp.js +0 -6
  384. package/dist/client/types/fileReferenceTypes.js +0 -8
  385. package/dist/client/types/fileTypes.js +0 -4
  386. package/dist/client/types/generateTypes.js +0 -1
  387. package/dist/client/types/guardrails.js +0 -1
  388. package/dist/client/types/hitlTypes.js +0 -8
  389. package/dist/client/types/index.js +0 -57
  390. package/dist/client/types/mcpTypes.js +0 -5
  391. package/dist/client/types/middlewareTypes.js +0 -1
  392. package/dist/client/types/modelTypes.js +0 -30
  393. package/dist/client/types/multimodal.js +0 -135
  394. package/dist/client/types/observability.js +0 -6
  395. package/dist/client/types/pptTypes.js +0 -82
  396. package/dist/client/types/providers.js +0 -111
  397. package/dist/client/types/proxyTypes.js +0 -16
  398. package/dist/client/types/ragTypes.js +0 -7
  399. package/dist/client/types/sdkTypes.js +0 -8
  400. package/dist/client/types/serviceTypes.js +0 -5
  401. package/dist/client/types/streamTypes.js +0 -1
  402. package/dist/client/types/subscriptionTypes.js +0 -9
  403. package/dist/client/types/taskClassificationTypes.js +0 -5
  404. package/dist/client/types/tools.js +0 -24
  405. package/dist/client/types/ttsTypes.js +0 -57
  406. package/dist/client/types/typeAliases.js +0 -48
  407. package/dist/client/types/utilities.js +0 -4
  408. package/dist/client/types/workflowTypes.js +0 -30
  409. package/dist/client/utils/async/withTimeout.js +0 -98
  410. package/dist/client/utils/asyncMutex.js +0 -60
  411. package/dist/client/utils/conversationMemory.js +0 -431
  412. package/dist/client/utils/csvProcessor.js +0 -846
  413. package/dist/client/utils/errorHandling.js +0 -936
  414. package/dist/client/utils/evaluationUtils.js +0 -131
  415. package/dist/client/utils/factoryProcessing.js +0 -589
  416. package/dist/client/utils/fileDetector.js +0 -2161
  417. package/dist/client/utils/imageCache.js +0 -376
  418. package/dist/client/utils/imageProcessor.js +0 -704
  419. package/dist/client/utils/logger.js +0 -491
  420. package/dist/client/utils/mcpDefaults.js +0 -134
  421. package/dist/client/utils/messageBuilder.js +0 -1653
  422. package/dist/client/utils/modelAliasResolver.js +0 -54
  423. package/dist/client/utils/modelDetection.js +0 -80
  424. package/dist/client/utils/modelRouter.js +0 -292
  425. package/dist/client/utils/multimodalOptionsBuilder.js +0 -65
  426. package/dist/client/utils/observabilityHelpers.js +0 -47
  427. package/dist/client/utils/parameterValidation.js +0 -966
  428. package/dist/client/utils/pdfProcessor.js +0 -410
  429. package/dist/client/utils/performance.js +0 -222
  430. package/dist/client/utils/pricing.js +0 -340
  431. package/dist/client/utils/promptRedaction.js +0 -62
  432. package/dist/client/utils/providerConfig.js +0 -1009
  433. package/dist/client/utils/providerHealth.js +0 -1237
  434. package/dist/client/utils/providerRetry.js +0 -112
  435. package/dist/client/utils/providerUtils.js +0 -434
  436. package/dist/client/utils/rateLimiter.js +0 -200
  437. package/dist/client/utils/redis.js +0 -368
  438. package/dist/client/utils/retryHandler.js +0 -269
  439. package/dist/client/utils/retryability.js +0 -22
  440. package/dist/client/utils/sanitizers/svg.js +0 -481
  441. package/dist/client/utils/schemaConversion.js +0 -255
  442. package/dist/client/utils/taskClassificationUtils.js +0 -149
  443. package/dist/client/utils/taskClassifier.js +0 -94
  444. package/dist/client/utils/thinkingConfig.js +0 -104
  445. package/dist/client/utils/timeout.js +0 -359
  446. package/dist/client/utils/tokenEstimation.js +0 -142
  447. package/dist/client/utils/tokenLimits.js +0 -125
  448. package/dist/client/utils/tokenUtils.js +0 -239
  449. package/dist/client/utils/toolUtils.js +0 -75
  450. package/dist/client/utils/transformationUtils.js +0 -554
  451. package/dist/client/utils/ttsProcessor.js +0 -286
  452. package/dist/client/utils/typeUtils.js +0 -97
  453. package/dist/client/utils/videoAnalysisProcessor.js +0 -67
  454. package/dist/client/workflow/config.js +0 -398
  455. package/dist/client/workflow/core/ensembleExecutor.js +0 -407
  456. package/dist/client/workflow/core/judgeScorer.js +0 -544
  457. package/dist/client/workflow/core/responseConditioner.js +0 -225
  458. package/dist/client/workflow/core/types/conditionerTypes.js +0 -7
  459. package/dist/client/workflow/core/types/ensembleTypes.js +0 -7
  460. package/dist/client/workflow/core/types/index.js +0 -7
  461. package/dist/client/workflow/core/types/judgeTypes.js +0 -7
  462. package/dist/client/workflow/core/types/layerTypes.js +0 -7
  463. package/dist/client/workflow/core/types/registryTypes.js +0 -7
  464. package/dist/client/workflow/core/workflowRegistry.js +0 -304
  465. package/dist/client/workflow/core/workflowRunner.js +0 -586
  466. package/dist/client/workflow/index.js +0 -50
  467. package/dist/client/workflow/types.js +0 -9
  468. package/dist/client/workflow/utils/types/index.js +0 -7
  469. package/dist/client/workflow/utils/workflowMetrics.js +0 -311
  470. package/dist/client/workflow/utils/workflowValidation.js +0 -420
  471. package/dist/client/workflow/workflows/adaptiveWorkflow.js +0 -366
  472. package/dist/client/workflow/workflows/consensusWorkflow.js +0 -192
  473. package/dist/client/workflow/workflows/fallbackWorkflow.js +0 -225
  474. package/dist/client/workflow/workflows/multiJudgeWorkflow.js +0 -351
  475. /package/dist/client/{client/reactHooks.js → reactHooks.js} +0 -0
@@ -1,1579 +0,0 @@
1
- import { createAnalytics } from "../core/analytics.js";
2
- import { BaseProvider } from "../core/baseProvider.js";
3
- import { DEFAULT_MAX_STEPS } from "../core/constants.js";
4
- import { modelConfig } from "../core/modelConfiguration.js";
5
- import { createProxyFetch } from "../proxy/proxyFetch.js";
6
- import { logger } from "../utils/logger.js";
7
- import { buildMultimodalMessagesArray } from "../utils/messageBuilder.js";
8
- import { buildMultimodalOptions } from "../utils/multimodalOptionsBuilder.js";
9
- import { estimateTokens } from "../utils/tokenEstimation.js";
10
- import { InvalidModelError, NetworkError, ProviderError, } from "../types/errors.js";
11
- import { tracers, ATTR, withClientSpan } from "../telemetry/index.js";
12
- import { TimeoutError } from "../utils/timeout.js";
13
- // Model version constants (configurable via environment)
14
- const DEFAULT_OLLAMA_MODEL = "llama3.1:8b";
15
- const FALLBACK_OLLAMA_MODEL = "llama3.2:latest"; // Used when primary model fails
16
- // Configuration helpers
17
- const getOllamaBaseUrl = () => {
18
- return process.env.OLLAMA_BASE_URL || "http://localhost:11434";
19
- };
20
- const isOpenAICompatibleMode = () => {
21
- // Enable OpenAI-compatible API mode (/v1/chat/completions) instead of native Ollama API (/api/generate)
22
- // Useful for Ollama deployments that only support OpenAI-compatible routes (e.g., breezehq.dev)
23
- return process.env.OLLAMA_OPENAI_COMPATIBLE === "true";
24
- };
25
- // Create AbortController with timeout for better compatibility
26
- const createAbortSignalWithTimeout = (timeoutMs) => {
27
- const controller = new AbortController();
28
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
29
- // Clear timeout if signal is aborted through other means
30
- controller.signal.addEventListener("abort", () => {
31
- clearTimeout(timeoutId);
32
- });
33
- return controller.signal;
34
- };
35
- const getDefaultOllamaModel = () => {
36
- return process.env.OLLAMA_MODEL || DEFAULT_OLLAMA_MODEL;
37
- };
38
- const getOllamaTimeout = () => {
39
- // Increased default timeout to 240000ms (4 minutes) to support slower native API responses
40
- // especially for larger models like aliafshar/gemma3-it-qat-tools:latest (12.2B parameters)
41
- return parseInt(process.env.OLLAMA_TIMEOUT || "240000", 10);
42
- };
43
- // Create proxy-aware fetch instance
44
- const proxyFetch = createProxyFetch();
45
- // Custom LanguageModel implementation for Ollama
46
- class OllamaLanguageModel {
47
- /**
48
- * Specification version for the AI SDK LanguageModel interface.
49
- * Uses "v2" for structural compatibility with AI SDK v6's `LanguageModelV2`.
50
- * The AI SDK checks this field to determine which interface version to use.
51
- */
52
- specificationVersion = "v2";
53
- provider = "ollama";
54
- modelId;
55
- maxTokens;
56
- supportsStreaming = true;
57
- defaultObjectGenerationMode = "json";
58
- /**
59
- * Supported URL patterns by media type.
60
- * Ollama runs locally and does not natively download URLs, so this is empty.
61
- * Required by the LanguageModelV2 interface.
62
- */
63
- supportedUrls = {};
64
- baseUrl;
65
- timeout;
66
- constructor(modelId, baseUrl, timeout) {
67
- this.modelId = modelId;
68
- this.baseUrl = baseUrl;
69
- this.timeout = timeout;
70
- }
71
- estimateTokenCount(text) {
72
- return estimateTokens(text, "ollama");
73
- }
74
- convertMessagesToPrompt(messages) {
75
- return messages
76
- .map((msg) => {
77
- if (typeof msg.content === "string") {
78
- return `${msg.role}: ${msg.content}`;
79
- }
80
- return `${msg.role}: ${JSON.stringify(msg.content)}`;
81
- })
82
- .join("\n");
83
- }
84
- async doGenerate(options) {
85
- // Vercel AI SDK passes messages via options.messages (same as stream mode)
86
- // Check options.messages first, then fall back to options.prompt for backward compatibility
87
- const messages = options
88
- .messages ||
89
- options
90
- .prompt ||
91
- [];
92
- // Check if we should use OpenAI-compatible API
93
- const useOpenAIMode = isOpenAICompatibleMode();
94
- if (useOpenAIMode) {
95
- // OpenAI-compatible mode: Use /v1/chat/completions
96
- const requestBody = {
97
- model: this.modelId,
98
- messages,
99
- temperature: options.temperature,
100
- max_tokens: options.maxTokens,
101
- stream: false,
102
- };
103
- if (logger.shouldLog("debug")) {
104
- logger.debug("[OllamaLanguageModel] Using OpenAI-compatible API with messages:", JSON.stringify(messages, null, 2));
105
- }
106
- const response = await proxyFetch(`${this.baseUrl}/v1/chat/completions`, {
107
- method: "POST",
108
- headers: { "Content-Type": "application/json" },
109
- body: JSON.stringify(requestBody),
110
- signal: createAbortSignalWithTimeout(this.timeout),
111
- });
112
- if (!response.ok) {
113
- throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
114
- }
115
- const data = await response.json();
116
- logger.debug("[OllamaLanguageModel] OpenAI API Response:", JSON.stringify(data, null, 2));
117
- const text = data.choices?.[0]?.message?.content || "";
118
- const usage = data.usage || {};
119
- return {
120
- text,
121
- usage: {
122
- promptTokens: usage.prompt_tokens ??
123
- this.estimateTokenCount(JSON.stringify(messages)),
124
- completionTokens: usage.completion_tokens ?? this.estimateTokenCount(text),
125
- totalTokens: usage.total_tokens,
126
- },
127
- finishReason: "stop",
128
- rawCall: {
129
- rawPrompt: messages,
130
- rawSettings: {
131
- model: this.modelId,
132
- temperature: options.temperature,
133
- max_tokens: options.maxTokens,
134
- },
135
- },
136
- rawResponse: {
137
- headers: {},
138
- },
139
- };
140
- }
141
- else {
142
- // Native Ollama mode: Use /api/generate
143
- const prompt = this.convertMessagesToPrompt(messages);
144
- logger.debug("[OllamaLanguageModel] Using native API with prompt:", JSON.stringify(prompt));
145
- const response = await proxyFetch(`${this.baseUrl}/api/generate`, {
146
- method: "POST",
147
- headers: { "Content-Type": "application/json" },
148
- body: JSON.stringify({
149
- model: this.modelId,
150
- prompt,
151
- stream: false,
152
- system: messages.find((m) => m.role === "system")?.content,
153
- options: {
154
- temperature: options.temperature,
155
- num_predict: options.maxTokens,
156
- },
157
- }),
158
- signal: createAbortSignalWithTimeout(this.timeout),
159
- });
160
- if (!response.ok) {
161
- throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
162
- }
163
- const data = await response.json();
164
- logger.debug("[OllamaLanguageModel] Native API Response:", JSON.stringify(data, null, 2));
165
- return {
166
- text: data.response,
167
- usage: {
168
- promptTokens: data.prompt_eval_count ?? this.estimateTokenCount(prompt),
169
- completionTokens: data.eval_count ??
170
- this.estimateTokenCount(String(data.response ?? "")),
171
- totalTokens: (data.prompt_eval_count ?? this.estimateTokenCount(prompt)) +
172
- (data.eval_count ??
173
- this.estimateTokenCount(String(data.response ?? ""))),
174
- },
175
- finishReason: "stop",
176
- rawCall: {
177
- rawPrompt: prompt,
178
- rawSettings: {
179
- model: this.modelId,
180
- temperature: options.temperature,
181
- num_predict: options.maxTokens,
182
- },
183
- },
184
- rawResponse: {
185
- headers: {},
186
- },
187
- };
188
- }
189
- }
190
- async doStream(options) {
191
- const messages = options
192
- .messages || [];
193
- // Check if we should use OpenAI-compatible API
194
- const useOpenAIMode = isOpenAICompatibleMode();
195
- if (useOpenAIMode) {
196
- // OpenAI-compatible mode: Use /v1/chat/completions
197
- const requestUrl = `${this.baseUrl}/v1/chat/completions`;
198
- const requestBody = {
199
- model: this.modelId,
200
- messages,
201
- temperature: options.temperature,
202
- max_tokens: options.maxTokens,
203
- stream: true,
204
- };
205
- logger.debug("[OllamaLanguageModel] doStream: Using OpenAI-compatible API", {
206
- url: requestUrl,
207
- baseUrl: this.baseUrl,
208
- modelId: this.modelId,
209
- requestBody: JSON.stringify(requestBody),
210
- });
211
- const response = await proxyFetch(requestUrl, {
212
- method: "POST",
213
- headers: { "Content-Type": "application/json" },
214
- body: JSON.stringify(requestBody),
215
- signal: createAbortSignalWithTimeout(this.timeout),
216
- });
217
- logger.debug("[OllamaLanguageModel] doStream: Response received", {
218
- status: response.status,
219
- statusText: response.statusText,
220
- ok: response.ok,
221
- });
222
- if (!response.ok) {
223
- throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
224
- }
225
- const self = this;
226
- return {
227
- stream: new ReadableStream({
228
- async start(controller) {
229
- try {
230
- for await (const chunk of self.parseOpenAIStreamResponse(response, messages)) {
231
- controller.enqueue(chunk);
232
- }
233
- controller.close();
234
- }
235
- catch (error) {
236
- controller.error(error);
237
- }
238
- },
239
- }),
240
- rawCall: {
241
- rawPrompt: messages,
242
- rawSettings: {
243
- model: this.modelId,
244
- temperature: options.temperature,
245
- max_tokens: options.maxTokens,
246
- },
247
- },
248
- rawResponse: {
249
- headers: {},
250
- },
251
- };
252
- }
253
- else {
254
- // Native Ollama mode: Use /api/generate
255
- const prompt = this.convertMessagesToPrompt(messages);
256
- const requestUrl = `${this.baseUrl}/api/generate`;
257
- const requestBody = {
258
- model: this.modelId,
259
- prompt,
260
- stream: true,
261
- system: messages.find((m) => m.role === "system")?.content,
262
- options: {
263
- temperature: options.temperature,
264
- num_predict: options.maxTokens,
265
- },
266
- };
267
- logger.debug("[OllamaLanguageModel] doStream: Using native API", {
268
- url: requestUrl,
269
- baseUrl: this.baseUrl,
270
- modelId: this.modelId,
271
- requestBody: JSON.stringify(requestBody),
272
- });
273
- const response = await proxyFetch(requestUrl, {
274
- method: "POST",
275
- headers: { "Content-Type": "application/json" },
276
- body: JSON.stringify(requestBody),
277
- signal: createAbortSignalWithTimeout(this.timeout),
278
- });
279
- logger.debug("[OllamaLanguageModel] doStream: Response received", {
280
- status: response.status,
281
- statusText: response.statusText,
282
- ok: response.ok,
283
- });
284
- if (!response.ok) {
285
- throw new Error(`Ollama API error: ${response.status} ${response.statusText}`);
286
- }
287
- const self = this;
288
- return {
289
- stream: new ReadableStream({
290
- async start(controller) {
291
- try {
292
- for await (const chunk of self.parseStreamResponse(response)) {
293
- controller.enqueue(chunk);
294
- }
295
- controller.close();
296
- }
297
- catch (error) {
298
- controller.error(error);
299
- }
300
- },
301
- }),
302
- rawCall: {
303
- rawPrompt: messages,
304
- rawSettings: {
305
- model: this.modelId,
306
- temperature: options.temperature,
307
- num_predict: options.maxTokens,
308
- },
309
- },
310
- rawResponse: {
311
- headers: {},
312
- },
313
- };
314
- }
315
- }
316
- async *parseStreamResponse(response) {
317
- const reader = response.body?.getReader();
318
- if (!reader) {
319
- throw new Error("No response body");
320
- }
321
- const decoder = new TextDecoder();
322
- let buffer = "";
323
- try {
324
- while (true) {
325
- const { done, value } = await reader.read();
326
- if (done) {
327
- break;
328
- }
329
- buffer += decoder.decode(value, { stream: true });
330
- const lines = buffer.split("\n");
331
- buffer = lines.pop() || "";
332
- for (const line of lines) {
333
- if (line.trim()) {
334
- try {
335
- const data = JSON.parse(line);
336
- if (data.response) {
337
- yield {
338
- type: "text-delta",
339
- textDelta: data.response,
340
- };
341
- }
342
- if (data.done) {
343
- yield {
344
- type: "finish",
345
- finishReason: "stop",
346
- usage: {
347
- promptTokens: data.prompt_eval_count ||
348
- this.estimateTokenCount(data.context || ""),
349
- completionTokens: data.eval_count || 0,
350
- },
351
- };
352
- return;
353
- }
354
- }
355
- catch (error) {
356
- logger.error("Error parsing Ollama stream response", {
357
- error,
358
- });
359
- }
360
- }
361
- }
362
- }
363
- }
364
- finally {
365
- reader.releaseLock();
366
- }
367
- }
368
- async *parseOpenAIStreamResponse(response, messages) {
369
- const reader = response.body?.getReader();
370
- if (!reader) {
371
- throw new Error("No response body");
372
- }
373
- const decoder = new TextDecoder();
374
- let buffer = "";
375
- // Estimate prompt tokens from messages (matches non-streaming behavior)
376
- const totalPromptTokens = this.estimateTokenCount(JSON.stringify(messages));
377
- // Accumulate full completion text; estimate tokens once at the end to avoid
378
- // per-chunk rounding inflation that occurs when estimateTokenCount is called
379
- // on every delta and the results are summed.
380
- let completionText = "";
381
- try {
382
- while (true) {
383
- const { done, value } = await reader.read();
384
- if (done) {
385
- break;
386
- }
387
- buffer += decoder.decode(value, { stream: true });
388
- const lines = buffer.split("\n");
389
- buffer = lines.pop() || "";
390
- for (const line of lines) {
391
- const trimmed = line.trim();
392
- if (trimmed === "" || trimmed === "data: [DONE]") {
393
- continue;
394
- }
395
- if (trimmed.startsWith("data: ")) {
396
- try {
397
- const jsonStr = trimmed.slice(6); // Remove "data: " prefix
398
- const data = JSON.parse(jsonStr);
399
- // Extract content delta
400
- const content = data.choices?.[0]?.delta?.content;
401
- if (content) {
402
- yield {
403
- type: "text-delta",
404
- textDelta: content,
405
- };
406
- completionText += content;
407
- }
408
- // Check for finish
409
- const finishReason = data.choices?.[0]?.finish_reason;
410
- if (finishReason === "stop") {
411
- // Prefer server-reported usage; fall back to a single estimate over
412
- // the full accumulated text (avoids per-chunk rounding inflation).
413
- const promptTokens = data.usage?.prompt_tokens || totalPromptTokens;
414
- const completionTokens = data.usage?.completion_tokens ||
415
- this.estimateTokenCount(completionText);
416
- yield {
417
- type: "finish",
418
- finishReason: "stop",
419
- usage: {
420
- promptTokens,
421
- completionTokens,
422
- },
423
- };
424
- return;
425
- }
426
- }
427
- catch (error) {
428
- logger.error("Error parsing OpenAI stream response", {
429
- error,
430
- line: trimmed,
431
- });
432
- }
433
- }
434
- }
435
- }
436
- // If loop exits without explicit finish, yield final finish
437
- yield {
438
- type: "finish",
439
- finishReason: "stop",
440
- usage: {
441
- promptTokens: totalPromptTokens,
442
- completionTokens: this.estimateTokenCount(completionText),
443
- },
444
- };
445
- }
446
- finally {
447
- reader.releaseLock();
448
- }
449
- }
450
- }
451
- /**
452
- * Ollama Provider v2 - BaseProvider Implementation
453
- *
454
- * PHASE 3.7: BaseProvider wrap around existing custom Ollama implementation
455
- *
456
- * Features:
457
- * - Extends BaseProvider for shared functionality
458
- * - Preserves custom OllamaLanguageModel implementation
459
- * - Local model management and health checking
460
- * - Enhanced error handling with Ollama-specific guidance
461
- */
462
- export class OllamaProvider extends BaseProvider {
463
- ollamaModel;
464
- baseUrl;
465
- timeout;
466
- constructor(modelName) {
467
- super(modelName, "ollama");
468
- this.baseUrl = getOllamaBaseUrl();
469
- this.timeout = getOllamaTimeout();
470
- // Initialize Ollama model
471
- this.ollamaModel = new OllamaLanguageModel(this.modelName || getDefaultOllamaModel(), this.baseUrl, this.timeout);
472
- logger.debug("Ollama BaseProvider v2 initialized", {
473
- modelName: this.modelName,
474
- baseUrl: this.baseUrl,
475
- timeout: this.timeout,
476
- provider: this.providerName,
477
- });
478
- }
479
- getProviderName() {
480
- return "ollama";
481
- }
482
- getDefaultModel() {
483
- return getDefaultOllamaModel();
484
- }
485
- /**
486
- * Returns the Vercel AI SDK model instance for Ollama.
487
- *
488
- * OllamaLanguageModel implements OllamaAsLanguageModel which is structurally
489
- * compatible with LanguageModelV2 (specificationVersion "v2", modelId, provider,
490
- * supportedUrls, doGenerate, doStream).
491
- */
492
- getAISDKModel() {
493
- const model = this.ollamaModel;
494
- return model;
495
- }
496
- /**
497
- * Ollama Tool Calling Support (Enhanced 2025)
498
- *
499
- * Uses configurable model list from ModelConfiguration instead of hardcoded values.
500
- * Tool-capable models can be configured via OLLAMA_TOOL_CAPABLE_MODELS environment variable.
501
- *
502
- * **Configuration Options:**
503
- * - Environment variable: OLLAMA_TOOL_CAPABLE_MODELS (comma-separated list)
504
- * - Configuration file: providers.ollama.modelBehavior.toolCapableModels
505
- * - Fallback: Default list of known tool-capable models
506
- *
507
- * **Implementation Features:**
508
- * - Direct Ollama API integration (/v1/chat/completions)
509
- * - Automatic tool schema conversion to Ollama format
510
- * - Streaming tool calls with incremental response parsing
511
- * - Model compatibility validation and fallback handling
512
- *
513
- * @returns true for supported models, false for unsupported models
514
- */
515
- supportsTools() {
516
- const modelName = (this.modelName ?? getDefaultOllamaModel()).toLowerCase();
517
- // Get tool-capable models from configuration
518
- const ollamaConfig = modelConfig.getProviderConfiguration("ollama");
519
- const toolCapableModels = ollamaConfig?.modelBehavior?.toolCapableModels || [];
520
- // Only disable tools if we have positive evidence the model doesn't support them
521
- // If toolCapableModels config is empty, assume tools are supported (don't make assumptions)
522
- if (toolCapableModels.length === 0) {
523
- logger.debug("Ollama tool calling enabled", {
524
- model: this.modelName,
525
- reason: "No tool-capable config defined, assuming tools supported",
526
- baseUrl: this.baseUrl,
527
- });
528
- return true;
529
- }
530
- // Config exists - check if current model matches tool-capable model patterns
531
- const isToolCapable = toolCapableModels.some((capableModel) => modelName.includes(capableModel.toLowerCase()));
532
- if (isToolCapable) {
533
- logger.debug("Ollama tool calling enabled", {
534
- model: this.modelName,
535
- reason: "Model in tool-capable list",
536
- baseUrl: this.baseUrl,
537
- configuredModels: toolCapableModels.length,
538
- });
539
- return true;
540
- }
541
- // Config exists and model is NOT in list - disable tools
542
- logger.debug("Ollama tool calling disabled", {
543
- model: this.modelName,
544
- reason: "Model not in tool-capable list",
545
- suggestion: "Consider using llama3.1:8b-instruct, mistral:7b-instruct, or hermes3:8b for tool calling",
546
- availableToolModels: toolCapableModels.slice(0, 3), // Show first 3 for brevity
547
- });
548
- return false;
549
- }
550
- /**
551
- * Extract images from multimodal messages for Ollama API
552
- * Returns array of base64-encoded images
553
- */
554
- extractImagesFromMessages(messages) {
555
- const images = [];
556
- for (const msg of messages) {
557
- if (Array.isArray(msg.content)) {
558
- for (const content of msg.content) {
559
- const typedContent = content;
560
- if (typedContent.type === "image" && typedContent.image) {
561
- const imageData = typeof typedContent.image === "string"
562
- ? typedContent.image.replace(/^data:image\/\w+;base64,/, "")
563
- : Buffer.from(typedContent.image).toString("base64");
564
- images.push(imageData);
565
- }
566
- }
567
- }
568
- }
569
- return images;
570
- }
571
- /**
572
- * Convert multimodal messages to Ollama chat format
573
- * Extracts text content and handles images separately
574
- */
575
- convertToOllamaMessages(messages) {
576
- return messages.map((msg) => {
577
- let textContent = "";
578
- const images = [];
579
- if (typeof msg.content === "string") {
580
- textContent = msg.content;
581
- }
582
- else if (Array.isArray(msg.content)) {
583
- for (const content of msg.content) {
584
- const typedContent = content;
585
- if (typedContent.type === "text" && typedContent.text) {
586
- textContent += typedContent.text;
587
- }
588
- else if (typedContent.type === "image" && typedContent.image) {
589
- const imageData = typeof typedContent.image === "string"
590
- ? typedContent.image.replace(/^data:image\/\w+;base64,/, "")
591
- : Buffer.from(typedContent.image).toString("base64");
592
- images.push(imageData);
593
- }
594
- }
595
- }
596
- const ollamaMsg = {
597
- role: (msg.role === "system" ? "system" : msg.role),
598
- content: textContent,
599
- };
600
- if (images.length > 0) {
601
- ollamaMsg.images = images;
602
- }
603
- return ollamaMsg;
604
- });
605
- }
606
- // executeGenerate removed - BaseProvider handles all generation with tools
607
- async executeStream(options, analysisSchema) {
608
- try {
609
- this.validateStreamOptions(options);
610
- await this.checkOllamaHealth();
611
- // Check if tools are supported and provided
612
- const modelSupportsTools = this.supportsTools();
613
- const hasTools = options.tools && Object.keys(options.tools).length > 0;
614
- if (modelSupportsTools && hasTools) {
615
- // Use chat API with tools for tool-capable models
616
- return this.executeStreamWithTools(options, analysisSchema);
617
- }
618
- else {
619
- // Use generate API for non-tool scenarios
620
- return this.executeStreamWithoutTools(options, analysisSchema);
621
- }
622
- }
623
- catch (error) {
624
- throw this.handleProviderError(error);
625
- }
626
- }
627
- /**
628
- * Execute streaming with Ollama's function calling support
629
- * Uses conversation loop to handle multi-step tool execution
630
- */
631
- async executeStreamWithTools(options, _analysisSchema) {
632
- return withClientSpan({
633
- name: "neurolink.provider.stream",
634
- tracer: tracers.provider,
635
- attributes: {
636
- [ATTR.GEN_AI_SYSTEM]: "ollama",
637
- [ATTR.GEN_AI_MODEL]: this.modelName || FALLBACK_OLLAMA_MODEL,
638
- [ATTR.GEN_AI_OPERATION]: "stream",
639
- [ATTR.NL_HAS_TOOLS]: true,
640
- [ATTR.NL_STREAM_MODE]: true,
641
- },
642
- }, async (span) => {
643
- const startTime = Date.now();
644
- const maxIterations = options.maxSteps || DEFAULT_MAX_STEPS;
645
- let iteration = 0;
646
- // Get all available tools (direct + MCP + external)
647
- // BaseProvider.stream() pre-merges base tools + external tools into options.tools
648
- const allTools = options.tools ||
649
- (await this.getAllTools());
650
- // Convert tools to Ollama format
651
- const ollamaTools = this.convertToolsToOllamaFormat(allTools);
652
- span.setAttribute(ATTR.NL_TOOL_COUNT, ollamaTools.length);
653
- // Validate that PDFs are not provided
654
- if (options.input?.pdfFiles && options.input.pdfFiles.length > 0) {
655
- throw this.handleProviderError(new Error("PDF inputs are not supported by OllamaProvider. " +
656
- "Please remove PDFs or use a supported provider (OpenAI, Anthropic, Google Vertex AI, etc.)."));
657
- }
658
- // Initialize conversation history
659
- const conversationHistory = [];
660
- // Build initial messages
661
- const hasMultimodalInput = !!(options.input?.images?.length ||
662
- options.input?.content?.length ||
663
- options.input?.files?.length ||
664
- options.input?.csvFiles?.length);
665
- if (hasMultimodalInput) {
666
- logger.debug(`Ollama: Detected multimodal input, using multimodal message builder`, {
667
- hasImages: !!options.input?.images?.length,
668
- imageCount: options.input?.images?.length || 0,
669
- });
670
- const multimodalOptions = buildMultimodalOptions(options, this.providerName, this.modelName);
671
- const multimodalMessages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
672
- conversationHistory.push(...this.convertToOllamaMessages(multimodalMessages));
673
- }
674
- else {
675
- if (options.systemPrompt) {
676
- conversationHistory.push({
677
- role: "system",
678
- content: options.systemPrompt,
679
- });
680
- }
681
- conversationHistory.push({
682
- role: "user",
683
- content: options.input.text,
684
- });
685
- }
686
- // Conversation loop for multi-step tool execution
687
- const stream = new ReadableStream({
688
- start: async (controller) => {
689
- try {
690
- while (iteration < maxIterations) {
691
- logger.debug(`[OllamaProvider] Conversation iteration ${iteration + 1}/${maxIterations}`);
692
- // Make API request
693
- const response = await proxyFetch(`${this.baseUrl}/v1/chat/completions`, {
694
- method: "POST",
695
- headers: { "Content-Type": "application/json" },
696
- body: JSON.stringify({
697
- model: this.modelName || FALLBACK_OLLAMA_MODEL,
698
- messages: conversationHistory,
699
- tools: ollamaTools,
700
- tool_choice: "auto",
701
- stream: true,
702
- temperature: options.temperature,
703
- max_tokens: options.maxTokens,
704
- }),
705
- signal: createAbortSignalWithTimeout(this.timeout),
706
- });
707
- if (!response.ok) {
708
- throw this.handleProviderError(new Error(`Ollama API error: ${response.status} ${response.statusText}`));
709
- }
710
- // Process response stream
711
- const { content, toolCalls, finishReason } = await this.processOllamaResponse(response, controller);
712
- // Add assistant message to history
713
- const assistantMessage = {
714
- role: "assistant",
715
- content: content || "",
716
- };
717
- if (toolCalls && toolCalls.length > 0) {
718
- assistantMessage.tool_calls = toolCalls;
719
- }
720
- conversationHistory.push(assistantMessage);
721
- // Check finish reason
722
- if (finishReason === "stop" || !finishReason) {
723
- // Conversation complete
724
- span.setAttribute(ATTR.GEN_AI_FINISH_REASON, finishReason || "stop");
725
- controller.close();
726
- break;
727
- }
728
- else if (finishReason === "tool_calls" &&
729
- toolCalls &&
730
- toolCalls.length > 0) {
731
- // Execute tools
732
- logger.debug(`[OllamaProvider] Executing ${toolCalls.length} tools`);
733
- for (const tc of toolCalls) {
734
- span.addEvent("tool_call", {
735
- [ATTR.GEN_AI_TOOL_NAME]: tc.function.name,
736
- });
737
- }
738
- const toolResults = await this.executeOllamaTools(toolCalls, options);
739
- // Add tool results to conversation
740
- const toolMessage = {
741
- role: "tool",
742
- content: JSON.stringify(toolResults),
743
- };
744
- conversationHistory.push(toolMessage);
745
- iteration++;
746
- }
747
- else if (finishReason === "length") {
748
- // Max tokens reached, continue conversation
749
- logger.debug(`[OllamaProvider] Max tokens reached, continuing`);
750
- conversationHistory.push({
751
- role: "user",
752
- content: "Please continue.",
753
- });
754
- iteration++;
755
- }
756
- else {
757
- // Unknown finish reason, end conversation
758
- logger.warn(`[OllamaProvider] Unknown finish reason: ${finishReason}`);
759
- span.setAttribute(ATTR.GEN_AI_FINISH_REASON, finishReason);
760
- controller.close();
761
- break;
762
- }
763
- }
764
- if (iteration >= maxIterations) {
765
- controller.error(new Error(`Ollama conversation exceeded maximum iterations (${maxIterations})`));
766
- }
767
- }
768
- catch (error) {
769
- controller.error(error);
770
- }
771
- finally {
772
- // Resolve analytics with final values now that the loop has completed.
773
- resolveAnalytics(createAnalytics(this.providerName, this.modelName || FALLBACK_OLLAMA_MODEL, { usage: { input: 0, output: 0, total: 0 } }, Date.now() - startTime, {
774
- requestId: `ollama-stream-${Date.now()}`,
775
- streamingMode: true,
776
- iterations: iteration,
777
- note: "Token usage not available from Ollama streaming responses",
778
- }));
779
- }
780
- },
781
- });
782
- // Defer analytics resolution until the stream's start callback finishes.
783
- // This ensures responseTime and iteration reflect the actual completed values
784
- // rather than values captured before the tool-loop executes.
785
- let resolveAnalytics;
786
- const analyticsPromise = new Promise((resolve) => {
787
- resolveAnalytics = resolve;
788
- });
789
- return {
790
- stream: this.convertToAsyncIterable(stream),
791
- provider: this.providerName,
792
- model: this.modelName || FALLBACK_OLLAMA_MODEL,
793
- analytics: analyticsPromise,
794
- metadata: {
795
- startTime,
796
- streamId: `ollama-${Date.now()}`,
797
- },
798
- };
799
- });
800
- }
801
- /**
802
- * Execute streaming without tools using the generate API
803
- * Fallback for non-tool scenarios or when chat API is unavailable
804
- */
805
- async executeStreamWithoutTools(options, _analysisSchema) {
806
- return withClientSpan({
807
- name: "neurolink.provider.stream",
808
- tracer: tracers.provider,
809
- attributes: {
810
- [ATTR.GEN_AI_SYSTEM]: "ollama",
811
- [ATTR.GEN_AI_MODEL]: this.modelName || FALLBACK_OLLAMA_MODEL,
812
- [ATTR.GEN_AI_OPERATION]: "stream",
813
- [ATTR.NL_HAS_TOOLS]: false,
814
- [ATTR.NL_STREAM_MODE]: true,
815
- },
816
- }, async () => {
817
- // Validate that PDFs are not provided
818
- if (options.input?.pdfFiles && options.input.pdfFiles.length > 0) {
819
- throw this.handleProviderError(new Error("PDF inputs are not supported by OllamaProvider. " +
820
- "Please remove PDFs or use a supported provider (OpenAI, Anthropic, Google Vertex AI, etc.)."));
821
- }
822
- // Check for multimodal input
823
- const hasMultimodalInput = !!(options.input?.images?.length ||
824
- options.input?.content?.length ||
825
- options.input?.files?.length ||
826
- options.input?.csvFiles?.length);
827
- const useOpenAIMode = isOpenAICompatibleMode();
828
- if (useOpenAIMode) {
829
- // OpenAI-compatible mode: Use /v1/chat/completions with messages
830
- logger.debug(`Ollama (OpenAI mode): Building messages for streaming`);
831
- const messages = [];
832
- if (options.systemPrompt) {
833
- messages.push({ role: "system", content: options.systemPrompt });
834
- }
835
- if (hasMultimodalInput) {
836
- const multimodalOptions = buildMultimodalOptions(options, this.providerName, this.modelName);
837
- const multimodalMessages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
838
- // Convert multimodal messages to text (OpenAI-compatible mode doesn't support images in /v1/chat/completions for Ollama)
839
- const content = multimodalMessages
840
- .map((msg) => typeof msg.content === "string" ? msg.content : "")
841
- .join("\n");
842
- messages.push({ role: "user", content });
843
- }
844
- else {
845
- messages.push({ role: "user", content: options.input.text });
846
- }
847
- const requestUrl = `${this.baseUrl}/v1/chat/completions`;
848
- const requestBody = {
849
- model: this.modelName || FALLBACK_OLLAMA_MODEL,
850
- messages,
851
- temperature: options.temperature,
852
- max_tokens: options.maxTokens,
853
- stream: true,
854
- };
855
- logger.debug(`[Ollama OpenAI Mode] About to fetch:`, {
856
- url: requestUrl,
857
- baseUrl: this.baseUrl,
858
- modelName: this.modelName,
859
- requestBody: JSON.stringify(requestBody),
860
- });
861
- const response = await proxyFetch(requestUrl, {
862
- method: "POST",
863
- headers: { "Content-Type": "application/json" },
864
- body: JSON.stringify(requestBody),
865
- signal: createAbortSignalWithTimeout(this.timeout),
866
- });
867
- logger.debug(`[Ollama OpenAI Mode] Response received:`, {
868
- status: response.status,
869
- statusText: response.statusText,
870
- ok: response.ok,
871
- });
872
- if (!response.ok) {
873
- throw this.handleProviderError(new Error(`Ollama API error: ${response.status} ${response.statusText}`));
874
- }
875
- // Transform to async generator for OpenAI-compatible format
876
- const self = this;
877
- const transformedStream = async function* () {
878
- const generator = self.createOpenAIStream(response);
879
- for await (const chunk of generator) {
880
- yield chunk;
881
- }
882
- };
883
- return {
884
- stream: transformedStream(),
885
- provider: self.providerName,
886
- model: self.modelName,
887
- };
888
- }
889
- else {
890
- // Native Ollama mode: Use /api/generate
891
- let prompt = options.input.text;
892
- let images;
893
- if (hasMultimodalInput) {
894
- logger.debug(`Ollama (native mode): Detected multimodal input`, {
895
- hasImages: !!options.input?.images?.length,
896
- imageCount: options.input?.images?.length || 0,
897
- });
898
- const multimodalOptions = buildMultimodalOptions(options, this.providerName, this.modelName);
899
- const multimodalMessages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
900
- // Extract text from messages for prompt
901
- prompt = multimodalMessages
902
- .map((msg) => typeof msg.content === "string" ? msg.content : "")
903
- .join("\n");
904
- // Extract images
905
- images = this.extractImagesFromMessages(multimodalMessages);
906
- }
907
- const requestBody = {
908
- model: this.modelName || FALLBACK_OLLAMA_MODEL,
909
- prompt,
910
- system: options.systemPrompt,
911
- stream: true,
912
- options: {
913
- temperature: options.temperature,
914
- num_predict: options.maxTokens,
915
- },
916
- };
917
- if (images && images.length > 0) {
918
- requestBody.images = images;
919
- }
920
- const requestUrl = `${this.baseUrl}/api/generate`;
921
- logger.debug(`[Ollama Native Mode] About to fetch:`, {
922
- url: requestUrl,
923
- baseUrl: this.baseUrl,
924
- modelName: this.modelName,
925
- requestBody: JSON.stringify(requestBody),
926
- });
927
- const response = await proxyFetch(requestUrl, {
928
- method: "POST",
929
- headers: { "Content-Type": "application/json" },
930
- body: JSON.stringify(requestBody),
931
- signal: createAbortSignalWithTimeout(this.timeout),
932
- });
933
- logger.debug(`[Ollama Native Mode] Response received:`, {
934
- status: response.status,
935
- statusText: response.statusText,
936
- ok: response.ok,
937
- });
938
- if (!response.ok) {
939
- throw this.handleProviderError(new Error(`Ollama API error: ${response.status} ${response.statusText}`));
940
- }
941
- // Transform to async generator to match other providers
942
- const self = this;
943
- const transformedStream = async function* () {
944
- const generator = self.createOllamaStream(response);
945
- for await (const chunk of generator) {
946
- yield chunk;
947
- }
948
- };
949
- return {
950
- stream: transformedStream(),
951
- provider: this.providerName,
952
- model: this.modelName,
953
- };
954
- }
955
- });
956
- }
957
- /**
958
- * Convert AI SDK tools format to Ollama's function calling format
959
- */
960
- convertToolsToOllamaFormat(tools) {
961
- if (!tools || typeof tools !== "object") {
962
- return [];
963
- }
964
- const toolsArray = Array.isArray(tools) ? tools : Object.values(tools);
965
- return toolsArray.map((tool) => ({
966
- type: "function",
967
- function: {
968
- name: tool.name || tool.function?.name,
969
- description: tool.description || tool.function?.description,
970
- parameters: tool.parameters ||
971
- tool.function?.parameters || {
972
- type: "object",
973
- properties: {},
974
- required: [],
975
- },
976
- },
977
- }));
978
- }
979
- /**
980
- * Parse tool calls from Ollama API response
981
- */
982
- parseToolCalls(rawToolCalls) {
983
- if (!Array.isArray(rawToolCalls)) {
984
- return [];
985
- }
986
- return rawToolCalls
987
- .map((call) => {
988
- const callObj = call;
989
- if (!callObj.function?.name) {
990
- return null;
991
- }
992
- return {
993
- id: callObj.id ||
994
- `tool_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
995
- type: "function",
996
- function: {
997
- name: callObj.function.name,
998
- arguments: callObj.function.arguments || "{}",
999
- },
1000
- };
1001
- })
1002
- .filter((call) => call !== null);
1003
- }
1004
- /**
1005
- * Process Ollama streaming response and stream content to controller
1006
- * Returns aggregated content, tool calls, and finish reason
1007
- */
1008
- async processOllamaResponse(response, controller) {
1009
- const reader = response.body?.getReader();
1010
- if (!reader) {
1011
- throw new Error("No response body from Ollama");
1012
- }
1013
- const decoder = new TextDecoder();
1014
- let buffer = "";
1015
- let aggregatedContent = "";
1016
- let aggregatedToolCalls = [];
1017
- let finalFinishReason;
1018
- try {
1019
- while (true) {
1020
- const { done, value } = await reader.read();
1021
- if (done) {
1022
- break;
1023
- }
1024
- buffer += decoder.decode(value, { stream: true });
1025
- const lines = buffer.split("\n");
1026
- buffer = lines.pop() || "";
1027
- for (const line of lines) {
1028
- if (line.trim() && line.startsWith("data: ")) {
1029
- const dataLine = line.slice(6); // Remove "data: " prefix
1030
- if (dataLine === "[DONE]") {
1031
- break;
1032
- }
1033
- try {
1034
- const parsed = JSON.parse(dataLine);
1035
- const processed = this.processOllamaStreamData(parsed);
1036
- if (!processed) {
1037
- continue;
1038
- }
1039
- // Stream content to controller
1040
- if (processed.content) {
1041
- aggregatedContent += processed.content;
1042
- controller.enqueue({
1043
- content: processed.content,
1044
- });
1045
- }
1046
- // Collect tool calls
1047
- if (processed.toolCalls && processed.toolCalls.length > 0) {
1048
- aggregatedToolCalls = [
1049
- ...aggregatedToolCalls,
1050
- ...processed.toolCalls,
1051
- ];
1052
- }
1053
- // Update finish reason
1054
- if (processed.finishReason) {
1055
- finalFinishReason = processed.finishReason;
1056
- }
1057
- }
1058
- catch (parseError) {
1059
- logger.warn(`[OllamaProvider] Failed to parse stream chunk: ${dataLine}`, { error: parseError });
1060
- }
1061
- }
1062
- }
1063
- }
1064
- }
1065
- finally {
1066
- reader.releaseLock();
1067
- }
1068
- return {
1069
- content: aggregatedContent || undefined,
1070
- toolCalls: aggregatedToolCalls.length > 0 ? aggregatedToolCalls : undefined,
1071
- finishReason: finalFinishReason,
1072
- };
1073
- }
1074
- /**
1075
- * Process individual stream data chunk from Ollama
1076
- */
1077
- processOllamaStreamData(data) {
1078
- const dataRecord = data;
1079
- const choices = dataRecord.choices;
1080
- const delta = choices?.[0]?.delta;
1081
- const finishReason = choices?.[0]?.finish_reason;
1082
- let content = "";
1083
- if (delta?.content && typeof delta.content === "string") {
1084
- content += delta.content;
1085
- }
1086
- // Return tool calls for execution instead of formatting as text
1087
- if (delta?.tool_calls) {
1088
- const toolCalls = this.parseToolCalls(delta.tool_calls);
1089
- return {
1090
- toolCalls,
1091
- finishReason,
1092
- shouldReturn: !!finishReason,
1093
- };
1094
- }
1095
- // Also check for tool calls in the message field (some responses include it there)
1096
- if (choices?.[0]?.message?.tool_calls) {
1097
- const toolCalls = this.parseToolCalls(choices[0].message.tool_calls);
1098
- return {
1099
- toolCalls,
1100
- finishReason,
1101
- shouldReturn: !!finishReason,
1102
- };
1103
- }
1104
- const shouldReturn = !!finishReason;
1105
- return content
1106
- ? { content, finishReason, shouldReturn }
1107
- : { finishReason, shouldReturn };
1108
- }
1109
- /**
1110
- * Create stream generator for Ollama chat API with tool call support
1111
- */
1112
- async *createOllamaChatStream(response, _tools) {
1113
- const reader = response.body?.getReader();
1114
- if (!reader) {
1115
- throw new Error("No response body");
1116
- }
1117
- const decoder = new TextDecoder();
1118
- let buffer = "";
1119
- try {
1120
- while (true) {
1121
- const { done, value } = await reader.read();
1122
- if (done) {
1123
- break;
1124
- }
1125
- buffer += decoder.decode(value, { stream: true });
1126
- const lines = buffer.split("\n");
1127
- buffer = lines.pop() || "";
1128
- for (const line of lines) {
1129
- if (line.trim() && line.startsWith("data: ")) {
1130
- const dataLine = line.slice(6); // Remove "data: " prefix
1131
- if (dataLine === "[DONE]") {
1132
- return;
1133
- }
1134
- try {
1135
- const data = JSON.parse(dataLine);
1136
- const result = this.processOllamaStreamData(data);
1137
- if (result?.content) {
1138
- yield { content: result.content };
1139
- }
1140
- if (result?.shouldReturn) {
1141
- return;
1142
- }
1143
- }
1144
- catch (error) {
1145
- logger.error("Error parsing Ollama stream response", {
1146
- error,
1147
- });
1148
- }
1149
- }
1150
- }
1151
- }
1152
- }
1153
- finally {
1154
- reader.releaseLock();
1155
- }
1156
- }
1157
- /**
1158
- * Format tool calls for display when tools aren't executed directly
1159
- */
1160
- formatToolCallForDisplay(toolCalls) {
1161
- if (!toolCalls || toolCalls.length === 0) {
1162
- return "";
1163
- }
1164
- const descriptions = toolCalls.map((call) => {
1165
- const functionName = call.function?.name || "unknown_function";
1166
- let args = {};
1167
- if (call.function?.arguments) {
1168
- try {
1169
- args = JSON.parse(call.function.arguments);
1170
- }
1171
- catch (error) {
1172
- // If arguments are malformed, preserve for debugging while marking as invalid
1173
- logger.warn?.("Malformed tool call arguments: " + call.function.arguments);
1174
- args = {
1175
- _malformed: true,
1176
- _originalArguments: call.function.arguments,
1177
- _error: error instanceof Error ? error.message : String(error),
1178
- };
1179
- }
1180
- }
1181
- return `\n[Tool Call: ${functionName}(${JSON.stringify(args)})]`;
1182
- });
1183
- return descriptions.join("");
1184
- }
1185
- /**
1186
- * Convert AI SDK tools to ToolDefinition format
1187
- */
1188
- convertAISDKToolsToToolDefinitions(aiTools) {
1189
- const result = {};
1190
- for (const [name, tool] of Object.entries(aiTools)) {
1191
- if ("description" in tool && tool.description) {
1192
- // AI SDK v6 uses `inputSchema`; legacy tools may still use `parameters`
1193
- const toolSchema = "inputSchema" in tool
1194
- ? tool.inputSchema
1195
- : "parameters" in tool
1196
- ? tool
1197
- .parameters
1198
- : undefined;
1199
- result[name] = {
1200
- description: tool.description,
1201
- parameters: toolSchema,
1202
- execute: async (params) => {
1203
- if ("execute" in tool && tool.execute) {
1204
- const result = await tool.execute(params, {
1205
- toolCallId: `tool_${Date.now()}`,
1206
- messages: [],
1207
- });
1208
- return {
1209
- success: true,
1210
- data: result,
1211
- };
1212
- }
1213
- throw new Error(`Tool ${name} has no execute method`);
1214
- },
1215
- };
1216
- }
1217
- }
1218
- return result;
1219
- }
1220
- /**
1221
- * Execute a single tool and return the result
1222
- */
1223
- async executeSingleTool(toolName, args, _toolCallId) {
1224
- logger.debug(`[OllamaProvider] Executing single tool: ${toolName}`, {
1225
- args,
1226
- });
1227
- try {
1228
- // Use BaseProvider's tool execution mechanism
1229
- const aiTools = await this.getAllTools();
1230
- const tools = this.convertAISDKToolsToToolDefinitions(aiTools);
1231
- if (!tools[toolName]) {
1232
- throw new Error(`Tool not found: ${toolName}`);
1233
- }
1234
- const tool = tools[toolName];
1235
- if (!tool || !tool.execute) {
1236
- throw new Error(`Tool ${toolName} does not have execute method`);
1237
- }
1238
- const toolInput = args || {};
1239
- // Convert Record<string, unknown> to ToolArgs by filtering out non-JsonValue types
1240
- const toolArgs = {};
1241
- for (const [key, value] of Object.entries(toolInput)) {
1242
- // Only include values that are JsonValue compatible
1243
- if (value === null ||
1244
- typeof value === "string" ||
1245
- typeof value === "number" ||
1246
- typeof value === "boolean" ||
1247
- (typeof value === "object" && value !== null)) {
1248
- toolArgs[key] = value;
1249
- }
1250
- }
1251
- const result = await tool.execute(toolArgs);
1252
- logger.debug(`[OllamaProvider] Tool execution result:`, {
1253
- toolName,
1254
- result,
1255
- });
1256
- // Handle ToolResult type
1257
- if (result && typeof result === "object" && "success" in result) {
1258
- if (result.success && result.data !== undefined) {
1259
- if (typeof result.data === "string") {
1260
- return result.data;
1261
- }
1262
- else if (typeof result.data === "object") {
1263
- return JSON.stringify(result.data, null, 2);
1264
- }
1265
- else {
1266
- return String(result.data);
1267
- }
1268
- }
1269
- else if (result.error) {
1270
- const errorMessage = typeof result.error === "string"
1271
- ? result.error
1272
- : result.error.message || "Tool execution failed";
1273
- throw new Error(errorMessage);
1274
- }
1275
- }
1276
- // Fallback for non-ToolResult return types
1277
- if (typeof result === "string") {
1278
- return result;
1279
- }
1280
- else if (typeof result === "object") {
1281
- return JSON.stringify(result, null, 2);
1282
- }
1283
- else {
1284
- return String(result);
1285
- }
1286
- }
1287
- catch (error) {
1288
- logger.error(`[OllamaProvider] Tool execution error:`, {
1289
- toolName,
1290
- error,
1291
- });
1292
- throw error;
1293
- }
1294
- }
1295
- /**
1296
- * Execute tools and format results for Ollama API
1297
- * Similar to Bedrock's executeStreamTools but for Ollama format
1298
- */
1299
- async executeOllamaTools(toolCalls, options) {
1300
- const toolResults = [];
1301
- const toolCallsForStorage = [];
1302
- const toolResultsForStorage = [];
1303
- logger.debug(`[OllamaProvider] Executing ${toolCalls.length} tool calls`);
1304
- for (const call of toolCalls) {
1305
- logger.debug(`[OllamaProvider] Executing tool: ${call.function.name}`);
1306
- // Parse arguments
1307
- let args;
1308
- try {
1309
- args = JSON.parse(call.function.arguments);
1310
- }
1311
- catch (error) {
1312
- logger.error(`[OllamaProvider] Failed to parse tool arguments: ${call.function.arguments}`, { error });
1313
- args = {};
1314
- }
1315
- // Track tool call for storage
1316
- toolCallsForStorage.push({
1317
- type: "tool-call",
1318
- toolCallId: call.id,
1319
- toolName: call.function.name,
1320
- args,
1321
- });
1322
- try {
1323
- // Execute tool using existing tool framework
1324
- const result = await this.executeSingleTool(call.function.name, args, call.id);
1325
- logger.debug(`[OllamaProvider] Tool execution successful: ${call.function.name}`);
1326
- // Track result for storage
1327
- toolResultsForStorage.push({
1328
- type: "tool-result",
1329
- toolCallId: call.id,
1330
- toolName: call.function.name,
1331
- result,
1332
- });
1333
- // Format for Ollama API
1334
- toolResults.push({
1335
- tool_call_id: call.id,
1336
- content: JSON.stringify(result),
1337
- });
1338
- }
1339
- catch (error) {
1340
- logger.error(`[OllamaProvider] Tool execution failed: ${call.function.name}`, { error });
1341
- const errorMessage = error instanceof Error ? error.message : String(error);
1342
- // Track failed result
1343
- toolResultsForStorage.push({
1344
- type: "tool-result",
1345
- toolCallId: call.id,
1346
- toolName: call.function.name,
1347
- result: { error: errorMessage },
1348
- });
1349
- // Format error for Ollama API
1350
- toolResults.push({
1351
- tool_call_id: call.id,
1352
- content: JSON.stringify({ error: errorMessage }),
1353
- });
1354
- }
1355
- }
1356
- // Store tool executions (similar to Bedrock)
1357
- this.handleToolExecutionStorage(toolCallsForStorage, toolResultsForStorage, options, new Date()).catch((error) => {
1358
- logger.warn("[OllamaProvider] Failed to store tool executions", {
1359
- provider: this.providerName,
1360
- error: error instanceof Error ? error.message : String(error),
1361
- });
1362
- });
1363
- return toolResults;
1364
- }
1365
- /**
1366
- * Convert ReadableStream to AsyncIterable for compatibility with StreamResult interface
1367
- */
1368
- convertToAsyncIterable(stream) {
1369
- return {
1370
- async *[Symbol.asyncIterator]() {
1371
- const reader = stream.getReader();
1372
- try {
1373
- while (true) {
1374
- const { done, value } = await reader.read();
1375
- if (done) {
1376
- break;
1377
- }
1378
- yield value;
1379
- }
1380
- }
1381
- finally {
1382
- reader.releaseLock();
1383
- }
1384
- },
1385
- };
1386
- }
1387
- /**
1388
- * Create stream generator for Ollama generate API (non-tool mode)
1389
- */
1390
- async *createOllamaStream(response) {
1391
- const reader = response.body?.getReader();
1392
- if (!reader) {
1393
- throw new Error("No response body");
1394
- }
1395
- const decoder = new TextDecoder();
1396
- let buffer = "";
1397
- try {
1398
- while (true) {
1399
- const { done, value } = await reader.read();
1400
- if (done) {
1401
- break;
1402
- }
1403
- buffer += decoder.decode(value, { stream: true });
1404
- const lines = buffer.split("\n");
1405
- buffer = lines.pop() || "";
1406
- for (const line of lines) {
1407
- if (line.trim()) {
1408
- try {
1409
- const data = JSON.parse(line);
1410
- if (data.response) {
1411
- yield { content: data.response };
1412
- }
1413
- if (data.done) {
1414
- return;
1415
- }
1416
- }
1417
- catch (error) {
1418
- logger.error("Error parsing Ollama stream response", {
1419
- error,
1420
- });
1421
- }
1422
- }
1423
- }
1424
- }
1425
- }
1426
- finally {
1427
- reader.releaseLock();
1428
- }
1429
- }
1430
- async *createOpenAIStream(response) {
1431
- const reader = response.body?.getReader();
1432
- if (!reader) {
1433
- throw new Error("No response body");
1434
- }
1435
- const decoder = new TextDecoder();
1436
- let buffer = "";
1437
- try {
1438
- while (true) {
1439
- const { done, value } = await reader.read();
1440
- if (done) {
1441
- break;
1442
- }
1443
- buffer += decoder.decode(value, { stream: true });
1444
- const lines = buffer.split("\n");
1445
- buffer = lines.pop() || "";
1446
- for (const line of lines) {
1447
- const trimmedLine = line.trim();
1448
- if (!trimmedLine || trimmedLine === "data: [DONE]") {
1449
- continue;
1450
- }
1451
- if (trimmedLine.startsWith("data: ")) {
1452
- try {
1453
- const jsonStr = trimmedLine.slice(6); // Remove "data: " prefix
1454
- const data = JSON.parse(jsonStr);
1455
- const content = data.choices?.[0]?.delta?.content;
1456
- if (content) {
1457
- yield { content };
1458
- }
1459
- if (data.choices?.[0]?.finish_reason) {
1460
- return;
1461
- }
1462
- }
1463
- catch (error) {
1464
- logger.error("Error parsing OpenAI stream response", {
1465
- error,
1466
- line: trimmedLine,
1467
- });
1468
- }
1469
- }
1470
- }
1471
- }
1472
- }
1473
- finally {
1474
- reader.releaseLock();
1475
- }
1476
- }
1477
- formatProviderError(error) {
1478
- if (error instanceof TimeoutError) {
1479
- return new TimeoutError(`Ollama request timed out. The model might be loading or the request is too complex.`, this.timeout);
1480
- }
1481
- if (error.message?.includes("ECONNREFUSED") ||
1482
- error.message?.includes("fetch failed")) {
1483
- return new NetworkError(`āŒ Ollama Service Not Running\n\nCannot connect to Ollama at ${this.baseUrl}\n\nšŸ”§ Steps to Fix:\n1. Install Ollama: https://ollama.ai/\n2. Start Ollama service: 'ollama serve'\n3. Verify it's running: 'curl ${this.baseUrl}/api/version'\n4. Try again`, this.providerName);
1484
- }
1485
- if (error.message?.includes("model") &&
1486
- error.message?.includes("not found")) {
1487
- return new InvalidModelError(`āŒ Ollama Model Not Found\n\nModel '${this.modelName}' is not available locally.\n\nšŸ”§ Install Model:\n1. Run: ollama pull ${this.modelName}\n2. Or try a different model:\n - ollama pull ${FALLBACK_OLLAMA_MODEL}\n - ollama pull mistral:latest\n - ollama pull codellama:latest\n\nšŸ”§ List Available Models:\nollama list`, this.providerName);
1488
- }
1489
- if (error.message?.includes("404")) {
1490
- return new NetworkError(`āŒ Ollama API Endpoint Not Found\n\nThe API endpoint might have changed or Ollama version is incompatible.\n\nšŸ”§ Check:\n1. Ollama version: 'ollama --version'\n2. Update Ollama to latest version\n3. Verify API is available: 'curl ${this.baseUrl}/api/version'`, this.providerName);
1491
- }
1492
- return new ProviderError(`āŒ Ollama Provider Error\n\n${error.message || "Unknown error occurred"}\n\nšŸ”§ Troubleshooting:\n1. Check if Ollama service is running\n2. Verify model is installed: 'ollama list'\n3. Check network connectivity to ${this.baseUrl}\n4. Review Ollama logs for details`, this.providerName);
1493
- }
1494
- /**
1495
- * Check if Ollama service is healthy and accessible
1496
- */
1497
- async checkOllamaHealth() {
1498
- try {
1499
- // Use traditional AbortController for better compatibility
1500
- const controller = new AbortController();
1501
- const timeoutId = setTimeout(() => controller.abort(), 5000);
1502
- const response = await proxyFetch(`${this.baseUrl}/api/version`, {
1503
- method: "GET",
1504
- signal: controller.signal,
1505
- });
1506
- clearTimeout(timeoutId);
1507
- if (!response.ok) {
1508
- throw new Error(`Ollama health check failed: ${response.status}`);
1509
- }
1510
- }
1511
- catch (error) {
1512
- if (error instanceof Error && error.message.includes("ECONNREFUSED")) {
1513
- throw new Error(`āŒ Ollama Service Not Running\n\nCannot connect to Ollama service.\n\nšŸ”§ Start Ollama:\n1. Run: ollama serve\n2. Or start Ollama app\n3. Verify: curl ${this.baseUrl}/api/version`, { cause: error });
1514
- }
1515
- throw error;
1516
- }
1517
- }
1518
- /**
1519
- * Get available models from Ollama
1520
- */
1521
- async getAvailableModels() {
1522
- try {
1523
- const response = await proxyFetch(`${this.baseUrl}/api/tags`);
1524
- if (!response.ok) {
1525
- throw new Error(`Failed to fetch models: ${response.status}`);
1526
- }
1527
- const data = await response.json();
1528
- return data.models?.map((model) => model.name) || [];
1529
- }
1530
- catch (error) {
1531
- logger.warn("Failed to fetch Ollama models:", error);
1532
- return [];
1533
- }
1534
- }
1535
- /**
1536
- * Check if a specific model is available
1537
- */
1538
- async isModelAvailable(modelName) {
1539
- const models = await this.getAvailableModels();
1540
- return models.includes(modelName);
1541
- }
1542
- /**
1543
- * Get recommendations for tool-calling capable Ollama models
1544
- * Provides guidance for users who want to use function calling locally
1545
- */
1546
- static getToolCallingRecommendations() {
1547
- return {
1548
- recommended: [
1549
- "llama3.1:8b-instruct",
1550
- "mistral:7b-instruct-v0.3",
1551
- "hermes3:8b-llama3.1",
1552
- "codellama:34b-instruct",
1553
- "firefunction-v2:70b",
1554
- ],
1555
- performance: {
1556
- "llama3.1:8b-instruct": { speed: 3, quality: 3, size: "4.6GB" },
1557
- "mistral:7b-instruct-v0.3": { speed: 3, quality: 2, size: "4.1GB" },
1558
- "hermes3:8b-llama3.1": { speed: 3, quality: 3, size: "4.6GB" },
1559
- "codellama:34b-instruct": { speed: 1, quality: 3, size: "19GB" },
1560
- "firefunction-v2:70b": { speed: 1, quality: 3, size: "40GB" },
1561
- },
1562
- notes: {
1563
- "llama3.1:8b-instruct": "Best balance of speed, quality, and tool calling capability",
1564
- "mistral:7b-instruct-v0.3": "Lightweight with reliable function calling",
1565
- "hermes3:8b-llama3.1": "Specialized for tool execution and reasoning",
1566
- "codellama:34b-instruct": "Excellent for code-related tool calling, requires more resources",
1567
- "firefunction-v2:70b": "Optimized specifically for function calling, requires high-end hardware",
1568
- },
1569
- installation: {
1570
- "llama3.1:8b-instruct": "ollama pull llama3.1:8b-instruct",
1571
- "mistral:7b-instruct-v0.3": "ollama pull mistral:7b-instruct-v0.3",
1572
- "hermes3:8b-llama3.1": "ollama pull hermes3:8b-llama3.1",
1573
- "codellama:34b-instruct": "ollama pull codellama:34b-instruct",
1574
- "firefunction-v2:70b": "ollama pull firefunction-v2:70b",
1575
- },
1576
- };
1577
- }
1578
- }
1579
- export default OllamaProvider;