@gguf/coder 0.2.9 → 0.3.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 (439) hide show
  1. package/.editorconfig +16 -0
  2. package/.env.example +63 -0
  3. package/.gitattributes +1 -0
  4. package/.semgrepignore +19 -0
  5. package/coder-dummy-file.ts +52 -0
  6. package/coder.config.example.json +59 -0
  7. package/coder.config.json +13 -0
  8. package/color_picker.html +36 -0
  9. package/dist/tools/execute-bash.js +3 -3
  10. package/dist/tools/execute-bash.js.map +1 -1
  11. package/dist/tools/fetch-url.js +3 -3
  12. package/dist/tools/fetch-url.js.map +1 -1
  13. package/dist/tools/find-files.d.ts.map +1 -1
  14. package/dist/tools/find-files.js +1 -1
  15. package/dist/tools/find-files.js.map +1 -1
  16. package/dist/tools/lsp-get-diagnostics.js +1 -1
  17. package/dist/tools/lsp-get-diagnostics.js.map +1 -1
  18. package/dist/tools/read-file.d.ts.map +1 -1
  19. package/dist/tools/read-file.js +6 -6
  20. package/dist/tools/read-file.js.map +1 -1
  21. package/dist/tools/search-file-contents.d.ts.map +1 -1
  22. package/dist/tools/search-file-contents.js +1 -1
  23. package/dist/tools/search-file-contents.js.map +1 -1
  24. package/dist/tools/string-replace.js +11 -11
  25. package/dist/tools/string-replace.js.map +1 -1
  26. package/dist/tools/web-search.d.ts.map +1 -1
  27. package/dist/tools/web-search.js +3 -3
  28. package/dist/tools/web-search.js.map +1 -1
  29. package/dist/tools/write-file.js +4 -4
  30. package/dist/tools/write-file.js.map +1 -1
  31. package/dist/utils/tool-result-display.d.ts.map +1 -1
  32. package/dist/utils/tool-result-display.js +3 -3
  33. package/dist/utils/tool-result-display.js.map +1 -1
  34. package/package.json +2 -14
  35. package/scripts/extract-changelog.js +73 -0
  36. package/scripts/fetch-models.js +143 -0
  37. package/scripts/test.sh +40 -0
  38. package/scripts/update-homebrew-formula.sh +125 -0
  39. package/scripts/update-nix-version.sh +157 -0
  40. package/source/ai-sdk-client/AISDKClient.spec.ts +117 -0
  41. package/source/ai-sdk-client/AISDKClient.ts +155 -0
  42. package/source/ai-sdk-client/chat/chat-handler.spec.ts +121 -0
  43. package/source/ai-sdk-client/chat/chat-handler.ts +276 -0
  44. package/source/ai-sdk-client/chat/streaming-handler.spec.ts +173 -0
  45. package/source/ai-sdk-client/chat/streaming-handler.ts +110 -0
  46. package/source/ai-sdk-client/chat/tool-processor.spec.ts +92 -0
  47. package/source/ai-sdk-client/chat/tool-processor.ts +70 -0
  48. package/source/ai-sdk-client/converters/message-converter.spec.ts +220 -0
  49. package/source/ai-sdk-client/converters/message-converter.ts +113 -0
  50. package/source/ai-sdk-client/converters/tool-converter.spec.ts +90 -0
  51. package/source/ai-sdk-client/converters/tool-converter.ts +46 -0
  52. package/source/ai-sdk-client/error-handling/error-extractor.spec.ts +55 -0
  53. package/source/ai-sdk-client/error-handling/error-extractor.ts +15 -0
  54. package/source/ai-sdk-client/error-handling/error-parser.spec.ts +169 -0
  55. package/source/ai-sdk-client/error-handling/error-parser.ts +161 -0
  56. package/source/ai-sdk-client/index.ts +7 -0
  57. package/source/ai-sdk-client/providers/provider-factory.spec.ts +71 -0
  58. package/source/ai-sdk-client/providers/provider-factory.ts +41 -0
  59. package/source/ai-sdk-client/types.ts +9 -0
  60. package/source/ai-sdk-client-empty-message.spec.ts +141 -0
  61. package/source/ai-sdk-client-error-handling.spec.ts +186 -0
  62. package/source/ai-sdk-client-maxretries.spec.ts +114 -0
  63. package/source/ai-sdk-client-preparestep.spec.ts +279 -0
  64. package/source/app/App.spec.tsx +32 -0
  65. package/source/app/App.tsx +480 -0
  66. package/source/app/components/AppContainer.spec.tsx +96 -0
  67. package/source/app/components/AppContainer.tsx +56 -0
  68. package/source/app/components/ChatInterface.spec.tsx +163 -0
  69. package/source/app/components/ChatInterface.tsx +144 -0
  70. package/source/app/components/ModalSelectors.spec.tsx +141 -0
  71. package/source/app/components/ModalSelectors.tsx +135 -0
  72. package/source/app/helpers.spec.ts +97 -0
  73. package/source/app/helpers.ts +63 -0
  74. package/source/app/index.ts +4 -0
  75. package/source/app/types.ts +39 -0
  76. package/source/app/utils/appUtils.ts +294 -0
  77. package/source/app/utils/conversationState.ts +310 -0
  78. package/source/app.spec.tsx +244 -0
  79. package/source/cli.spec.ts +73 -0
  80. package/source/cli.tsx +51 -0
  81. package/source/client-factory.spec.ts +48 -0
  82. package/source/client-factory.ts +178 -0
  83. package/source/command-parser.spec.ts +127 -0
  84. package/source/command-parser.ts +36 -0
  85. package/source/commands/checkpoint.spec.tsx +277 -0
  86. package/source/commands/checkpoint.tsx +366 -0
  87. package/source/commands/clear.tsx +22 -0
  88. package/source/commands/custom-commands.tsx +121 -0
  89. package/source/commands/exit.ts +21 -0
  90. package/source/commands/export.spec.tsx +131 -0
  91. package/source/commands/export.tsx +79 -0
  92. package/source/commands/help.tsx +120 -0
  93. package/source/commands/index.ts +17 -0
  94. package/source/commands/init.tsx +339 -0
  95. package/source/commands/lsp-command.spec.tsx +281 -0
  96. package/source/commands/lsp.tsx +120 -0
  97. package/source/commands/mcp-command.spec.tsx +313 -0
  98. package/source/commands/mcp.tsx +162 -0
  99. package/source/commands/model-database.spec.tsx +758 -0
  100. package/source/commands/model-database.tsx +418 -0
  101. package/source/commands/model.ts +12 -0
  102. package/source/commands/provider.ts +12 -0
  103. package/source/commands/setup-config.tsx +16 -0
  104. package/source/commands/simple-commands.spec.tsx +175 -0
  105. package/source/commands/status.ts +12 -0
  106. package/source/commands/theme.ts +12 -0
  107. package/source/commands/update.spec.tsx +261 -0
  108. package/source/commands/update.tsx +201 -0
  109. package/source/commands/usage.spec.tsx +495 -0
  110. package/source/commands/usage.tsx +100 -0
  111. package/source/commands.spec.ts +436 -0
  112. package/source/commands.ts +83 -0
  113. package/source/components/assistant-message.spec.tsx +796 -0
  114. package/source/components/assistant-message.tsx +34 -0
  115. package/source/components/bash-execution-indicator.tsx +21 -0
  116. package/source/components/cancelling-indicator.tsx +16 -0
  117. package/source/components/chat-queue.spec.tsx +83 -0
  118. package/source/components/chat-queue.tsx +36 -0
  119. package/source/components/checkpoint-display.spec.tsx +219 -0
  120. package/source/components/checkpoint-display.tsx +126 -0
  121. package/source/components/checkpoint-selector.spec.tsx +173 -0
  122. package/source/components/checkpoint-selector.tsx +173 -0
  123. package/source/components/development-mode-indicator.spec.tsx +268 -0
  124. package/source/components/development-mode-indicator.tsx +38 -0
  125. package/source/components/message-box.spec.tsx +427 -0
  126. package/source/components/message-box.tsx +87 -0
  127. package/source/components/model-selector.tsx +132 -0
  128. package/source/components/provider-selector.tsx +75 -0
  129. package/source/components/random-spinner.tsx +19 -0
  130. package/source/components/security-disclaimer.tsx +73 -0
  131. package/source/components/status-connection-display.spec.tsx +133 -0
  132. package/source/components/status.tsx +267 -0
  133. package/source/components/theme-selector.tsx +126 -0
  134. package/source/components/tool-confirmation.tsx +190 -0
  135. package/source/components/tool-execution-indicator.tsx +33 -0
  136. package/source/components/tool-message.tsx +85 -0
  137. package/source/components/ui/titled-box.spec.tsx +207 -0
  138. package/source/components/ui/titled-box.tsx +57 -0
  139. package/source/components/usage/progress-bar.spec.tsx +398 -0
  140. package/source/components/usage/progress-bar.tsx +30 -0
  141. package/source/components/usage/usage-display.spec.tsx +780 -0
  142. package/source/components/usage/usage-display.tsx +291 -0
  143. package/source/components/user-input.spec.tsx +327 -0
  144. package/source/components/user-input.tsx +533 -0
  145. package/source/components/user-message.spec.tsx +230 -0
  146. package/source/components/user-message.tsx +84 -0
  147. package/source/components/welcome-message.tsx +76 -0
  148. package/source/config/env-substitution.ts +65 -0
  149. package/source/config/index.spec.ts +171 -0
  150. package/source/config/index.ts +154 -0
  151. package/source/config/paths.spec.ts +241 -0
  152. package/source/config/paths.ts +55 -0
  153. package/source/config/preferences.ts +51 -0
  154. package/source/config/themes.ts +315 -0
  155. package/source/constants.ts +130 -0
  156. package/source/context/mode-context.spec.ts +79 -0
  157. package/source/context/mode-context.ts +24 -0
  158. package/source/custom-commands/executor.spec.ts +142 -0
  159. package/source/custom-commands/executor.ts +64 -0
  160. package/source/custom-commands/loader.spec.ts +314 -0
  161. package/source/custom-commands/loader.ts +153 -0
  162. package/source/custom-commands/parser.ts +196 -0
  163. package/source/hooks/chat-handler/conversation/conversation-loop.spec.ts +39 -0
  164. package/source/hooks/chat-handler/conversation/conversation-loop.tsx +511 -0
  165. package/source/hooks/chat-handler/conversation/tool-executor.spec.ts +50 -0
  166. package/source/hooks/chat-handler/conversation/tool-executor.tsx +109 -0
  167. package/source/hooks/chat-handler/index.ts +12 -0
  168. package/source/hooks/chat-handler/state/streaming-state.spec.ts +26 -0
  169. package/source/hooks/chat-handler/state/streaming-state.ts +19 -0
  170. package/source/hooks/chat-handler/types.ts +38 -0
  171. package/source/hooks/chat-handler/useChatHandler.spec.tsx +321 -0
  172. package/source/hooks/chat-handler/useChatHandler.tsx +194 -0
  173. package/source/hooks/chat-handler/utils/context-checker.spec.ts +60 -0
  174. package/source/hooks/chat-handler/utils/context-checker.tsx +73 -0
  175. package/source/hooks/chat-handler/utils/message-helpers.spec.ts +42 -0
  176. package/source/hooks/chat-handler/utils/message-helpers.tsx +36 -0
  177. package/source/hooks/chat-handler/utils/tool-filters.spec.ts +109 -0
  178. package/source/hooks/chat-handler/utils/tool-filters.ts +64 -0
  179. package/source/hooks/useAppHandlers.tsx +291 -0
  180. package/source/hooks/useAppInitialization.tsx +422 -0
  181. package/source/hooks/useAppState.tsx +311 -0
  182. package/source/hooks/useDirectoryTrust.tsx +98 -0
  183. package/source/hooks/useInputState.ts +414 -0
  184. package/source/hooks/useModeHandlers.tsx +302 -0
  185. package/source/hooks/useNonInteractiveMode.ts +140 -0
  186. package/source/hooks/useTerminalWidth.tsx +81 -0
  187. package/source/hooks/useTheme.ts +18 -0
  188. package/source/hooks/useToolHandler.tsx +349 -0
  189. package/source/hooks/useUIState.ts +61 -0
  190. package/source/init/agents-template-generator.ts +421 -0
  191. package/source/init/existing-rules-extractor.ts +319 -0
  192. package/source/init/file-scanner.spec.ts +227 -0
  193. package/source/init/file-scanner.ts +238 -0
  194. package/source/init/framework-detector.ts +382 -0
  195. package/source/init/language-detector.ts +269 -0
  196. package/source/init/project-analyzer.spec.ts +231 -0
  197. package/source/init/project-analyzer.ts +458 -0
  198. package/source/lsp/index.ts +31 -0
  199. package/source/lsp/lsp-client.spec.ts +508 -0
  200. package/source/lsp/lsp-client.ts +487 -0
  201. package/source/lsp/lsp-manager.spec.ts +477 -0
  202. package/source/lsp/lsp-manager.ts +419 -0
  203. package/source/lsp/protocol.spec.ts +502 -0
  204. package/source/lsp/protocol.ts +360 -0
  205. package/source/lsp/server-discovery.spec.ts +654 -0
  206. package/source/lsp/server-discovery.ts +515 -0
  207. package/source/markdown-parser/html-entities.spec.ts +88 -0
  208. package/source/markdown-parser/html-entities.ts +45 -0
  209. package/source/markdown-parser/index.spec.ts +281 -0
  210. package/source/markdown-parser/index.ts +126 -0
  211. package/source/markdown-parser/table-parser.spec.ts +133 -0
  212. package/source/markdown-parser/table-parser.ts +114 -0
  213. package/source/markdown-parser/utils.spec.ts +70 -0
  214. package/source/markdown-parser/utils.ts +13 -0
  215. package/source/mcp/mcp-client.spec.ts +81 -0
  216. package/source/mcp/mcp-client.ts +625 -0
  217. package/source/mcp/transport-factory.spec.ts +406 -0
  218. package/source/mcp/transport-factory.ts +312 -0
  219. package/source/message-handler.ts +67 -0
  220. package/source/model-database/database-engine.spec.ts +494 -0
  221. package/source/model-database/database-engine.ts +50 -0
  222. package/source/model-database/model-database.spec.ts +363 -0
  223. package/source/model-database/model-database.ts +91 -0
  224. package/source/model-database/model-engine.spec.ts +447 -0
  225. package/source/model-database/model-engine.ts +65 -0
  226. package/source/model-database/model-fetcher.spec.ts +583 -0
  227. package/source/model-database/model-fetcher.ts +330 -0
  228. package/source/models/index.ts +1 -0
  229. package/source/models/models-cache.spec.ts +214 -0
  230. package/source/models/models-cache.ts +78 -0
  231. package/source/models/models-dev-client.spec.ts +379 -0
  232. package/source/models/models-dev-client.ts +329 -0
  233. package/source/models/models-types.ts +68 -0
  234. package/source/prompt-history.ts +155 -0
  235. package/source/security/command-injection.spec.ts +240 -0
  236. package/source/services/checkpoint-manager.spec.ts +523 -0
  237. package/source/services/checkpoint-manager.ts +466 -0
  238. package/source/services/file-snapshot.spec.ts +569 -0
  239. package/source/services/file-snapshot.ts +220 -0
  240. package/source/test-utils/render-with-theme.tsx +48 -0
  241. package/source/tokenization/index.ts +1 -0
  242. package/source/tokenization/tokenizer-factory.spec.ts +170 -0
  243. package/source/tokenization/tokenizer-factory.ts +125 -0
  244. package/source/tokenization/tokenizers/anthropic-tokenizer.spec.ts +200 -0
  245. package/source/tokenization/tokenizers/anthropic-tokenizer.ts +43 -0
  246. package/source/tokenization/tokenizers/fallback-tokenizer.spec.ts +236 -0
  247. package/source/tokenization/tokenizers/fallback-tokenizer.ts +26 -0
  248. package/source/tokenization/tokenizers/llama-tokenizer.spec.ts +224 -0
  249. package/source/tokenization/tokenizers/llama-tokenizer.ts +41 -0
  250. package/source/tokenization/tokenizers/openai-tokenizer.spec.ts +184 -0
  251. package/source/tokenization/tokenizers/openai-tokenizer.ts +57 -0
  252. package/source/tool-calling/index.ts +5 -0
  253. package/source/tool-calling/json-parser.spec.ts +639 -0
  254. package/source/tool-calling/json-parser.ts +247 -0
  255. package/source/tool-calling/tool-parser.spec.ts +395 -0
  256. package/source/tool-calling/tool-parser.ts +120 -0
  257. package/source/tool-calling/xml-parser.spec.ts +662 -0
  258. package/source/tool-calling/xml-parser.ts +289 -0
  259. package/source/tools/execute-bash.spec.tsx +353 -0
  260. package/source/tools/execute-bash.tsx +219 -0
  261. package/source/tools/execute-function.spec.ts +130 -0
  262. package/source/tools/fetch-url.spec.tsx +342 -0
  263. package/source/tools/fetch-url.tsx +172 -0
  264. package/source/tools/find-files.spec.tsx +924 -0
  265. package/source/tools/find-files.tsx +293 -0
  266. package/source/tools/index.ts +102 -0
  267. package/source/tools/lsp-get-diagnostics.tsx +192 -0
  268. package/source/tools/needs-approval.spec.ts +282 -0
  269. package/source/tools/read-file.spec.tsx +801 -0
  270. package/source/tools/read-file.tsx +387 -0
  271. package/source/tools/search-file-contents.spec.tsx +1273 -0
  272. package/source/tools/search-file-contents.tsx +293 -0
  273. package/source/tools/string-replace.spec.tsx +730 -0
  274. package/source/tools/string-replace.tsx +548 -0
  275. package/source/tools/tool-manager.ts +210 -0
  276. package/source/tools/tool-registry.spec.ts +415 -0
  277. package/source/tools/tool-registry.ts +228 -0
  278. package/source/tools/web-search.tsx +223 -0
  279. package/source/tools/write-file.spec.tsx +559 -0
  280. package/source/tools/write-file.tsx +228 -0
  281. package/source/types/app.ts +37 -0
  282. package/source/types/checkpoint.ts +48 -0
  283. package/source/types/commands.ts +46 -0
  284. package/source/types/components.ts +27 -0
  285. package/source/types/config.ts +103 -0
  286. package/source/types/core-connection-status.spec.ts +67 -0
  287. package/source/types/core.ts +181 -0
  288. package/source/types/hooks.ts +50 -0
  289. package/source/types/index.ts +12 -0
  290. package/source/types/markdown-parser.ts +11 -0
  291. package/source/types/mcp.ts +52 -0
  292. package/source/types/system.ts +16 -0
  293. package/source/types/tokenization.ts +41 -0
  294. package/source/types/ui.ts +40 -0
  295. package/source/types/usage.ts +58 -0
  296. package/source/types/utils.ts +16 -0
  297. package/source/usage/calculator.spec.ts +385 -0
  298. package/source/usage/calculator.ts +104 -0
  299. package/source/usage/storage.spec.ts +703 -0
  300. package/source/usage/storage.ts +238 -0
  301. package/source/usage/tracker.spec.ts +456 -0
  302. package/source/usage/tracker.ts +102 -0
  303. package/source/utils/atomic-deletion.spec.ts +194 -0
  304. package/source/utils/atomic-deletion.ts +127 -0
  305. package/source/utils/bounded-map.spec.ts +300 -0
  306. package/source/utils/bounded-map.ts +193 -0
  307. package/source/utils/checkpoint-utils.spec.ts +222 -0
  308. package/source/utils/checkpoint-utils.ts +92 -0
  309. package/source/utils/error-formatter.spec.ts +169 -0
  310. package/source/utils/error-formatter.ts +194 -0
  311. package/source/utils/file-autocomplete.spec.ts +173 -0
  312. package/source/utils/file-autocomplete.ts +196 -0
  313. package/source/utils/file-cache.spec.ts +309 -0
  314. package/source/utils/file-cache.ts +195 -0
  315. package/source/utils/file-content-loader.spec.ts +180 -0
  316. package/source/utils/file-content-loader.ts +179 -0
  317. package/source/utils/file-mention-handler.spec.ts +261 -0
  318. package/source/utils/file-mention-handler.ts +84 -0
  319. package/source/utils/file-mention-parser.spec.ts +182 -0
  320. package/source/utils/file-mention-parser.ts +170 -0
  321. package/source/utils/fuzzy-matching.spec.ts +149 -0
  322. package/source/utils/fuzzy-matching.ts +146 -0
  323. package/source/utils/indentation-normalizer.spec.ts +216 -0
  324. package/source/utils/indentation-normalizer.ts +76 -0
  325. package/source/utils/installation-detector.spec.ts +178 -0
  326. package/source/utils/installation-detector.ts +153 -0
  327. package/source/utils/logging/config.spec.ts +311 -0
  328. package/source/utils/logging/config.ts +210 -0
  329. package/source/utils/logging/console-facade.spec.ts +184 -0
  330. package/source/utils/logging/console-facade.ts +384 -0
  331. package/source/utils/logging/correlation.spec.ts +679 -0
  332. package/source/utils/logging/correlation.ts +474 -0
  333. package/source/utils/logging/formatters.spec.ts +464 -0
  334. package/source/utils/logging/formatters.ts +207 -0
  335. package/source/utils/logging/health-monitor/alerts/alert-manager.spec.ts +93 -0
  336. package/source/utils/logging/health-monitor/alerts/alert-manager.ts +79 -0
  337. package/source/utils/logging/health-monitor/checks/configuration-check.spec.ts +56 -0
  338. package/source/utils/logging/health-monitor/checks/configuration-check.ts +43 -0
  339. package/source/utils/logging/health-monitor/checks/logging-check.spec.ts +56 -0
  340. package/source/utils/logging/health-monitor/checks/logging-check.ts +58 -0
  341. package/source/utils/logging/health-monitor/checks/memory-check.spec.ts +100 -0
  342. package/source/utils/logging/health-monitor/checks/memory-check.ts +78 -0
  343. package/source/utils/logging/health-monitor/checks/performance-check.spec.ts +56 -0
  344. package/source/utils/logging/health-monitor/checks/performance-check.ts +56 -0
  345. package/source/utils/logging/health-monitor/checks/request-check.spec.ts +56 -0
  346. package/source/utils/logging/health-monitor/checks/request-check.ts +76 -0
  347. package/source/utils/logging/health-monitor/core/health-check-runner.spec.ts +70 -0
  348. package/source/utils/logging/health-monitor/core/health-check-runner.ts +138 -0
  349. package/source/utils/logging/health-monitor/core/health-monitor.spec.ts +58 -0
  350. package/source/utils/logging/health-monitor/core/health-monitor.ts +344 -0
  351. package/source/utils/logging/health-monitor/core/scoring.spec.ts +65 -0
  352. package/source/utils/logging/health-monitor/core/scoring.ts +91 -0
  353. package/source/utils/logging/health-monitor/index.ts +15 -0
  354. package/source/utils/logging/health-monitor/instances.ts +48 -0
  355. package/source/utils/logging/health-monitor/middleware/http-middleware.spec.ts +141 -0
  356. package/source/utils/logging/health-monitor/middleware/http-middleware.ts +75 -0
  357. package/source/utils/logging/health-monitor/types.ts +126 -0
  358. package/source/utils/logging/index.spec.ts +284 -0
  359. package/source/utils/logging/index.ts +236 -0
  360. package/source/utils/logging/integration.spec.ts +441 -0
  361. package/source/utils/logging/log-method-factory.spec.ts +573 -0
  362. package/source/utils/logging/log-method-factory.ts +233 -0
  363. package/source/utils/logging/log-query/aggregation/aggregator.spec.ts +277 -0
  364. package/source/utils/logging/log-query/aggregation/aggregator.ts +159 -0
  365. package/source/utils/logging/log-query/aggregation/facet-generator.spec.ts +159 -0
  366. package/source/utils/logging/log-query/aggregation/facet-generator.ts +47 -0
  367. package/source/utils/logging/log-query/index.ts +23 -0
  368. package/source/utils/logging/log-query/query/filter-predicates.spec.ts +247 -0
  369. package/source/utils/logging/log-query/query/filter-predicates.ts +154 -0
  370. package/source/utils/logging/log-query/query/query-builder.spec.ts +182 -0
  371. package/source/utils/logging/log-query/query/query-builder.ts +151 -0
  372. package/source/utils/logging/log-query/query/query-engine.spec.ts +214 -0
  373. package/source/utils/logging/log-query/query/query-engine.ts +45 -0
  374. package/source/utils/logging/log-query/storage/circular-buffer.spec.ts +143 -0
  375. package/source/utils/logging/log-query/storage/circular-buffer.ts +75 -0
  376. package/source/utils/logging/log-query/storage/index-manager.spec.ts +150 -0
  377. package/source/utils/logging/log-query/storage/index-manager.ts +71 -0
  378. package/source/utils/logging/log-query/storage/log-storage.spec.ts +257 -0
  379. package/source/utils/logging/log-query/storage/log-storage.ts +80 -0
  380. package/source/utils/logging/log-query/types.ts +163 -0
  381. package/source/utils/logging/log-query/utils/helpers.spec.ts +263 -0
  382. package/source/utils/logging/log-query/utils/helpers.ts +72 -0
  383. package/source/utils/logging/log-query/utils/sorting.spec.ts +182 -0
  384. package/source/utils/logging/log-query/utils/sorting.ts +61 -0
  385. package/source/utils/logging/logger-provider.spec.ts +262 -0
  386. package/source/utils/logging/logger-provider.ts +362 -0
  387. package/source/utils/logging/performance.spec.ts +209 -0
  388. package/source/utils/logging/performance.ts +757 -0
  389. package/source/utils/logging/pino-logger.spec.ts +425 -0
  390. package/source/utils/logging/pino-logger.ts +514 -0
  391. package/source/utils/logging/redaction.spec.ts +490 -0
  392. package/source/utils/logging/redaction.ts +267 -0
  393. package/source/utils/logging/request-tracker.spec.ts +1198 -0
  394. package/source/utils/logging/request-tracker.ts +803 -0
  395. package/source/utils/logging/transports.spec.ts +505 -0
  396. package/source/utils/logging/transports.ts +305 -0
  397. package/source/utils/logging/types.ts +216 -0
  398. package/source/utils/message-builder.spec.ts +179 -0
  399. package/source/utils/message-builder.ts +101 -0
  400. package/source/utils/message-queue.tsx +486 -0
  401. package/source/utils/paste-detection.spec.ts +69 -0
  402. package/source/utils/paste-detection.ts +124 -0
  403. package/source/utils/paste-roundtrip.spec.ts +442 -0
  404. package/source/utils/paste-utils.spec.ts +128 -0
  405. package/source/utils/paste-utils.ts +52 -0
  406. package/source/utils/programming-language-helper.spec.ts +74 -0
  407. package/source/utils/programming-language-helper.ts +32 -0
  408. package/source/utils/prompt-assembly.spec.ts +221 -0
  409. package/source/utils/prompt-processor.ts +173 -0
  410. package/source/utils/tool-args-parser.spec.ts +136 -0
  411. package/source/utils/tool-args-parser.ts +54 -0
  412. package/source/utils/tool-cancellation.spec.ts +230 -0
  413. package/source/utils/tool-cancellation.ts +28 -0
  414. package/source/utils/tool-result-display.spec.tsx +469 -0
  415. package/source/utils/tool-result-display.tsx +90 -0
  416. package/source/utils/update-checker.spec.ts +383 -0
  417. package/source/utils/update-checker.ts +183 -0
  418. package/source/wizard/config-wizard.spec.tsx +103 -0
  419. package/source/wizard/config-wizard.tsx +382 -0
  420. package/source/wizard/steps/location-step.spec.tsx +186 -0
  421. package/source/wizard/steps/location-step.tsx +147 -0
  422. package/source/wizard/steps/mcp-step.spec.tsx +607 -0
  423. package/source/wizard/steps/mcp-step.tsx +632 -0
  424. package/source/wizard/steps/provider-step.spec.tsx +342 -0
  425. package/source/wizard/steps/provider-step.tsx +957 -0
  426. package/source/wizard/steps/summary-step.spec.tsx +749 -0
  427. package/source/wizard/steps/summary-step.tsx +228 -0
  428. package/source/wizard/templates/mcp-templates.spec.ts +613 -0
  429. package/source/wizard/templates/mcp-templates.ts +570 -0
  430. package/source/wizard/templates/provider-templates.spec.ts +152 -0
  431. package/source/wizard/templates/provider-templates.ts +485 -0
  432. package/source/wizard/utils/fetch-cloud-models.spec.ts +428 -0
  433. package/source/wizard/utils/fetch-cloud-models.ts +223 -0
  434. package/source/wizard/utils/fetch-local-models.spec.ts +297 -0
  435. package/source/wizard/utils/fetch-local-models.ts +192 -0
  436. package/source/wizard/validation-array.spec.ts +264 -0
  437. package/source/wizard/validation.spec.ts +373 -0
  438. package/source/wizard/validation.ts +232 -0
  439. package/source/app/prompts/main-prompt.md +0 -122
