whale-code 6.5.4 → 6.5.6

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 (853) hide show
  1. package/README.md +39 -31
  2. package/bin/{swagmanager-mcp.js → whale-code.js} +17 -2
  3. package/dist/cli/app.js +148 -72
  4. package/dist/cli/app.js.map +1 -0
  5. package/dist/cli/chat/AgentSelector.js +105 -10
  6. package/dist/cli/chat/AgentSelector.js.map +1 -0
  7. package/dist/cli/chat/ChatApp.d.ts +31 -0
  8. package/dist/cli/chat/ChatApp.js +539 -286
  9. package/dist/cli/chat/ChatApp.js.map +1 -0
  10. package/dist/cli/chat/ChatInput.js +1088 -770
  11. package/dist/cli/chat/ChatInput.js.map +1 -0
  12. package/dist/cli/chat/MarkdownText.js +39 -14
  13. package/dist/cli/chat/MarkdownText.js.map +1 -0
  14. package/dist/cli/chat/MemoryManager.js +181 -46
  15. package/dist/cli/chat/MemoryManager.js.map +1 -0
  16. package/dist/cli/chat/MessageList.d.ts +2 -3
  17. package/dist/cli/chat/MessageList.js +186 -45
  18. package/dist/cli/chat/MessageList.js.map +1 -0
  19. package/dist/cli/chat/ModelSelector.js +282 -63
  20. package/dist/cli/chat/ModelSelector.js.map +1 -0
  21. package/dist/cli/chat/NodeManager.js +165 -75
  22. package/dist/cli/chat/NodeManager.js.map +1 -0
  23. package/dist/cli/chat/NodeSelector.js +171 -30
  24. package/dist/cli/chat/NodeSelector.js.map +1 -0
  25. package/dist/cli/chat/PlanApproval.js +281 -57
  26. package/dist/cli/chat/PlanApproval.js.map +1 -0
  27. package/dist/cli/chat/RewindViewer.js +559 -144
  28. package/dist/cli/chat/RewindViewer.js.map +1 -0
  29. package/dist/cli/chat/SessionManager.js +137 -30
  30. package/dist/cli/chat/SessionManager.js.map +1 -0
  31. package/dist/cli/chat/SlashMenu.js +293 -164
  32. package/dist/cli/chat/SlashMenu.js.map +1 -0
  33. package/dist/cli/chat/StatusBar.js +172 -9
  34. package/dist/cli/chat/StatusBar.js.map +1 -0
  35. package/dist/cli/chat/StoreSelector.js +147 -18
  36. package/dist/cli/chat/StoreSelector.js.map +1 -0
  37. package/dist/cli/chat/StreamingText.d.ts +1 -5
  38. package/dist/cli/chat/StreamingText.js +22 -7
  39. package/dist/cli/chat/StreamingText.js.map +1 -0
  40. package/dist/cli/chat/SubagentPanel.d.ts +1 -2
  41. package/dist/cli/chat/SubagentPanel.js +612 -72
  42. package/dist/cli/chat/SubagentPanel.js.map +1 -0
  43. package/dist/cli/chat/TeamPanel.d.ts +1 -0
  44. package/dist/cli/chat/TeamPanel.js +230 -30
  45. package/dist/cli/chat/TeamPanel.js.map +1 -0
  46. package/dist/cli/chat/ThemeSelector.js +84 -24
  47. package/dist/cli/chat/ThemeSelector.js.map +1 -0
  48. package/dist/cli/chat/ToolIndicator.js +1476 -371
  49. package/dist/cli/chat/ToolIndicator.js.map +1 -0
  50. package/dist/cli/chat/hooks/useAgentLoop.d.ts +1 -0
  51. package/dist/cli/chat/hooks/useAgentLoop.js +481 -367
  52. package/dist/cli/chat/hooks/useAgentLoop.js.map +1 -0
  53. package/dist/cli/chat/hooks/useSlashCommands.d.ts +3 -14
  54. package/dist/cli/chat/hooks/useSlashCommands.js +744 -572
  55. package/dist/cli/chat/hooks/useSlashCommands.js.map +1 -0
  56. package/dist/cli/commands/config-cmd.js +56 -57
  57. package/dist/cli/commands/config-cmd.js.map +1 -0
  58. package/dist/cli/commands/db.js +184 -169
  59. package/dist/cli/commands/db.js.map +1 -0
  60. package/dist/cli/commands/doctor.js +212 -122
  61. package/dist/cli/commands/doctor.js.map +1 -0
  62. package/dist/cli/commands/init.js +211 -244
  63. package/dist/cli/commands/init.js.map +1 -0
  64. package/dist/cli/commands/mcp.js +127 -122
  65. package/dist/cli/commands/mcp.js.map +1 -0
  66. package/dist/cli/login/LoginApp.js +355 -141
  67. package/dist/cli/login/LoginApp.js.map +1 -0
  68. package/dist/cli/print-mode.js +196 -177
  69. package/dist/cli/print-mode.js.map +1 -0
  70. package/dist/cli/serve-mode.js +615 -530
  71. package/dist/cli/serve-mode.js.map +1 -0
  72. package/dist/cli/services/agent-config.d.ts +29 -0
  73. package/dist/cli/services/agent-config.js +91 -0
  74. package/dist/cli/services/agent-config.js.map +1 -0
  75. package/dist/cli/services/agent-definitions.d.ts +4 -1
  76. package/dist/cli/services/agent-definitions.js +97 -56
  77. package/dist/cli/services/agent-definitions.js.map +1 -0
  78. package/dist/cli/services/agent-events.js +225 -162
  79. package/dist/cli/services/agent-events.js.map +1 -0
  80. package/dist/cli/services/agent-loop.js +978 -669
  81. package/dist/cli/services/agent-loop.js.map +1 -0
  82. package/dist/cli/services/agent-worker-base.d.ts +35 -5
  83. package/dist/cli/services/agent-worker-base.js +337 -153
  84. package/dist/cli/services/agent-worker-base.js.map +1 -0
  85. package/dist/cli/services/api-retry.js +69 -64
  86. package/dist/cli/services/api-retry.js.map +1 -0
  87. package/dist/cli/services/auth-service.d.ts +3 -3
  88. package/dist/cli/services/auth-service.js +209 -132
  89. package/dist/cli/services/auth-service.js.map +1 -0
  90. package/dist/cli/services/background-processes.js +343 -267
  91. package/dist/cli/services/background-processes.js.map +1 -0
  92. package/dist/cli/services/browser-auth.d.ts +2 -2
  93. package/dist/cli/services/browser-auth.js +159 -118
  94. package/dist/cli/services/browser-auth.js.map +1 -0
  95. package/dist/cli/services/claude-md-loader.js +40 -36
  96. package/dist/cli/services/claude-md-loader.js.map +1 -0
  97. package/dist/cli/services/config-store.d.ts +9 -4
  98. package/dist/cli/services/config-store.js +164 -117
  99. package/dist/cli/services/config-store.js.map +1 -0
  100. package/dist/cli/services/debug-log.d.ts +1 -1
  101. package/dist/cli/services/debug-log.js +34 -35
  102. package/dist/cli/services/debug-log.js.map +1 -0
  103. package/dist/cli/services/env-detect.d.ts +7 -0
  104. package/dist/cli/services/env-detect.js +9 -0
  105. package/dist/cli/services/env-detect.js.map +1 -0
  106. package/dist/cli/services/error-logger.d.ts +2 -3
  107. package/dist/cli/services/error-logger.js +189 -180
  108. package/dist/cli/services/error-logger.js.map +1 -0
  109. package/dist/cli/services/file-history.d.ts +1 -1
  110. package/dist/cli/services/file-history.js +50 -54
  111. package/dist/cli/services/file-history.js.map +1 -0
  112. package/dist/cli/services/format-server-response.js +332 -372
  113. package/dist/cli/services/format-server-response.js.map +1 -0
  114. package/dist/cli/services/git-context.js +61 -45
  115. package/dist/cli/services/git-context.js.map +1 -0
  116. package/dist/cli/services/hooks.d.ts +2 -2
  117. package/dist/cli/services/hooks.js +195 -180
  118. package/dist/cli/services/hooks.js.map +1 -0
  119. package/dist/cli/services/ink-incremental.d.ts +19 -0
  120. package/dist/cli/services/ink-incremental.js +59 -0
  121. package/dist/cli/services/ink-incremental.js.map +1 -0
  122. package/dist/cli/services/ink-resize-fix.js +54 -44
  123. package/dist/cli/services/ink-resize-fix.js.map +1 -0
  124. package/dist/cli/services/ink-sync-output.d.ts +12 -0
  125. package/dist/cli/services/ink-sync-output.js +16 -0
  126. package/dist/cli/services/ink-sync-output.js.map +1 -0
  127. package/dist/cli/services/interactive-tools.js +268 -212
  128. package/dist/cli/services/interactive-tools.js.map +1 -0
  129. package/dist/cli/services/keybinding-manager.d.ts +11 -1
  130. package/dist/cli/services/keybinding-manager.js +126 -63
  131. package/dist/cli/services/keybinding-manager.js.map +1 -0
  132. package/dist/cli/services/local-tools.d.ts +1 -1
  133. package/dist/cli/services/local-tools.js +939 -656
  134. package/dist/cli/services/local-tools.js.map +1 -0
  135. package/dist/cli/services/lsp-manager.js +757 -594
  136. package/dist/cli/services/lsp-manager.js.map +1 -0
  137. package/dist/cli/services/mcp-client.d.ts +1 -1
  138. package/dist/cli/services/mcp-client.js +173 -134
  139. package/dist/cli/services/mcp-client.js.map +1 -0
  140. package/dist/cli/services/memory-manager.js +53 -40
  141. package/dist/cli/services/memory-manager.js.map +1 -0
  142. package/dist/cli/services/model-manager.js +55 -40
  143. package/dist/cli/services/model-manager.js.map +1 -0
  144. package/dist/cli/services/model-router.js +115 -85
  145. package/dist/cli/services/model-router.js.map +1 -0
  146. package/dist/cli/services/paths.d.ts +30 -0
  147. package/dist/cli/services/paths.js +81 -0
  148. package/dist/cli/services/paths.js.map +1 -0
  149. package/dist/cli/services/permission-modes.js +32 -25
  150. package/dist/cli/services/permission-modes.js.map +1 -0
  151. package/dist/cli/services/rewind.js +182 -168
  152. package/dist/cli/services/rewind.js.map +1 -0
  153. package/dist/cli/services/ripgrep.js +115 -115
  154. package/dist/cli/services/ripgrep.js.map +1 -0
  155. package/dist/cli/services/sandbox.d.ts +1 -1
  156. package/dist/cli/services/sandbox.js +58 -37
  157. package/dist/cli/services/sandbox.js.map +1 -0
  158. package/dist/cli/services/server-tools.js +738 -565
  159. package/dist/cli/services/server-tools.js.map +1 -0
  160. package/dist/cli/services/session-persistence.js +69 -74
  161. package/dist/cli/services/session-persistence.js.map +1 -0
  162. package/dist/cli/services/subagent-worker.js +42 -27
  163. package/dist/cli/services/subagent-worker.js.map +1 -0
  164. package/dist/cli/services/subagent.d.ts +2 -0
  165. package/dist/cli/services/subagent.js +606 -430
  166. package/dist/cli/services/subagent.js.map +1 -0
  167. package/dist/cli/services/system-prompt.js +86 -78
  168. package/dist/cli/services/system-prompt.js.map +1 -0
  169. package/dist/cli/services/task-decomposer.d.ts +1 -1
  170. package/dist/cli/services/task-decomposer.js +172 -139
  171. package/dist/cli/services/task-decomposer.js.map +1 -0
  172. package/dist/cli/services/team-lead.d.ts +2 -2
  173. package/dist/cli/services/team-lead.js +727 -529
  174. package/dist/cli/services/team-lead.js.map +1 -0
  175. package/dist/cli/services/team-state.js +319 -319
  176. package/dist/cli/services/team-state.js.map +1 -0
  177. package/dist/cli/services/teammate.d.ts +8 -2
  178. package/dist/cli/services/teammate.js +862 -560
  179. package/dist/cli/services/teammate.js.map +1 -0
  180. package/dist/cli/services/telemetry.d.ts +6 -1
  181. package/dist/cli/services/telemetry.js +180 -157
  182. package/dist/cli/services/telemetry.js.map +1 -0
  183. package/dist/cli/services/tools/agent-tools.d.ts +3 -3
  184. package/dist/cli/services/tools/agent-tools.js +480 -322
  185. package/dist/cli/services/tools/agent-tools.js.map +1 -0
  186. package/dist/cli/services/tools/file-ops.js +563 -450
  187. package/dist/cli/services/tools/file-ops.js.map +1 -0
  188. package/dist/cli/services/tools/search-tools.js +231 -162
  189. package/dist/cli/services/tools/search-tools.js.map +1 -0
  190. package/dist/cli/services/tools/shell-exec.js +197 -151
  191. package/dist/cli/services/tools/shell-exec.js.map +1 -0
  192. package/dist/cli/services/tools/task-manager.js +206 -173
  193. package/dist/cli/services/tools/task-manager.js.map +1 -0
  194. package/dist/cli/services/tools/web-tools.js +388 -341
  195. package/dist/cli/services/tools/web-tools.js.map +1 -0
  196. package/dist/cli/setup/SetupApp.d.ts +2 -2
  197. package/dist/cli/setup/SetupApp.js +608 -160
  198. package/dist/cli/setup/SetupApp.js.map +1 -0
  199. package/dist/cli/shared/ErrorBoundary.d.ts +22 -0
  200. package/dist/cli/shared/ErrorBoundary.js +73 -0
  201. package/dist/cli/shared/ErrorBoundary.js.map +1 -0
  202. package/dist/cli/shared/MatrixIntro.js +66 -69
  203. package/dist/cli/shared/MatrixIntro.js.map +1 -0
  204. package/dist/cli/shared/SpinnerSlot.d.ts +14 -0
  205. package/dist/cli/shared/SpinnerSlot.js +63 -0
  206. package/dist/cli/shared/SpinnerSlot.js.map +1 -0
  207. package/dist/cli/shared/Theme.d.ts +1 -1
  208. package/dist/cli/shared/Theme.js +136 -92
  209. package/dist/cli/shared/Theme.js.map +1 -0
  210. package/dist/cli/shared/WhaleBanner.js +99 -11
  211. package/dist/cli/shared/WhaleBanner.js.map +1 -0
  212. package/dist/cli/shared/markdown.d.ts +3 -1
  213. package/dist/cli/shared/markdown.js +736 -674
  214. package/dist/cli/shared/markdown.js.map +1 -0
  215. package/dist/cli/shared/marked-terminal.d.js +2 -0
  216. package/dist/cli/shared/marked-terminal.d.js.map +1 -0
  217. package/dist/cli/shared/theme-manager.js +99 -90
  218. package/dist/cli/shared/theme-manager.js.map +1 -0
  219. package/dist/cli/shared/theme-presets.js +256 -254
  220. package/dist/cli/shared/theme-presets.js.map +1 -0
  221. package/dist/cli/status/StatusApp.js +235 -86
  222. package/dist/cli/status/StatusApp.js.map +1 -0
  223. package/dist/cli/stores/StoreApp.js +275 -65
  224. package/dist/cli/stores/StoreApp.js.map +1 -0
  225. package/dist/index.d.ts +2 -2
  226. package/dist/index.js +509 -396
  227. package/dist/index.js.map +1 -0
  228. package/dist/local-agent/connection.d.ts +2 -2
  229. package/dist/local-agent/connection.js +352 -293
  230. package/dist/local-agent/connection.js.map +1 -0
  231. package/dist/local-agent/discovery.js +259 -122
  232. package/dist/local-agent/discovery.js.map +1 -0
  233. package/dist/local-agent/executor.js +216 -193
  234. package/dist/local-agent/executor.js.map +1 -0
  235. package/dist/local-agent/index.d.ts +2 -2
  236. package/dist/local-agent/index.js +156 -156
  237. package/dist/local-agent/index.js.map +1 -0
  238. package/dist/node/adapters/base.js +18 -8
  239. package/dist/node/adapters/base.js.map +1 -0
  240. package/dist/node/adapters/discord.js +286 -275
  241. package/dist/node/adapters/discord.js.map +1 -0
  242. package/dist/node/adapters/email.js +189 -202
  243. package/dist/node/adapters/email.js.map +1 -0
  244. package/dist/node/adapters/imessage.js +145 -142
  245. package/dist/node/adapters/imessage.js.map +1 -0
  246. package/dist/node/adapters/slack.js +237 -236
  247. package/dist/node/adapters/slack.js.map +1 -0
  248. package/dist/node/adapters/sms.js +149 -151
  249. package/dist/node/adapters/sms.js.map +1 -0
  250. package/dist/node/adapters/telegram.js +88 -92
  251. package/dist/node/adapters/telegram.js.map +1 -0
  252. package/dist/node/adapters/webchat.js +160 -136
  253. package/dist/node/adapters/webchat.js.map +1 -0
  254. package/dist/node/adapters/whatsapp.js +212 -215
  255. package/dist/node/adapters/whatsapp.js.map +1 -0
  256. package/dist/node/cli.js +884 -653
  257. package/dist/node/cli.js.map +1 -0
  258. package/dist/node/config.js +20 -18
  259. package/dist/node/config.js.map +1 -0
  260. package/dist/node/gateway-client.js +191 -181
  261. package/dist/node/gateway-client.js.map +1 -0
  262. package/dist/node/portal/clipboard.js +161 -130
  263. package/dist/node/portal/clipboard.js.map +1 -0
  264. package/dist/node/portal/discovery.js +51 -45
  265. package/dist/node/portal/discovery.js.map +1 -0
  266. package/dist/node/portal/forward.js +64 -58
  267. package/dist/node/portal/forward.js.map +1 -0
  268. package/dist/node/portal/index.js +246 -221
  269. package/dist/node/portal/index.js.map +1 -0
  270. package/dist/node/portal/multiplexer.js +192 -182
  271. package/dist/node/portal/multiplexer.js.map +1 -0
  272. package/dist/node/portal/permissions.js +102 -70
  273. package/dist/node/portal/permissions.js.map +1 -0
  274. package/dist/node/portal/protocol.js +153 -116
  275. package/dist/node/portal/protocol.js.map +1 -0
  276. package/dist/node/portal/screen.js +80 -69
  277. package/dist/node/portal/screen.js.map +1 -0
  278. package/dist/node/portal/session.js +124 -117
  279. package/dist/node/portal/session.js.map +1 -0
  280. package/dist/node/portal/shell.js +140 -113
  281. package/dist/node/portal/shell.js.map +1 -0
  282. package/dist/node/portal/stream.js +77 -75
  283. package/dist/node/portal/stream.js.map +1 -0
  284. package/dist/node/portal/transfer.js +190 -167
  285. package/dist/node/portal/transfer.js.map +1 -0
  286. package/dist/node/portal/ui.js +124 -99
  287. package/dist/node/portal/ui.js.map +1 -0
  288. package/dist/node/remote-desktop/compile-helper.js +50 -45
  289. package/dist/node/remote-desktop/compile-helper.js.map +1 -0
  290. package/dist/node/remote-desktop/index.js +215 -187
  291. package/dist/node/remote-desktop/index.js.map +1 -0
  292. package/dist/node/remote-desktop/protocol.js +45 -29
  293. package/dist/node/remote-desktop/protocol.js.map +1 -0
  294. package/dist/node/runtime.js +493 -410
  295. package/dist/node/runtime.js.map +1 -0
  296. package/dist/server/handlers/__test-utils__/test-db.js +39 -89
  297. package/dist/server/handlers/__test-utils__/test-db.js.map +1 -0
  298. package/dist/server/handlers/analytics.js +467 -261
  299. package/dist/server/handlers/analytics.js.map +1 -0
  300. package/dist/server/handlers/api-docs.d.ts +6 -0
  301. package/dist/server/handlers/api-docs.js +1613 -0
  302. package/dist/server/handlers/api-docs.js.map +1 -0
  303. package/dist/server/handlers/api-keys.js +295 -232
  304. package/dist/server/handlers/api-keys.js.map +1 -0
  305. package/dist/server/handlers/billing.js +330 -239
  306. package/dist/server/handlers/billing.js.map +1 -0
  307. package/dist/server/handlers/browser.js +468 -395
  308. package/dist/server/handlers/browser.js.map +1 -0
  309. package/dist/server/handlers/catalog.js +1377 -978
  310. package/dist/server/handlers/catalog.js.map +1 -0
  311. package/dist/server/handlers/clickhouse.js +157 -109
  312. package/dist/server/handlers/clickhouse.js.map +1 -0
  313. package/dist/server/handlers/comms.d.ts +0 -53
  314. package/dist/server/handlers/comms.js +1443 -970
  315. package/dist/server/handlers/comms.js.map +1 -0
  316. package/dist/server/handlers/creations.js +461 -394
  317. package/dist/server/handlers/creations.js.map +1 -0
  318. package/dist/server/handlers/crm.js +1082 -791
  319. package/dist/server/handlers/crm.js.map +1 -0
  320. package/dist/server/handlers/discovery.js +251 -232
  321. package/dist/server/handlers/discovery.js.map +1 -0
  322. package/dist/server/handlers/embeddings.js +241 -164
  323. package/dist/server/handlers/embeddings.js.map +1 -0
  324. package/dist/server/handlers/enrichment.js +887 -718
  325. package/dist/server/handlers/enrichment.js.map +1 -0
  326. package/dist/server/handlers/image-gen.js +467 -376
  327. package/dist/server/handlers/image-gen.js.map +1 -0
  328. package/dist/server/handlers/inventory.js +797 -424
  329. package/dist/server/handlers/inventory.js.map +1 -0
  330. package/dist/server/handlers/kali.js +272 -230
  331. package/dist/server/handlers/kali.js.map +1 -0
  332. package/dist/server/handlers/llm-providers.js +803 -580
  333. package/dist/server/handlers/llm-providers.js.map +1 -0
  334. package/dist/server/handlers/local-agent.js +133 -105
  335. package/dist/server/handlers/local-agent.js.map +1 -0
  336. package/dist/server/handlers/media.js +1179 -857
  337. package/dist/server/handlers/media.js.map +1 -0
  338. package/dist/server/handlers/meta-ads.js +2669 -2093
  339. package/dist/server/handlers/meta-ads.js.map +1 -0
  340. package/dist/server/handlers/nodes.js +1321 -913
  341. package/dist/server/handlers/nodes.js.map +1 -0
  342. package/dist/server/handlers/operations.js +183 -157
  343. package/dist/server/handlers/operations.js.map +1 -0
  344. package/dist/server/handlers/platform.js +346 -210
  345. package/dist/server/handlers/platform.js.map +1 -0
  346. package/dist/server/handlers/remove-bg.js +118 -86
  347. package/dist/server/handlers/remove-bg.js.map +1 -0
  348. package/dist/server/handlers/storefront.js +586 -446
  349. package/dist/server/handlers/storefront.js.map +1 -0
  350. package/dist/server/handlers/supply-chain.js +546 -326
  351. package/dist/server/handlers/supply-chain.js.map +1 -0
  352. package/dist/server/handlers/transcription.js +106 -97
  353. package/dist/server/handlers/transcription.js.map +1 -0
  354. package/dist/server/handlers/video-gen.js +593 -424
  355. package/dist/server/handlers/video-gen.js.map +1 -0
  356. package/dist/server/handlers/voice.js +1458 -1017
  357. package/dist/server/handlers/voice.js.map +1 -0
  358. package/dist/server/handlers/workflow-steps.js +2837 -2116
  359. package/dist/server/handlers/workflow-steps.js.map +1 -0
  360. package/dist/server/handlers/workflows.js +1630 -933
  361. package/dist/server/handlers/workflows.js.map +1 -0
  362. package/dist/server/index.js +3166 -2390
  363. package/dist/server/index.js.map +1 -0
  364. package/dist/server/lib/batch-client.js +471 -409
  365. package/dist/server/lib/batch-client.js.map +1 -0
  366. package/dist/server/lib/clickhouse-buffer.js +118 -104
  367. package/dist/server/lib/clickhouse-buffer.js.map +1 -0
  368. package/dist/server/lib/clickhouse-client.js +107 -107
  369. package/dist/server/lib/clickhouse-client.js.map +1 -0
  370. package/dist/server/lib/coa-renderer.js +1786 -356
  371. package/dist/server/lib/coa-renderer.js.map +1 -0
  372. package/dist/server/lib/code-worker-pool.js +227 -177
  373. package/dist/server/lib/code-worker-pool.js.map +1 -0
  374. package/dist/server/lib/code-worker.js +174 -164
  375. package/dist/server/lib/code-worker.js.map +1 -0
  376. package/dist/server/lib/compaction-service.d.ts +2 -12
  377. package/dist/server/lib/compaction-service.js +74 -184
  378. package/dist/server/lib/compaction-service.js.map +1 -0
  379. package/dist/server/lib/logger.js +36 -24
  380. package/dist/server/lib/logger.js.map +1 -0
  381. package/dist/server/lib/otel.js +101 -80
  382. package/dist/server/lib/otel.js.map +1 -0
  383. package/dist/server/lib/pdf-renderer.d.ts +1 -1
  384. package/dist/server/lib/pdf-renderer.js +954 -776
  385. package/dist/server/lib/pdf-renderer.js.map +1 -0
  386. package/dist/server/lib/prompt-sanitizer.js +188 -108
  387. package/dist/server/lib/prompt-sanitizer.js.map +1 -0
  388. package/dist/server/lib/provider-capabilities.js +136 -138
  389. package/dist/server/lib/provider-capabilities.js.map +1 -0
  390. package/dist/server/lib/provider-failover.js +190 -168
  391. package/dist/server/lib/provider-failover.js.map +1 -0
  392. package/dist/server/lib/rate-limiter.js +186 -117
  393. package/dist/server/lib/rate-limiter.js.map +1 -0
  394. package/dist/server/lib/react-pdf-layout.js +551 -382
  395. package/dist/server/lib/react-pdf-layout.js.map +1 -0
  396. package/dist/server/lib/server-agent-loop.d.ts +9 -0
  397. package/dist/server/lib/server-agent-loop.js +906 -624
  398. package/dist/server/lib/server-agent-loop.js.map +1 -0
  399. package/dist/server/lib/server-subagent.d.ts +2 -0
  400. package/dist/server/lib/server-subagent.js +260 -162
  401. package/dist/server/lib/server-subagent.js.map +1 -0
  402. package/dist/server/lib/session-checkpoint.js +105 -96
  403. package/dist/server/lib/session-checkpoint.js.map +1 -0
  404. package/dist/server/lib/ssrf-guard.js +193 -184
  405. package/dist/server/lib/ssrf-guard.js.map +1 -0
  406. package/dist/server/lib/supabase-client.js +94 -82
  407. package/dist/server/lib/supabase-client.js.map +1 -0
  408. package/dist/server/lib/template-resolver.js +154 -176
  409. package/dist/server/lib/template-resolver.js.map +1 -0
  410. package/dist/server/lib/utils.js +242 -133
  411. package/dist/server/lib/utils.js.map +1 -0
  412. package/dist/server/local-agent-gateway.d.ts +2 -2
  413. package/dist/server/local-agent-gateway.js +785 -627
  414. package/dist/server/local-agent-gateway.js.map +1 -0
  415. package/dist/server/providers/anthropic.js +254 -176
  416. package/dist/server/providers/anthropic.js.map +1 -0
  417. package/dist/server/providers/bedrock.js +221 -162
  418. package/dist/server/providers/bedrock.js.map +1 -0
  419. package/dist/server/providers/gemini.js +548 -418
  420. package/dist/server/providers/gemini.js.map +1 -0
  421. package/dist/server/providers/openai.js +571 -437
  422. package/dist/server/providers/openai.js.map +1 -0
  423. package/dist/server/providers/registry.js +23 -18
  424. package/dist/server/providers/registry.js.map +1 -0
  425. package/dist/server/providers/shared.js +123 -95
  426. package/dist/server/providers/shared.js.map +1 -0
  427. package/dist/server/providers/types.js +1 -11
  428. package/dist/server/providers/types.js.map +1 -0
  429. package/dist/server/proxy-handlers.js +209 -165
  430. package/dist/server/proxy-handlers.js.map +1 -0
  431. package/dist/server/tool-router.d.ts +13 -0
  432. package/dist/server/tool-router.js +960 -598
  433. package/dist/server/tool-router.js.map +1 -0
  434. package/dist/server/validation.js +248 -188
  435. package/dist/server/validation.js.map +1 -0
  436. package/dist/server/worker.js +202 -133
  437. package/dist/server/worker.js.map +1 -0
  438. package/dist/setup.d.ts +2 -2
  439. package/dist/setup.js +151 -147
  440. package/dist/setup.js.map +1 -0
  441. package/dist/shared/agent-core.d.ts +191 -24
  442. package/dist/shared/agent-core.js +971 -462
  443. package/dist/shared/agent-core.js.map +1 -0
  444. package/dist/shared/anthropic-types.js +1 -6
  445. package/dist/shared/anthropic-types.js.map +1 -0
  446. package/dist/shared/api-client.d.ts +17 -9
  447. package/dist/shared/api-client.js +419 -327
  448. package/dist/shared/api-client.js.map +1 -0
  449. package/dist/shared/compaction.d.ts +36 -0
  450. package/dist/shared/compaction.js +138 -0
  451. package/dist/shared/compaction.js.map +1 -0
  452. package/dist/shared/constants.js +67 -64
  453. package/dist/shared/constants.js.map +1 -0
  454. package/dist/shared/sse-parser.js +221 -219
  455. package/dist/shared/sse-parser.js.map +1 -0
  456. package/dist/shared/tool-dispatch.d.ts +4 -2
  457. package/dist/shared/tool-dispatch.js +226 -165
  458. package/dist/shared/tool-dispatch.js.map +1 -0
  459. package/dist/shared/types.js +1 -6
  460. package/dist/shared/types.js.map +1 -0
  461. package/dist/types/cli-highlight.d.js +2 -0
  462. package/dist/types/cli-highlight.d.js.map +1 -0
  463. package/dist/types/diff.d.js +2 -0
  464. package/dist/types/diff.d.js.map +1 -0
  465. package/dist/types/pdf-parse.d.js +2 -0
  466. package/dist/types/pdf-parse.d.js.map +1 -0
  467. package/dist/updater.d.ts +1 -1
  468. package/dist/updater.js +118 -92
  469. package/dist/updater.js.map +1 -0
  470. package/dist/webchat/widget.js +227 -380
  471. package/dist/webchat/widget.js.map +1 -0
  472. package/package.json +22 -10
  473. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  474. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  475. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  476. package/vendor/ink/build/apply-styles.js +175 -0
  477. package/vendor/ink/build/build-layout.js +77 -0
  478. package/vendor/ink/build/calculate-wrapped-text.js +53 -0
  479. package/vendor/ink/build/colorize.d.ts +3 -0
  480. package/vendor/ink/build/colorize.js +48 -0
  481. package/vendor/ink/build/colorize.js.map +1 -0
  482. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  483. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  484. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  485. package/vendor/ink/build/components/App.d.ts +18 -0
  486. package/vendor/ink/build/components/App.js +351 -0
  487. package/vendor/ink/build/components/App.js.map +1 -0
  488. package/vendor/ink/build/components/AppContext.d.ts +15 -0
  489. package/vendor/ink/build/components/AppContext.js +11 -0
  490. package/vendor/ink/build/components/AppContext.js.map +1 -0
  491. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  492. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  493. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  494. package/vendor/ink/build/components/Box.d.ts +117 -0
  495. package/vendor/ink/build/components/Box.js +34 -0
  496. package/vendor/ink/build/components/Box.js.map +1 -0
  497. package/vendor/ink/build/components/Color.js +62 -0
  498. package/vendor/ink/build/components/Cursor.d.ts +83 -0
  499. package/vendor/ink/build/components/Cursor.js +53 -0
  500. package/vendor/ink/build/components/Cursor.js.map +1 -0
  501. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  502. package/vendor/ink/build/components/CursorContext.js +8 -0
  503. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  504. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  505. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  506. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  507. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  508. package/vendor/ink/build/components/ErrorOverview.js +84 -0
  509. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  510. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  511. package/vendor/ink/build/components/FocusContext.js +17 -0
  512. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  513. package/vendor/ink/build/components/Newline.d.ts +13 -0
  514. package/vendor/ink/build/components/Newline.js +8 -0
  515. package/vendor/ink/build/components/Newline.js.map +1 -0
  516. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  517. package/vendor/ink/build/components/Spacer.js +11 -0
  518. package/vendor/ink/build/components/Spacer.js.map +1 -0
  519. package/vendor/ink/build/components/Static.d.ts +24 -0
  520. package/vendor/ink/build/components/Static.js +28 -0
  521. package/vendor/ink/build/components/Static.js.map +1 -0
  522. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  523. package/vendor/ink/build/components/StderrContext.js +13 -0
  524. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  525. package/vendor/ink/build/components/StdinContext.d.ts +22 -0
  526. package/vendor/ink/build/components/StdinContext.js +19 -0
  527. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  528. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  529. package/vendor/ink/build/components/StdoutContext.js +13 -0
  530. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  531. package/vendor/ink/build/components/Text.d.ts +55 -0
  532. package/vendor/ink/build/components/Text.js +50 -0
  533. package/vendor/ink/build/components/Text.js.map +1 -0
  534. package/vendor/ink/build/components/Transform.d.ts +16 -0
  535. package/vendor/ink/build/components/Transform.js +15 -0
  536. package/vendor/ink/build/components/Transform.js.map +1 -0
  537. package/vendor/ink/build/cursor-helpers.d.ts +38 -0
  538. package/vendor/ink/build/cursor-helpers.js +56 -0
  539. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  540. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  541. package/vendor/ink/build/devtools-window-polyfill.js +65 -0
  542. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  543. package/vendor/ink/build/devtools.d.ts +1 -0
  544. package/vendor/ink/build/devtools.js +11 -0
  545. package/vendor/ink/build/devtools.js.map +1 -0
  546. package/vendor/ink/build/dom.d.ts +56 -0
  547. package/vendor/ink/build/dom.js +124 -0
  548. package/vendor/ink/build/dom.js.map +1 -0
  549. package/vendor/ink/build/experimental/apply-style.js +140 -0
  550. package/vendor/ink/build/experimental/dom.js +123 -0
  551. package/vendor/ink/build/experimental/output.js +91 -0
  552. package/vendor/ink/build/experimental/reconciler.js +141 -0
  553. package/vendor/ink/build/experimental/renderer.js +81 -0
  554. package/vendor/ink/build/get-max-width.d.ts +3 -0
  555. package/vendor/ink/build/get-max-width.js +10 -0
  556. package/vendor/ink/build/get-max-width.js.map +1 -0
  557. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  558. package/vendor/ink/build/hooks/use-app.js +8 -0
  559. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  560. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  561. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  562. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  563. package/vendor/ink/build/hooks/use-focus-manager.d.ts +28 -0
  564. package/vendor/ink/build/hooks/use-focus-manager.js +17 -0
  565. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  566. package/vendor/ink/build/hooks/use-focus.d.ts +29 -0
  567. package/vendor/ink/build/hooks/use-focus.js +42 -0
  568. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  569. package/vendor/ink/build/hooks/use-input.d.ts +131 -0
  570. package/vendor/ink/build/hooks/use-input.js +124 -0
  571. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  572. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +5 -0
  573. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +11 -0
  574. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  575. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  576. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  577. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  578. package/vendor/ink/build/hooks/use-stdin.d.ts +5 -0
  579. package/vendor/ink/build/hooks/use-stdin.js +8 -0
  580. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  581. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  582. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  583. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  584. package/vendor/ink/build/hooks/useInput.js +38 -0
  585. package/vendor/ink/build/index.d.ts +34 -0
  586. package/vendor/ink/build/index.js +20 -0
  587. package/vendor/ink/build/index.js.map +1 -0
  588. package/vendor/ink/build/ink.d.ts +90 -0
  589. package/vendor/ink/build/ink.js +654 -0
  590. package/vendor/ink/build/ink.js.map +1 -0
  591. package/vendor/ink/build/input-parser.d.ts +7 -0
  592. package/vendor/ink/build/input-parser.js +154 -0
  593. package/vendor/ink/build/input-parser.js.map +1 -0
  594. package/vendor/ink/build/instance.js +205 -0
  595. package/vendor/ink/build/instances.d.ts +3 -0
  596. package/vendor/ink/build/instances.js +8 -0
  597. package/vendor/ink/build/instances.js.map +1 -0
  598. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  599. package/vendor/ink/build/kitty-keyboard.js +32 -0
  600. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  601. package/vendor/ink/build/layout.d.ts +7 -0
  602. package/vendor/ink/build/layout.js +33 -0
  603. package/vendor/ink/build/layout.js.map +1 -0
  604. package/vendor/ink/build/log-update.d.ts +19 -0
  605. package/vendor/ink/build/log-update.js +243 -0
  606. package/vendor/ink/build/log-update.js.map +1 -0
  607. package/vendor/ink/build/measure-element.d.ts +16 -0
  608. package/vendor/ink/build/measure-element.js +9 -0
  609. package/vendor/ink/build/measure-element.js.map +1 -0
  610. package/vendor/ink/build/measure-text.d.ts +6 -0
  611. package/vendor/ink/build/measure-text.js +21 -0
  612. package/vendor/ink/build/measure-text.js.map +1 -0
  613. package/vendor/ink/build/options.d.ts +52 -0
  614. package/vendor/ink/build/options.js +2 -0
  615. package/vendor/ink/build/options.js.map +1 -0
  616. package/vendor/ink/build/output.d.ts +35 -0
  617. package/vendor/ink/build/output.js +183 -0
  618. package/vendor/ink/build/output.js.map +1 -0
  619. package/vendor/ink/build/parse-keypress.d.ts +22 -0
  620. package/vendor/ink/build/parse-keypress.js +493 -0
  621. package/vendor/ink/build/parse-keypress.js.map +1 -0
  622. package/vendor/ink/build/reconciler.d.ts +4 -0
  623. package/vendor/ink/build/reconciler.js +274 -0
  624. package/vendor/ink/build/reconciler.js.map +1 -0
  625. package/vendor/ink/build/render-background.d.ts +4 -0
  626. package/vendor/ink/build/render-background.js +25 -0
  627. package/vendor/ink/build/render-background.js.map +1 -0
  628. package/vendor/ink/build/render-border.d.ts +4 -0
  629. package/vendor/ink/build/render-border.js +73 -0
  630. package/vendor/ink/build/render-border.js.map +1 -0
  631. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  632. package/vendor/ink/build/render-node-to-output.js +147 -0
  633. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  634. package/vendor/ink/build/render-to-string.d.ts +38 -0
  635. package/vendor/ink/build/render-to-string.js +115 -0
  636. package/vendor/ink/build/render-to-string.js.map +1 -0
  637. package/vendor/ink/build/render.d.ts +121 -0
  638. package/vendor/ink/build/render.js +55 -0
  639. package/vendor/ink/build/render.js.map +1 -0
  640. package/vendor/ink/build/renderer.d.ts +8 -0
  641. package/vendor/ink/build/renderer.js +55 -0
  642. package/vendor/ink/build/renderer.js.map +1 -0
  643. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  644. package/vendor/ink/build/sanitize-ansi.js +27 -0
  645. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  646. package/vendor/ink/build/screen-reader-update.d.ts +13 -0
  647. package/vendor/ink/build/screen-reader-update.js +38 -0
  648. package/vendor/ink/build/screen-reader-update.js.map +1 -0
  649. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  650. package/vendor/ink/build/squash-text-nodes.js +36 -0
  651. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  652. package/vendor/ink/build/styles.d.ts +240 -0
  653. package/vendor/ink/build/styles.js +232 -0
  654. package/vendor/ink/build/styles.js.map +1 -0
  655. package/vendor/ink/build/utils.d.ts +2 -0
  656. package/vendor/ink/build/utils.js +4 -0
  657. package/vendor/ink/build/utils.js.map +1 -0
  658. package/vendor/ink/build/wrap-text.d.ts +3 -0
  659. package/vendor/ink/build/wrap-text.js +31 -0
  660. package/vendor/ink/build/wrap-text.js.map +1 -0
  661. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  662. package/vendor/ink/build/write-synchronized.js +7 -0
  663. package/vendor/ink/build/write-synchronized.js.map +1 -0
  664. package/vendor/ink/license +10 -0
  665. package/vendor/ink/node_modules/@types/node/LICENSE +21 -0
  666. package/vendor/ink/node_modules/@types/node/README.md +15 -0
  667. package/vendor/ink/node_modules/@types/node/assert/strict.d.ts +105 -0
  668. package/vendor/ink/node_modules/@types/node/assert.d.ts +955 -0
  669. package/vendor/ink/node_modules/@types/node/async_hooks.d.ts +623 -0
  670. package/vendor/ink/node_modules/@types/node/buffer.buffer.d.ts +466 -0
  671. package/vendor/ink/node_modules/@types/node/buffer.d.ts +1810 -0
  672. package/vendor/ink/node_modules/@types/node/child_process.d.ts +1428 -0
  673. package/vendor/ink/node_modules/@types/node/cluster.d.ts +486 -0
  674. package/vendor/ink/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
  675. package/vendor/ink/node_modules/@types/node/console.d.ts +151 -0
  676. package/vendor/ink/node_modules/@types/node/constants.d.ts +20 -0
  677. package/vendor/ink/node_modules/@types/node/crypto.d.ts +4065 -0
  678. package/vendor/ink/node_modules/@types/node/dgram.d.ts +564 -0
  679. package/vendor/ink/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
  680. package/vendor/ink/node_modules/@types/node/dns/promises.d.ts +503 -0
  681. package/vendor/ink/node_modules/@types/node/dns.d.ts +922 -0
  682. package/vendor/ink/node_modules/@types/node/domain.d.ts +166 -0
  683. package/vendor/ink/node_modules/@types/node/events.d.ts +1054 -0
  684. package/vendor/ink/node_modules/@types/node/fs/promises.d.ts +1329 -0
  685. package/vendor/ink/node_modules/@types/node/fs.d.ts +4676 -0
  686. package/vendor/ink/node_modules/@types/node/globals.d.ts +150 -0
  687. package/vendor/ink/node_modules/@types/node/globals.typedarray.d.ts +101 -0
  688. package/vendor/ink/node_modules/@types/node/http.d.ts +2167 -0
  689. package/vendor/ink/node_modules/@types/node/http2.d.ts +2480 -0
  690. package/vendor/ink/node_modules/@types/node/https.d.ts +405 -0
  691. package/vendor/ink/node_modules/@types/node/index.d.ts +115 -0
  692. package/vendor/ink/node_modules/@types/node/inspector/promises.d.ts +41 -0
  693. package/vendor/ink/node_modules/@types/node/inspector.d.ts +224 -0
  694. package/vendor/ink/node_modules/@types/node/inspector.generated.d.ts +4226 -0
  695. package/vendor/ink/node_modules/@types/node/module.d.ts +819 -0
  696. package/vendor/ink/node_modules/@types/node/net.d.ts +933 -0
  697. package/vendor/ink/node_modules/@types/node/os.d.ts +507 -0
  698. package/vendor/ink/node_modules/@types/node/package.json +155 -0
  699. package/vendor/ink/node_modules/@types/node/path/posix.d.ts +8 -0
  700. package/vendor/ink/node_modules/@types/node/path/win32.d.ts +8 -0
  701. package/vendor/ink/node_modules/@types/node/path.d.ts +187 -0
  702. package/vendor/ink/node_modules/@types/node/perf_hooks.d.ts +643 -0
  703. package/vendor/ink/node_modules/@types/node/process.d.ts +2156 -0
  704. package/vendor/ink/node_modules/@types/node/punycode.d.ts +117 -0
  705. package/vendor/ink/node_modules/@types/node/querystring.d.ts +152 -0
  706. package/vendor/ink/node_modules/@types/node/quic.d.ts +910 -0
  707. package/vendor/ink/node_modules/@types/node/readline/promises.d.ts +161 -0
  708. package/vendor/ink/node_modules/@types/node/readline.d.ts +541 -0
  709. package/vendor/ink/node_modules/@types/node/repl.d.ts +415 -0
  710. package/vendor/ink/node_modules/@types/node/sea.d.ts +162 -0
  711. package/vendor/ink/node_modules/@types/node/sqlite.d.ts +955 -0
  712. package/vendor/ink/node_modules/@types/node/stream/consumers.d.ts +38 -0
  713. package/vendor/ink/node_modules/@types/node/stream/promises.d.ts +211 -0
  714. package/vendor/ink/node_modules/@types/node/stream/web.d.ts +296 -0
  715. package/vendor/ink/node_modules/@types/node/stream.d.ts +1760 -0
  716. package/vendor/ink/node_modules/@types/node/string_decoder.d.ts +67 -0
  717. package/vendor/ink/node_modules/@types/node/test/reporters.d.ts +96 -0
  718. package/vendor/ink/node_modules/@types/node/test.d.ts +2240 -0
  719. package/vendor/ink/node_modules/@types/node/timers/promises.d.ts +108 -0
  720. package/vendor/ink/node_modules/@types/node/timers.d.ts +159 -0
  721. package/vendor/ink/node_modules/@types/node/tls.d.ts +1198 -0
  722. package/vendor/ink/node_modules/@types/node/trace_events.d.ts +197 -0
  723. package/vendor/ink/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +462 -0
  724. package/vendor/ink/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
  725. package/vendor/ink/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
  726. package/vendor/ink/node_modules/@types/node/ts5.6/index.d.ts +117 -0
  727. package/vendor/ink/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
  728. package/vendor/ink/node_modules/@types/node/ts5.7/index.d.ts +117 -0
  729. package/vendor/ink/node_modules/@types/node/tty.d.ts +250 -0
  730. package/vendor/ink/node_modules/@types/node/url.d.ts +519 -0
  731. package/vendor/ink/node_modules/@types/node/util/types.d.ts +558 -0
  732. package/vendor/ink/node_modules/@types/node/util.d.ts +1662 -0
  733. package/vendor/ink/node_modules/@types/node/v8.d.ts +983 -0
  734. package/vendor/ink/node_modules/@types/node/vm.d.ts +1208 -0
  735. package/vendor/ink/node_modules/@types/node/wasi.d.ts +202 -0
  736. package/vendor/ink/node_modules/@types/node/web-globals/abortcontroller.d.ts +59 -0
  737. package/vendor/ink/node_modules/@types/node/web-globals/blob.d.ts +23 -0
  738. package/vendor/ink/node_modules/@types/node/web-globals/console.d.ts +9 -0
  739. package/vendor/ink/node_modules/@types/node/web-globals/crypto.d.ts +39 -0
  740. package/vendor/ink/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  741. package/vendor/ink/node_modules/@types/node/web-globals/encoding.d.ts +11 -0
  742. package/vendor/ink/node_modules/@types/node/web-globals/events.d.ts +106 -0
  743. package/vendor/ink/node_modules/@types/node/web-globals/fetch.d.ts +69 -0
  744. package/vendor/ink/node_modules/@types/node/web-globals/importmeta.d.ts +13 -0
  745. package/vendor/ink/node_modules/@types/node/web-globals/messaging.d.ts +23 -0
  746. package/vendor/ink/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
  747. package/vendor/ink/node_modules/@types/node/web-globals/performance.d.ts +45 -0
  748. package/vendor/ink/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  749. package/vendor/ink/node_modules/@types/node/web-globals/streams.d.ts +115 -0
  750. package/vendor/ink/node_modules/@types/node/web-globals/timers.d.ts +44 -0
  751. package/vendor/ink/node_modules/@types/node/web-globals/url.d.ts +24 -0
  752. package/vendor/ink/node_modules/@types/node/worker_threads.d.ts +717 -0
  753. package/vendor/ink/node_modules/@types/node/zlib.d.ts +618 -0
  754. package/vendor/ink/node_modules/node-pty/LICENSE +69 -0
  755. package/vendor/ink/node_modules/node-pty/README.md +164 -0
  756. package/vendor/ink/node_modules/node-pty/binding.gyp +150 -0
  757. package/vendor/ink/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
  758. package/vendor/ink/node_modules/node-pty/lib/eventEmitter2.js +47 -0
  759. package/vendor/ink/node_modules/node-pty/lib/index.js +52 -0
  760. package/vendor/ink/node_modules/node-pty/lib/interfaces.js +7 -0
  761. package/vendor/ink/node_modules/node-pty/lib/shared/conout.js +11 -0
  762. package/vendor/ink/node_modules/node-pty/lib/terminal.js +190 -0
  763. package/vendor/ink/node_modules/node-pty/lib/types.js +7 -0
  764. package/vendor/ink/node_modules/node-pty/lib/unixTerminal.js +349 -0
  765. package/vendor/ink/node_modules/node-pty/lib/utils.js +39 -0
  766. package/vendor/ink/node_modules/node-pty/lib/windowsConoutConnection.js +125 -0
  767. package/vendor/ink/node_modules/node-pty/lib/windowsPtyAgent.js +287 -0
  768. package/vendor/ink/node_modules/node-pty/lib/windowsTerminal.js +201 -0
  769. package/vendor/ink/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  770. package/vendor/ink/node_modules/node-pty/package.json +65 -0
  771. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
  772. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  773. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
  774. package/vendor/ink/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
  775. package/vendor/ink/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
  776. package/vendor/ink/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
  777. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  778. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  779. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  780. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty.pdb +0 -0
  781. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  782. package/vendor/ink/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
  783. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  784. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  785. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  786. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty.pdb +0 -0
  787. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  788. package/vendor/ink/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
  789. package/vendor/ink/node_modules/node-pty/scripts/post-install.js +76 -0
  790. package/vendor/ink/node_modules/node-pty/scripts/prebuild.js +34 -0
  791. package/vendor/ink/node_modules/node-pty/src/unix/pty.cc +875 -0
  792. package/vendor/ink/node_modules/node-pty/src/unix/spawn-helper.cc +23 -0
  793. package/vendor/ink/node_modules/node-pty/src/win/conpty.cc +582 -0
  794. package/vendor/ink/node_modules/node-pty/src/win/conpty.h +41 -0
  795. package/vendor/ink/node_modules/node-pty/src/win/conpty_console_list.cc +44 -0
  796. package/vendor/ink/node_modules/node-pty/src/win/path_util.cc +95 -0
  797. package/vendor/ink/node_modules/node-pty/src/win/path_util.h +26 -0
  798. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
  799. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
  800. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
  801. package/vendor/ink/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
  802. package/vendor/ink/node_modules/node-pty/typings/node-pty.d.ts +215 -0
  803. package/vendor/ink/node_modules/undici-types/LICENSE +21 -0
  804. package/vendor/ink/node_modules/undici-types/README.md +6 -0
  805. package/vendor/ink/node_modules/undici-types/agent.d.ts +32 -0
  806. package/vendor/ink/node_modules/undici-types/api.d.ts +43 -0
  807. package/vendor/ink/node_modules/undici-types/balanced-pool.d.ts +30 -0
  808. package/vendor/ink/node_modules/undici-types/cache-interceptor.d.ts +173 -0
  809. package/vendor/ink/node_modules/undici-types/cache.d.ts +36 -0
  810. package/vendor/ink/node_modules/undici-types/client-stats.d.ts +15 -0
  811. package/vendor/ink/node_modules/undici-types/client.d.ts +108 -0
  812. package/vendor/ink/node_modules/undici-types/connector.d.ts +34 -0
  813. package/vendor/ink/node_modules/undici-types/content-type.d.ts +21 -0
  814. package/vendor/ink/node_modules/undici-types/cookies.d.ts +30 -0
  815. package/vendor/ink/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
  816. package/vendor/ink/node_modules/undici-types/dispatcher.d.ts +276 -0
  817. package/vendor/ink/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
  818. package/vendor/ink/node_modules/undici-types/errors.d.ts +161 -0
  819. package/vendor/ink/node_modules/undici-types/eventsource.d.ts +66 -0
  820. package/vendor/ink/node_modules/undici-types/fetch.d.ts +211 -0
  821. package/vendor/ink/node_modules/undici-types/formdata.d.ts +108 -0
  822. package/vendor/ink/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  823. package/vendor/ink/node_modules/undici-types/global-origin.d.ts +7 -0
  824. package/vendor/ink/node_modules/undici-types/h2c-client.d.ts +73 -0
  825. package/vendor/ink/node_modules/undici-types/handlers.d.ts +15 -0
  826. package/vendor/ink/node_modules/undici-types/header.d.ts +160 -0
  827. package/vendor/ink/node_modules/undici-types/index.d.ts +88 -0
  828. package/vendor/ink/node_modules/undici-types/interceptors.d.ts +73 -0
  829. package/vendor/ink/node_modules/undici-types/mock-agent.d.ts +68 -0
  830. package/vendor/ink/node_modules/undici-types/mock-call-history.d.ts +111 -0
  831. package/vendor/ink/node_modules/undici-types/mock-client.d.ts +27 -0
  832. package/vendor/ink/node_modules/undici-types/mock-errors.d.ts +12 -0
  833. package/vendor/ink/node_modules/undici-types/mock-interceptor.d.ts +94 -0
  834. package/vendor/ink/node_modules/undici-types/mock-pool.d.ts +27 -0
  835. package/vendor/ink/node_modules/undici-types/package.json +55 -0
  836. package/vendor/ink/node_modules/undici-types/patch.d.ts +29 -0
  837. package/vendor/ink/node_modules/undici-types/pool-stats.d.ts +19 -0
  838. package/vendor/ink/node_modules/undici-types/pool.d.ts +41 -0
  839. package/vendor/ink/node_modules/undici-types/proxy-agent.d.ts +29 -0
  840. package/vendor/ink/node_modules/undici-types/readable.d.ts +68 -0
  841. package/vendor/ink/node_modules/undici-types/retry-agent.d.ts +8 -0
  842. package/vendor/ink/node_modules/undici-types/retry-handler.d.ts +125 -0
  843. package/vendor/ink/node_modules/undici-types/round-robin-pool.d.ts +41 -0
  844. package/vendor/ink/node_modules/undici-types/snapshot-agent.d.ts +109 -0
  845. package/vendor/ink/node_modules/undici-types/util.d.ts +18 -0
  846. package/vendor/ink/node_modules/undici-types/utility.d.ts +7 -0
  847. package/vendor/ink/node_modules/undici-types/webidl.d.ts +341 -0
  848. package/vendor/ink/node_modules/undici-types/websocket.d.ts +186 -0
  849. package/vendor/ink/package.json +201 -0
  850. package/vendor/ink/readme.md +2636 -0
  851. package/bin/swag-agent.js +0 -9
  852. package/dist/server/lib/pg-rate-limiter.d.ts +0 -21
  853. package/dist/server/lib/pg-rate-limiter.js +0 -86
