centaurus-cli 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (552) hide show
  1. package/dist/ai/types.js +0 -1
  2. package/dist/ai/types.js.map +1 -1
  3. package/dist/cli-adapter.js +5047 -5158
  4. package/dist/cli-adapter.js.map +1 -1
  5. package/dist/commands/CommandParser.js +372 -315
  6. package/dist/commands/CommandParser.js.map +1 -1
  7. package/dist/config/build-config.js +11 -42
  8. package/dist/config/build-config.js.map +1 -1
  9. package/dist/config/defaultConfig.js +94 -82
  10. package/dist/config/defaultConfig.js.map +1 -1
  11. package/dist/config/manager.js +144 -160
  12. package/dist/config/manager.js.map +1 -1
  13. package/dist/config/mcp-config-manager.js +411 -364
  14. package/dist/config/mcp-config-manager.js.map +1 -1
  15. package/dist/config/models.js +118 -185
  16. package/dist/config/models.js.map +1 -1
  17. package/dist/config/slash-commands.js +186 -184
  18. package/dist/config/slash-commands.js.map +1 -1
  19. package/dist/config/types.js +33 -26
  20. package/dist/config/types.js.map +1 -1
  21. package/dist/context/command-detector.js +63 -67
  22. package/dist/context/command-detector.js.map +1 -1
  23. package/dist/context/context-manager.js +533 -518
  24. package/dist/context/context-manager.js.map +1 -1
  25. package/dist/context/handlers/docker-handler.js +518 -576
  26. package/dist/context/handlers/docker-handler.js.map +1 -1
  27. package/dist/context/handlers/ssh-handler.js +1050 -1109
  28. package/dist/context/handlers/ssh-handler.js.map +1 -1
  29. package/dist/context/handlers/wsl-handler.js +558 -630
  30. package/dist/context/handlers/wsl-handler.js.map +1 -1
  31. package/dist/context/index.js +42 -6
  32. package/dist/context/index.js.map +1 -1
  33. package/dist/context/subshell-handler.js +0 -4
  34. package/dist/context/subshell-handler.js.map +1 -1
  35. package/dist/context/types.js +20 -31
  36. package/dist/context/types.js.map +1 -1
  37. package/dist/hooks/useConnectivity.js +13 -10
  38. package/dist/hooks/useConnectivity.js.map +1 -1
  39. package/dist/hooks/useTerminalDimensions.js +67 -79
  40. package/dist/hooks/useTerminalDimensions.js.map +1 -1
  41. package/dist/index.js +228 -251
  42. package/dist/index.js.map +1 -1
  43. package/dist/mcp/mcp-command-handler.js +297 -260
  44. package/dist/mcp/mcp-command-handler.js.map +1 -1
  45. package/dist/mcp/mcp-server-manager.js +139 -155
  46. package/dist/mcp/mcp-server-manager.js.map +1 -1
  47. package/dist/mcp/mcp-tool-wrapper.js +74 -94
  48. package/dist/mcp/mcp-tool-wrapper.js.map +1 -1
  49. package/dist/services/ai-autocomplete-agent.js +169 -181
  50. package/dist/services/ai-autocomplete-agent.js.map +1 -1
  51. package/dist/services/ai-context-injector.js +180 -93
  52. package/dist/services/ai-context-injector.js.map +1 -1
  53. package/dist/services/ai-service-client.js +513 -456
  54. package/dist/services/ai-service-client.js.map +1 -1
  55. package/dist/services/api-client.js +443 -441
  56. package/dist/services/api-client.js.map +1 -1
  57. package/dist/services/auth-handler.js +162 -198
  58. package/dist/services/auth-handler.js.map +1 -1
  59. package/dist/services/background-task-manager.js +258 -282
  60. package/dist/services/background-task-manager.js.map +1 -1
  61. package/dist/services/checkpoint-manager.js +1526 -1512
  62. package/dist/services/checkpoint-manager.js.map +1 -1
  63. package/dist/services/clipboard-service.js +151 -200
  64. package/dist/services/clipboard-service.js.map +1 -1
  65. package/dist/services/connectivity-manager.js +63 -65
  66. package/dist/services/connectivity-manager.js.map +1 -1
  67. package/dist/services/conversation-manager.js +118 -121
  68. package/dist/services/conversation-manager.js.map +1 -1
  69. package/dist/services/environment-context-injector.js +160 -187
  70. package/dist/services/environment-context-injector.js.map +1 -1
  71. package/dist/services/fast-context-agent.js +203 -243
  72. package/dist/services/fast-context-agent.js.map +1 -1
  73. package/dist/services/input-detection-agent.js +190 -202
  74. package/dist/services/input-detection-agent.js.map +1 -1
  75. package/dist/services/input-requirement-detector.js +155 -189
  76. package/dist/services/input-requirement-detector.js.map +1 -1
  77. package/dist/services/local-chat-storage.js +342 -365
  78. package/dist/services/local-chat-storage.js.map +1 -1
  79. package/dist/services/monitored-shell-manager.js +225 -233
  80. package/dist/services/monitored-shell-manager.js.map +1 -1
  81. package/dist/services/ollama-service.js +293 -310
  82. package/dist/services/ollama-service.js.map +1 -1
  83. package/dist/services/rules-storage.js +142 -0
  84. package/dist/services/rules-storage.js.map +1 -0
  85. package/dist/services/session-quota-manager.js +219 -235
  86. package/dist/services/session-quota-manager.js.map +1 -1
  87. package/dist/services/shell-input-agent.js +299 -334
  88. package/dist/services/shell-input-agent.js.map +1 -1
  89. package/dist/services/sub-agent-manager.js +459 -501
  90. package/dist/services/sub-agent-manager.js.map +1 -1
  91. package/dist/services/warpify-detector.js +133 -183
  92. package/dist/services/warpify-detector.js.map +1 -1
  93. package/dist/services/workflow-storage.js +202 -217
  94. package/dist/services/workflow-storage.js.map +1 -1
  95. package/dist/test-ssh-handler.js +148 -193
  96. package/dist/test-ssh-handler.js.map +1 -1
  97. package/dist/tools/add-mcp.js +161 -0
  98. package/dist/tools/add-mcp.js.map +1 -0
  99. package/dist/tools/background-command.js +240 -273
  100. package/dist/tools/background-command.js.map +1 -1
  101. package/dist/tools/command.js +447 -440
  102. package/dist/tools/command.js.map +1 -1
  103. package/dist/tools/create-image.js +172 -202
  104. package/dist/tools/create-image.js.map +1 -1
  105. package/dist/tools/enter-remote-session.js +169 -215
  106. package/dist/tools/enter-remote-session.js.map +1 -1
  107. package/dist/tools/fast-context.js +60 -67
  108. package/dist/tools/fast-context.js.map +1 -1
  109. package/dist/tools/file-ops.js +601 -572
  110. package/dist/tools/file-ops.js.map +1 -1
  111. package/dist/tools/find-files.js +262 -303
  112. package/dist/tools/find-files.js.map +1 -1
  113. package/dist/tools/get-diff.js +423 -406
  114. package/dist/tools/get-diff.js.map +1 -1
  115. package/dist/tools/grep-search.js +966 -948
  116. package/dist/tools/grep-search.js.map +1 -1
  117. package/dist/tools/inspect-symbol.js +308 -323
  118. package/dist/tools/inspect-symbol.js.map +1 -1
  119. package/dist/tools/plan-mode.js +459 -503
  120. package/dist/tools/plan-mode.js.map +1 -1
  121. package/dist/tools/read-binary-file.js +160 -190
  122. package/dist/tools/read-binary-file.js.map +1 -1
  123. package/dist/tools/registry.js +100 -84
  124. package/dist/tools/registry.js.map +1 -1
  125. package/dist/tools/reproduce_issue.js +170 -151
  126. package/dist/tools/reproduce_issue.js.map +1 -1
  127. package/dist/tools/sub-agent.js +223 -228
  128. package/dist/tools/sub-agent.js.map +1 -1
  129. package/dist/tools/task-complete.js +28 -27
  130. package/dist/tools/task-complete.js.map +1 -1
  131. package/dist/tools/types.js +0 -1
  132. package/dist/tools/types.js.map +1 -1
  133. package/dist/tools/validation.js +96 -118
  134. package/dist/tools/validation.js.map +1 -1
  135. package/dist/tools/web-search.js +194 -194
  136. package/dist/tools/web-search.js.map +1 -1
  137. package/dist/tools/workflow-tool.js +77 -82
  138. package/dist/tools/workflow-tool.js.map +1 -1
  139. package/dist/types/index.js +0 -1
  140. package/dist/types/index.js.map +1 -1
  141. package/dist/types/rule.js +1 -0
  142. package/dist/types/rule.js.map +1 -0
  143. package/dist/types/workflow.js +0 -7
  144. package/dist/types/workflow.js.map +1 -1
  145. package/dist/ui/components/AgentTimer.js +24 -25
  146. package/dist/ui/components/AgentTimer.js.map +1 -1
  147. package/dist/ui/components/App.js +3266 -3263
  148. package/dist/ui/components/App.js.map +1 -1
  149. package/dist/ui/components/AuthScreen.js +22 -34
  150. package/dist/ui/components/AuthScreen.js.map +1 -1
  151. package/dist/ui/components/AuthWelcomeScreen.js +30 -24
  152. package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
  153. package/dist/ui/components/Breadcrumbs.js +53 -82
  154. package/dist/ui/components/Breadcrumbs.js.map +1 -1
  155. package/dist/ui/components/CircularSelectInput.js +59 -67
  156. package/dist/ui/components/CircularSelectInput.js.map +1 -1
  157. package/dist/ui/components/ClipboardFileAutocomplete.js +78 -39
  158. package/dist/ui/components/ClipboardFileAutocomplete.js.map +1 -1
  159. package/dist/ui/components/CodeBlock.js +24 -42
  160. package/dist/ui/components/CodeBlock.js.map +1 -1
  161. package/dist/ui/components/ConfigViewer.js +18 -25
  162. package/dist/ui/components/ConfigViewer.js.map +1 -1
  163. package/dist/ui/components/ConfirmPrompt.js +49 -71
  164. package/dist/ui/components/ConfirmPrompt.js.map +1 -1
  165. package/dist/ui/components/ConnectionStatusMessage.js +32 -83
  166. package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
  167. package/dist/ui/components/ContextWindowIndicator.js +34 -49
  168. package/dist/ui/components/ContextWindowIndicator.js.map +1 -1
  169. package/dist/ui/components/DetailedPlanReviewScreen.js +104 -106
  170. package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
  171. package/dist/ui/components/DiffViewer.js +68 -121
  172. package/dist/ui/components/DiffViewer.js.map +1 -1
  173. package/dist/ui/components/ErrorBoundary.js +40 -48
  174. package/dist/ui/components/ErrorBoundary.js.map +1 -1
  175. package/dist/ui/components/FileCreationPreview.js +29 -60
  176. package/dist/ui/components/FileCreationPreview.js.map +1 -1
  177. package/dist/ui/components/FileOperation.js +34 -29
  178. package/dist/ui/components/FileOperation.js.map +1 -1
  179. package/dist/ui/components/FileTagAutocomplete.js +55 -25
  180. package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
  181. package/dist/ui/components/FontRecommendation.js.map +1 -1
  182. package/dist/ui/components/GitDiffBreadcrumb.js +29 -0
  183. package/dist/ui/components/GitDiffBreadcrumb.js.map +1 -0
  184. package/dist/ui/components/InputBox.js +1620 -2150
  185. package/dist/ui/components/InputBox.js.map +1 -1
  186. package/dist/ui/components/InteractiveShell.js +234 -352
  187. package/dist/ui/components/InteractiveShell.js.map +1 -1
  188. package/dist/ui/components/KeyboardHelp.js +34 -35
  189. package/dist/ui/components/KeyboardHelp.js.map +1 -1
  190. package/dist/ui/components/LoadingIndicator.js +22 -25
  191. package/dist/ui/components/LoadingIndicator.js.map +1 -1
  192. package/dist/ui/components/MCPAddScreen.js +40 -51
  193. package/dist/ui/components/MCPAddScreen.js.map +1 -1
  194. package/dist/ui/components/MCPListScreen.js +40 -48
  195. package/dist/ui/components/MCPListScreen.js.map +1 -1
  196. package/dist/ui/components/MCPServerListScreen.js +49 -56
  197. package/dist/ui/components/MCPServerListScreen.js.map +1 -1
  198. package/dist/ui/components/MarkdownRenderer.js +69 -96
  199. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  200. package/dist/ui/components/MessageBox.js +66 -48
  201. package/dist/ui/components/MessageBox.js.map +1 -1
  202. package/dist/ui/components/MessageDisplay.js +150 -142
  203. package/dist/ui/components/MessageDisplay.js.map +1 -1
  204. package/dist/ui/components/MonitorModeAIPanel.js +46 -65
  205. package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
  206. package/dist/ui/components/MultiLineInput.js +243 -277
  207. package/dist/ui/components/MultiLineInput.js.map +1 -1
  208. package/dist/ui/components/PasswordPrompt.js +37 -18
  209. package/dist/ui/components/PasswordPrompt.js.map +1 -1
  210. package/dist/ui/components/PlanAcceptedMessage.js +27 -38
  211. package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
  212. package/dist/ui/components/PlanReviewScreen.js +46 -50
  213. package/dist/ui/components/PlanReviewScreen.js.map +1 -1
  214. package/dist/ui/components/RulesEditorScreen.js +81 -0
  215. package/dist/ui/components/RulesEditorScreen.js.map +1 -0
  216. package/dist/ui/components/SelectPrompt.js +19 -8
  217. package/dist/ui/components/SelectPrompt.js.map +1 -1
  218. package/dist/ui/components/ShimmerText.js +44 -0
  219. package/dist/ui/components/ShimmerText.js.map +1 -0
  220. package/dist/ui/components/SlashCommandAutocomplete.js +49 -22
  221. package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
  222. package/dist/ui/components/StatusBar.js +56 -87
  223. package/dist/ui/components/StatusBar.js.map +1 -1
  224. package/dist/ui/components/StreamingMessageDisplay.js +116 -99
  225. package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
  226. package/dist/ui/components/TaskCompletedMessage.js +28 -23
  227. package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
  228. package/dist/ui/components/TaskProgressIndicator.js +44 -70
  229. package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
  230. package/dist/ui/components/ThinkingDisplay.js +44 -41
  231. package/dist/ui/components/ThinkingDisplay.js.map +1 -1
  232. package/dist/ui/components/ToolExecutionMessage.js +772 -1326
  233. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  234. package/dist/ui/components/ToolExecutionStatus.js +53 -84
  235. package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
  236. package/dist/ui/components/ToolResult.js +22 -15
  237. package/dist/ui/components/ToolResult.js.map +1 -1
  238. package/dist/ui/components/VersionUpdatePrompt.js +88 -120
  239. package/dist/ui/components/VersionUpdatePrompt.js.map +1 -1
  240. package/dist/ui/components/WelcomeBanner.js +176 -26
  241. package/dist/ui/components/WelcomeBanner.js.map +1 -1
  242. package/dist/ui/components/WorkflowCreatorScreen.js +94 -161
  243. package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
  244. package/dist/utils/ansi-encoder.js +30 -61
  245. package/dist/utils/ansi-encoder.js.map +1 -1
  246. package/dist/utils/chat-formatter.js +327 -305
  247. package/dist/utils/chat-formatter.js.map +1 -1
  248. package/dist/utils/command-history.js +152 -174
  249. package/dist/utils/command-history.js.map +1 -1
  250. package/dist/utils/context-sanitizer.js +49 -112
  251. package/dist/utils/context-sanitizer.js.map +1 -1
  252. package/dist/utils/conversation-logger.js +292 -324
  253. package/dist/utils/conversation-logger.js.map +1 -1
  254. package/dist/utils/custom-commands-manager.js +126 -131
  255. package/dist/utils/custom-commands-manager.js.map +1 -1
  256. package/dist/utils/editor-utils.js +732 -837
  257. package/dist/utils/editor-utils.js.map +1 -1
  258. package/dist/utils/file.js +174 -213
  259. package/dist/utils/file.js.map +1 -1
  260. package/dist/utils/git-stats.js +169 -0
  261. package/dist/utils/git-stats.js.map +1 -0
  262. package/dist/utils/input-classifier.js +960 -482
  263. package/dist/utils/input-classifier.js.map +1 -1
  264. package/dist/utils/logger.js +48 -73
  265. package/dist/utils/logger.js.map +1 -1
  266. package/dist/utils/markdown-parser.js +277 -310
  267. package/dist/utils/markdown-parser.js.map +1 -1
  268. package/dist/utils/rule-reference-resolver.js +54 -0
  269. package/dist/utils/rule-reference-resolver.js.map +1 -0
  270. package/dist/utils/shell.js +144 -156
  271. package/dist/utils/shell.js.map +1 -1
  272. package/dist/utils/state.js +23 -22
  273. package/dist/utils/state.js.map +1 -1
  274. package/dist/utils/syntax-checker.js +279 -327
  275. package/dist/utils/syntax-checker.js.map +1 -1
  276. package/dist/utils/terminal-output.js +199 -302
  277. package/dist/utils/terminal-output.js.map +1 -1
  278. package/dist/utils/text-clipboard.js +47 -70
  279. package/dist/utils/text-clipboard.js.map +1 -1
  280. package/dist/utils/unicode-sanitizer.js +134 -197
  281. package/dist/utils/unicode-sanitizer.js.map +1 -1
  282. package/dist/utils/version-checker.js +46 -56
  283. package/dist/utils/version-checker.js.map +1 -1
  284. package/package.json +6 -4
  285. package/dist/ai/types.d.ts +0 -20
  286. package/dist/ai/types.d.ts.map +0 -1
  287. package/dist/cli-adapter.d.ts +0 -514
  288. package/dist/cli-adapter.d.ts.map +0 -1
  289. package/dist/commands/CommandParser.d.ts +0 -27
  290. package/dist/commands/CommandParser.d.ts.map +0 -1
  291. package/dist/config/build-config.d.ts +0 -42
  292. package/dist/config/build-config.d.ts.map +0 -1
  293. package/dist/config/defaultConfig.d.ts +0 -79
  294. package/dist/config/defaultConfig.d.ts.map +0 -1
  295. package/dist/config/manager.d.ts +0 -62
  296. package/dist/config/manager.d.ts.map +0 -1
  297. package/dist/config/mcp-config-manager.d.ts +0 -79
  298. package/dist/config/mcp-config-manager.d.ts.map +0 -1
  299. package/dist/config/models.d.ts +0 -83
  300. package/dist/config/models.d.ts.map +0 -1
  301. package/dist/config/slash-commands.d.ts +0 -23
  302. package/dist/config/slash-commands.d.ts.map +0 -1
  303. package/dist/config/types.d.ts +0 -35
  304. package/dist/config/types.d.ts.map +0 -1
  305. package/dist/context/command-detector.d.ts +0 -50
  306. package/dist/context/command-detector.d.ts.map +0 -1
  307. package/dist/context/context-manager.d.ts +0 -157
  308. package/dist/context/context-manager.d.ts.map +0 -1
  309. package/dist/context/handlers/docker-handler.d.ts +0 -130
  310. package/dist/context/handlers/docker-handler.d.ts.map +0 -1
  311. package/dist/context/handlers/ssh-handler.d.ts +0 -201
  312. package/dist/context/handlers/ssh-handler.d.ts.map +0 -1
  313. package/dist/context/handlers/wsl-handler.d.ts +0 -146
  314. package/dist/context/handlers/wsl-handler.d.ts.map +0 -1
  315. package/dist/context/index.d.ts +0 -8
  316. package/dist/context/index.d.ts.map +0 -1
  317. package/dist/context/subshell-handler.d.ts +0 -165
  318. package/dist/context/subshell-handler.d.ts.map +0 -1
  319. package/dist/context/types.d.ts +0 -70
  320. package/dist/context/types.d.ts.map +0 -1
  321. package/dist/hooks/useConnectivity.d.ts +0 -2
  322. package/dist/hooks/useConnectivity.d.ts.map +0 -1
  323. package/dist/hooks/useTerminalDimensions.d.ts +0 -41
  324. package/dist/hooks/useTerminalDimensions.d.ts.map +0 -1
  325. package/dist/index.d.ts +0 -9
  326. package/dist/index.d.ts.map +0 -1
  327. package/dist/mcp/mcp-command-handler.d.ts +0 -47
  328. package/dist/mcp/mcp-command-handler.d.ts.map +0 -1
  329. package/dist/mcp/mcp-server-manager.d.ts +0 -30
  330. package/dist/mcp/mcp-server-manager.d.ts.map +0 -1
  331. package/dist/mcp/mcp-tool-wrapper.d.ts +0 -12
  332. package/dist/mcp/mcp-tool-wrapper.d.ts.map +0 -1
  333. package/dist/services/ai-autocomplete-agent.d.ts +0 -39
  334. package/dist/services/ai-autocomplete-agent.d.ts.map +0 -1
  335. package/dist/services/ai-context-injector.d.ts +0 -41
  336. package/dist/services/ai-context-injector.d.ts.map +0 -1
  337. package/dist/services/ai-service-client.d.ts +0 -128
  338. package/dist/services/ai-service-client.d.ts.map +0 -1
  339. package/dist/services/api-client.d.ts +0 -353
  340. package/dist/services/api-client.d.ts.map +0 -1
  341. package/dist/services/auth-handler.d.ts +0 -30
  342. package/dist/services/auth-handler.d.ts.map +0 -1
  343. package/dist/services/background-task-manager.d.ts +0 -114
  344. package/dist/services/background-task-manager.d.ts.map +0 -1
  345. package/dist/services/checkpoint-manager.d.ts +0 -204
  346. package/dist/services/checkpoint-manager.d.ts.map +0 -1
  347. package/dist/services/clipboard-service.d.ts +0 -37
  348. package/dist/services/clipboard-service.d.ts.map +0 -1
  349. package/dist/services/connectivity-manager.d.ts +0 -18
  350. package/dist/services/connectivity-manager.d.ts.map +0 -1
  351. package/dist/services/conversation-manager.d.ts +0 -73
  352. package/dist/services/conversation-manager.d.ts.map +0 -1
  353. package/dist/services/environment-context-injector.d.ts +0 -69
  354. package/dist/services/environment-context-injector.d.ts.map +0 -1
  355. package/dist/services/fast-context-agent.d.ts +0 -12
  356. package/dist/services/fast-context-agent.d.ts.map +0 -1
  357. package/dist/services/input-detection-agent.d.ts +0 -40
  358. package/dist/services/input-detection-agent.d.ts.map +0 -1
  359. package/dist/services/input-requirement-detector.d.ts +0 -28
  360. package/dist/services/input-requirement-detector.d.ts.map +0 -1
  361. package/dist/services/local-chat-storage.d.ts +0 -182
  362. package/dist/services/local-chat-storage.d.ts.map +0 -1
  363. package/dist/services/monitored-shell-manager.d.ts +0 -120
  364. package/dist/services/monitored-shell-manager.d.ts.map +0 -1
  365. package/dist/services/ollama-service.d.ts +0 -197
  366. package/dist/services/ollama-service.d.ts.map +0 -1
  367. package/dist/services/session-quota-manager.d.ts +0 -101
  368. package/dist/services/session-quota-manager.d.ts.map +0 -1
  369. package/dist/services/shell-input-agent.d.ts +0 -89
  370. package/dist/services/shell-input-agent.d.ts.map +0 -1
  371. package/dist/services/sub-agent-manager.d.ts +0 -140
  372. package/dist/services/sub-agent-manager.d.ts.map +0 -1
  373. package/dist/services/warpify-detector.d.ts +0 -43
  374. package/dist/services/warpify-detector.d.ts.map +0 -1
  375. package/dist/services/workflow-storage.d.ts +0 -72
  376. package/dist/services/workflow-storage.d.ts.map +0 -1
  377. package/dist/test-ssh-handler.d.ts +0 -8
  378. package/dist/test-ssh-handler.d.ts.map +0 -1
  379. package/dist/tools/background-command.d.ts +0 -11
  380. package/dist/tools/background-command.d.ts.map +0 -1
  381. package/dist/tools/command.d.ts +0 -3
  382. package/dist/tools/command.d.ts.map +0 -1
  383. package/dist/tools/create-image.d.ts +0 -10
  384. package/dist/tools/create-image.d.ts.map +0 -1
  385. package/dist/tools/enter-remote-session.d.ts +0 -48
  386. package/dist/tools/enter-remote-session.d.ts.map +0 -1
  387. package/dist/tools/fast-context.d.ts +0 -3
  388. package/dist/tools/fast-context.d.ts.map +0 -1
  389. package/dist/tools/file-ops.d.ts +0 -7
  390. package/dist/tools/file-ops.d.ts.map +0 -1
  391. package/dist/tools/find-files.d.ts +0 -49
  392. package/dist/tools/find-files.d.ts.map +0 -1
  393. package/dist/tools/get-diff.d.ts +0 -14
  394. package/dist/tools/get-diff.d.ts.map +0 -1
  395. package/dist/tools/grep-search.d.ts +0 -155
  396. package/dist/tools/grep-search.d.ts.map +0 -1
  397. package/dist/tools/inspect-symbol.d.ts +0 -32
  398. package/dist/tools/inspect-symbol.d.ts.map +0 -1
  399. package/dist/tools/plan-mode.d.ts +0 -140
  400. package/dist/tools/plan-mode.d.ts.map +0 -1
  401. package/dist/tools/read-binary-file.d.ts +0 -10
  402. package/dist/tools/read-binary-file.d.ts.map +0 -1
  403. package/dist/tools/registry.d.ts +0 -31
  404. package/dist/tools/registry.d.ts.map +0 -1
  405. package/dist/tools/reproduce_issue.d.ts +0 -2
  406. package/dist/tools/reproduce_issue.d.ts.map +0 -1
  407. package/dist/tools/sub-agent.d.ts +0 -9
  408. package/dist/tools/sub-agent.d.ts.map +0 -1
  409. package/dist/tools/task-complete.d.ts +0 -3
  410. package/dist/tools/task-complete.d.ts.map +0 -1
  411. package/dist/tools/types.d.ts +0 -40
  412. package/dist/tools/types.d.ts.map +0 -1
  413. package/dist/tools/validation.d.ts +0 -47
  414. package/dist/tools/validation.d.ts.map +0 -1
  415. package/dist/tools/web-search.d.ts +0 -24
  416. package/dist/tools/web-search.d.ts.map +0 -1
  417. package/dist/tools/workflow-tool.d.ts +0 -11
  418. package/dist/tools/workflow-tool.d.ts.map +0 -1
  419. package/dist/types/index.d.ts +0 -123
  420. package/dist/types/index.d.ts.map +0 -1
  421. package/dist/types/workflow.d.ts +0 -110
  422. package/dist/types/workflow.d.ts.map +0 -1
  423. package/dist/ui/components/AgentTimer.d.ts +0 -7
  424. package/dist/ui/components/AgentTimer.d.ts.map +0 -1
  425. package/dist/ui/components/App.d.ts +0 -197
  426. package/dist/ui/components/App.d.ts.map +0 -1
  427. package/dist/ui/components/AuthScreen.d.ts +0 -8
  428. package/dist/ui/components/AuthScreen.d.ts.map +0 -1
  429. package/dist/ui/components/AuthWelcomeScreen.d.ts +0 -8
  430. package/dist/ui/components/AuthWelcomeScreen.d.ts.map +0 -1
  431. package/dist/ui/components/Breadcrumbs.d.ts +0 -13
  432. package/dist/ui/components/Breadcrumbs.d.ts.map +0 -1
  433. package/dist/ui/components/CircularSelectInput.d.ts +0 -24
  434. package/dist/ui/components/CircularSelectInput.d.ts.map +0 -1
  435. package/dist/ui/components/ClipboardFileAutocomplete.d.ts +0 -10
  436. package/dist/ui/components/ClipboardFileAutocomplete.d.ts.map +0 -1
  437. package/dist/ui/components/CodeBlock.d.ts +0 -9
  438. package/dist/ui/components/CodeBlock.d.ts.map +0 -1
  439. package/dist/ui/components/ConfigViewer.d.ts +0 -11
  440. package/dist/ui/components/ConfigViewer.d.ts.map +0 -1
  441. package/dist/ui/components/ConfirmPrompt.d.ts +0 -13
  442. package/dist/ui/components/ConfirmPrompt.d.ts.map +0 -1
  443. package/dist/ui/components/ConnectionStatusMessage.d.ts +0 -17
  444. package/dist/ui/components/ConnectionStatusMessage.d.ts.map +0 -1
  445. package/dist/ui/components/ContextWindowIndicator.d.ts +0 -8
  446. package/dist/ui/components/ContextWindowIndicator.d.ts.map +0 -1
  447. package/dist/ui/components/DetailedPlanReviewScreen.d.ts +0 -17
  448. package/dist/ui/components/DetailedPlanReviewScreen.d.ts.map +0 -1
  449. package/dist/ui/components/DiffViewer.d.ts +0 -9
  450. package/dist/ui/components/DiffViewer.d.ts.map +0 -1
  451. package/dist/ui/components/ErrorBoundary.d.ts +0 -17
  452. package/dist/ui/components/ErrorBoundary.d.ts.map +0 -1
  453. package/dist/ui/components/FileCreationPreview.d.ts +0 -8
  454. package/dist/ui/components/FileCreationPreview.d.ts.map +0 -1
  455. package/dist/ui/components/FileOperation.d.ts +0 -10
  456. package/dist/ui/components/FileOperation.d.ts.map +0 -1
  457. package/dist/ui/components/FileTagAutocomplete.d.ts +0 -11
  458. package/dist/ui/components/FileTagAutocomplete.d.ts.map +0 -1
  459. package/dist/ui/components/FontRecommendation.d.ts +0 -1
  460. package/dist/ui/components/FontRecommendation.d.ts.map +0 -1
  461. package/dist/ui/components/InputBox.d.ts +0 -42
  462. package/dist/ui/components/InputBox.d.ts.map +0 -1
  463. package/dist/ui/components/InteractiveShell.d.ts +0 -30
  464. package/dist/ui/components/InteractiveShell.d.ts.map +0 -1
  465. package/dist/ui/components/KeyboardHelp.d.ts +0 -7
  466. package/dist/ui/components/KeyboardHelp.d.ts.map +0 -1
  467. package/dist/ui/components/LoadingIndicator.d.ts +0 -3
  468. package/dist/ui/components/LoadingIndicator.d.ts.map +0 -1
  469. package/dist/ui/components/MCPAddScreen.d.ts +0 -13
  470. package/dist/ui/components/MCPAddScreen.d.ts.map +0 -1
  471. package/dist/ui/components/MCPListScreen.d.ts +0 -17
  472. package/dist/ui/components/MCPListScreen.d.ts.map +0 -1
  473. package/dist/ui/components/MCPServerListScreen.d.ts +0 -16
  474. package/dist/ui/components/MCPServerListScreen.d.ts.map +0 -1
  475. package/dist/ui/components/MarkdownRenderer.d.ts +0 -8
  476. package/dist/ui/components/MarkdownRenderer.d.ts.map +0 -1
  477. package/dist/ui/components/MessageBox.d.ts +0 -10
  478. package/dist/ui/components/MessageBox.d.ts.map +0 -1
  479. package/dist/ui/components/MessageDisplay.d.ts +0 -14
  480. package/dist/ui/components/MessageDisplay.d.ts.map +0 -1
  481. package/dist/ui/components/MonitorModeAIPanel.d.ts +0 -23
  482. package/dist/ui/components/MonitorModeAIPanel.d.ts.map +0 -1
  483. package/dist/ui/components/MultiLineInput.d.ts +0 -13
  484. package/dist/ui/components/MultiLineInput.d.ts.map +0 -1
  485. package/dist/ui/components/PasswordPrompt.d.ts +0 -9
  486. package/dist/ui/components/PasswordPrompt.d.ts.map +0 -1
  487. package/dist/ui/components/PlanAcceptedMessage.d.ts +0 -20
  488. package/dist/ui/components/PlanAcceptedMessage.d.ts.map +0 -1
  489. package/dist/ui/components/PlanReviewScreen.d.ts +0 -14
  490. package/dist/ui/components/PlanReviewScreen.d.ts.map +0 -1
  491. package/dist/ui/components/SelectPrompt.d.ts +0 -12
  492. package/dist/ui/components/SelectPrompt.d.ts.map +0 -1
  493. package/dist/ui/components/SlashCommandAutocomplete.d.ts +0 -13
  494. package/dist/ui/components/SlashCommandAutocomplete.d.ts.map +0 -1
  495. package/dist/ui/components/StatusBar.d.ts +0 -14
  496. package/dist/ui/components/StatusBar.d.ts.map +0 -1
  497. package/dist/ui/components/StreamingMessageDisplay.d.ts +0 -15
  498. package/dist/ui/components/StreamingMessageDisplay.d.ts.map +0 -1
  499. package/dist/ui/components/TaskCompletedMessage.d.ts +0 -14
  500. package/dist/ui/components/TaskCompletedMessage.d.ts.map +0 -1
  501. package/dist/ui/components/TaskProgressIndicator.d.ts +0 -18
  502. package/dist/ui/components/TaskProgressIndicator.d.ts.map +0 -1
  503. package/dist/ui/components/ThinkingDisplay.d.ts +0 -15
  504. package/dist/ui/components/ThinkingDisplay.d.ts.map +0 -1
  505. package/dist/ui/components/ToolExecutionMessage.d.ts +0 -8
  506. package/dist/ui/components/ToolExecutionMessage.d.ts.map +0 -1
  507. package/dist/ui/components/ToolExecutionStatus.d.ts +0 -10
  508. package/dist/ui/components/ToolExecutionStatus.d.ts.map +0 -1
  509. package/dist/ui/components/ToolResult.d.ts +0 -10
  510. package/dist/ui/components/ToolResult.d.ts.map +0 -1
  511. package/dist/ui/components/VersionUpdatePrompt.d.ts +0 -9
  512. package/dist/ui/components/VersionUpdatePrompt.d.ts.map +0 -1
  513. package/dist/ui/components/WelcomeBanner.d.ts +0 -3
  514. package/dist/ui/components/WelcomeBanner.d.ts.map +0 -1
  515. package/dist/ui/components/WorkflowCreatorScreen.d.ts +0 -25
  516. package/dist/ui/components/WorkflowCreatorScreen.d.ts.map +0 -1
  517. package/dist/utils/ansi-encoder.d.ts +0 -7
  518. package/dist/utils/ansi-encoder.d.ts.map +0 -1
  519. package/dist/utils/chat-formatter.d.ts +0 -12
  520. package/dist/utils/chat-formatter.d.ts.map +0 -1
  521. package/dist/utils/command-history.d.ts +0 -24
  522. package/dist/utils/command-history.d.ts.map +0 -1
  523. package/dist/utils/context-sanitizer.d.ts +0 -50
  524. package/dist/utils/context-sanitizer.d.ts.map +0 -1
  525. package/dist/utils/conversation-logger.d.ts +0 -142
  526. package/dist/utils/conversation-logger.d.ts.map +0 -1
  527. package/dist/utils/custom-commands-manager.d.ts +0 -59
  528. package/dist/utils/custom-commands-manager.d.ts.map +0 -1
  529. package/dist/utils/editor-utils.d.ts +0 -101
  530. package/dist/utils/editor-utils.d.ts.map +0 -1
  531. package/dist/utils/file.d.ts +0 -61
  532. package/dist/utils/file.d.ts.map +0 -1
  533. package/dist/utils/input-classifier.d.ts +0 -25
  534. package/dist/utils/input-classifier.d.ts.map +0 -1
  535. package/dist/utils/logger.d.ts +0 -17
  536. package/dist/utils/logger.d.ts.map +0 -1
  537. package/dist/utils/markdown-parser.d.ts +0 -60
  538. package/dist/utils/markdown-parser.d.ts.map +0 -1
  539. package/dist/utils/shell.d.ts +0 -47
  540. package/dist/utils/shell.d.ts.map +0 -1
  541. package/dist/utils/state.d.ts +0 -13
  542. package/dist/utils/state.d.ts.map +0 -1
  543. package/dist/utils/syntax-checker.d.ts +0 -24
  544. package/dist/utils/syntax-checker.d.ts.map +0 -1
  545. package/dist/utils/terminal-output.d.ts +0 -25
  546. package/dist/utils/terminal-output.d.ts.map +0 -1
  547. package/dist/utils/text-clipboard.d.ts +0 -12
  548. package/dist/utils/text-clipboard.d.ts.map +0 -1
  549. package/dist/utils/unicode-sanitizer.d.ts +0 -44
  550. package/dist/utils/unicode-sanitizer.d.ts.map +0 -1
  551. package/dist/utils/version-checker.d.ts +0 -14
  552. package/dist/utils/version-checker.d.ts.map +0 -1