@@ -0,0 +1,121 @@
1
+ import test from 'ava';
2
+ import type {
3
+ AIProviderConfig,
4
+ AISDKCoreTool,
5
+ Message,
6
+ StreamCallbacks,
7
+ } from '@/types/index';
8
+ import type {LanguageModel} from 'ai';
9
+ import type {ChatHandlerParams} from './chat-handler.js';
10
+
11
+ // Note: This file contains basic structure tests
12
+ // Full integration tests would require mocking the AI SDK's generateText function
13
+ // which is complex and better tested through the full AISDKClient
14
+
15
+ test('ChatHandlerParams has correct structure', t => {
16
+ const params: ChatHandlerParams = {
17
+ model: {} as LanguageModel,
18
+ currentModel: 'test-model',
19
+ providerConfig: {
20
+ name: 'TestProvider',
21
+ type: 'openai',
22
+ models: ['test-model'],
23
+ config: {
24
+ baseURL: 'https://api.test.com',
25
+ apiKey: 'test-key',
26
+ },
27
+ },
28
+ messages: [],
29
+ tools: {},
30
+ callbacks: {},
31
+ maxRetries: 2,
32
+ };
33
+
34
+ t.is(params.currentModel, 'test-model');
35
+ t.is(params.providerConfig.name, 'TestProvider');
36
+ t.deepEqual(params.messages, []);
37
+ t.deepEqual(params.tools, {});
38
+ });
39
+
40
+ test('ChatHandlerParams accepts optional signal', t => {
41
+ const controller = new AbortController();
42
+ const params: ChatHandlerParams = {
43
+ model: {} as LanguageModel,
44
+ currentModel: 'test-model',
45
+ providerConfig: {
46
+ name: 'TestProvider',
47
+ type: 'openai',
48
+ models: ['test-model'],
49
+ config: {
50
+ baseURL: 'https://api.test.com',
51
+ },
52
+ },
53
+ messages: [],
54
+ tools: {},
55
+ callbacks: {},
56
+ signal: controller.signal,
57
+ maxRetries: 2,
58
+ };
59
+
60
+ t.is(params.signal, controller.signal);
61
+ });
62
+
63
+ test('ChatHandlerParams accepts messages and tools', t => {
64
+ const messages: Message[] = [
65
+ {role: 'user', content: 'Hello'},
66
+ ];
67
+ const tools: Record<string, AISDKCoreTool> = {
68
+ test_tool: {} as AISDKCoreTool,
69
+ };
70
+
71
+ const params: ChatHandlerParams = {
72
+ model: {} as LanguageModel,
73
+ currentModel: 'test-model',
74
+ providerConfig: {
75
+ name: 'TestProvider',
76
+ type: 'openai',
77
+ models: ['test-model'],
78
+ config: {
79
+ baseURL: 'https://api.test.com',
80
+ },
81
+ },
82
+ messages,
83
+ tools,
84
+ callbacks: {},
85
+ maxRetries: 2,
86
+ };
87
+
88
+ t.is(params.messages.length, 1);
89
+ t.is(Object.keys(params.tools).length, 1);
90
+ });
91
+
92
+ test('ChatHandlerParams accepts callbacks', t => {
93
+ const callbacks: StreamCallbacks = {
94
+ onToken: () => {},
95
+ onToolCall: () => {},
96
+ onToolExecuted: () => {},
97
+ onFinish: () => {},
98
+ };
99
+
100
+ const params: ChatHandlerParams = {
101
+ model: {} as LanguageModel,
102
+ currentModel: 'test-model',
103
+ providerConfig: {
104
+ name: 'TestProvider',
105
+ type: 'openai',
106
+ models: ['test-model'],
107
+ config: {
108
+ baseURL: 'https://api.test.com',
109
+ },
110
+ },
111
+ messages: [],
112
+ tools: {},
113
+ callbacks,
114
+ maxRetries: 2,
115
+ };
116
+
117
+ t.truthy(params.callbacks.onToken);
118
+ t.truthy(params.callbacks.onToolCall);
119
+ t.truthy(params.callbacks.onToolExecuted);
120
+ t.truthy(params.callbacks.onFinish);
121
+ });
@@ -0,0 +1,276 @@
1
+ import {MAX_TOOL_STEPS} from '@/constants';
2
+ import type {
3
+ AIProviderConfig,
4
+ AISDKCoreTool,
5
+ LLMChatResponse,
6
+ Message,
7
+ StreamCallbacks,
8
+ ToolCall,
9
+ } from '@/types/index';
10
+ import {
11
+ endMetrics,
12
+ formatMemoryUsage,
13
+ generateCorrelationId,
14
+ getCorrelationId,
15
+ getLogger,
16
+ startMetrics,
17
+ withNewCorrelationContext,
18
+ } from '@/utils/logging';
19
+ import type {LanguageModel} from 'ai';
20
+ import {generateText, stepCountIs} from 'ai';
21
+ import {convertToModelMessages} from '../converters/message-converter.js';
22
+ import {
23
+ convertAISDKToolCalls,
24
+ getToolResultOutput,
25
+ } from '../converters/tool-converter.js';
26
+ import {extractRootError} from '../error-handling/error-extractor.js';
27
+ import {parseAPIError} from '../error-handling/error-parser.js';
28
+ import {
29
+ createOnStepFinishHandler,
30
+ createPrepareStepHandler,
31
+ } from './streaming-handler.js';
32
+ import {processXMLToolCalls} from './tool-processor.js';
33
+
34
+ export interface ChatHandlerParams {
35
+ model: LanguageModel;
36
+ currentModel: string;
37
+ providerConfig: AIProviderConfig;
38
+ messages: Message[];
39
+ tools: Record<string, AISDKCoreTool>;
40
+ callbacks: StreamCallbacks;
41
+ signal?: AbortSignal;
42
+ maxRetries: number;
43
+ }
44
+
45
+ /**
46
+ * Main chat handler - orchestrates the entire chat flow
47
+ */
48
+ export async function handleChat(
49
+ params: ChatHandlerParams,
50
+ ): Promise<LLMChatResponse> {
51
+ const {
52
+ model,
53
+ currentModel,
54
+ providerConfig,
55
+ messages,
56
+ tools,
57
+ callbacks,
58
+ signal,
59
+ maxRetries,
60
+ } = params;
61
+ const logger = getLogger();
62
+
63
+ // Check if already aborted before starting
64
+ if (signal?.aborted) {
65
+ logger.debug('Chat request already aborted');
66
+ throw new Error('Operation was cancelled');
67
+ }
68
+
69
+ // Start performance tracking
70
+ const metrics = startMetrics();
71
+ const correlationId = getCorrelationId() || generateCorrelationId();
72
+
73
+ logger.info('Chat request starting', {
74
+ model: currentModel,
75
+ messageCount: messages.length,
76
+ toolCount: Object.keys(tools).length,
77
+ correlationId,
78
+ provider: providerConfig.name,
79
+ });
80
+
81
+ return await withNewCorrelationContext(async _context => {
82
+ try {
83
+ // Tools are already in AI SDK format - use directly
84
+ const aiTools = Object.keys(tools).length > 0 ? tools : undefined;
85
+
86
+ // Convert messages to AI SDK v5 ModelMessage format
87
+ const modelMessages = convertToModelMessages(messages);
88
+
89
+ logger.debug('AI SDK request prepared', {
90
+ messageCount: modelMessages.length,
91
+ hasTools: !!aiTools,
92
+ toolCount: aiTools ? Object.keys(aiTools).length : 0,
93
+ });
94
+
95
+ // Tools with needsApproval: false auto-execute in the loop
96
+ // Tools with needsApproval: true cause interruptions for manual approval
97
+ // stopWhen controls when the tool loop stops (max MAX_TOOL_STEPS steps)
98
+ const result = await generateText({
99
+ model,
100
+ messages: modelMessages,
101
+ tools: aiTools,
102
+ abortSignal: signal,
103
+ maxRetries,
104
+ stopWhen: stepCountIs(MAX_TOOL_STEPS), // Allow up to MAX_TOOL_STEPS tool execution steps
105
+ // Can be used to add custom logging, metrics, or step tracking
106
+ onStepFinish: createOnStepFinishHandler(callbacks),
107
+ prepareStep: createPrepareStepHandler(),
108
+ });
109
+
110
+ // Get the full text from the result
111
+ const fullText = result.text;
112
+
113
+ logger.debug('AI SDK response received', {
114
+ responseLength: fullText.length,
115
+ hasToolCalls: !!(result.toolCalls && result.toolCalls.length > 0),
116
+ toolCallCount: result.toolCalls?.length || 0,
117
+ });
118
+
119
+ // Send the complete text to the callback
120
+ if (fullText) {
121
+ callbacks.onToken?.(fullText);
122
+ }
123
+
124
+ // Get tool calls from result
125
+ const toolCallsResult = result.toolCalls;
126
+
127
+ // Extract auto-executed assistant messages and tool results from steps
128
+ // These need to be added to the messages array so usage tracking can count them
129
+ const autoExecutedMessages: Array<Message> = [];
130
+ const steps = result.steps;
131
+ for (const step of steps) {
132
+ if (
133
+ step.toolCalls &&
134
+ step.toolResults &&
135
+ step.toolCalls.length === step.toolResults.length
136
+ ) {
137
+ // This step had tool calls that were auto-executed
138
+ // Add the assistant message with tool_calls
139
+ const stepToolCalls: ToolCall[] = convertAISDKToolCalls(
140
+ step.toolCalls,
141
+ );
142
+
143
+ autoExecutedMessages.push({
144
+ role: 'assistant',
145
+ content: step.text || '',
146
+ tool_calls: stepToolCalls,
147
+ });
148
+
149
+ // Add the tool result messages
150
+ step.toolCalls.forEach((toolCall, idx) => {
151
+ const toolResult = step.toolResults[idx];
152
+ const resultStr = getToolResultOutput(toolResult.output);
153
+
154
+ autoExecutedMessages.push({
155
+ role: 'tool' as const,
156
+ content: resultStr,
157
+ tool_call_id:
158
+ toolCall.toolCallId ||
159
+ `tool_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`,
160
+ name: toolCall.toolName,
161
+ });
162
+ });
163
+ }
164
+ }
165
+
166
+ // Extract tool calls
167
+ const toolCalls: ToolCall[] = [];
168
+ if (toolCallsResult && toolCallsResult.length > 0) {
169
+ logger.debug('Processing tool calls from response', {
170
+ toolCallCount: toolCallsResult.length,
171
+ });
172
+
173
+ for (const toolCall of toolCallsResult) {
174
+ const tc: ToolCall = convertAISDKToolCalls([toolCall])[0];
175
+ toolCalls.push(tc);
176
+
177
+ logger.debug('Tool call processed', {
178
+ toolName: tc.function.name,
179
+ hasArguments: !!tc.function.arguments,
180
+ });
181
+
182
+ // Note: onToolCall already fired in onStepFinish - no need to call again
183
+ }
184
+ }
185
+
186
+ // Check for XML tool calls if no native ones
187
+ let content = fullText;
188
+ const xmlResult = processXMLToolCalls(content, tools, callbacks);
189
+ if (xmlResult.toolCalls.length > 0) {
190
+ toolCalls.push(...xmlResult.toolCalls);
191
+ content = xmlResult.cleanedContent;
192
+ }
193
+
194
+ // Calculate performance metrics
195
+ const finalMetrics = endMetrics(metrics);
196
+
197
+ logger.info('Chat request completed successfully', {
198
+ model: currentModel,
199
+ duration: `${finalMetrics.duration.toFixed(2)}ms`,
200
+ responseLength: content.length,
201
+ toolCallsFound: toolCalls.length,
202
+ memoryDelta: formatMemoryUsage(
203
+ finalMetrics.memoryUsage || process.memoryUsage(),
204
+ ),
205
+ correlationId,
206
+ provider: providerConfig.name,
207
+ });
208
+
209
+ callbacks.onFinish?.();
210
+
211
+ return {
212
+ choices: [
213
+ {
214
+ message: {
215
+ role: 'assistant',
216
+ content,
217
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
218
+ },
219
+ },
220
+ ],
221
+ // Include auto-executed messages so they can be added to message history
222
+ autoExecutedMessages:
223
+ autoExecutedMessages.length > 0 ? autoExecutedMessages : undefined,
224
+ };
225
+ } catch (error) {
226
+ // Calculate performance metrics even for errors
227
+ const finalMetrics = endMetrics(metrics);
228
+
229
+ // Check if this was a user-initiated cancellation
230
+ if (error instanceof Error && error.name === 'AbortError') {
231
+ logger.info('Chat request cancelled by user', {
232
+ model: currentModel,
233
+ duration: `${finalMetrics.duration.toFixed(2)}ms`,
234
+ correlationId,
235
+ provider: providerConfig.name,
236
+ });
237
+ throw new Error('Operation was cancelled');
238
+ }
239
+
240
+ // Log the error with performance metrics
241
+ logger.error('Chat request failed', {
242
+ model: currentModel,
243
+ duration: `${finalMetrics.duration.toFixed(2)}ms`,
244
+ error: error instanceof Error ? error.message : error,
245
+ errorName: error instanceof Error ? error.name : 'Unknown',
246
+ correlationId,
247
+ provider: providerConfig.name,
248
+ memoryDelta: formatMemoryUsage(
249
+ finalMetrics.memoryUsage || process.memoryUsage(),
250
+ ),
251
+ });
252
+
253
+ // AI SDK wraps errors in NoOutputGeneratedError with no useful cause
254
+ // Check if it's a cancellation without an underlying API error
255
+ if (
256
+ error instanceof Error &&
257
+ (error.name === 'AI_NoOutputGeneratedError' ||
258
+ error.message.includes('No output generated'))
259
+ ) {
260
+ // Check if there's an underlying RetryError with the real cause
261
+ const rootError = extractRootError(error);
262
+ if (rootError === error) {
263
+ // No underlying error - this is just a cancellation
264
+ throw new Error('Operation was cancelled');
265
+ }
266
+ // There's a real error underneath, parse it
267
+ const userMessage = parseAPIError(rootError);
268
+ throw new Error(userMessage);
269
+ }
270
+
271
+ // Parse any other error (including RetryError and APICallError)
272
+ const userMessage = parseAPIError(error);
273
+ throw new Error(userMessage);
274
+ }
275
+ }, correlationId); // End of withNewCorrelationContext
276
+ }
@@ -0,0 +1,173 @@
1
+ import test from 'ava';
2
+ import type {StreamCallbacks} from '@/types/index';
3
+ import {createOnStepFinishHandler, createPrepareStepHandler} from './streaming-handler.js';
4
+ import type {TestableMessage} from '../types.js';
5
+
6
+ test('createOnStepFinishHandler calls onToolExecuted callback', t => {
7
+ let callbackCalled = false;
8
+ const callbacks: StreamCallbacks = {
9
+ onToolExecuted: (toolCall, result) => {
10
+ callbackCalled = true;
11
+ t.is(toolCall.function.name, 'test_tool');
12
+ t.is(result, 'test output');
13
+ },
14
+ };
15
+
16
+ const handler = createOnStepFinishHandler(callbacks);
17
+ handler({
18
+ toolCalls: [
19
+ {
20
+ toolCallId: 'call_123',
21
+ toolName: 'test_tool',
22
+ input: {},
23
+ },
24
+ ],
25
+ toolResults: [
26
+ {
27
+ output: 'test output',
28
+ },
29
+ ],
30
+ });
31
+
32
+ t.true(callbackCalled);
33
+ });
34
+
35
+ test('createOnStepFinishHandler handles steps without tool calls', t => {
36
+ const callbacks: StreamCallbacks = {
37
+ onToolExecuted: () => {
38
+ t.fail('Should not be called');
39
+ },
40
+ };
41
+
42
+ const handler = createOnStepFinishHandler(callbacks);
43
+ handler({
44
+ text: 'Some text',
45
+ });
46
+
47
+ t.pass();
48
+ });
49
+
50
+ test('createOnStepFinishHandler handles steps with tool calls but no results', t => {
51
+ const callbacks: StreamCallbacks = {
52
+ onToolExecuted: () => {
53
+ t.fail('Should not be called');
54
+ },
55
+ };
56
+
57
+ const handler = createOnStepFinishHandler(callbacks);
58
+ handler({
59
+ toolCalls: [
60
+ {
61
+ toolCallId: 'call_123',
62
+ toolName: 'test_tool',
63
+ input: {},
64
+ },
65
+ ],
66
+ });
67
+
68
+ t.pass();
69
+ });
70
+
71
+ test('createOnStepFinishHandler converts object output to JSON string', t => {
72
+ let resultReceived = '';
73
+ const callbacks: StreamCallbacks = {
74
+ onToolExecuted: (_toolCall, result) => {
75
+ resultReceived = result;
76
+ },
77
+ };
78
+
79
+ const handler = createOnStepFinishHandler(callbacks);
80
+ handler({
81
+ toolCalls: [
82
+ {
83
+ toolCallId: 'call_123',
84
+ toolName: 'test_tool',
85
+ input: {},
86
+ },
87
+ ],
88
+ toolResults: [
89
+ {
90
+ output: {key: 'value'},
91
+ },
92
+ ],
93
+ });
94
+
95
+ t.is(resultReceived, '{"key":"value"}');
96
+ });
97
+
98
+ test('createPrepareStepHandler filters empty assistant messages', t => {
99
+ const handler = createPrepareStepHandler();
100
+ const messages = [
101
+ {role: 'user', content: 'Hello'},
102
+ {role: 'assistant', content: ''},
103
+ {role: 'user', content: 'World'},
104
+ ] as unknown as TestableMessage[];
105
+
106
+ const result = handler({messages: messages as any});
107
+
108
+ t.truthy(result.messages);
109
+ t.is(result.messages?.length, 2);
110
+ t.is((result.messages?.[0] as any).content, 'Hello');
111
+ t.is((result.messages?.[1] as any).content, 'World');
112
+ });
113
+
114
+ test('createPrepareStepHandler filters orphaned tool messages', t => {
115
+ const handler = createPrepareStepHandler();
116
+ const messages = [
117
+ {role: 'user', content: 'Hello'},
118
+ {role: 'assistant', content: ''},
119
+ {role: 'tool', content: 'Tool result'},
120
+ {role: 'user', content: 'World'},
121
+ ] as unknown as TestableMessage[];
122
+
123
+ const result = handler({messages: messages as any});
124
+
125
+ t.truthy(result.messages);
126
+ t.is(result.messages?.length, 2);
127
+ t.is((result.messages?.[0] as any).content, 'Hello');
128
+ t.is((result.messages?.[1] as any).content, 'World');
129
+ });
130
+
131
+ test('createPrepareStepHandler returns empty object when no filtering needed', t => {
132
+ const handler = createPrepareStepHandler();
133
+ const messages = [
134
+ {role: 'user', content: 'Hello'},
135
+ {role: 'assistant', content: 'Hi'},
136
+ ] as unknown as TestableMessage[];
137
+
138
+ const result = handler({messages: messages as any});
139
+
140
+ t.deepEqual(result, {});
141
+ });
142
+
143
+ test('createPrepareStepHandler filters multiple empty assistant messages', t => {
144
+ const handler = createPrepareStepHandler();
145
+ const messages = [
146
+ {role: 'user', content: 'Hello'},
147
+ {role: 'assistant', content: ''},
148
+ {role: 'user', content: 'World'},
149
+ {role: 'assistant', content: ' '},
150
+ {role: 'user', content: 'Test'},
151
+ ] as unknown as TestableMessage[];
152
+
153
+ const result = handler({messages: messages as any});
154
+
155
+ t.truthy(result.messages);
156
+ t.is(result.messages?.length, 3);
157
+ t.is(result.messages?.[0].role, 'user');
158
+ t.is(result.messages?.[1].role, 'user');
159
+ t.is(result.messages?.[2].role, 'user');
160
+ });
161
+
162
+ test('createPrepareStepHandler keeps non-empty assistant messages', t => {
163
+ const handler = createPrepareStepHandler();
164
+ const messages = [
165
+ {role: 'user', content: 'Hello'},
166
+ {role: 'assistant', content: 'Response'},
167
+ {role: 'user', content: 'World'},
168
+ ] as unknown as TestableMessage[];
169
+
170
+ const result = handler({messages: messages as any});
171
+
172
+ t.deepEqual(result, {});
173
+ });
@@ -0,0 +1,110 @@
1
+ import type {StreamCallbacks, ToolCall} from '@/types/index';
2
+ import {getLogger} from '@/utils/logging';
3
+ import type {ModelMessage} from 'ai';
4
+ import {isEmptyAssistantMessage} from '../converters/message-converter.js';
5
+ import {
6
+ convertAISDKToolCall,
7
+ getToolResultOutput,
8
+ } from '../converters/tool-converter.js';
9
+ import type {TestableMessage} from '../types.js';
10
+
11
+ /**
12
+ * Creates the onStepFinish callback for AI SDK generateText
13
+ * This handles logging and displaying tool execution results
14
+ */
15
+ export function createOnStepFinishHandler(callbacks: StreamCallbacks): (step: {
16
+ toolCalls?: Array<{toolCallId?: string; toolName: string; input: unknown}>;
17
+ toolResults?: Array<{output: unknown}>;
18
+ text?: string;
19
+ }) => void {
20
+ const logger = getLogger();
21
+
22
+ return step => {
23
+ // Log tool execution steps
24
+ if (step.toolCalls && step.toolCalls.length > 0) {
25
+ logger.trace('AI SDK tool step', {
26
+ stepType: 'tool_execution',
27
+ toolCount: step.toolCalls.length,
28
+ hasResults: !!step.toolResults,
29
+ });
30
+ }
31
+
32
+ // Display formatters for auto-executed tools (after execution with results)
33
+ if (
34
+ step.toolCalls &&
35
+ step.toolResults &&
36
+ step.toolCalls.length === step.toolResults.length
37
+ ) {
38
+ step.toolCalls.forEach((toolCall, idx) => {
39
+ const toolResult = step.toolResults?.[idx];
40
+ if (!toolResult) return;
41
+ const tc: ToolCall = convertAISDKToolCall(toolCall);
42
+ const resultStr = getToolResultOutput(toolResult.output);
43
+
44
+ logger.debug('Tool executed', {
45
+ toolName: tc.function.name,
46
+ resultLength: resultStr.length,
47
+ });
48
+
49
+ callbacks.onToolExecuted?.(tc, resultStr);
50
+ });
51
+ }
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Creates the prepareStep callback for AI SDK generateText
57
+ * This filters out empty assistant messages and orphaned tool results
58
+ */
59
+ export function createPrepareStepHandler(): (params: {
60
+ messages: ModelMessage[];
61
+ }) => {messages?: ModelMessage[]} | Record<string, never> {
62
+ const logger = getLogger();
63
+
64
+ return ({messages}) => {
65
+ // Filter out empty assistant messages that would cause API errors
66
+ // "Assistant message must have either content or tool_calls"
67
+ // Also filter out orphaned tool messages that follow empty assistant messages
68
+ const filteredMessages: ModelMessage[] = [];
69
+ const indicesToSkip = new Set<number>();
70
+
71
+ // First pass: identify empty assistant messages and their orphaned tool results
72
+ for (let i = 0; i < messages.length; i++) {
73
+ if (isEmptyAssistantMessage(messages[i] as unknown as TestableMessage)) {
74
+ indicesToSkip.add(i);
75
+
76
+ // Mark any immediately following tool messages as orphaned
77
+ let j = i + 1;
78
+ while (j < messages.length && messages[j].role === 'tool') {
79
+ indicesToSkip.add(j);
80
+ j++;
81
+ }
82
+ }
83
+ }
84
+
85
+ // Second pass: build filtered array
86
+ for (let i = 0; i < messages.length; i++) {
87
+ if (!indicesToSkip.has(i)) {
88
+ filteredMessages.push(messages[i]);
89
+ }
90
+ }
91
+
92
+ // Log message filtering
93
+ if (filteredMessages.length !== messages.length) {
94
+ logger.debug(
95
+ 'Filtered empty assistant messages and orphaned tool results',
96
+ {
97
+ originalCount: messages.length,
98
+ filteredCount: filteredMessages.length,
99
+ removedCount: messages.length - filteredMessages.length,
100
+ },
101
+ );
102
+ }
103
+
104
+ // Return filtered messages if any were removed, otherwise no changes
105
+ if (filteredMessages.length !== messages.length) {
106
+ return {messages: filteredMessages};
107
+ }
108
+ return {}; // No modifications needed
109
+ };
110
+ }