@@ -8,679 +8,961 @@
8
8
  * Consolidates: streaming, prompt caching, context management betas, compaction,
9
9
  * loop detection, parallel tool execution, subagent delegation, retry, cost tracking.
10
10
  */
11
- import { LoopDetector, getContextManagement, getMaxOutputTokens, getThinkingConfig, addPromptCaching, estimateCostUsd, isRetryableError, sanitizeError, routeModel, resolveToolChoice, emitCostWarningIfNeeded, demoteSubagentModel, COMPACTION_TRIGGER_TOKENS, COMPACTION_TOTAL_BUDGET, DEFAULT_SESSION_COST_BUDGET_USD, } from "../../shared/agent-core.js";
11
+
12
+ import { LoopDetector, getContextManagement, getMaxOutputTokens, getThinkingConfig, addPromptCaching, estimateCostUsd, isRetryableError, sanitizeError, routeModel, resolveToolChoice, emitCostWarningIfNeeded, demoteSubagentModel, COMPACTION_TOTAL_BUDGET, DEFAULT_SESSION_COST_BUDGET_USD, AGENT_DEFAULTS } from "../../shared/agent-core.js";
12
13
  import { processStreamWithCallbacks } from "../../shared/sse-parser.js";
13
14
  import { MODELS } from "../../shared/constants.js";
