@juspay/neurolink 9.32.0 → 9.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/CHANGELOG.md +6 -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/server/routes/claudeProxyRoutes.js +45 -9
  11. package/dist/mcp/elicitationProtocol.js +1 -1
  12. package/dist/mcp/servers/agent/directToolsServer.js +0 -1
  13. package/dist/providers/azureOpenai.js +1 -1
  14. package/dist/providers/huggingFace.js +0 -1
  15. package/dist/providers/openaiCompatible.js +0 -1
  16. package/dist/sdk/toolRegistration.js +0 -1
  17. package/dist/server/openapi/generator.js +1 -1
  18. package/dist/server/routes/claudeProxyRoutes.js +45 -9
  19. package/dist/types/configTypes.js +0 -5
  20. package/dist/types/modelTypes.js +0 -1
  21. package/dist/types/tools.js +0 -1
  22. package/dist/types/typeAliases.js +0 -1
  23. package/dist/types/utilities.js +1 -1
  24. package/dist/types/workflowTypes.js +0 -1
  25. package/dist/utils/providerRetry.js +0 -1
  26. package/dist/utils/providerUtils.js +0 -1
  27. package/package.json +2 -2
  28. package/dist/client/adapters/providerImageAdapter.js +0 -588
  29. package/dist/client/adapters/tts/googleTTSHandler.js +0 -344
  30. package/dist/client/adapters/video/directorPipeline.js +0 -516
  31. package/dist/client/adapters/video/ffmpegAdapter.js +0 -206
  32. package/dist/client/adapters/video/frameExtractor.js +0 -143
  33. package/dist/client/adapters/video/vertexVideoHandler.js +0 -763
  34. package/dist/client/adapters/video/videoAnalyzer.js +0 -238
  35. package/dist/client/adapters/video/videoMerger.js +0 -171
  36. package/dist/client/agent/directTools.js +0 -840
  37. package/dist/client/auth/AuthProviderFactory.js +0 -111
  38. package/dist/client/auth/AuthProviderRegistry.js +0 -190
  39. package/dist/client/auth/RequestContext.js +0 -78
  40. package/dist/client/auth/accountPool.js +0 -178
  41. package/dist/client/auth/anthropicOAuth.js +0 -974
  42. package/dist/client/auth/authContext.js +0 -314
  43. package/dist/client/auth/errors.js +0 -39
  44. package/dist/client/auth/index.js +0 -61
  45. package/dist/client/auth/middleware/AuthMiddleware.js +0 -519
  46. package/dist/client/auth/middleware/rateLimitByUser.js +0 -554
  47. package/dist/client/auth/providers/BaseAuthProvider.js +0 -723
  48. package/dist/client/auth/providers/CognitoProvider.js +0 -304
  49. package/dist/client/auth/providers/KeycloakProvider.js +0 -393
  50. package/dist/client/auth/providers/auth0.js +0 -274
  51. package/dist/client/auth/providers/betterAuth.js +0 -182
  52. package/dist/client/auth/providers/clerk.js +0 -317
  53. package/dist/client/auth/providers/custom.js +0 -112
  54. package/dist/client/auth/providers/firebase.js +0 -226
  55. package/dist/client/auth/providers/jwt.js +0 -212
  56. package/dist/client/auth/providers/oauth2.js +0 -303
  57. package/dist/client/auth/providers/supabase.js +0 -259
  58. package/dist/client/auth/providers/workos.js +0 -284
  59. package/dist/client/auth/serverBridge.js +0 -25
  60. package/dist/client/auth/sessionManager.js +0 -437
  61. package/dist/client/auth/tokenStore.js +0 -799
  62. package/dist/client/client/aiSdkAdapter.js +0 -487
  63. package/dist/client/client/auth.js +0 -473
  64. package/dist/client/client/errors.js +0 -552
  65. package/dist/client/client/httpClient.js +0 -837
  66. package/dist/client/client/index.js +0 -172
  67. package/dist/client/client/interceptors.js +0 -601
  68. package/dist/client/client/sseClient.js +0 -545
  69. package/dist/client/client/streamingClient.js +0 -917
  70. package/dist/client/client/wsClient.js +0 -369
  71. package/dist/client/config/configManager.js +0 -303
  72. package/dist/client/config/conversationMemory.js +0 -86
  73. package/dist/client/config/taskClassificationConfig.js +0 -148
  74. package/dist/client/constants/contextWindows.js +0 -295
  75. package/dist/client/constants/enums.js +0 -853
  76. package/dist/client/constants/index.js +0 -207
  77. package/dist/client/constants/performance.js +0 -389
  78. package/dist/client/constants/retry.js +0 -266
  79. package/dist/client/constants/timeouts.js +0 -182
  80. package/dist/client/constants/tokens.js +0 -380
  81. package/dist/client/constants/videoErrors.js +0 -46
  82. package/dist/client/context/budgetChecker.js +0 -98
  83. package/dist/client/context/contextCompactor.js +0 -205
  84. package/dist/client/context/emergencyTruncation.js +0 -88
  85. package/dist/client/context/errorDetection.js +0 -171
  86. package/dist/client/context/errors.js +0 -21
  87. package/dist/client/context/fileTokenBudget.js +0 -127
  88. package/dist/client/context/prompts/summarizationPrompt.js +0 -117
  89. package/dist/client/context/stages/fileReadDeduplicator.js +0 -66
  90. package/dist/client/context/stages/slidingWindowTruncator.js +0 -190
  91. package/dist/client/context/stages/structuredSummarizer.js +0 -99
  92. package/dist/client/context/stages/toolOutputPruner.js +0 -52
  93. package/dist/client/context/summarizationEngine.js +0 -136
  94. package/dist/client/context/toolOutputLimits.js +0 -78
  95. package/dist/client/context/toolPairRepair.js +0 -66
  96. package/dist/client/core/analytics.js +0 -88
  97. package/dist/client/core/baseProvider.js +0 -1385
  98. package/dist/client/core/constants.js +0 -140
  99. package/dist/client/core/conversationMemoryFactory.js +0 -141
  100. package/dist/client/core/conversationMemoryInitializer.js +0 -128
  101. package/dist/client/core/conversationMemoryManager.js +0 -344
  102. package/dist/client/core/dynamicModels.js +0 -358
  103. package/dist/client/core/evaluation.js +0 -309
  104. package/dist/client/core/evaluationProviders.js +0 -248
  105. package/dist/client/core/factory.js +0 -412
  106. package/dist/client/core/infrastructure/baseError.js +0 -22
  107. package/dist/client/core/infrastructure/baseFactory.js +0 -54
  108. package/dist/client/core/infrastructure/baseRegistry.js +0 -53
  109. package/dist/client/core/infrastructure/index.js +0 -5
  110. package/dist/client/core/infrastructure/retry.js +0 -20
  111. package/dist/client/core/infrastructure/typedEventEmitter.js +0 -23
  112. package/dist/client/core/modelConfiguration.js +0 -851
  113. package/dist/client/core/modules/GenerationHandler.js +0 -588
  114. package/dist/client/core/modules/MessageBuilder.js +0 -273
  115. package/dist/client/core/modules/StreamHandler.js +0 -185
  116. package/dist/client/core/modules/TelemetryHandler.js +0 -203
  117. package/dist/client/core/modules/ToolsManager.js +0 -499
  118. package/dist/client/core/modules/Utilities.js +0 -331
  119. package/dist/client/core/redisConversationMemoryManager.js +0 -1435
  120. package/dist/client/core/streamAnalytics.js +0 -131
  121. package/dist/client/evaluation/contextBuilder.js +0 -134
  122. package/dist/client/evaluation/index.js +0 -61
  123. package/dist/client/evaluation/prompts.js +0 -73
  124. package/dist/client/evaluation/ragasEvaluator.js +0 -110
  125. package/dist/client/evaluation/retryManager.js +0 -78
  126. package/dist/client/evaluation/scoring.js +0 -61
  127. package/dist/client/factories/providerFactory.js +0 -166
  128. package/dist/client/factories/providerRegistry.js +0 -166
  129. package/dist/client/features/ppt/constants.js +0 -896
  130. package/dist/client/features/ppt/contentPlanner.js +0 -529
  131. package/dist/client/features/ppt/presentationOrchestrator.js +0 -236
  132. package/dist/client/features/ppt/slideGenerator.js +0 -532
  133. package/dist/client/features/ppt/slideRenderers.js +0 -2383
  134. package/dist/client/features/ppt/slideTypeInference.js +0 -405
  135. package/dist/client/features/ppt/types.js +0 -13
  136. package/dist/client/features/ppt/utils.js +0 -443
  137. package/dist/client/files/fileReferenceRegistry.js +0 -1543
  138. package/dist/client/files/fileTools.js +0 -450
  139. package/dist/client/files/streamingReader.js +0 -321
  140. package/dist/client/files/types.js +0 -23
  141. package/dist/client/hitl/hitlErrors.js +0 -54
  142. package/dist/client/hitl/hitlManager.js +0 -460
  143. package/dist/client/mcp/agentExposure.js +0 -356
  144. package/dist/client/mcp/auth/index.js +0 -11
  145. package/dist/client/mcp/auth/oauthClientProvider.js +0 -325
  146. package/dist/client/mcp/auth/tokenStorage.js +0 -134
  147. package/dist/client/mcp/batching/index.js +0 -10
  148. package/dist/client/mcp/batching/requestBatcher.js +0 -441
  149. package/dist/client/mcp/caching/index.js +0 -10
  150. package/dist/client/mcp/caching/toolCache.js +0 -433
  151. package/dist/client/mcp/elicitation/elicitationManager.js +0 -376
  152. package/dist/client/mcp/elicitation/index.js +0 -11
  153. package/dist/client/mcp/elicitation/types.js +0 -10
  154. package/dist/client/mcp/elicitationProtocol.js +0 -375
  155. package/dist/client/mcp/enhancedToolDiscovery.js +0 -481
  156. package/dist/client/mcp/externalServerManager.js +0 -1478
  157. package/dist/client/mcp/factory.js +0 -161
  158. package/dist/client/mcp/flexibleToolValidator.js +0 -161
  159. package/dist/client/mcp/httpRateLimiter.js +0 -391
  160. package/dist/client/mcp/httpRetryHandler.js +0 -178
  161. package/dist/client/mcp/index.js +0 -74
  162. package/dist/client/mcp/mcpCircuitBreaker.js +0 -427
  163. package/dist/client/mcp/mcpClientFactory.js +0 -708
  164. package/dist/client/mcp/mcpRegistryClient.js +0 -488
  165. package/dist/client/mcp/mcpServerBase.js +0 -373
  166. package/dist/client/mcp/multiServerManager.js +0 -579
  167. package/dist/client/mcp/registry.js +0 -158
  168. package/dist/client/mcp/routing/index.js +0 -10
  169. package/dist/client/mcp/routing/toolRouter.js +0 -416
  170. package/dist/client/mcp/serverCapabilities.js +0 -502
  171. package/dist/client/mcp/servers/agent/directToolsServer.js +0 -150
  172. package/dist/client/mcp/toolAnnotations.js +0 -239
  173. package/dist/client/mcp/toolConverter.js +0 -258
  174. package/dist/client/mcp/toolDiscoveryService.js +0 -798
  175. package/dist/client/mcp/toolIntegration.js +0 -334
  176. package/dist/client/mcp/toolRegistry.js +0 -729
  177. package/dist/client/memory/hippocampusInitializer.js +0 -19
  178. package/dist/client/memory/memoryRetrievalTools.js +0 -166
  179. package/dist/client/middleware/builtin/analytics.js +0 -132
  180. package/dist/client/middleware/builtin/autoEvaluation.js +0 -203
  181. package/dist/client/middleware/builtin/guardrails.js +0 -109
  182. package/dist/client/middleware/builtin/lifecycle.js +0 -168
  183. package/dist/client/middleware/factory.js +0 -327
  184. package/dist/client/middleware/registry.js +0 -295
  185. package/dist/client/middleware/utils/guardrailsUtils.js +0 -396
  186. package/dist/client/models/anthropicModels.js +0 -527
  187. package/dist/client/neurolink.js +0 -8233
  188. package/dist/client/observability/exporterRegistry.js +0 -413
  189. package/dist/client/observability/exporters/arizeExporter.js +0 -138
  190. package/dist/client/observability/exporters/baseExporter.js +0 -190
  191. package/dist/client/observability/exporters/braintrustExporter.js +0 -154
  192. package/dist/client/observability/exporters/datadogExporter.js +0 -196
  193. package/dist/client/observability/exporters/laminarExporter.js +0 -302
  194. package/dist/client/observability/exporters/langfuseExporter.js +0 -209
  195. package/dist/client/observability/exporters/langsmithExporter.js +0 -143
  196. package/dist/client/observability/exporters/otelExporter.js +0 -164
  197. package/dist/client/observability/exporters/posthogExporter.js +0 -287
  198. package/dist/client/observability/exporters/sentryExporter.js +0 -165
  199. package/dist/client/observability/index.js +0 -31
  200. package/dist/client/observability/metricsAggregator.js +0 -556
  201. package/dist/client/observability/otelBridge.js +0 -131
  202. package/dist/client/observability/retryPolicy.js +0 -383
  203. package/dist/client/observability/sampling/samplers.js +0 -216
  204. package/dist/client/observability/spanProcessor.js +0 -303
  205. package/dist/client/observability/tokenTracker.js +0 -413
  206. package/dist/client/observability/types/exporterTypes.js +0 -5
  207. package/dist/client/observability/types/index.js +0 -4
  208. package/dist/client/observability/types/spanTypes.js +0 -92
  209. package/dist/client/observability/utils/safeMetadata.js +0 -25
  210. package/dist/client/observability/utils/spanSerializer.js +0 -292
  211. package/dist/client/processors/archive/ArchiveProcessor.js +0 -1308
  212. package/dist/client/processors/base/BaseFileProcessor.js +0 -614
  213. package/dist/client/processors/base/types.js +0 -82
  214. package/dist/client/processors/config/fileTypes.js +0 -520
  215. package/dist/client/processors/config/index.js +0 -92
  216. package/dist/client/processors/config/languageMap.js +0 -410
  217. package/dist/client/processors/config/mimeTypes.js +0 -363
  218. package/dist/client/processors/config/sizeLimits.js +0 -258
  219. package/dist/client/processors/document/ExcelProcessor.js +0 -590
  220. package/dist/client/processors/document/OpenDocumentProcessor.js +0 -212
  221. package/dist/client/processors/document/PptxProcessor.js +0 -157
  222. package/dist/client/processors/document/RtfProcessor.js +0 -361
  223. package/dist/client/processors/document/WordProcessor.js +0 -353
  224. package/dist/client/processors/errors/FileErrorCode.js +0 -255
  225. package/dist/client/processors/errors/errorHelpers.js +0 -386
  226. package/dist/client/processors/errors/errorSerializer.js +0 -507
  227. package/dist/client/processors/errors/index.js +0 -49
  228. package/dist/client/processors/markup/SvgProcessor.js +0 -240
  229. package/dist/client/processors/media/AudioProcessor.js +0 -707
  230. package/dist/client/processors/media/VideoProcessor.js +0 -1045
  231. package/dist/client/providers/amazonBedrock.js +0 -1512
  232. package/dist/client/providers/amazonSagemaker.js +0 -162
  233. package/dist/client/providers/anthropic.js +0 -831
  234. package/dist/client/providers/azureOpenai.js +0 -143
  235. package/dist/client/providers/googleAiStudio.js +0 -1200
  236. package/dist/client/providers/googleNativeGemini3.js +0 -543
  237. package/dist/client/providers/googleVertex.js +0 -2936
  238. package/dist/client/providers/huggingFace.js +0 -315
  239. package/dist/client/providers/litellm.js +0 -488
  240. package/dist/client/providers/mistral.js +0 -157
  241. package/dist/client/providers/ollama.js +0 -1579
  242. package/dist/client/providers/openAI.js +0 -627
  243. package/dist/client/providers/openRouter.js +0 -543
  244. package/dist/client/providers/openaiCompatible.js +0 -290
  245. package/dist/client/providers/providerTypeUtils.js +0 -46
  246. package/dist/client/providers/sagemaker/adaptive-semaphore.js +0 -215
  247. package/dist/client/providers/sagemaker/client.js +0 -472
  248. package/dist/client/providers/sagemaker/config.js +0 -317
  249. package/dist/client/providers/sagemaker/detection.js +0 -606
  250. package/dist/client/providers/sagemaker/error-constants.js +0 -227
  251. package/dist/client/providers/sagemaker/errors.js +0 -299
  252. package/dist/client/providers/sagemaker/language-model.js +0 -775
  253. package/dist/client/providers/sagemaker/parsers.js +0 -634
  254. package/dist/client/providers/sagemaker/streaming.js +0 -331
  255. package/dist/client/providers/sagemaker/structured-parser.js +0 -625
  256. package/dist/client/proxy/accountQuota.js +0 -162
  257. package/dist/client/proxy/claudeFormat.js +0 -595
  258. package/dist/client/proxy/modelRouter.js +0 -29
  259. package/dist/client/proxy/oauthFetch.js +0 -367
  260. package/dist/client/proxy/proxyFetch.js +0 -586
  261. package/dist/client/proxy/requestLogger.js +0 -207
  262. package/dist/client/proxy/tokenRefresh.js +0 -124
  263. package/dist/client/proxy/usageStats.js +0 -74
  264. package/dist/client/proxy/utils/noProxyUtils.js +0 -149
  265. package/dist/client/rag/ChunkerFactory.js +0 -320
  266. package/dist/client/rag/ChunkerRegistry.js +0 -421
  267. package/dist/client/rag/chunkers/BaseChunker.js +0 -143
  268. package/dist/client/rag/chunkers/CharacterChunker.js +0 -28
  269. package/dist/client/rag/chunkers/HTMLChunker.js +0 -38
  270. package/dist/client/rag/chunkers/JSONChunker.js +0 -68
  271. package/dist/client/rag/chunkers/LaTeXChunker.js +0 -63
  272. package/dist/client/rag/chunkers/MarkdownChunker.js +0 -306
  273. package/dist/client/rag/chunkers/RecursiveChunker.js +0 -139
  274. package/dist/client/rag/chunkers/SemanticMarkdownChunker.js +0 -138
  275. package/dist/client/rag/chunkers/SentenceChunker.js +0 -66
  276. package/dist/client/rag/chunkers/TokenChunker.js +0 -61
  277. package/dist/client/rag/chunkers/index.js +0 -15
  278. package/dist/client/rag/chunking/characterChunker.js +0 -142
  279. package/dist/client/rag/chunking/chunkerRegistry.js +0 -194
  280. package/dist/client/rag/chunking/htmlChunker.js +0 -247
  281. package/dist/client/rag/chunking/index.js +0 -17
  282. package/dist/client/rag/chunking/jsonChunker.js +0 -281
  283. package/dist/client/rag/chunking/latexChunker.js +0 -251
  284. package/dist/client/rag/chunking/markdownChunker.js +0 -373
  285. package/dist/client/rag/chunking/recursiveChunker.js +0 -148
  286. package/dist/client/rag/chunking/semanticChunker.js +0 -306
  287. package/dist/client/rag/chunking/sentenceChunker.js +0 -230
  288. package/dist/client/rag/chunking/tokenChunker.js +0 -183
  289. package/dist/client/rag/document/MDocument.js +0 -392
  290. package/dist/client/rag/document/index.js +0 -5
  291. package/dist/client/rag/document/loaders.js +0 -500
  292. package/dist/client/rag/errors/RAGError.js +0 -274
  293. package/dist/client/rag/errors/index.js +0 -6
  294. package/dist/client/rag/graphRag/graphRAG.js +0 -401
  295. package/dist/client/rag/graphRag/index.js +0 -4
  296. package/dist/client/rag/index.js +0 -141
  297. package/dist/client/rag/metadata/MetadataExtractorFactory.js +0 -418
  298. package/dist/client/rag/metadata/MetadataExtractorRegistry.js +0 -362
  299. package/dist/client/rag/metadata/index.js +0 -9
  300. package/dist/client/rag/metadata/metadataExtractor.js +0 -280
  301. package/dist/client/rag/pipeline/RAGPipeline.js +0 -436
  302. package/dist/client/rag/pipeline/contextAssembly.js +0 -341
  303. package/dist/client/rag/pipeline/index.js +0 -5
  304. package/dist/client/rag/ragIntegration.js +0 -321
  305. package/dist/client/rag/reranker/RerankerFactory.js +0 -430
  306. package/dist/client/rag/reranker/RerankerRegistry.js +0 -402
  307. package/dist/client/rag/reranker/index.js +0 -9
  308. package/dist/client/rag/reranker/reranker.js +0 -277
  309. package/dist/client/rag/resilience/CircuitBreaker.js +0 -431
  310. package/dist/client/rag/resilience/RetryHandler.js +0 -304
  311. package/dist/client/rag/resilience/index.js +0 -7
  312. package/dist/client/rag/retrieval/hybridSearch.js +0 -335
  313. package/dist/client/rag/retrieval/index.js +0 -5
  314. package/dist/client/rag/retrieval/vectorQueryTool.js +0 -307
  315. package/dist/client/rag/types.js +0 -8
  316. package/dist/client/sdk/toolRegistration.js +0 -377
  317. package/dist/client/server/abstract/baseServerAdapter.js +0 -575
  318. package/dist/client/server/adapters/expressAdapter.js +0 -486
  319. package/dist/client/server/adapters/fastifyAdapter.js +0 -472
  320. package/dist/client/server/adapters/honoAdapter.js +0 -632
  321. package/dist/client/server/adapters/koaAdapter.js +0 -510
  322. package/dist/client/server/errors.js +0 -486
  323. package/dist/client/server/factory/serverAdapterFactory.js +0 -160
  324. package/dist/client/server/index.js +0 -108
  325. package/dist/client/server/middleware/abortSignal.js +0 -111
  326. package/dist/client/server/middleware/auth.js +0 -388
  327. package/dist/client/server/middleware/cache.js +0 -359
  328. package/dist/client/server/middleware/common.js +0 -281
  329. package/dist/client/server/middleware/deprecation.js +0 -190
  330. package/dist/client/server/middleware/mcpBodyAttachment.js +0 -63
  331. package/dist/client/server/middleware/rateLimit.js +0 -227
  332. package/dist/client/server/middleware/validation.js +0 -388
  333. package/dist/client/server/openapi/generator.js +0 -398
  334. package/dist/client/server/openapi/index.js +0 -36
  335. package/dist/client/server/openapi/schemas.js +0 -695
  336. package/dist/client/server/openapi/templates.js +0 -374
  337. package/dist/client/server/routes/agentRoutes.js +0 -189
  338. package/dist/client/server/routes/claudeProxyRoutes.js +0 -1600
  339. package/dist/client/server/routes/healthRoutes.js +0 -187
  340. package/dist/client/server/routes/index.js +0 -57
  341. package/dist/client/server/routes/mcpRoutes.js +0 -342
  342. package/dist/client/server/routes/memoryRoutes.js +0 -350
  343. package/dist/client/server/routes/openApiRoutes.js +0 -126
  344. package/dist/client/server/routes/toolRoutes.js +0 -199
  345. package/dist/client/server/streaming/dataStream.js +0 -486
  346. package/dist/client/server/streaming/index.js +0 -11
  347. package/dist/client/server/types.js +0 -67
  348. package/dist/client/server/utils/redaction.js +0 -334
  349. package/dist/client/server/utils/validation.js +0 -243
  350. package/dist/client/server/websocket/WebSocketHandler.js +0 -383
  351. package/dist/client/server/websocket/index.js +0 -4
  352. package/dist/client/services/server/ai/observability/instrumentation.js +0 -808
  353. package/dist/client/telemetry/attributes.js +0 -100
  354. package/dist/client/telemetry/index.js +0 -26
  355. package/dist/client/telemetry/telemetryService.js +0 -308
  356. package/dist/client/telemetry/tracers.js +0 -17
  357. package/dist/client/telemetry/withSpan.js +0 -34
  358. package/dist/client/types/actionTypes.js +0 -6
  359. package/dist/client/types/analytics.js +0 -5
  360. package/dist/client/types/authTypes.js +0 -9
  361. package/dist/client/types/circuitBreakerErrors.js +0 -34
  362. package/dist/client/types/cli.js +0 -21
  363. package/dist/client/types/clientTypes.js +0 -10
  364. package/dist/client/types/common.js +0 -51
  365. package/dist/client/types/configTypes.js +0 -49
  366. package/dist/client/types/content.js +0 -19
  367. package/dist/client/types/contextTypes.js +0 -400
  368. package/dist/client/types/conversation.js +0 -47
  369. package/dist/client/types/conversationMemoryInterface.js +0 -6
  370. package/dist/client/types/domainTypes.js +0 -5
  371. package/dist/client/types/errors.js +0 -167
  372. package/dist/client/types/evaluation.js +0 -5
  373. package/dist/client/types/evaluationProviders.js +0 -5
  374. package/dist/client/types/evaluationTypes.js +0 -1
  375. package/dist/client/types/externalMcp.js +0 -6
  376. package/dist/client/types/fileReferenceTypes.js +0 -8
  377. package/dist/client/types/fileTypes.js +0 -4
  378. package/dist/client/types/generateTypes.js +0 -1
  379. package/dist/client/types/guardrails.js +0 -1
  380. package/dist/client/types/hitlTypes.js +0 -8
  381. package/dist/client/types/index.js +0 -57
  382. package/dist/client/types/mcpTypes.js +0 -5
  383. package/dist/client/types/middlewareTypes.js +0 -1
  384. package/dist/client/types/modelTypes.js +0 -30
  385. package/dist/client/types/multimodal.js +0 -135
  386. package/dist/client/types/observability.js +0 -6
  387. package/dist/client/types/pptTypes.js +0 -82
  388. package/dist/client/types/providers.js +0 -111
  389. package/dist/client/types/proxyTypes.js +0 -16
  390. package/dist/client/types/ragTypes.js +0 -7
  391. package/dist/client/types/sdkTypes.js +0 -8
  392. package/dist/client/types/serviceTypes.js +0 -5
  393. package/dist/client/types/streamTypes.js +0 -1
  394. package/dist/client/types/subscriptionTypes.js +0 -9
  395. package/dist/client/types/taskClassificationTypes.js +0 -5
  396. package/dist/client/types/tools.js +0 -24
  397. package/dist/client/types/ttsTypes.js +0 -57
  398. package/dist/client/types/typeAliases.js +0 -48
  399. package/dist/client/types/utilities.js +0 -4
  400. package/dist/client/types/workflowTypes.js +0 -30
  401. package/dist/client/utils/async/withTimeout.js +0 -98
  402. package/dist/client/utils/asyncMutex.js +0 -60
  403. package/dist/client/utils/conversationMemory.js +0 -431
  404. package/dist/client/utils/csvProcessor.js +0 -846
  405. package/dist/client/utils/errorHandling.js +0 -936
  406. package/dist/client/utils/evaluationUtils.js +0 -131
  407. package/dist/client/utils/factoryProcessing.js +0 -589
  408. package/dist/client/utils/fileDetector.js +0 -2161
  409. package/dist/client/utils/imageCache.js +0 -376
  410. package/dist/client/utils/imageProcessor.js +0 -704
  411. package/dist/client/utils/logger.js +0 -491
  412. package/dist/client/utils/mcpDefaults.js +0 -134
  413. package/dist/client/utils/messageBuilder.js +0 -1653
  414. package/dist/client/utils/modelAliasResolver.js +0 -54
  415. package/dist/client/utils/modelDetection.js +0 -80
  416. package/dist/client/utils/modelRouter.js +0 -292
  417. package/dist/client/utils/multimodalOptionsBuilder.js +0 -65
  418. package/dist/client/utils/observabilityHelpers.js +0 -47
  419. package/dist/client/utils/parameterValidation.js +0 -966
  420. package/dist/client/utils/pdfProcessor.js +0 -410
  421. package/dist/client/utils/performance.js +0 -222
  422. package/dist/client/utils/pricing.js +0 -340
  423. package/dist/client/utils/promptRedaction.js +0 -62
  424. package/dist/client/utils/providerConfig.js +0 -1009
  425. package/dist/client/utils/providerHealth.js +0 -1237
  426. package/dist/client/utils/providerRetry.js +0 -112
  427. package/dist/client/utils/providerUtils.js +0 -434
  428. package/dist/client/utils/rateLimiter.js +0 -200
  429. package/dist/client/utils/redis.js +0 -368
  430. package/dist/client/utils/retryHandler.js +0 -269
  431. package/dist/client/utils/retryability.js +0 -22
  432. package/dist/client/utils/sanitizers/svg.js +0 -481
  433. package/dist/client/utils/schemaConversion.js +0 -255
  434. package/dist/client/utils/taskClassificationUtils.js +0 -149
  435. package/dist/client/utils/taskClassifier.js +0 -94
  436. package/dist/client/utils/thinkingConfig.js +0 -104
  437. package/dist/client/utils/timeout.js +0 -359
  438. package/dist/client/utils/tokenEstimation.js +0 -142
  439. package/dist/client/utils/tokenLimits.js +0 -125
  440. package/dist/client/utils/tokenUtils.js +0 -239
  441. package/dist/client/utils/toolUtils.js +0 -75
  442. package/dist/client/utils/transformationUtils.js +0 -554
  443. package/dist/client/utils/ttsProcessor.js +0 -286
  444. package/dist/client/utils/typeUtils.js +0 -97
  445. package/dist/client/utils/videoAnalysisProcessor.js +0 -67
  446. package/dist/client/workflow/config.js +0 -398
  447. package/dist/client/workflow/core/ensembleExecutor.js +0 -407
  448. package/dist/client/workflow/core/judgeScorer.js +0 -544
  449. package/dist/client/workflow/core/responseConditioner.js +0 -225
  450. package/dist/client/workflow/core/types/conditionerTypes.js +0 -7
  451. package/dist/client/workflow/core/types/ensembleTypes.js +0 -7
  452. package/dist/client/workflow/core/types/index.js +0 -7
  453. package/dist/client/workflow/core/types/judgeTypes.js +0 -7
  454. package/dist/client/workflow/core/types/layerTypes.js +0 -7
  455. package/dist/client/workflow/core/types/registryTypes.js +0 -7
  456. package/dist/client/workflow/core/workflowRegistry.js +0 -304
  457. package/dist/client/workflow/core/workflowRunner.js +0 -586
  458. package/dist/client/workflow/index.js +0 -50
  459. package/dist/client/workflow/types.js +0 -9
  460. package/dist/client/workflow/utils/types/index.js +0 -7
  461. package/dist/client/workflow/utils/workflowMetrics.js +0 -311
  462. package/dist/client/workflow/utils/workflowValidation.js +0 -420
  463. package/dist/client/workflow/workflows/adaptiveWorkflow.js +0 -366
  464. package/dist/client/workflow/workflows/consensusWorkflow.js +0 -192
  465. package/dist/client/workflow/workflows/fallbackWorkflow.js +0 -225
  466. package/dist/client/workflow/workflows/multiJudgeWorkflow.js +0 -351
  467. /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;