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