14
15
  import { dispatchTools, buildAssistantContent } from "../../shared/tool-dispatch.js";
15
16
  import { getCachedToolDefs, getFullToolSchemas } from "../tool-router.js";
16
17
  import { queueSpan, auditRowToSpan } from "./clickhouse-buffer.js";
17
- import { DELEGATE_TASK_TOOL_DEF, runServerSubagent, } from "./server-subagent.js";
18
+ import { DELEGATE_TASK_TOOL_DEF, runServerSubagent } from "./server-subagent.js";
18
19
  import { handleTranscribe } from "../handlers/transcription.js";
19
20
  import { preCompact } from "./compaction-service.js";
20
21
  import { providerFailover } from "./provider-failover.js";
21
22
  import { saveCheckpoint } from "./session-checkpoint.js";
22
23
  import { createLogger } from "./logger.js";
23
24
  const log = createLogger("agent-loop");
25
+
26
+ // ============================================================================
27
+ // TYPES
28
+ // ============================================================================
29
+
30
+ // Re-export for consumers
31
+
24
32
  // ============================================================================
25
33
  // CONSTANTS
26
34
  // ============================================================================
35
+
27
36
  const MAX_RETRIES = 3;
28
37
  const RETRY_BASE_DELAY_MS = 1000;
29
38
  const DEFAULT_MAX_CONCURRENT_TOOLS = 7;