@@ -1,484 +1,541 @@
1
- /**
2
- * AI Service Client
3
- *
4
- * Handles communication with the backend AI proxy service for streaming
5
- * AI chat requests. Replaces direct Gemini SDK usage in the CLI.
6
- */
7
- import { apiClient } from './api-client.js';
8
- import { readFileSync, existsSync } from 'fs';
9
- import { join } from 'path';
10
- import { homedir } from 'os';
11
- import { IS_DEV_BUILD, DEV_BACKEND_URL, PRODUCTION_BACKEND_URL } from '../config/build-config.js';
12
- import { logWarning } from '../utils/logger.js';
13
- import { ollamaService, OllamaService } from './ollama-service.js';
14
- import { quickLog } from '../utils/conversation-logger.js';
15
- /**
16
- * AI Service Client for streaming chat requests to backend
17
- */
18
- export class AIServiceClient {
19
- baseURL;
20
- maxRetries = 3;
21
- retryDelay = 1000; // Start with 1 second
22
- constructor() {
23
- // Don't set baseURL yet - lazy load it when first used
24
- // This allows environment variables to be loaded first
25
- this.baseURL = '';
1
+ import { apiClient } from "./api-client.js";
2
+ import { readFileSync, existsSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ import { IS_DEV_BUILD, DEV_BACKEND_URL, PRODUCTION_BACKEND_URL } from "../config/build-config.js";
6
+ import { logWarning } from "../utils/logger.js";
7
+ import { ollamaService, OllamaService } from "./ollama-service.js";
8
+ import { quickLog } from "../utils/conversation-logger.js";
9
+ class AIServiceClient {
10
+ baseURL;
11
+ maxRetries = 5;
12
+ retryDelay = 1e3;
13
+ // Start with 1 second
14
+ maxRetryDelay = 3e4;
15
+ maxRetryAfterDelay = 6e4;
16
+ highDemandMessage = "Very high demand right now. Please wait and retry after some time.";
17
+ constructor() {
18
+ this.baseURL = "";
19
+ }
20
+ /**
21
+ * Get the base URL for API requests
22
+ * Lazy-loaded to ensure environment variables are loaded first
23
+ */
24
+ getBaseURL() {
25
+ if (!this.baseURL) {
26
+ this.baseURL = IS_DEV_BUILD ? DEV_BACKEND_URL : PRODUCTION_BACKEND_URL;
26
27
  }
27
- /**
28
- * Get the base URL for API requests
29
- * Lazy-loaded to ensure environment variables are loaded first
30
- */
31
- getBaseURL() {
32
- if (!this.baseURL) {
33
- // Import build config - values frozen at compile time for security
34
- // SECURITY: This prevents malicious .env files from overriding production URLs
35
- // Use production URL in production builds, localhost only in dev builds
36
- this.baseURL = IS_DEV_BUILD ? DEV_BACKEND_URL : PRODUCTION_BACKEND_URL;
37
- }
38
- return this.baseURL;
39
- }
40
- /**
41
- * Stream chat request to backend AI proxy
42
- *
43
- * @param model - The AI model to use (e.g., 'gemini-2.5-flash')
44
- * @param messages - Conversation history including system, user, assistant, and tool messages
45
- * @param tools - Available tool schemas for the AI to use
46
- * @param environmentContext - Optional environment context (OS, shell, cwd, etc.)
47
- * @param mode - Optional mode (default, plan, command)
48
- * @yields Stream chunks (text, tool calls, done, or error events)
49
- */
50
- async *streamChat(model, messages, tools, environmentContext, mode, thinkingConfig, abortSignal) {
51
- // Check if using a local Ollama model
52
- if (this.isUsingLocalModel()) {
53
- const localModel = this.getCurrentModel();
54
- const supportsTools = OllamaService.modelSupportsTools(localModel);
55
- quickLog(`[${new Date().toISOString()}] [AIServiceClient] Routing to local Ollama model: ${localModel}, supportsTools: ${supportsTools}\n`);
56
- // Show warning only if tools are provided but model doesn't support them
57
- if (tools.length > 0 && !supportsTools) {
58
- yield {
59
- type: 'text',
60
- content: `⚠️ Note: Model "${localModel}" does not support tool calling. Running in text-only mode.\n\n`,
61
- };
62
- }
63
- // Route to local Ollama with tools
64
- yield* this.streamLocalChat(localModel, messages, tools);
65
- return;
66
- }
67
- // Build request payload for cloud backend
68
- const payload = {
69
- model,
70
- messages,
71
- tools,
72
- stream: true,
73
- clientType: 'cli', // Tell backend this is a CLI request
74
- environmentContext,
75
- mode,
76
- thinkingConfig,
28
+ return this.baseURL;
29
+ }
30
+ /**
31
+ * Stream chat request to backend AI proxy
32
+ *
33
+ * @param model - The AI model to use (e.g., 'gemini-2.5-flash')
34
+ * @param messages - Conversation history including system, user, assistant, and tool messages
35
+ * @param tools - Available tool schemas for the AI to use
36
+ * @param environmentContext - Optional environment context (OS, shell, cwd, etc.)
37
+ * @param mode - Optional mode (default, plan, command)
38
+ * @yields Stream chunks (text, tool calls, done, or error events)
39
+ */
40
+ async *streamChat(model, messages, tools, environmentContext, mode, thinkingConfig, abortSignal) {
41
+ if (this.isUsingLocalModel()) {
42
+ const localModel = this.getCurrentModel();
43
+ const supportsTools = OllamaService.modelSupportsTools(localModel);
44
+ quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Routing to local Ollama model: ${localModel}, supportsTools: ${supportsTools}
45
+ `);
46
+ if (tools.length > 0 && !supportsTools) {
47
+ yield {
48
+ type: "text",
49
+ content: `\u26A0\uFE0F Note: Model "${localModel}" does not support tool calling. Running in text-only mode.
50
+
51
+ `
77
52
  };
78
- // Get authentication token from api client
79
- if (!apiClient.isAuthenticated()) {
53
+ }
54
+ yield* this.streamLocalChat(localModel, messages, tools);
55
+ return;
56
+ }
57
+ const payload = {
58
+ model,
59
+ messages,
60
+ tools,
61
+ stream: true,
62
+ clientType: "cli",
63
+ // Tell backend this is a CLI request
64
+ environmentContext,
65
+ mode,
66
+ thinkingConfig
67
+ };
68
+ if (!apiClient.isAuthenticated()) {
69
+ yield {
70
+ type: "error",
71
+ message: "Authentication required. Please sign in.",
72
+ code: "AUTH_REQUIRED"
73
+ };
74
+ return;
75
+ }
76
+ let lastError = null;
77
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
78
+ try {
79
+ const response = await fetch(`${this.getBaseURL()}/chat/completions`, {
80
+ method: "POST",
81
+ headers: {
82
+ "Content-Type": "application/json",
83
+ "Authorization": `Bearer ${this.getSessionToken()}`
84
+ },
85
+ body: JSON.stringify(payload),
86
+ signal: abortSignal
87
+ // Only abort when user explicitly cancels
88
+ });
89
+ if (!response.ok) {
90
+ const errorText = await response.text();
91
+ const parsedHttpError = this.parseHttpError(response.status, response.statusText, errorText);
92
+ if (response.status === 401) {
80
93
  yield {
81
- type: 'error',
82
- message: 'Authentication required. Please sign in.',
83
- code: 'AUTH_REQUIRED',
94
+ type: "error",
95
+ message: "Session expired. Please sign in again.",
96
+ code: "AUTH_REQUIRED"
84
97
  };
85
98
  return;
99
+ }
100
+ lastError = parsedHttpError;
101
+ if (this.isRetryableError(parsedHttpError.code, parsedHttpError.message, response.status) && attempt < this.maxRetries - 1) {
102
+ const retryAfterMs = this.getRetryAfterMs(response.headers);
103
+ await this.sleep(this.getRetryDelayMs(attempt, retryAfterMs));
104
+ continue;
105
+ }
106
+ if (this.isRateLimitError(parsedHttpError.code, parsedHttpError.message, response.status)) {
107
+ yield this.createHighDemandError();
108
+ return;
109
+ }
110
+ yield parsedHttpError;
111
+ return;
86
112
  }
87
- // Retry logic for transient errors
88
- let lastError = null;
89
- for (let attempt = 0; attempt < this.maxRetries; attempt++) {
90
- try {
91
- // Make fetch request to backend AI endpoint
92
- // NOTE: We intentionally do NOT set a timeout here because:
93
- // 1. Tool execution happens during streaming (in-stream execution)
94
- // 2. Interactive commands may require user input for arbitrary duration
95
- // 3. The only timeout should be explicit user cancellation via abortSignal
96
- // Connection issues will manifest as network errors, not timeouts
97
- const response = await fetch(`${this.getBaseURL()}/ai/chat`, {
98
- method: 'POST',
99
- headers: {
100
- 'Content-Type': 'application/json',
101
- 'Authorization': `Bearer ${this.getSessionToken()}`,
102
- },
103
- body: JSON.stringify(payload),
104
- signal: abortSignal, // Only abort when user explicitly cancels
105
- });
106
- // Check for HTTP errors
107
- if (!response.ok) {
108
- const errorText = await response.text();
109
- let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
110
- let errorCode = 'HTTP_ERROR';
111
- try {
112
- const errorData = JSON.parse(errorText);
113
- if (errorData.error) {
114
- errorMessage = errorData.error.message || errorMessage;
115
- errorCode = errorData.error.code || errorCode;
116
- }
117
- }
118
- catch {
119
- // If response is not JSON, use the text as message
120
- if (errorText) {
121
- errorMessage = errorText;
122
- }
123
- }
124
- // Handle specific error codes
125
- if (response.status === 401) {
126
- yield {
127
- type: 'error',
128
- message: 'Session expired. Please sign in again.',
129
- code: 'AUTH_REQUIRED',
130
- };
131
- return;
132
- }
133
- if (response.status === 429) {
134
- // Rate limit - don't retry immediately
135
- yield {
136
- type: 'error',
137
- message: 'Service temporarily unavailable due to high demand. Please try again in a moment.',
138
- code: 'RATE_LIMIT',
139
- };
140
- return;
141
- }
142
- if (response.status === 504) {
143
- // Timeout error - retryable
144
- lastError = {
145
- type: 'error',
146
- message: 'Request timed out. Retrying...',
147
- code: 'TIMEOUT',
148
- };
149
- if (attempt < this.maxRetries - 1) {
150
- await this.sleep(this.retryDelay * Math.pow(2, attempt));
151
- continue;
152
- }
153
- }
154
- // For other errors, yield and return
155
- yield {
156
- type: 'error',
157
- message: errorMessage,
158
- code: errorCode,
159
- };
160
- return;
161
- }
162
- // Parse SSE stream
163
- // We iterate manually to catch retryable errors from the stream
164
- let contentReceived = false;
165
- let shouldRetry = false;
166
- for await (const chunk of this.parseSSEStream(response.body)) {
167
- if (chunk.type === 'error') {
168
- // Check if this is a retryable error (like rate limit) AND we haven't sent partial content yet
169
- if (this.isRetryableError(chunk.code) && !contentReceived) {
170
- lastError = chunk;
171
- shouldRetry = true;
172
- break; // Break the stream loop to trigger retry
173
- }
174
- // Not retryable or content already sent - yield error and stop
175
- yield chunk;
176
- return;
177
- }
178
- // Mark that we've received content
179
- if (chunk.type !== 'done' && chunk.type !== 'thought' && chunk.type !== 'thinking_signature') {
180
- contentReceived = true;
181
- }
182
- yield chunk;
183
- }
184
- // If stream finished cleanly (without error chunk), we are done
185
- if (!shouldRetry) {
186
- return;
187
- }
188
- // If we need to retry, check attempts and wait
189
- if (attempt < this.maxRetries - 1) {
190
- // We're going to retry, so we need to wait for the backoff period
191
- await this.sleep(this.retryDelay * Math.pow(2, attempt));
192
- continue;
193
- }
194
- // If we've exhausted retries, we'll fall through to the end of the loop
195
- // and yield the lastError below
196
- }
197
- catch (error) {
198
- // Handle network errors
199
- if (error.name === 'TypeError' && error.message.includes('fetch')) {
200
- lastError = {
201
- type: 'error',
202
- message: 'Backend service is unreachable. Please check your connection.',
203
- code: 'NETWORK_ERROR',
204
- };
205
- }
206
- else if (error.name === 'AbortError' || error.name === 'TimeoutError') {
207
- lastError = {
208
- type: 'error',
209
- message: 'Request timed out. Please try again.',
210
- code: 'TIMEOUT',
211
- };
212
- }
213
- else {
214
- lastError = {
215
- type: 'error',
216
- message: error.message || 'Unknown error occurred',
217
- code: error.code || 'UNKNOWN_ERROR',
218
- };
219
- }
220
- // Retry for transient errors
221
- if (this.isRetryableError(lastError.code) && attempt < this.maxRetries - 1) {
222
- await this.sleep(this.retryDelay * Math.pow(2, attempt));
223
- continue;
224
- }
225
- // If not retryable or max retries reached, yield error and return
226
- break;
113
+ let contentReceived = false;
114
+ let shouldRetry = false;
115
+ for await (const chunk of this.parseSSEStream(response.body)) {
116
+ if (chunk.type === "error") {
117
+ const normalizedChunk = this.normalizeErrorChunk(chunk);
118
+ if (this.isRetryableError(normalizedChunk.code, normalizedChunk.message) && !contentReceived) {
119
+ lastError = normalizedChunk;
120
+ shouldRetry = true;
121
+ break;
227
122
  }
123
+ yield normalizedChunk;
124
+ return;
125
+ }
126
+ if (chunk.type !== "done" && chunk.type !== "thought" && chunk.type !== "thinking_signature" && chunk.type !== "file_descriptions") {
127
+ contentReceived = true;
128
+ }
129
+ yield chunk;
228
130
  }
229
- // If we get here, we've exhausted retries
230
- if (lastError) {
231
- yield lastError;
131
+ if (!shouldRetry) {
132
+ return;
232
133
  }
233
- }
234
- /**
235
- * Check if an error code is retryable
236
- */
237
- isRetryableError(code) {
238
- const retryableCodes = ['NETWORK_ERROR', 'TIMEOUT', 'UNKNOWN_ERROR', 'RATE_LIMIT'];
239
- return retryableCodes.includes(code);
240
- }
241
- /**
242
- * Sleep for specified milliseconds
243
- */
244
- sleep(ms) {
245
- return new Promise(resolve => setTimeout(resolve, ms));
246
- }
247
- /**
248
- * Get session token from apiClient
249
- * This is a workaround since sessionToken is private
250
- */
251
- getSessionToken() {
252
- // Read session token from the same location apiClient uses
253
- const configPath = join(homedir(), '.centaurus', 'session.json');
254
- try {
255
- if (existsSync(configPath)) {
256
- const data = readFileSync(configPath, 'utf-8');
257
- const session = JSON.parse(data);
258
- return session.sessionToken || '';
259
- }
134
+ if (attempt < this.maxRetries - 1) {
135
+ await this.sleep(this.getRetryDelayMs(attempt));
136
+ continue;
260
137
  }
261
- catch (error) {
262
- // Return empty string if unable to read
138
+ } catch (error) {
139
+ lastError = this.normalizeThrownError(error);
140
+ const wasIntentionalAbort = (error?.name === "AbortError" || error?.name === "TimeoutError") && !!abortSignal?.aborted;
141
+ if (wasIntentionalAbort) {
142
+ break;
263
143
  }
264
- return '';
265
- }
266
- /**
267
- * Check if the current configuration is using a local Ollama model
268
- */
269
- isUsingLocalModel() {
270
- const configPath = join(homedir(), '.centaurus', 'config.json');
271
- try {
272
- if (existsSync(configPath)) {
273
- const data = readFileSync(configPath, 'utf-8');
274
- const config = JSON.parse(data);
275
- return config.isLocalModel === true;
276
- }
277
- }
278
- catch (error) {
279
- // Return false if unable to read
144
+ if (this.isRetryableError(lastError.code, lastError.message) && attempt < this.maxRetries - 1) {
145
+ await this.sleep(this.getRetryDelayMs(attempt));
146
+ continue;
280
147
  }
281
- return false;
148
+ break;
149
+ }
282
150
  }
283
- /**
284
- * Get the current model name from config
285
- */
286
- getCurrentModel() {
287
- const configPath = join(homedir(), '.centaurus', 'config.json');
288
- try {
289
- if (existsSync(configPath)) {
290
- const data = readFileSync(configPath, 'utf-8');
291
- const config = JSON.parse(data);
292
- return config.model || 'gemini-2.5-flash';
293
- }
294
- }
295
- catch (error) {
296
- // Return default if unable to read
151
+ if (lastError) {
152
+ if (this.isRateLimitError(lastError.code, lastError.message)) {
153
+ yield this.createHighDemandError();
154
+ return;
155
+ }
156
+ yield lastError;
157
+ }
158
+ }
159
+ /**
160
+ * Create a normalized high-demand error response.
161
+ */
162
+ createHighDemandError() {
163
+ return {
164
+ type: "error",
165
+ message: this.highDemandMessage,
166
+ code: "RATE_LIMIT"
167
+ };
168
+ }
169
+ /**
170
+ * Parse backend HTTP error body into a normalized error chunk.
171
+ */
172
+ parseHttpError(status, statusText, errorText) {
173
+ let errorMessage = `HTTP ${status}: ${statusText}`;
174
+ let errorCode = "HTTP_ERROR";
175
+ if (errorText) {
176
+ try {
177
+ const parsed = JSON.parse(errorText);
178
+ const rootError = Array.isArray(parsed) ? parsed[0]?.error ?? parsed[0] : parsed?.error ?? parsed;
179
+ if (rootError) {
180
+ if (typeof rootError.message === "string" && rootError.message.trim()) {
181
+ errorMessage = rootError.message;
182
+ }
183
+ if (typeof rootError.code === "string" || typeof rootError.code === "number") {
184
+ errorCode = String(rootError.code);
185
+ } else if (typeof rootError.status === "string") {
186
+ errorCode = rootError.status;
187
+ }
297
188
  }
298
- return 'gemini-2.5-flash';
189
+ } catch {
190
+ errorMessage = errorText;
191
+ }
299
192
  }
300
- /**
301
- * Convert internal message format to Ollama format (with tool support)
302
- */
303
- convertToOllamaMessages(messages) {
304
- return messages.map(msg => {
305
- if (msg.role === 'tool') {
306
- // Tool results - convert to Ollama's tool message format
307
- return {
308
- role: 'tool',
309
- content: msg.content,
310
- tool_name: msg.tool_call_id || 'unknown', // Use tool_call_id as tool_name
311
- };
312
- }
313
- if (msg.role === 'assistant' && msg.tool_calls?.length) {
314
- // Assistant message with tool calls
315
- return {
316
- role: 'assistant',
317
- content: msg.content || '',
318
- tool_calls: msg.tool_calls.map(tc => ({
319
- function: {
320
- name: tc.name,
321
- arguments: tc.arguments,
322
- }
323
- })),
324
- };
325
- }
326
- // Regular message
327
- return {
328
- role: msg.role,
329
- content: msg.content,
330
- };
331
- });
193
+ if (status === 504) {
194
+ return {
195
+ type: "error",
196
+ message: "Request timed out. Please try again.",
197
+ code: "TIMEOUT"
198
+ };
332
199
  }
333
- /**
334
- * Convert ToolSchema array to Ollama tool format
335
- */
336
- convertToolsToOllamaFormat(tools) {
337
- return tools.map(tool => ({
338
- type: 'function',
339
- function: {
340
- name: tool.name,
341
- description: tool.description,
342
- parameters: {
343
- type: 'object',
344
- properties: tool.parameters.properties,
345
- required: tool.parameters.required,
346
- },
347
- },
348
- }));
200
+ if (this.isRateLimitError(errorCode, errorMessage, status)) {
201
+ return this.createHighDemandError();
349
202
  }
350
- /**
351
- * Stream chat request to local Ollama instance with tool calling support
352
- *
353
- * @param model - The local Ollama model to use (e.g., 'llama3.2:latest')
354
- * @param messages - Conversation history
355
- * @param tools - Available tools (will be converted to Ollama format)
356
- * @yields Stream chunks (text, tool_call, or done events)
357
- */
358
- async *streamLocalChat(model, messages, tools = []) {
359
- try {
360
- const supportsTools = OllamaService.modelSupportsTools(model);
361
- const effectiveTools = supportsTools ? tools : [];
362
- quickLog(`[${new Date().toISOString()}] [AIServiceClient] Starting local chat with model: ${model}, tools: ${effectiveTools.length}, supportsTools: ${supportsTools}\n`);
363
- // Convert messages to Ollama format
364
- const ollamaMessages = this.convertToOllamaMessages(messages);
365
- // Convert tools to Ollama format if model supports them
366
- const ollamaTools = effectiveTools.length > 0
367
- ? this.convertToolsToOllamaFormat(effectiveTools)
368
- : undefined;
369
- // Send request to Ollama with tools
370
- const response = await ollamaService.sendChatMessage(model, ollamaMessages, ollamaTools);
371
- // Check for tool calls in response
372
- if (response.message?.tool_calls?.length) {
373
- quickLog(`[${new Date().toISOString()}] [AIServiceClient] Received ${response.message.tool_calls.length} tool calls from Ollama\n`);
374
- // Yield each tool call
375
- for (const toolCall of response.message.tool_calls) {
376
- yield {
377
- type: 'tool_call',
378
- toolCall: {
379
- id: `ollama-${Date.now()}-${toolCall.function.name}`, // Generate unique ID
380
- name: toolCall.function.name,
381
- arguments: toolCall.function.arguments,
382
- },
383
- };
384
- }
385
- // Signal completion (tool execution will happen in cli-adapter)
386
- yield { type: 'done' };
387
- return;
388
- }
389
- // No tool calls - yield text response
390
- if (response.message.content) {
391
- yield {
392
- type: 'text',
393
- content: response.message.content,
394
- };
203
+ return {
204
+ type: "error",
205
+ message: errorMessage,
206
+ code: errorCode
207
+ };
208
+ }
209
+ /**
210
+ * Normalize streamed error chunks to stable internal codes/messages.
211
+ */
212
+ normalizeErrorChunk(chunk) {
213
+ const normalizedCode = chunk.code ? String(chunk.code) : "UNKNOWN_ERROR";
214
+ const normalizedMessage = chunk.message || "Unknown error occurred";
215
+ if (this.isRateLimitError(normalizedCode, normalizedMessage)) {
216
+ return this.createHighDemandError();
217
+ }
218
+ if (normalizedCode === "504") {
219
+ return {
220
+ type: "error",
221
+ message: "Request timed out. Please try again.",
222
+ code: "TIMEOUT"
223
+ };
224
+ }
225
+ return {
226
+ type: "error",
227
+ message: normalizedMessage,
228
+ code: normalizedCode
229
+ };
230
+ }
231
+ /**
232
+ * Normalize thrown errors from fetch/network/runtime paths.
233
+ */
234
+ normalizeThrownError(error) {
235
+ const rawMessage = error?.message || "Unknown error occurred";
236
+ const rawCode = error?.code ? String(error.code) : "UNKNOWN_ERROR";
237
+ if (this.isRateLimitError(rawCode, rawMessage, error?.status)) {
238
+ return this.createHighDemandError();
239
+ }
240
+ if (error?.name === "TypeError" && rawMessage.includes("fetch")) {
241
+ return {
242
+ type: "error",
243
+ message: "Backend service is unreachable. Please check your connection.",
244
+ code: "NETWORK_ERROR"
245
+ };
246
+ }
247
+ if (error?.name === "AbortError" || error?.name === "TimeoutError") {
248
+ return {
249
+ type: "error",
250
+ message: "Request timed out. Please try again.",
251
+ code: "TIMEOUT"
252
+ };
253
+ }
254
+ return {
255
+ type: "error",
256
+ message: rawMessage,
257
+ code: rawCode
258
+ };
259
+ }
260
+ /**
261
+ * Check if an error is a rate-limit/resource-exhausted signal.
262
+ */
263
+ isRateLimitError(code, message = "", status) {
264
+ const normalizedCode = (code || "").toString().toLowerCase();
265
+ const normalizedMessage = message.toLowerCase();
266
+ return status === 429 || normalizedCode === "429" || normalizedCode === "8" || normalizedCode === "rate_limit" || normalizedCode === "resource_exhausted" || normalizedMessage.includes("rate limit") || normalizedMessage.includes("too many requests") || normalizedMessage.includes("quota") || normalizedMessage.includes("resource exhausted") || normalizedMessage.includes("resource_exhausted") || normalizedMessage.includes("maas api returned 429");
267
+ }
268
+ /**
269
+ * Check if HTTP status is retryable.
270
+ */
271
+ isRetryableStatus(status) {
272
+ if (typeof status !== "number") {
273
+ return false;
274
+ }
275
+ return [408, 425, 429, 500, 502, 503, 504].includes(status);
276
+ }
277
+ /**
278
+ * Check if an error should be retried.
279
+ */
280
+ isRetryableError(code, message = "", status) {
281
+ if (this.isRateLimitError(code, message, status)) {
282
+ return true;
283
+ }
284
+ if (this.isRetryableStatus(status)) {
285
+ return true;
286
+ }
287
+ const retryableCodes = ["NETWORK_ERROR", "TIMEOUT", "UNKNOWN_ERROR", "RATE_LIMIT"];
288
+ if (retryableCodes.includes(code)) {
289
+ return true;
290
+ }
291
+ const normalizedMessage = message.toLowerCase();
292
+ return normalizedMessage.includes("timeout") || normalizedMessage.includes("timed out") || normalizedMessage.includes("temporarily unavailable") || normalizedMessage.includes("network error");
293
+ }
294
+ /**
295
+ * Parse Retry-After from response headers.
296
+ */
297
+ getRetryAfterMs(headers) {
298
+ const retryAfterValue = headers.get("retry-after");
299
+ if (!retryAfterValue) {
300
+ return void 0;
301
+ }
302
+ const seconds = Number(retryAfterValue);
303
+ if (Number.isFinite(seconds) && seconds >= 0) {
304
+ return seconds * 1e3;
305
+ }
306
+ const retryAfterDate = Date.parse(retryAfterValue);
307
+ if (!Number.isNaN(retryAfterDate)) {
308
+ return Math.max(0, retryAfterDate - Date.now());
309
+ }
310
+ return void 0;
311
+ }
312
+ /**
313
+ * Compute retry delay with exponential backoff + jitter.
314
+ */
315
+ getRetryDelayMs(attempt, retryAfterMs) {
316
+ const exponentialDelay = this.retryDelay * Math.pow(2, attempt);
317
+ const cappedDelay = Math.min(exponentialDelay, this.maxRetryDelay);
318
+ const jitteredDelay = Math.round(Math.min(cappedDelay * (0.5 + Math.random()), this.maxRetryDelay));
319
+ if (retryAfterMs === void 0) {
320
+ return jitteredDelay;
321
+ }
322
+ const cappedRetryAfter = Math.min(Math.max(0, retryAfterMs), this.maxRetryAfterDelay);
323
+ return Math.max(jitteredDelay, cappedRetryAfter);
324
+ }
325
+ /**
326
+ * Sleep for specified milliseconds
327
+ */
328
+ sleep(ms) {
329
+ return new Promise((resolve) => setTimeout(resolve, ms));
330
+ }
331
+ /**
332
+ * Get session token from apiClient
333
+ * This is a workaround since sessionToken is private
334
+ */
335
+ getSessionToken() {
336
+ const configPath = join(homedir(), ".centaurus", "session.json");
337
+ try {
338
+ if (existsSync(configPath)) {
339
+ const data = readFileSync(configPath, "utf-8");
340
+ const session = JSON.parse(data);
341
+ return session.sessionToken || "";
342
+ }
343
+ } catch (error) {
344
+ }
345
+ return "";
346
+ }
347
+ /**
348
+ * Check if the current configuration is using a local Ollama model
349
+ */
350
+ isUsingLocalModel() {
351
+ const configPath = join(homedir(), ".centaurus", "config.json");
352
+ try {
353
+ if (existsSync(configPath)) {
354
+ const data = readFileSync(configPath, "utf-8");
355
+ const config = JSON.parse(data);
356
+ return config.isLocalModel === true;
357
+ }
358
+ } catch (error) {
359
+ }
360
+ return false;
361
+ }
362
+ /**
363
+ * Get the current model name from config
364
+ */
365
+ getCurrentModel() {
366
+ const configPath = join(homedir(), ".centaurus", "config.json");
367
+ try {
368
+ if (existsSync(configPath)) {
369
+ const data = readFileSync(configPath, "utf-8");
370
+ const config = JSON.parse(data);
371
+ return config.model || "gemini-2.5-flash";
372
+ }
373
+ } catch (error) {
374
+ }
375
+ return "gemini-2.5-flash";
376
+ }
377
+ /**
378
+ * Convert internal message format to Ollama format (with tool support)
379
+ */
380
+ convertToOllamaMessages(messages) {
381
+ return messages.map((msg) => {
382
+ if (msg.role === "tool") {
383
+ return {
384
+ role: "tool",
385
+ content: msg.content,
386
+ tool_name: msg.tool_call_id || "unknown"
387
+ // Use tool_call_id as tool_name
388
+ };
389
+ }
390
+ if (msg.role === "assistant" && msg.tool_calls?.length) {
391
+ return {
392
+ role: "assistant",
393
+ content: msg.content || "",
394
+ tool_calls: msg.tool_calls.map((tc) => ({
395
+ function: {
396
+ name: tc.name,
397
+ arguments: tc.arguments
395
398
  }
396
- // Signal completion
397
- yield { type: 'done' };
398
- quickLog(`[${new Date().toISOString()}] [AIServiceClient] Local chat completed\n`);
399
+ }))
400
+ };
401
+ }
402
+ return {
403
+ role: msg.role,
404
+ content: msg.content
405
+ };
406
+ });
407
+ }
408
+ /**
409
+ * Convert ToolSchema array to Ollama tool format
410
+ */
411
+ convertToolsToOllamaFormat(tools) {
412
+ return tools.map((tool) => ({
413
+ type: "function",
414
+ function: {
415
+ name: tool.name,
416
+ description: tool.description,
417
+ parameters: {
418
+ type: "object",
419
+ properties: tool.parameters.properties,
420
+ required: tool.parameters.required
399
421
  }
400
- catch (error) {
401
- quickLog(`[${new Date().toISOString()}] [AIServiceClient] Local chat error: ${error.message}\n`);
402
- yield {
403
- type: 'error',
404
- message: error.message || 'Failed to communicate with Ollama',
405
- code: 'OLLAMA_ERROR',
406
- };
422
+ }
423
+ }));
424
+ }
425
+ /**
426
+ * Stream chat request to local Ollama instance with tool calling support
427
+ *
428
+ * @param model - The local Ollama model to use (e.g., 'llama3.2:latest')
429
+ * @param messages - Conversation history
430
+ * @param tools - Available tools (will be converted to Ollama format)
431
+ * @yields Stream chunks (text, tool_call, or done events)
432
+ */
433
+ async *streamLocalChat(model, messages, tools = []) {
434
+ try {
435
+ const supportsTools = OllamaService.modelSupportsTools(model);
436
+ const effectiveTools = supportsTools ? tools : [];
437
+ quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Starting local chat with model: ${model}, tools: ${effectiveTools.length}, supportsTools: ${supportsTools}
438
+ `);
439
+ const ollamaMessages = this.convertToOllamaMessages(messages);
440
+ const ollamaTools = effectiveTools.length > 0 ? this.convertToolsToOllamaFormat(effectiveTools) : void 0;
441
+ const response = await ollamaService.sendChatMessage(model, ollamaMessages, ollamaTools);
442
+ if (response.message?.tool_calls?.length) {
443
+ quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Received ${response.message.tool_calls.length} tool calls from Ollama
444
+ `);
445
+ for (const toolCall of response.message.tool_calls) {
446
+ yield {
447
+ type: "tool_call",
448
+ toolCall: {
449
+ id: `ollama-${Date.now()}-${toolCall.function.name}`,
450
+ // Generate unique ID
451
+ name: toolCall.function.name,
452
+ arguments: toolCall.function.arguments
453
+ }
454
+ };
407
455
  }
456
+ yield { type: "done" };
457
+ return;
458
+ }
459
+ if (response.message.content) {
460
+ yield {
461
+ type: "text",
462
+ content: response.message.content
463
+ };
464
+ }
465
+ yield { type: "done" };
466
+ quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Local chat completed
467
+ `);
468
+ } catch (error) {
469
+ quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Local chat error: ${error.message}
470
+ `);
471
+ yield {
472
+ type: "error",
473
+ message: error.message || "Failed to communicate with Ollama",
474
+ code: "OLLAMA_ERROR"
475
+ };
408
476
  }
409
- /**
410
- * Parse Server-Sent Events stream from response body
411
- *
412
- * @param body - ReadableStream from fetch response
413
- * @yields Parsed stream chunks
414
- */
415
- async *parseSSEStream(body) {
416
- const reader = body.getReader();
417
- const decoder = new TextDecoder();
418
- let buffer = '';
419
- try {
420
- while (true) {
421
- const { done, value } = await reader.read();
422
- if (done) {
423
- // Process any remaining data in buffer before exiting
424
- if (buffer.trim()) {
425
- // Split remaining buffer and process
426
- const remainingLines = buffer.split('\n');
427
- for (const line of remainingLines) {
428
- if (line.startsWith('data: ')) {
429
- const dataStr = line.slice(6);
430
- if (dataStr.trim()) {
431
- try {
432
- const chunk = JSON.parse(dataStr);
433
- yield chunk;
434
- }
435
- catch (error) {
436
- // Skip malformed JSON
437
- logWarning(`Failed to parse SSE data (in buffer): ${dataStr}`);
438
- }
439
- }
440
- }
441
- }
442
- }
443
- break;
444
- }
445
- // Decode chunk and add to buffer
446
- buffer += decoder.decode(value, { stream: true });
447
- // Process complete lines in buffer
448
- const lines = buffer.split('\n');
449
- // Keep the last incomplete line in buffer
450
- buffer = lines.pop() || '';
451
- for (const line of lines) {
452
- // SSE format: "data: {json}"
453
- if (line.startsWith('data: ')) {
454
- const dataStr = line.slice(6); // Remove "data: " prefix
455
- // Skip empty data lines
456
- if (!dataStr.trim()) {
457
- continue;
458
- }
459
- try {
460
- const chunk = JSON.parse(dataStr);
461
- yield chunk;
462
- // Stop if we receive a done or error event
463
- if (chunk.type === 'done' || chunk.type === 'error') {
464
- return;
465
- }
466
- }
467
- catch (error) {
468
- // Skip malformed JSON
469
- logWarning(`Failed to parse SSE data: ${dataStr}`);
470
- }
471
- }
472
- // SSE event type line: "event: chunk"
473
- // We don't need to process these separately since the data contains the type
477
+ }
478
+ /**
479
+ * Parse Server-Sent Events stream from response body
480
+ *
481
+ * @param body - ReadableStream from fetch response
482
+ * @yields Parsed stream chunks
483
+ */
484
+ async *parseSSEStream(body) {
485
+ const reader = body.getReader();
486
+ const decoder = new TextDecoder();
487
+ let buffer = "";
488
+ try {
489
+ while (true) {
490
+ const { done, value } = await reader.read();
491
+ if (done) {
492
+ if (buffer.trim()) {
493
+ const remainingLines = buffer.split("\n");
494
+ for (const line of remainingLines) {
495
+ if (line.startsWith("data: ")) {
496
+ const dataStr = line.slice(6);
497
+ if (dataStr.trim()) {
498
+ try {
499
+ const chunk = JSON.parse(dataStr);
500
+ yield chunk;
501
+ } catch (error) {
502
+ logWarning(`Failed to parse SSE data (in buffer): ${dataStr}`);
503
+ }
474
504
  }
505
+ }
475
506
  }
507
+ }
508
+ break;
476
509
  }
477
- finally {
478
- reader.releaseLock();
510
+ buffer += decoder.decode(value, { stream: true });
511
+ const lines = buffer.split("\n");
512
+ buffer = lines.pop() || "";
513
+ for (const line of lines) {
514
+ if (line.startsWith("data: ")) {
515
+ const dataStr = line.slice(6);
516
+ if (!dataStr.trim()) {
517
+ continue;
518
+ }
519
+ try {
520
+ const chunk = JSON.parse(dataStr);
521
+ yield chunk;
522
+ if (chunk.type === "done" || chunk.type === "error") {
523
+ return;
524
+ }
525
+ } catch (error) {
526
+ logWarning(`Failed to parse SSE data: ${dataStr}`);
527
+ }
528
+ }
479
529
  }
530
+ }
531
+ } finally {
532
+ reader.releaseLock();
480
533
  }
534
+ }
481
535
  }
482
- // Export singleton instance
483
- export const aiServiceClient = new AIServiceClient();
536
+ const aiServiceClient = new AIServiceClient();
537
+ export {
538
+ AIServiceClient,
539
+ aiServiceClient
540
+ };
484
541
  //# sourceMappingURL=ai-service-client.js.map