39
+
30
40
  // ============================================================================
31
41
  // TOOL CHOICE MAPPING — convert ToolChoice to provider-specific format
32
42
  // ============================================================================
43
+
33
44
  /**
34
45
  * Map ToolChoice to Anthropic API `tool_choice` format.
35
46
  * Returns undefined if tools should be omitted entirely.
36
47
  */
37
48
  function mapToolChoiceForAnthropic(tc) {
38
- if (tc === "auto")
39
- return { toolChoice: { type: "auto" } };
40
- if (tc === "any")
41
- return { toolChoice: { type: "any" } };
42
- if (tc === "none")
43
- return { omitTools: true };
44
- if (typeof tc === "object" && tc.type === "tool") {
45
- return { toolChoice: { type: "tool", name: tc.name } };
49
+ if (tc === "auto") return {
50
+ toolChoice: {
51
+ type: "auto"
52
+ }
53
+ };
54
+ if (tc === "any") return {
55
+ toolChoice: {
56
+ type: "any"
46
57
  }
47
- return { toolChoice: { type: "auto" } };
58
+ };
59
+ if (tc === "none") return {
60
+ omitTools: true
61
+ };
62
+ if (typeof tc === "object" && tc.type === "tool") {
63
+ return {
64
+ toolChoice: {
65
+ type: "tool",
66
+ name: tc.name
67
+ }
68
+ };
69
+ }
70
+ return {
71
+ toolChoice: {
72
+ type: "auto"
73
+ }
74
+ };
48
75
  }
76
+
49
77
  // ============================================================================
50
78
  // UNIFIED AGENT LOOP
51
79
  // ============================================================================
80
+
52
81
  export async function runServerAgentLoop(opts) {
53
- const { anthropic, model, systemPrompt, messages, tools: inputTools, maxTurns, temperature, enableDelegation = true, enablePromptCaching = true, enableStreaming = true, maxConcurrentTools = DEFAULT_MAX_CONCURRENT_TOOLS, maxCostUsd: maxCostUsdOpt, onText, onToolStart, onCitation, documents, clientDisconnected = { value: false }, startedAt = Date.now(), maxDurationMs = 15 * 60 * 1000, } = opts;
54
- // Resolve cost budget: explicit opt > env var > default
55
- const envBudget = parseFloat(process.env.WHALE_COST_BUDGET_USD || "");
56
- const maxCostUsd = maxCostUsdOpt ?? (isFinite(envBudget) ? envBudget : DEFAULT_SESSION_COST_BUDGET_USD);
57
- // Auto-inject delegate_task for all models (subagents always use Claude Haiku/Sonnet)
58
- // activeTools is mutable — discover_tools adds to it during the session
59
- const activeTools = [...inputTools];
60
- if (enableDelegation) {
61
- if (!activeTools.some((t) => t.name === "delegate_task")) {
62
- activeTools.push(DELEGATE_TASK_TOOL_DEF);
63
- }
82
+ const {
83
+ anthropic,
84
+ model,
85
+ systemPrompt,
86
+ messages,
87
+ tools: inputTools,
88
+ maxTurns,
89
+ temperature,
90
+ enableDelegation = true,
91
+ enablePromptCaching = true,
92
+ enableStreaming = true,
93
+ enableModelRouting = true,
94
+ maxConcurrentTools = DEFAULT_MAX_CONCURRENT_TOOLS,
95
+ maxCostUsd: maxCostUsdOpt,
96
+ onText,
97
+ onToolStart,
98
+ onCitation,
99
+ documents,
100
+ clientDisconnected = {
101
+ value: false
102
+ },
103
+ startedAt = Date.now(),
104
+ maxDurationMs = 15 * 60 * 1000
105
+ } = opts;
106
+
107
+ // Resolve cost budget: context_config > explicit opt > env var > default
108
+ const ctxOverrides = opts.contextOverrides;
109
+ const envBudget = parseFloat(process.env.WHALE_COST_BUDGET_USD || "");
110
+ const maxCostUsd = ctxOverrides?.session_cost_budget_usd ?? maxCostUsdOpt ?? (isFinite(envBudget) ? envBudget : DEFAULT_SESSION_COST_BUDGET_USD);
111
+
112
+ // Resolve compaction budget from overrides (used for compaction exhaustion checks)
113
+ const effectiveCompactionTrigger = ctxOverrides?.compaction_trigger_tokens ?? 150_000;
114
+ const effectiveCompactionBudget = ctxOverrides?.compaction_total_budget ?? COMPACTION_TOTAL_BUDGET;
115
+
116
+ // Auto-inject delegate_task for all models (subagents always use Claude Haiku/Sonnet)
117
+ // activeTools is mutable — discover_tools adds to it during the session
118
+ const activeTools = [...inputTools];
119
+ if (enableDelegation) {
120
+ if (!activeTools.some(t => t.name === "delegate_task")) {
121
+ activeTools.push(DELEGATE_TASK_TOOL_DEF);
64
122
  }
65
- // Per-conversation tracking of discovered tools — accumulates tool names
66
- // activated via discover_tools so they persist across turns within this session.
67
- // If extendedTools were provided (from a previous session or pre-load), we
68
- // don't inject them yet (that defeats lazy loading), but we keep the full
69
- // list available for the executor to reference.
70
- const discoveredToolNames = new Set();
71
- // Alias for backward compat within this function
72
- const tools = activeTools;
73
- const loopDetector = new LoopDetector();
74
- // Model routing: extract first user message for complexity estimation
75
- const firstUserMsg = messages.find((m) => m.role === "user");
76
- const firstUserText = firstUserMsg
77
- ? typeof firstUserMsg.content === "string"
78
- ? firstUserMsg.content
79
- : Array.isArray(firstUserMsg.content)
80
- ? firstUserMsg.content
81
- .filter((b) => b.type === "text" && b.text)
82
- .map((b) => b.text)
83
- .join(" ")
84
- : ""
85
- : "";
86
- // Pre-computed tool defs — reused across turns, only rebuilt when tools array changes
87
- let cachedToolDefsForSession = getCachedToolDefs(tools);
88
- let lastToolCount = tools.length;
89
- // Accumulators
90
- let turnCount = 0;
91
- let toolCallCount = 0;
92
- let totalIn = 0;
93
- let totalOut = 0;
94
- let cacheCreationTokens = 0;
95
- let cacheReadTokens = 0;
96
- let sessionCostUsd = 0;
97
- let compactionCount = 0;
98
- let finalResponse = "";
99
- let lastStopReason = "end_turn";
100
- const allTextResponses = [];
101
- const allToolNames = [];
102
- const allCitations = [];
103
- const turnMetrics = [];
104
- const costWarningsEmitted = new Set();
105
- while (turnCount < maxTurns) {
106
- // Abort checks
107
- if (clientDisconnected.value) {
108
- log.info("client disconnected, stopping");
109
- break;
110
- }
111
- if (Date.now() - startedAt > maxDurationMs) {
112
- onText?.("[Request timeout exceeded]");
113
- break;
114
- }
115
- // Cost budget enforcement — prevent runaway spending (skip if unlimited)
116
- if (isFinite(maxCostUsd) && sessionCostUsd >= maxCostUsd) {
117
- log.warn({ sessionCostUsd, maxCostUsd }, "cost budget exceeded");
118
- onText?.(`\n[Session cost budget reached ($${sessionCostUsd.toFixed(2)}/$${maxCostUsd.toFixed(2)}). Wrapping up.]`);
119
- break;
120
- }
121
- turnCount++;
122
- loopDetector.resetTurn();
123
- // Route model on the FIRST turn only — subsequent turns use the requested model
124
- // since the conversation may have become complex after tool results.
125
- const effectiveModel = turnCount === 1
126
- ? routeModel(firstUserText, model)
127
- : model;
128
- if (turnCount === 1 && effectiveModel !== model) {
129
- log.info({ from: model, to: effectiveModel }, "model routed");
130
- }
131
- // Per-turn model config — uses effectiveModel so routed models get correct settings
132
- const maxTokens = opts.maxTokens ?? getMaxOutputTokens(effectiveModel);
133
- const ctxMgmt = getContextManagement(effectiveModel);
134
- const thinkingCfg = getThinkingConfig(effectiveModel, true);
135
- // Prepare tool definitions — use pre-computed cache, only rebuild when tools change
136
- // (discover_tools can add tools mid-session, detected via length change)
137
- if (tools.length !== lastToolCount) {
138
- cachedToolDefsForSession = getCachedToolDefs(tools);
139
- lastToolCount = tools.length;
140
- }
141
- // Pre-compaction: mechanically strip redundant data before LLM call
142
- // Runs every turn but only modifies messages when there's significant bloat
143
- const { messages: preCompacted, bytesRemoved } = preCompact(messages);
144
- if (bytesRemoved > 10000) {
145
- log.info({ bytesRemoved, bytesRemovedKB: Math.round(bytesRemoved / 1024) }, "pre-compaction applied");
146
- // Replace messages in-place so the outer array reference stays valid
147
- messages.length = 0;
148
- messages.push(...preCompacted);
123
+ }
124
+
125
+ // Per-conversation tracking of discovered tools accumulates tool names
126
+ // activated via discover_tools so they persist across turns within this session.
127
+ // If extendedTools were provided (from a previous session or pre-load), we
128
+ // don't inject them yet (that defeats lazy loading), but we keep the full
129
+ // list available for the executor to reference.
130
+ const discoveredToolNames = new Set();
131
+
132
+ // Alias for backward compat within this function
133
+ const tools = activeTools;
134
+ const loopDetector = new LoopDetector(opts.loopDetectorConfig);
135
+
136
+ // Model routing: extract first user message for complexity estimation
137
+ const firstUserMsg = messages.find(m => m.role === "user");
138
+ const firstUserText = firstUserMsg ? typeof firstUserMsg.content === "string" ? firstUserMsg.content : Array.isArray(firstUserMsg.content) ? firstUserMsg.content.filter(b => b.type === "text" && b.text).map(b => b.text).join(" ") : "" : "";
139
+
140
+ // Pre-computed tool defs — reused across turns, only rebuilt when tools array changes
141
+ let cachedToolDefsForSession = getCachedToolDefs(tools);
142
+ let lastToolCount = tools.length;
143
+
144
+ // Accumulators
145
+ let turnCount = 0;
146
+ let toolCallCount = 0;
147
+ let totalIn = 0;
148
+ let totalOut = 0;
149
+ let cacheCreationTokens = 0;
150
+ let cacheReadTokens = 0;
151
+ let sessionCostUsd = 0;
152
+ let compactionCount = 0;
153
+ let consecutiveCompactions = 0;
154
+ let finalResponse = "";
155
+ let lastStopReason = "end_turn";
156
+ const allTextResponses = [];
157
+ const allToolNames = [];
158
+ const allCitations = [];
159
+ const turnMetrics = [];
160
+ const costWarningsEmitted = new Set();
161
+ while (turnCount < maxTurns) {
162
+ // Abort checks
163
+ if (clientDisconnected.value) {
164
+ log.info("client disconnected, stopping");
165
+ break;
166
+ }
167
+ if (Date.now() - startedAt > maxDurationMs) {
168
+ onText?.("[Request timeout exceeded]");
169
+ break;
170
+ }
171
+ // Cost budget enforcement — prevent runaway spending (skip if unlimited)
172
+ if (isFinite(maxCostUsd) && sessionCostUsd >= maxCostUsd) {
173
+ log.warn({
174
+ sessionCostUsd,
175
+ maxCostUsd
176
+ }, "cost budget exceeded");
177
+ onText?.(`\n[Session cost budget reached ($${sessionCostUsd.toFixed(2)}/$${maxCostUsd.toFixed(2)}). Wrapping up.]`);
178
+ break;
179
+ }
180
+ turnCount++;
181
+ loopDetector.resetTurn();
182
+
183
+ // Route model on the FIRST turn only — subsequent turns use the requested model
184
+ // since the conversation may have become complex after tool results.
185
+ // enableModelRouting=false prevents downgrade (e.g. Opus agents that should stay Opus)
186
+ const effectiveModel = turnCount === 1 && enableModelRouting ? routeModel(firstUserText, model) : model;
187
+ if (turnCount === 1 && effectiveModel !== model) {
188
+ log.info({
189
+ from: model,
190
+ to: effectiveModel
191
+ }, "model routed");
192
+ }
193
+
194
+ // Per-turn model config uses effectiveModel so routed models get correct settings
195
+ const maxTokens = opts.maxTokens ?? getMaxOutputTokens(effectiveModel);
196
+ const ctxMgmt = getContextManagement(effectiveModel, opts.contextOverrides);
197
+ const thinkingCfg = getThinkingConfig(effectiveModel, true);
198
+
199
+ // Prepare tool definitions — use pre-computed cache, only rebuild when tools change
200
+ // (discover_tools can add tools mid-session, detected via length change)
201
+ if (tools.length !== lastToolCount) {
202
+ cachedToolDefsForSession = getCachedToolDefs(tools);
203
+ lastToolCount = tools.length;
204
+ }
205
+
206
+ // Pre-compaction: mechanically strip redundant data before LLM call
207
+ // Runs every turn but only modifies messages when there's significant bloat
208
+ const {
209
+ messages: preCompacted,
210
+ bytesRemoved
211
+ } = preCompact(messages);
212
+ if (bytesRemoved > 10000) {
213
+ log.info({
214
+ bytesRemoved,
215
+ bytesRemovedKB: Math.round(bytesRemoved / 1024)
216
+ }, "pre-compaction applied");
217
+ // Replace messages in-place so the outer array reference stays valid
218
+ messages.length = 0;
219
+ messages.push(...preCompacted);
220
+ }
221
+
222
+ // Prompt caching: tools + turn boundary
223
+ let finalToolDefs = cachedToolDefsForSession;
224
+ let finalMessages = messages;
225
+ if (enablePromptCaching) {
226
+ const cached = addPromptCaching(cachedToolDefsForSession, messages);
227
+ finalToolDefs = cached.tools;
228
+ finalMessages = cached.messages;
229
+ }
230
+
231
+ // System prompt: cached block + dynamic cost context (skip cost line if unlimited budget)
232
+ const costContext = isFinite(maxCostUsd) ? `Session cost: $${sessionCostUsd.toFixed(2)} / $${maxCostUsd.toFixed(2)}` : `Session cost: $${sessionCostUsd.toFixed(2)}`;
233
+ const system = enablePromptCaching ? [{
234
+ type: "text",
235
+ text: systemPrompt,
236
+ cache_control: {
237
+ type: "ephemeral"
238
+ }
239
+ }, {
240
+ type: "text",
241
+ text: costContext
242
+ }] : [{
243
+ type: "text",
244
+ text: systemPrompt
245
+ }, {
246
+ type: "text",
247
+ text: costContext
248
+ }];
249
+
250
+ // Resolve tool_choice for this turn
251
+ const recentToolUses = turnMetrics.slice(-3).flatMap(t => t.toolsUsed);
252
+ let resolvedToolChoice = resolveToolChoice({
253
+ toolChoice: opts.toolChoice,
254
+ turnCount,
255
+ recentToolUses,
256
+ availableToolNames: tools.map(t => t.name),
257
+ userMessage: firstUserText
258
+ });
259
+ // Anthropic API: forced tool_choice ("any" or specific tool) is incompatible with thinking — downgrade to "auto"
260
+ if (thinkingCfg.thinking.type !== "disabled" && resolvedToolChoice !== "auto" && resolvedToolChoice !== "none") {
261
+ resolvedToolChoice = "auto";
262
+ }
263
+ const {
264
+ toolChoice: anthropicToolChoice,
265
+ omitTools
266
+ } = mapToolChoiceForAnthropic(resolvedToolChoice);
267
+ if (omitTools) {
268
+ log.info({
269
+ turn: turnCount,
270
+ resolvedToolChoice
271
+ }, "tool_choice=none — omitting tools");
272
+ }
273
+
274
+ // Provider failover check — route to healthy provider (capability-aware)
275
+ const failoverResult = providerFailover.getActiveProvider(effectiveModel, opts.requiredCapabilities);
276
+ const activeModel = failoverResult.model;
277
+ const activeProvider = failoverResult.provider;
278
+ let turnFailoverInfo;
279
+ if (failoverResult.failedOver) {
280
+ turnFailoverInfo = {
281
+ originalProvider: failoverResult.originalProvider,
282
+ activeProvider: failoverResult.provider,
283
+ model: failoverResult.model
284
+ };
285
+ // Re-compute model config for the failover model
286
+ // (context management, thinking, max tokens may differ)
287
+ }
288
+
289
+ // API call with retry
290
+ if (enableStreaming) {
291
+ // ---- STREAMING PATH ----
292
+ let stream = null;
293
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
294
+ try {
295
+ // Cast through unknown: context_management.edits is Record<string, unknown>[]
296
+ // from getContextManagement() but SDK expects specific edit union types
297
+ const streamBetas = [...ctxMgmt.betas];
298
+ if (thinkingCfg.beta) streamBetas.push(thinkingCfg.beta);
299
+ // Citations API: add beta when source documents are provided
300
+ if (documents?.length && !streamBetas.includes("citations-2025-04-15")) {
301
+ streamBetas.push("citations-2025-04-15");
302
+ }
303
+ stream = await anthropic.beta.messages.create({
304
+ model: activeModel,
305
+ max_tokens: maxTokens,
306
+ temperature: thinkingCfg.thinking.type !== "disabled" ? 1 : temperature,
307
+ system,
308
+ ...(omitTools ? {} : {
309
+ tools: finalToolDefs
310
+ }),
311
+ ...(anthropicToolChoice && !omitTools ? {
312
+ tool_choice: anthropicToolChoice
313
+ } : {}),
314
+ messages: finalMessages,
315
+ stream: true,
316
+ thinking: thinkingCfg.thinking,
317
+ betas: streamBetas,
318
+ context_management: ctxMgmt.config,
319
+ ...(documents?.length ? {
320
+ documents
321
+ } : {})
322
+ });
323
+ providerFailover.recordSuccess(activeProvider);
324
+ break;
325
+ } catch (err) {
326
+ providerFailover.recordFailure(activeProvider);
327
+ if (attempt < MAX_RETRIES && isRetryableError(err)) {
328
+ const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt);
329
+ log.warn({
330
+ attempt: attempt + 1,
331
+ maxRetries: MAX_RETRIES,
332
+ delayMs: delay,
333
+ err: sanitizeError(err)
334
+ }, "retrying API call");
335
+ await new Promise(resolve => setTimeout(resolve, delay));
336
+ continue;
337
+ }
338
+ throw err;
149
339
  }
150
- // Prompt caching: tools + turn boundary
151
- let finalToolDefs = cachedToolDefsForSession;
152
- let finalMessages = messages;
153
- if (enablePromptCaching) {
154
- const cached = addPromptCaching(cachedToolDefsForSession, messages);
155
- finalToolDefs = cached.tools;
156
- finalMessages = cached.messages;
340
+ }
341
+ if (!stream) throw new Error("Failed to get response after retries");
342
+
343
+ // Process stream events via unified parser
344
+ const streamResult = await processStreamWithCallbacks(stream, {
345
+ onText,
346
+ onToolStart,
347
+ onCitation
348
+ });
349
+ const currentText = streamResult.text;
350
+ const toolUseBlocks = streamResult.toolUseBlocks;
351
+ const compactionContent = streamResult.compactionContent;
352
+
353
+ // Accumulate citations from this turn
354
+ if (streamResult.citations.length > 0) {
355
+ allCitations.push(...streamResult.citations);
356
+ }
357
+
358
+ // Accumulate per-turn tokens into session totals
359
+ const turnIn = streamResult.usage.inputTokens;
360
+ const turnOut = streamResult.usage.outputTokens;
361
+ const turnCacheRead = streamResult.usage.cacheReadTokens;
362
+ const turnCacheCreation = streamResult.usage.cacheCreationTokens;
363
+ totalIn += turnIn;
364
+ totalOut += turnOut;
365
+ cacheCreationTokens += turnCacheCreation;
366
+ cacheReadTokens += turnCacheRead;
367
+
368
+ // Update cost (include cache tokens for accurate pricing)
369
+ sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens);
370
+
371
+ // Graduated cost warnings — give the LLM visibility into spend
372
+ emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
373
+
374
+ // Record per-turn metrics for observability
375
+ const turnToolNames = toolUseBlocks.map(b => b.name);
376
+ turnMetrics.push({
377
+ turn: turnCount,
378
+ inputTokens: turnIn,
379
+ outputTokens: turnOut,
380
+ cacheRead: turnCacheRead,
381
+ cacheCreation: turnCacheCreation,
382
+ toolsUsed: turnToolNames,
383
+ costUsd: estimateCostUsd(turnIn, turnOut, model, 0, turnCacheRead, turnCacheCreation),
384
+ ...(turnFailoverInfo ? {
385
+ failover: turnFailoverInfo
386
+ } : {})
387
+ });
388
+ if (currentText) allTextResponses.push(currentText);
389
+
390
+ // Compaction handling — API paused after generating summary.
391
+ // Preserve last 2 messages (1 user + 1 assistant turn) for continuity,
392
+ // then resume. This is NOT a new turn — just context compression.
393
+ lastStopReason = streamResult.stopReason || "end_turn";
394
+ if (streamResult.stopReason === "compaction" && compactionContent) {
395
+ compactionCount++;
396
+ consecutiveCompactions++;
397
+ log.info({
398
+ compactionCount,
399
+ consecutiveCompactions
400
+ }, "compaction — rebuilding context from summary");
401
+
402
+ // Circuit breaker + budget enforcement
403
+ const MAX_CONSECUTIVE_COMPACTIONS = 3;
404
+ const shouldWrapUp = consecutiveCompactions > MAX_CONSECUTIVE_COMPACTIONS || compactionCount * effectiveCompactionTrigger >= effectiveCompactionBudget;
405
+ if (shouldWrapUp) {
406
+ log.warn({
407
+ compactionCount,
408
+ consecutiveCompactions,
409
+ triggerTokens: effectiveCompactionTrigger
410
+ }, "compaction wrap-up triggered");
411
+ onText?.(consecutiveCompactions > MAX_CONSECUTIVE_COMPACTIONS ? "\n[Compaction loop detected — wrapping up.]" : "\n[Context budget reached — wrapping up.]");
157
412
  }
158
- // System prompt: cached block + dynamic cost context (skip cost line if unlimited budget)
159
- const costContext = isFinite(maxCostUsd)
160
- ? `Session cost: $${sessionCostUsd.toFixed(2)} / $${maxCostUsd.toFixed(2)}`
161
- : `Session cost: $${sessionCostUsd.toFixed(2)}`;
162
- const system = enablePromptCaching
163
- ? [
164
- { type: "text", text: systemPrompt, cache_control: { type: "ephemeral" } },
165
- { type: "text", text: costContext },
166
- ]
167
- : [
168
- { type: "text", text: systemPrompt },
169
- { type: "text", text: costContext },
170
- ];
171
- // Resolve tool_choice for this turn
172
- const recentToolUses = turnMetrics.slice(-3).flatMap(t => t.toolsUsed);
173
- let resolvedToolChoice = resolveToolChoice({
174
- toolChoice: opts.toolChoice,
175
- turnCount,
176
- recentToolUses,
177
- availableToolNames: tools.map(t => t.name),
178
- userMessage: firstUserText,
179
- });
180
- // Anthropic API: forced tool_choice ("any" or specific tool) is incompatible with thinking — downgrade to "auto"
181
- if (thinkingCfg.thinking.type !== "disabled" && resolvedToolChoice !== "auto" && resolvedToolChoice !== "none") {
182
- resolvedToolChoice = "auto";
413
+ const compactedMessages = [{
414
+ role: "assistant",
415
+ content: [{
416
+ type: "compaction",
417
+ content: compactionContent
418
+ }]
419
+ }, {
420
+ role: "user",
421
+ content: [{
422
+ type: "text",
423
+ text: shouldWrapUp ? "You have reached the context budget. Please wrap up your current work and provide a final summary of what was accomplished and what remains." : "Continue with your task."
424
+ }]
425
+ }];
426
+ messages.length = 0;
427
+ messages.push(...compactedMessages);
428
+ turnCount--; // Don't count compaction as a turn
429
+ continue;
430
+ }
431
+
432
+ // No tool calls — check if truncated at max_tokens
433
+ if (toolUseBlocks.length === 0) {
434
+ if (streamResult.stopReason === "max_tokens") {
435
+ const assistantContent = buildAssistantContent({
436
+ text: currentText,
437
+ toolUseBlocks: [],
438
+ compactionContent
439
+ });
440
+ messages.push({
441
+ role: "assistant",
442
+ content: assistantContent
443
+ });
444
+ messages.push({
445
+ role: "user",
446
+ content: [{
447
+ type: "text",
448
+ text: "[Your response was truncated due to length. Please continue where you left off.]"
449
+ }]
450
+ });
451
+ continue;
183
452
  }
184
- const { toolChoice: anthropicToolChoice, omitTools } = mapToolChoiceForAnthropic(resolvedToolChoice);
185
- if (omitTools) {
186
- log.info({ turn: turnCount, resolvedToolChoice }, "tool_choice=none — omitting tools");
453
+ finalResponse = currentText;
454
+ break;
455
+ }
456
+
457
+ // Reset — model is making progress (tool calls)
458
+ consecutiveCompactions = 0;
459
+
460
+ // Execute tools and build messages for next turn
461
+ const subagentTokens = {
462
+ input: 0,
463
+ output: 0,
464
+ costUsd: 0
465
+ };
466
+ const executor = makeToolExecutor(opts, tools, allToolNames, subagentTokens, discoveredToolNames);
467
+ const {
468
+ results: toolResults
469
+ } = await dispatchTools(toolUseBlocks, executor, {
470
+ loopDetector,
471
+ maxConcurrent: maxConcurrentTools,
472
+ batchErrorLimit: opts.batchErrorLimit ?? AGENT_DEFAULTS.loopBatchErrorLimit,
473
+ // maxResultChars removed — Anthropic context_management handles limits
474
+ transcribeAudio: opts.storeId ? async (base64, mediaType) => {
475
+ const result = await handleTranscribe(opts.supabase, opts.storeId, base64, mediaType);
476
+ if (!result.success || !result.transcript) {
477
+ throw new Error(result.error || "Transcription returned no transcript");
478
+ }
479
+ return result.transcript;
480
+ } : undefined
481
+ });
482
+ toolCallCount += toolUseBlocks.length;
483
+
484
+ // Aggregate subagent tokens into parent totals
485
+ totalIn += subagentTokens.input;
486
+ totalOut += subagentTokens.output;
487
+ sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens) + subagentTokens.costUsd;
488
+
489
+ // Cost warnings after subagent aggregation (subagents can be expensive)
490
+ emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
491
+ const assistantContent = buildAssistantContent({
492
+ text: currentText,
493
+ toolUseBlocks,
494
+ compactionContent
495
+ });
496
+ messages.push({
497
+ role: "assistant",
498
+ content: assistantContent
499
+ });
500
+ messages.push({
501
+ role: "user",
502
+ content: toolResults
503
+ });
504
+
505
+ // Session checkpoint — fire-and-forget, never blocks the loop
506
+ if (opts.conversationId) {
507
+ saveCheckpoint(opts.supabase, opts.conversationId, turnCount, messages, {
508
+ input: totalIn,
509
+ output: totalOut,
510
+ cacheRead: cacheReadTokens,
511
+ cacheCreation: cacheCreationTokens
512
+ }, sessionCostUsd, allToolNames).catch(() => {}); // swallow — saveCheckpoint already logs internally
513
+ }
514
+ } else {
515
+ // ---- NON-STREAMING PATH ----
516
+ let response = null;
517
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
518
+ try {
519
+ // Cast through unknown: context_management.edits is Record<string, unknown>[]
520
+ // from getContextManagement() but SDK expects specific edit union types
521
+ const nsBetas = [...ctxMgmt.betas];
522
+ if (thinkingCfg.beta) nsBetas.push(thinkingCfg.beta);
523
+ // Citations API: add beta when source documents are provided
524
+ if (documents?.length && !nsBetas.includes("citations-2025-04-15")) {
525
+ nsBetas.push("citations-2025-04-15");
526
+ }
527
+ response = await anthropic.beta.messages.create({
528
+ model: activeModel,
529
+ max_tokens: maxTokens,
530
+ temperature: thinkingCfg.thinking.type !== "disabled" ? 1 : temperature,
531
+ system,
532
+ ...(omitTools ? {} : {
533
+ tools: finalToolDefs
534
+ }),
535
+ ...(anthropicToolChoice && !omitTools ? {
536
+ tool_choice: anthropicToolChoice
537
+ } : {}),
538
+ messages: finalMessages,
539
+ thinking: thinkingCfg.thinking,
540
+ betas: nsBetas,
541
+ context_management: ctxMgmt.config,
542
+ ...(documents?.length ? {
543
+ documents
544
+ } : {})
545
+ });
546
+ providerFailover.recordSuccess(activeProvider);
547
+ break;
548
+ } catch (err) {
549
+ providerFailover.recordFailure(activeProvider);
550
+ if (attempt < MAX_RETRIES && isRetryableError(err)) {
551
+ const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt);
552
+ log.warn({
553
+ attempt: attempt + 1,
554
+ maxRetries: MAX_RETRIES,
555
+ delayMs: delay,
556
+ err: sanitizeError(err)
557
+ }, "retrying API call");
558
+ await new Promise(resolve => setTimeout(resolve, delay));
559
+ continue;
560
+ }
561
+ throw err;
187
562
  }
188
- // Provider failover check — route to healthy provider (capability-aware)
189
- const failoverResult = providerFailover.getActiveProvider(effectiveModel, opts.requiredCapabilities);
190
- const activeModel = failoverResult.model;
191
- const activeProvider = failoverResult.provider;
192
- let turnFailoverInfo;
193
- if (failoverResult.failedOver) {
194
- turnFailoverInfo = {
195
- originalProvider: failoverResult.originalProvider,
196
- activeProvider: failoverResult.provider,
197
- model: failoverResult.model,
198
- };
199
- // Re-compute model config for the failover model
200
- // (context management, thinking, max tokens may differ)
563
+ }
564
+ if (!response) throw new Error("Failed to get response after retries");
565
+
566
+ // Track tokens
567
+ const nsTurnIn = response.usage?.input_tokens || 0;
568
+ const nsTurnOut = response.usage?.output_tokens || 0;
569
+ const nsTurnCacheCreation = response.usage?.cache_creation_input_tokens ?? 0;
570
+ const nsTurnCacheRead = response.usage?.cache_read_input_tokens ?? 0;
571
+ totalIn += nsTurnIn;
572
+ totalOut += nsTurnOut;
573
+ cacheCreationTokens += nsTurnCacheCreation;
574
+ cacheReadTokens += nsTurnCacheRead;
575
+
576
+ // Extract text, tool_use, cite, and compaction blocks
577
+ let currentText = "";
578
+ let nsCompactionContent = null;
579
+ const toolUseBlocks = [];
580
+ for (const block of response.content) {
581
+ if (block.type === "text") {
582
+ currentText += block.text;
583
+ onText?.(block.text);
584
+ } else if (block.type === "tool_use") {
585
+ toolUseBlocks.push({
586
+ id: block.id,
587
+ name: block.name,
588
+ input: block.input
589
+ });
590
+ onToolStart?.(block.name, block.input);
591
+ } else if (block.type === "cite") {
592
+ const citeBlock = block;
593
+ const citation = {
594
+ type: "cite",
595
+ cited_text: citeBlock.cited_text ?? "",
596
+ document_index: citeBlock.document_index ?? 0,
597
+ start_char_index: citeBlock.start_char_index ?? 0,
598
+ end_char_index: citeBlock.end_char_index ?? 0,
599
+ ...(citeBlock.document_title ? {
600
+ document_title: citeBlock.document_title
601
+ } : {})
602
+ };
603
+ allCitations.push(citation);
604
+ onCitation?.(citation);
605
+ } else if (block.type === "compaction") {
606
+ nsCompactionContent = block.content || "";
201
607
  }
202
- // API call with retry
203
- if (enableStreaming) {
204
- // ---- STREAMING PATH ----
205
- let stream = null;
206
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
207
- try {
208
- // Cast through unknown: context_management.edits is Record<string, unknown>[]
209
- // from getContextManagement() but SDK expects specific edit union types
210
- const streamBetas = [...ctxMgmt.betas];
211
- if (thinkingCfg.beta)
212
- streamBetas.push(thinkingCfg.beta);
213
- // Citations API: add beta when source documents are provided
214
- if (documents?.length && !streamBetas.includes("citations-2025-04-15")) {
215
- streamBetas.push("citations-2025-04-15");
216
- }
217
- stream = await anthropic.beta.messages.create({
218
- model: activeModel,
219
- max_tokens: maxTokens,
220
- temperature: thinkingCfg.thinking.type !== "disabled" ? 1 : temperature,
221
- system,
222
- ...(omitTools ? {} : { tools: finalToolDefs }),
223
- ...(anthropicToolChoice && !omitTools ? { tool_choice: anthropicToolChoice } : {}),
224
- messages: finalMessages,
225
- stream: true,
226
- thinking: thinkingCfg.thinking,
227
- betas: streamBetas,
228
- context_management: ctxMgmt.config,
229
- ...(documents?.length ? { documents } : {}),
230
- });
231
- providerFailover.recordSuccess(activeProvider);
232
- break;
233
- }
234
- catch (err) {
235
- providerFailover.recordFailure(activeProvider);
236
- if (attempt < MAX_RETRIES && isRetryableError(err)) {
237
- const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt);
238
- log.warn({ attempt: attempt + 1, maxRetries: MAX_RETRIES, delayMs: delay, err: sanitizeError(err) }, "retrying API call");
239
- await new Promise((resolve) => setTimeout(resolve, delay));
240
- continue;
241
- }
242
- throw err;
243
- }
244
- }
245
- if (!stream)
246
- throw new Error("Failed to get response after retries");
247
- // Process stream events via unified parser
248
- const streamResult = await processStreamWithCallbacks(stream, { onText, onToolStart, onCitation });
249
- const currentText = streamResult.text;
250
- const toolUseBlocks = streamResult.toolUseBlocks;
251
- const compactionContent = streamResult.compactionContent;
252
- // Accumulate citations from this turn
253
- if (streamResult.citations.length > 0) {
254
- allCitations.push(...streamResult.citations);
255
- }
256
- // Accumulate per-turn tokens into session totals
257
- const turnIn = streamResult.usage.inputTokens;
258
- const turnOut = streamResult.usage.outputTokens;
259
- const turnCacheRead = streamResult.usage.cacheReadTokens;
260
- const turnCacheCreation = streamResult.usage.cacheCreationTokens;
261
- totalIn += turnIn;
262
- totalOut += turnOut;
263
- cacheCreationTokens += turnCacheCreation;
264
- cacheReadTokens += turnCacheRead;
265
- // Update cost (include cache tokens for accurate pricing)
266
- sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens);
267
- // Graduated cost warnings — give the LLM visibility into spend
268
- emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
269
- // Record per-turn metrics for observability
270
- const turnToolNames = toolUseBlocks.map(b => b.name);
271
- turnMetrics.push({
272
- turn: turnCount,
273
- inputTokens: turnIn,
274
- outputTokens: turnOut,
275
- cacheRead: turnCacheRead,
276
- cacheCreation: turnCacheCreation,
277
- toolsUsed: turnToolNames,
278
- costUsd: estimateCostUsd(turnIn, turnOut, model, 0, turnCacheRead, turnCacheCreation),
279
- ...(turnFailoverInfo ? { failover: turnFailoverInfo } : {}),
280
- });
281
- if (currentText)
282
- allTextResponses.push(currentText);
283
- // Compaction handling — API paused after generating summary.
284
- // Preserve last 2 messages (1 user + 1 assistant turn) for continuity,
285
- // then resume. This is NOT a new turn — just context compression.
286
- lastStopReason = streamResult.stopReason || "end_turn";
287
- if (streamResult.stopReason === "compaction" && compactionContent) {
288
- compactionCount++;
289
- log.info({ compactionCount }, "compaction — preserving last 2 messages, resuming");
290
- // Budget enforcement: if cumulative compaction cost exceeds budget, force wrap-up
291
- if (compactionCount * COMPACTION_TRIGGER_TOKENS >= COMPACTION_TOTAL_BUDGET) {
292
- log.warn({ compactionCount, triggerTokens: COMPACTION_TRIGGER_TOKENS, estimatedTokens: compactionCount * COMPACTION_TRIGGER_TOKENS }, "compaction budget exhausted");
293
- onText?.("\n[Context budget reached — wrapping up.]");
294
- // Rebuild messages: compaction summary + wrap-up instruction
295
- const compactedMessages = [
296
- { role: "assistant", content: [{ type: "compaction", content: compactionContent }] },
297
- { role: "user", content: [{ type: "text", text: "You have reached the context budget. Please wrap up your current work and provide a final summary of what was accomplished and what remains." }] },
298
- ];
299
- messages.length = 0;
300
- messages.push(...compactedMessages);
301
- continue;
302
- }
303
- // Normal compaction: preserve last 2 messages for continuity
304
- const preserved = messages.slice(-2);
305
- const compactedMessages = [
306
- { role: "assistant", content: [{ type: "compaction", content: compactionContent }] },
307
- ...preserved,
308
- ];
309
- messages.length = 0;
310
- messages.push(...compactedMessages);
311
- turnCount--; // Don't count compaction as a turn
312
- continue;
313
- }
314
- // No tool calls — check if truncated at max_tokens
315
- if (toolUseBlocks.length === 0) {
316
- if (streamResult.stopReason === "max_tokens") {
317
- const assistantContent = buildAssistantContent({ text: currentText, toolUseBlocks: [], compactionContent });
318
- messages.push({ role: "assistant", content: assistantContent });
319
- messages.push({ role: "user", content: [{ type: "text", text: "[Your response was truncated due to length. Please continue where you left off.]" }] });
320
- continue;
321
- }
322
- finalResponse = currentText;
323
- break;
324
- }
325
- // Execute tools and build messages for next turn
326
- const subagentTokens = { input: 0, output: 0, costUsd: 0 };
327
- const executor = makeToolExecutor(opts, tools, allToolNames, subagentTokens, discoveredToolNames);
328
- const { results: toolResults } = await dispatchTools(toolUseBlocks, executor, {
329
- loopDetector,
330
- maxConcurrent: maxConcurrentTools,
331
- // maxResultChars removed — Anthropic context_management handles limits
332
- transcribeAudio: opts.storeId
333
- ? async (base64, mediaType) => {
334
- const result = await handleTranscribe(opts.supabase, opts.storeId, base64, mediaType);
335
- if (!result.success || !result.transcript) {
336
- throw new Error(result.error || "Transcription returned no transcript");
337
- }
338
- return result.transcript;
339
- }
340
- : undefined,
341
- });
342
- toolCallCount += toolUseBlocks.length;
343
- // Aggregate subagent tokens into parent totals
344
- totalIn += subagentTokens.input;
345
- totalOut += subagentTokens.output;
346
- sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens) + subagentTokens.costUsd;
347
- // Cost warnings after subagent aggregation (subagents can be expensive)
348
- emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
349
- const assistantContent = buildAssistantContent({ text: currentText, toolUseBlocks, compactionContent });
350
- messages.push({ role: "assistant", content: assistantContent });
351
- messages.push({ role: "user", content: toolResults });
352
- // Session checkpoint — fire-and-forget, never blocks the loop
353
- if (opts.conversationId) {
354
- saveCheckpoint(opts.supabase, opts.conversationId, turnCount, messages, { input: totalIn, output: totalOut, cacheRead: cacheReadTokens, cacheCreation: cacheCreationTokens }, sessionCostUsd, allToolNames).catch(() => { }); // swallow — saveCheckpoint already logs internally
355
- }
608
+ }
609
+ sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens);
610
+
611
+ // Graduated cost warnings (non-streaming path)
612
+ emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
613
+
614
+ // Record per-turn metrics (non-streaming)
615
+ const nsTurnToolNames = toolUseBlocks.map(b => b.name);
616
+ turnMetrics.push({
617
+ turn: turnCount,
618
+ inputTokens: nsTurnIn,
619
+ outputTokens: nsTurnOut,
620
+ cacheRead: nsTurnCacheRead,
621
+ cacheCreation: nsTurnCacheCreation,
622
+ toolsUsed: nsTurnToolNames,
623
+ costUsd: estimateCostUsd(nsTurnIn, nsTurnOut, model, 0, nsTurnCacheRead, nsTurnCacheCreation),
624
+ ...(turnFailoverInfo ? {
625
+ failover: turnFailoverInfo
626
+ } : {})
627
+ });
628
+ if (currentText) allTextResponses.push(currentText);
629
+ lastStopReason = response.stop_reason || "end_turn";
630
+
631
+ // Compaction handling (non-streaming) — same logic as streaming path
632
+ if (response.stop_reason === "compaction" && nsCompactionContent !== null) {
633
+ compactionCount++;
634
+ consecutiveCompactions++;
635
+ log.info({
636
+ compactionCount,
637
+ consecutiveCompactions,
638
+ streaming: false
639
+ }, "compaction — rebuilding context from summary");
640
+ const MAX_CONSECUTIVE_COMPACTIONS = 3;
641
+ const shouldWrapUp = consecutiveCompactions > MAX_CONSECUTIVE_COMPACTIONS || compactionCount * effectiveCompactionTrigger >= effectiveCompactionBudget;
642
+ if (shouldWrapUp) {
643
+ onText?.(consecutiveCompactions > MAX_CONSECUTIVE_COMPACTIONS ? "\n[Compaction loop detected — wrapping up.]" : "\n[Context budget reached — wrapping up.]");
356
644
  }
357
- else {
358
- // ---- NON-STREAMING PATH ----
359
- let response = null;
360
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
361
- try {
362
- // Cast through unknown: context_management.edits is Record<string, unknown>[]
363
- // from getContextManagement() but SDK expects specific edit union types
364
- const nsBetas = [...ctxMgmt.betas];
365
- if (thinkingCfg.beta)
366
- nsBetas.push(thinkingCfg.beta);
367
- // Citations API: add beta when source documents are provided
368
- if (documents?.length && !nsBetas.includes("citations-2025-04-15")) {
369
- nsBetas.push("citations-2025-04-15");
370
- }
371
- response = await anthropic.beta.messages.create({
372
- model: activeModel,
373
- max_tokens: maxTokens,
374
- temperature: thinkingCfg.thinking.type !== "disabled" ? 1 : temperature,
375
- system,
376
- ...(omitTools ? {} : { tools: finalToolDefs }),
377
- ...(anthropicToolChoice && !omitTools ? { tool_choice: anthropicToolChoice } : {}),
378
- messages: finalMessages,
379
- thinking: thinkingCfg.thinking,
380
- betas: nsBetas,
381
- context_management: ctxMgmt.config,
382
- ...(documents?.length ? { documents } : {}),
383
- });
384
- providerFailover.recordSuccess(activeProvider);
385
- break;
386
- }
387
- catch (err) {
388
- providerFailover.recordFailure(activeProvider);
389
- if (attempt < MAX_RETRIES && isRetryableError(err)) {
390
- const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt);
391
- log.warn({ attempt: attempt + 1, maxRetries: MAX_RETRIES, delayMs: delay, err: sanitizeError(err) }, "retrying API call");
392
- await new Promise((resolve) => setTimeout(resolve, delay));
393
- continue;
394
- }
395
- throw err;
396
- }
397
- }
398
- if (!response)
399
- throw new Error("Failed to get response after retries");
400
- // Track tokens
401
- const nsTurnIn = response.usage?.input_tokens || 0;
402
- const nsTurnOut = response.usage?.output_tokens || 0;
403
- const nsTurnCacheCreation = response.usage?.cache_creation_input_tokens ?? 0;
404
- const nsTurnCacheRead = response.usage?.cache_read_input_tokens ?? 0;
405
- totalIn += nsTurnIn;
406
- totalOut += nsTurnOut;
407
- cacheCreationTokens += nsTurnCacheCreation;
408
- cacheReadTokens += nsTurnCacheRead;
409
- // Extract text, tool_use, cite, and compaction blocks
410
- let currentText = "";
411
- let nsCompactionContent = null;
412
- const toolUseBlocks = [];
413
- for (const block of response.content) {
414
- if (block.type === "text") {
415
- currentText += block.text;
416
- onText?.(block.text);
417
- }
418
- else if (block.type === "tool_use") {
419
- toolUseBlocks.push({
420
- id: block.id,
421
- name: block.name,
422
- input: block.input,
423
- });
424
- onToolStart?.(block.name, block.input);
425
- }
426
- else if (block.type === "cite") {
427
- const citeBlock = block;
428
- const citation = {
429
- type: "cite",
430
- cited_text: citeBlock.cited_text ?? "",
431
- document_index: citeBlock.document_index ?? 0,
432
- start_char_index: citeBlock.start_char_index ?? 0,
433
- end_char_index: citeBlock.end_char_index ?? 0,
434
- ...(citeBlock.document_title ? { document_title: citeBlock.document_title } : {}),
435
- };
436
- allCitations.push(citation);
437
- onCitation?.(citation);
438
- }
439
- else if (block.type === "compaction") {
440
- nsCompactionContent = block.content || "";
441
- }
442
- }
443
- sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens);
444
- // Graduated cost warnings (non-streaming path)
445
- emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
446
- // Record per-turn metrics (non-streaming)
447
- const nsTurnToolNames = toolUseBlocks.map(b => b.name);
448
- turnMetrics.push({
449
- turn: turnCount,
450
- inputTokens: nsTurnIn,
451
- outputTokens: nsTurnOut,
452
- cacheRead: nsTurnCacheRead,
453
- cacheCreation: nsTurnCacheCreation,
454
- toolsUsed: nsTurnToolNames,
455
- costUsd: estimateCostUsd(nsTurnIn, nsTurnOut, model, 0, nsTurnCacheRead, nsTurnCacheCreation),
456
- ...(turnFailoverInfo ? { failover: turnFailoverInfo } : {}),
457
- });
458
- if (currentText)
459
- allTextResponses.push(currentText);
460
- lastStopReason = response.stop_reason || "end_turn";
461
- // Compaction handling (non-streaming) — same logic as streaming path
462
- if (response.stop_reason === "compaction" && nsCompactionContent !== null) {
463
- compactionCount++;
464
- log.info({ compactionCount, streaming: false }, "compaction — preserving last 2 messages");
465
- if (compactionCount * COMPACTION_TRIGGER_TOKENS >= COMPACTION_TOTAL_BUDGET) {
466
- onText?.("\n[Context budget reached — wrapping up.]");
467
- const compactedMessages = [
468
- { role: "assistant", content: [{ type: "compaction", content: nsCompactionContent }] },
469
- { role: "user", content: [{ type: "text", text: "You have reached the context budget. Please wrap up your current work and provide a final summary." }] },
470
- ];
471
- messages.length = 0;
472
- messages.push(...compactedMessages);
473
- continue;
474
- }
475
- const preserved = messages.slice(-2);
476
- const compactedMessages = [
477
- { role: "assistant", content: [{ type: "compaction", content: nsCompactionContent }] },
478
- ...preserved,
479
- ];
480
- messages.length = 0;
481
- messages.push(...compactedMessages);
482
- turnCount--;
483
- continue;
484
- }
485
- // No tool calls — check if truncated at max_tokens
486
- if (toolUseBlocks.length === 0) {
487
- if (response.stop_reason === "max_tokens") {
488
- const assistantContent = buildAssistantContent({ text: currentText, toolUseBlocks: [] });
489
- messages.push({ role: "assistant", content: assistantContent });
490
- messages.push({ role: "user", content: [{ type: "text", text: "[Your response was truncated due to length. Please continue where you left off.]" }] });
491
- continue;
492
- }
493
- finalResponse = currentText;
494
- break;
495
- }
496
- // Execute tools
497
- const nonStreamSubTokens = { input: 0, output: 0, costUsd: 0 };
498
- const nsExecutor = makeToolExecutor(opts, tools, allToolNames, nonStreamSubTokens, discoveredToolNames);
499
- const { results: toolResults } = await dispatchTools(toolUseBlocks, nsExecutor, {
500
- loopDetector,
501
- maxConcurrent: maxConcurrentTools,
502
- // maxResultChars removed — Anthropic context_management handles limits
503
- });
504
- toolCallCount += toolUseBlocks.length;
505
- // Aggregate subagent tokens into parent totals
506
- totalIn += nonStreamSubTokens.input;
507
- totalOut += nonStreamSubTokens.output;
508
- sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens) + nonStreamSubTokens.costUsd;
509
- // Cost warnings after subagent aggregation (non-streaming)
510
- emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
511
- const assistantContent = buildAssistantContent({ text: currentText, toolUseBlocks });
512
- messages.push({ role: "assistant", content: assistantContent });
513
- messages.push({ role: "user", content: toolResults });
514
- // Session checkpoint — fire-and-forget, never blocks the loop
515
- if (opts.conversationId) {
516
- saveCheckpoint(opts.supabase, opts.conversationId, turnCount, messages, { input: totalIn, output: totalOut, cacheRead: cacheReadTokens, cacheCreation: cacheCreationTokens }, sessionCostUsd, allToolNames).catch(() => { }); // swallow — saveCheckpoint already logs internally
517
- }
645
+ const compactedMessages = [{
646
+ role: "assistant",
647
+ content: [{
648
+ type: "compaction",
649
+ content: nsCompactionContent
650
+ }]
651
+ }, {
652
+ role: "user",
653
+ content: [{
654
+ type: "text",
655
+ text: shouldWrapUp ? "You have reached the context budget. Please wrap up your current work and provide a final summary." : "Continue with your task."
656
+ }]
657
+ }];
658
+ messages.length = 0;
659
+ messages.push(...compactedMessages);
660
+ turnCount--;
661
+ continue;
662
+ }
663
+
664
+ // No tool calls check if truncated at max_tokens
665
+ if (toolUseBlocks.length === 0) {
666
+ if (response.stop_reason === "max_tokens") {
667
+ const assistantContent = buildAssistantContent({
668
+ text: currentText,
669
+ toolUseBlocks: []
670
+ });
671
+ messages.push({
672
+ role: "assistant",
673
+ content: assistantContent
674
+ });
675
+ messages.push({
676
+ role: "user",
677
+ content: [{
678
+ type: "text",
679
+ text: "[Your response was truncated due to length. Please continue where you left off.]"
680
+ }]
681
+ });
682
+ continue;
518
683
  }
684
+ finalResponse = currentText;
685
+ break;
686
+ }
687
+
688
+ // Reset — model is making progress (tool calls)
689
+ consecutiveCompactions = 0;
690
+
691
+ // Execute tools
692
+ const nonStreamSubTokens = {
693
+ input: 0,
694
+ output: 0,
695
+ costUsd: 0
696
+ };
697
+ const nsExecutor = makeToolExecutor(opts, tools, allToolNames, nonStreamSubTokens, discoveredToolNames);
698
+ const {
699
+ results: toolResults
700
+ } = await dispatchTools(toolUseBlocks, nsExecutor, {
701
+ loopDetector,
702
+ maxConcurrent: maxConcurrentTools,
703
+ batchErrorLimit: opts.batchErrorLimit ?? AGENT_DEFAULTS.loopBatchErrorLimit
704
+ // maxResultChars removed — Anthropic context_management handles limits
705
+ });
706
+ toolCallCount += toolUseBlocks.length;
707
+
708
+ // Aggregate subagent tokens into parent totals
709
+ totalIn += nonStreamSubTokens.input;
710
+ totalOut += nonStreamSubTokens.output;
711
+ sessionCostUsd = estimateCostUsd(totalIn, totalOut, model, 0, cacheReadTokens, cacheCreationTokens) + nonStreamSubTokens.costUsd;
712
+
713
+ // Cost warnings after subagent aggregation (non-streaming)
714
+ emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText);
715
+ const assistantContent = buildAssistantContent({
716
+ text: currentText,
717
+ toolUseBlocks
718
+ });
719
+ messages.push({
720
+ role: "assistant",
721
+ content: assistantContent
722
+ });
723
+ messages.push({
724
+ role: "user",
725
+ content: toolResults
726
+ });
727
+
728
+ // Session checkpoint — fire-and-forget, never blocks the loop
729
+ if (opts.conversationId) {
730
+ saveCheckpoint(opts.supabase, opts.conversationId, turnCount, messages, {
731
+ input: totalIn,
732
+ output: totalOut,
733
+ cacheRead: cacheReadTokens,
734
+ cacheCreation: cacheCreationTokens
735
+ }, sessionCostUsd, allToolNames).catch(() => {}); // swallow — saveCheckpoint already logs internally
736
+ }
519
737
  }
520
- const fullText = allTextResponses.join("\n\n") || finalResponse;
521
- return {
522
- finalText: fullText,
523
- allTextResponses,
524
- turnCount,
525
- toolCallCount,
526
- toolsUsed: [...new Set(allToolNames)],
527
- tokens: {
528
- input: totalIn,
529
- output: totalOut,
530
- cacheCreation: cacheCreationTokens,
531
- cacheRead: cacheReadTokens,
532
- },
533
- costUsd: sessionCostUsd,
534
- loopDetectorStats: loopDetector.getSessionStats(),
535
- turns: turnMetrics,
536
- citations: allCitations,
537
- stopReason: lastStopReason,
538
- };
738
+ }
739
+ const fullText = allTextResponses.join("\n\n") || finalResponse;
740
+ return {
741
+ finalText: fullText,
742
+ allTextResponses,
743
+ turnCount,
744
+ toolCallCount,
745
+ toolsUsed: [...new Set(allToolNames)],
746
+ tokens: {
747
+ input: totalIn,
748
+ output: totalOut,
749
+ cacheCreation: cacheCreationTokens,
750
+ cacheRead: cacheReadTokens
751
+ },
752
+ costUsd: sessionCostUsd,
753
+ loopDetectorStats: loopDetector.getSessionStats(),
754
+ turns: turnMetrics,
755
+ citations: allCitations,
756
+ stopReason: lastStopReason
757
+ };
539
758
  }
759
+
540
760
  // ============================================================================
541
761
  // TOOL EXECUTOR FACTORY — creates executor for dispatchTools with delegation
542
762
  // ============================================================================
763
+
543
764
  function makeToolExecutor(opts, tools, allToolNames, subagentTokens, discoveredToolNames) {
544
- const { anthropic, supabase, storeId, traceId, userId, userEmail, conversationId, agentId, executeTool, onToolResult, onToolProgress, onSubagentProgress, clientDisconnected = { value: false }, startedAt = Date.now(), maxDurationMs = 15 * 60 * 1000, } = opts;
545
- return async (name, input) => {
546
- allToolNames.push(name);
547
- // Subagent delegation — demote models to control cost (sub-agents should never run Opus)
548
- if (name === "delegate_task") {
549
- const subPrompt = String(input.prompt || "");
550
- const subModel = demoteSubagentModel(input.model ? String(input.model) : undefined);
551
- const subMaxTurns = Math.min(Math.max(1, Number(input.max_turns) || 6), 12);
552
- const subTools = tools.filter((t) => t.name !== "delegate_task");
553
- const subId = `sub-${Date.now().toString(36)}`;
554
- onSubagentProgress?.({ subagentId: subId, event: "started", model: subModel });
555
- const subStartTime = Date.now();
556
- const subResult = await runServerSubagent({
557
- anthropic, supabase, storeId, prompt: subPrompt, model: subModel,
558
- maxTurns: subMaxTurns, tools: subTools,
559
- executeTool: async (toolName, args) => executeTool(toolName, args, "server_subagent"),
560
- onProgress: onSubagentProgress, clientDisconnected, startedAt, maxDurationMs,
765
+ const {
766
+ anthropic,
767
+ supabase,
768
+ storeId,
769
+ traceId,
770
+ userId,
771
+ userEmail,
772
+ conversationId,
773
+ agentId,
774
+ executeTool,
775
+ onToolResult,
776
+ onToolProgress,
777
+ onSubagentProgress,
778
+ clientDisconnected = {
779
+ value: false
780
+ },
781
+ startedAt = Date.now(),
782
+ maxDurationMs = 15 * 60 * 1000
783
+ } = opts;
784
+ return async (name, input) => {
785
+ allToolNames.push(name);
786
+
787
+ // Subagent delegation — demote models to control cost (sub-agents should never run Opus)
788
+ if (name === "delegate_task") {
789
+ const subPrompt = String(input.prompt || "");
790
+ const subModel = demoteSubagentModel(input.model ? String(input.model) : undefined);
791
+ const defaultSubMaxTurns = opts.subagentMaxTurns ?? AGENT_DEFAULTS.subagentMaxTurns;
792
+ const subMaxTurns = Math.min(Math.max(1, Number(input.max_turns) || defaultSubMaxTurns), 12);
793
+ const subTools = tools.filter(t => t.name !== "delegate_task");
794
+ const subId = `sub-${Date.now().toString(36)}`;
795
+ onSubagentProgress?.({
796
+ subagentId: subId,
797
+ event: "started",
798
+ model: subModel
799
+ });
800
+ const subStartTime = Date.now();
801
+ const subResult = await runServerSubagent({
802
+ anthropic,
803
+ supabase,
804
+ storeId,
805
+ prompt: subPrompt,
806
+ model: subModel,
807
+ maxTurns: subMaxTurns,
808
+ tools: subTools,
809
+ executeTool: async (toolName, args) => executeTool(toolName, args, "server_subagent"),
810
+ onProgress: onSubagentProgress,
811
+ clientDisconnected,
812
+ startedAt,
813
+ maxDurationMs,
814
+ maxOutputTokens: opts.subagentMaxTokens,
815
+ temperature: opts.subagentTemperature
816
+ });
817
+ onSubagentProgress?.({
818
+ subagentId: subId,
819
+ event: "done",
820
+ output: subResult.output
821
+ });
822
+
823
+ // Audit log
824
+ const subDurationMs = Date.now() - subStartTime;
825
+ const subModelId = subModel === "opus" ? MODELS.OPUS : subModel === "sonnet" ? MODELS.SONNET : MODELS.HAIKU;
826
+ try {
827
+ const subEndTime = Date.now();
828
+ queueSpan(auditRowToSpan({
829
+ action: "chat.subagent_complete",
830
+ severity: "info",
831
+ store_id: storeId || null,
832
+ resource_type: "chat_subagent",
833
+ resource_id: agentId || null,
834
+ request_id: traceId || null,
835
+ conversation_id: conversationId || null,
836
+ source: "server_subagent",
837
+ user_id: userId || null,
838
+ user_email: userEmail || null,
839
+ input_tokens: subResult.tokensUsed.input,
840
+ output_tokens: subResult.tokensUsed.output,
841
+ total_cost: subResult.costUsd,
842
+ model: subModelId,
843
+ duration_ms: subDurationMs,
844
+ trace_id: traceId || null,
845
+ span_kind: "INTERNAL",
846
+ service_name: "agent-server",
847
+ status_code: subResult.success ? "OK" : "ERROR",
848
+ start_time: new Date(subEndTime - subDurationMs).toISOString(),
849
+ end_time: new Date(subEndTime).toISOString(),
850
+ stop_reason: subResult.stopReason || undefined,
851
+ turn_number: subResult.turnCount || 1,
852
+ parent_conversation_id: conversationId || undefined,
853
+ details: {
854
+ subagent_model: subModel,
855
+ turn_count: subResult.turnCount,
856
+ tool_calls: subResult.toolsUsed.length,
857
+ tool_names: subResult.toolsUsed,
858
+ cost_usd: subResult.costUsd,
859
+ success: subResult.success,
860
+ prompt_preview: subPrompt.substring(0, 200),
861
+ "gen_ai.request.model": subModelId,
862
+ "gen_ai.usage.input_tokens": subResult.tokensUsed.input,
863
+ "gen_ai.usage.output_tokens": subResult.tokensUsed.output,
864
+ "gen_ai.usage.cache_read_tokens": subResult.tokensUsed.cacheRead || 0,
865
+ "gen_ai.usage.cache_creation_tokens": subResult.tokensUsed.cacheCreation || 0,
866
+ "gen_ai.usage.cost": subResult.costUsd
867
+ }
868
+ }));
869
+ } catch (err) {
870
+ log.error({
871
+ err: err.message
872
+ }, "failed to log subagent delegation audit");
873
+ }
874
+ subagentTokens.input += subResult.tokensUsed.input;
875
+ subagentTokens.output += subResult.tokensUsed.output;
876
+ subagentTokens.costUsd += subResult.costUsd;
877
+ allToolNames.push(...subResult.toolsUsed);
878
+ return {
879
+ success: subResult.success,
880
+ output: subResult.output
881
+ };
882
+ }
883
+
884
+ // Regular tool execution — pass onToolProgress for streaming tools (kali)
885
+ const result = await executeTool(name, input, undefined, onToolProgress);
886
+ onToolResult?.(name, result.success, result.success ? result.data : result.error);
887
+
888
+ // discover_tools: dynamically add discovered tools to the active set
889
+ if (name === "discover_tools" && result.success && result.data) {
890
+ const refreshRequested = !!input.refresh;
891
+ const discovered = result.data?.tools;
892
+
893
+ // If refresh requested, remove previously-discovered tools so they can be re-loaded
894
+ // with fresh schemas from DB. Core tools and delegate_task are never removed.
895
+ if (refreshRequested) {
896
+ const coreNames = new Set((opts.tools || []).map(t => t.name));
897
+ coreNames.add("delegate_task");
898
+ for (let i = tools.length - 1; i >= 0; i--) {
899
+ if (discoveredToolNames.has(tools[i].name) && !coreNames.has(tools[i].name)) {
900
+ tools.splice(i, 1);
901
+ }
902
+ }
903
+ discoveredToolNames.clear();
904
+ log.info("discover_tools refresh — cleared previously discovered tools");
905
+ }
906
+ if (Array.isArray(discovered)) {
907
+ // Use getFullToolSchemas as authoritative source — supplements handler response
908
+ // with any schemas the handler returned, ensuring we have complete definitions.
909
+ const discoveredNames = discovered.filter(t => t.name).map(t => t.name);
910
+ const fullSchemas = getFullToolSchemas(discoveredNames);
911
+ // Build a map for O(1) lookup: prefer full schemas from cache, fall back to handler data
912
+ const schemaMap = new Map();
913
+ for (const t of discovered) {
914
+ if (t.name && t.input_schema) {
915
+ schemaMap.set(t.name, {
916
+ name: t.name,
917
+ description: t.description || t.name,
918
+ input_schema: t.input_schema
561
919
  });
562
- onSubagentProgress?.({ subagentId: subId, event: "done", output: subResult.output });
563
- // Audit log
564
- const subDurationMs = Date.now() - subStartTime;
565
- const subModelId = subModel === "opus" ? MODELS.OPUS
566
- : subModel === "sonnet" ? MODELS.SONNET : MODELS.HAIKU;
567
- try {
568
- const subEndTime = Date.now();
569
- queueSpan(auditRowToSpan({
570
- action: "chat.subagent_complete", severity: "info",
571
- store_id: storeId || null, resource_type: "chat_subagent",
572
- resource_id: agentId || null, request_id: traceId || null,
573
- conversation_id: conversationId || null, source: "server_subagent",
574
- user_id: userId || null,
575
- user_email: userEmail || null,
576
- input_tokens: subResult.tokensUsed.input, output_tokens: subResult.tokensUsed.output,
577
- total_cost: subResult.costUsd, model: subModelId, duration_ms: subDurationMs,
578
- trace_id: traceId || null,
579
- span_kind: "INTERNAL",
580
- service_name: "agent-server",
581
- status_code: subResult.success ? "OK" : "ERROR",
582
- start_time: new Date(subEndTime - subDurationMs).toISOString(),
583
- end_time: new Date(subEndTime).toISOString(),
584
- stop_reason: subResult.stopReason || undefined,
585
- turn_number: subResult.turnCount || 1,
586
- parent_conversation_id: conversationId || undefined,
587
- details: {
588
- subagent_model: subModel, turn_count: subResult.turnCount,
589
- tool_calls: subResult.toolsUsed.length, tool_names: subResult.toolsUsed,
590
- cost_usd: subResult.costUsd, success: subResult.success,
591
- prompt_preview: subPrompt.substring(0, 200),
592
- "gen_ai.request.model": subModelId,
593
- "gen_ai.usage.input_tokens": subResult.tokensUsed.input,
594
- "gen_ai.usage.output_tokens": subResult.tokensUsed.output,
595
- "gen_ai.usage.cache_read_tokens": subResult.tokensUsed.cacheRead || 0,
596
- "gen_ai.usage.cache_creation_tokens": subResult.tokensUsed.cacheCreation || 0,
597
- "gen_ai.usage.cost": subResult.costUsd,
598
- },
599
- }));
600
- }
601
- catch (err) {
602
- log.error({ err: err.message }, "failed to log subagent delegation audit");
603
- }
604
- subagentTokens.input += subResult.tokensUsed.input;
605
- subagentTokens.output += subResult.tokensUsed.output;
606
- subagentTokens.costUsd += subResult.costUsd;
607
- allToolNames.push(...subResult.toolsUsed);
608
- return { success: subResult.success, output: subResult.output };
920
+ }
609
921
  }
610
- // Regular tool execution pass onToolProgress for streaming tools (kali)
611
- const result = await executeTool(name, input, undefined, onToolProgress);
612
- onToolResult?.(name, result.success, result.success ? result.data : result.error);
613
- // discover_tools: dynamically add discovered tools to the active set
614
- if (name === "discover_tools" && result.success && result.data) {
615
- const refreshRequested = !!input.refresh;
616
- const discovered = result.data?.tools;
617
- // If refresh requested, remove previously-discovered tools so they can be re-loaded
618
- // with fresh schemas from DB. Core tools and delegate_task are never removed.
619
- if (refreshRequested) {
620
- const coreNames = new Set((opts.tools || []).map(t => t.name));
621
- coreNames.add("delegate_task");
622
- for (let i = tools.length - 1; i >= 0; i--) {
623
- if (discoveredToolNames.has(tools[i].name) && !coreNames.has(tools[i].name)) {
624
- tools.splice(i, 1);
625
- }
626
- }
627
- discoveredToolNames.clear();
628
- log.info("discover_tools refresh — cleared previously discovered tools");
629
- }
630
- if (Array.isArray(discovered)) {
631
- // Use getFullToolSchemas as authoritative source — supplements handler response
632
- // with any schemas the handler returned, ensuring we have complete definitions.
633
- const discoveredNames = discovered.filter((t) => t.name).map((t) => t.name);
634
- const fullSchemas = getFullToolSchemas(discoveredNames);
635
- // Build a map for O(1) lookup: prefer full schemas from cache, fall back to handler data
636
- const schemaMap = new Map();
637
- for (const t of discovered) {
638
- if (t.name && t.input_schema) {
639
- schemaMap.set(t.name, { name: t.name, description: t.description || t.name, input_schema: t.input_schema });
640
- }
641
- }
642
- for (const t of fullSchemas) {
643
- schemaMap.set(t.name, t); // Full cache schemas override handler data (more complete)
644
- }
645
- const activated = [];
646
- const alreadyActive = [];
647
- for (const [toolName, toolDef] of schemaMap) {
648
- // Track as discovered regardless of whether already active
649
- discoveredToolNames.add(toolName);
650
- if (!tools.some(existing => existing.name === toolName)) {
651
- tools.push(toolDef);
652
- activated.push(toolName);
653
- }
654
- else if (refreshRequested) {
655
- // Re-add after refresh cleared it, or update existing schema
656
- tools.push(toolDef);
657
- activated.push(toolName);
658
- }
659
- else {
660
- alreadyActive.push(toolName);
661
- }
662
- }
663
- if (activated.length > 0) {
664
- log.info({ activatedTools: activated, refreshed: refreshRequested }, "discover_tools activated");
665
- }
666
- // Return a cleaner message to the model
667
- return {
668
- success: true,
669
- output: JSON.stringify({
670
- activated,
671
- already_active: alreadyActive,
672
- refreshed: refreshRequested,
673
- message: activated.length > 0
674
- ? `Activated ${activated.length} tool(s): ${activated.join(", ")}. You can now use them.`
675
- : "Requested tools were already active.",
676
- total_discovered: discoveredToolNames.size,
677
- }),
678
- };
679
- }
922
+ for (const t of fullSchemas) {
923
+ schemaMap.set(t.name, t); // Full cache schemas override handler data (more complete)
680
924
  }
925
+ const activated = [];
926
+ const alreadyActive = [];
927
+ for (const [toolName, toolDef] of schemaMap) {
928
+ // Track as discovered regardless of whether already active
929
+ discoveredToolNames.add(toolName);
930
+ if (!tools.some(existing => existing.name === toolName)) {
931
+ tools.push(toolDef);
932
+ activated.push(toolName);
933
+ } else if (refreshRequested) {
934
+ // Re-add after refresh cleared it, or update existing schema
935
+ tools.push(toolDef);
936
+ activated.push(toolName);
937
+ } else {
938
+ alreadyActive.push(toolName);
939
+ }
940
+ }
941
+ if (activated.length > 0) {
942
+ log.info({
943
+ activatedTools: activated,
944
+ refreshed: refreshRequested
945
+ }, "discover_tools activated");
946
+ }
947
+ // Return a cleaner message to the model
681
948
  return {
682
- success: result.success,
683
- output: JSON.stringify(result.success ? result.data : { error: result.error }),
949
+ success: true,
950
+ output: JSON.stringify({
951
+ activated,
952
+ already_active: alreadyActive,
953
+ refreshed: refreshRequested,
954
+ message: activated.length > 0 ? `Activated ${activated.length} tool(s): ${activated.join(", ")}. You can now use them.` : "Requested tools were already active.",
955
+ total_discovered: discoveredToolNames.size
956
+ })
684
957
  };
958
+ }
959
+ }
960
+ return {
961
+ success: result.success,
962
+ output: JSON.stringify(result.success ? result.data : {
963
+ error: result.error
964
+ })
685
965
  };
966
+ };
686
967
  }
968
+ //# sourceMappingURL=server-agent-loop.js.map