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
@@ -4,7 +4,25 @@
4
4
  * Pure TypeScript, no runtime-specific APIs (no Deno.env, no process.env, no fs).
5
5
  * Both the CLI (Node.js) and server (Fly container) import from here.
6
6
  */
7
+
7
8
  import { getProvider } from "./constants.js";
9
+
10
+ // ============================================================================
11
+ // TYPES
12
+ // ============================================================================
13
+
14
+ // ============================================================================
15
+ // TOOL CHOICE
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Controls which tools the model can/must use:
20
+ * - "auto": Model decides whether to use tools (default)
21
+ * - "any": Model must use at least one tool
22
+ * - "none": Model must not use any tools (text-only response)
23
+ * - { type: "tool", name: string }: Model must use the specified tool
24
+ */
25
+
8
26
  /**
9
27
  * Resolve the effective tool_choice for a given turn.
10
28
  *
@@ -15,62 +33,92 @@ import { getProvider } from "./constants.js";
15
33
  * 4. Default: "auto"
16
34
  */
17
35
  export function resolveToolChoice(opts) {
18
- // 1. Explicit override always wins
19
- if (opts.toolChoice !== undefined)
20
- return opts.toolChoice;
21
- // 2. Loop detection: if last 3+ turns all used the exact same tool, force text
22
- if (opts.recentToolUses.length >= 3) {
23
- const last3 = opts.recentToolUses.slice(-3);
24
- if (last3[0] === last3[1] && last3[1] === last3[2]) {
25
- return "none";
26
- }
36
+ // 1. Explicit override always wins
37
+ if (opts.toolChoice !== undefined) return opts.toolChoice;
38
+
39
+ // 2. Loop detection: if last 3+ turns all used the exact same tool, force text
40
+ if (opts.recentToolUses.length >= 3) {
41
+ const last3 = opts.recentToolUses.slice(-3);
42
+ if (last3[0] === last3[1] && last3[1] === last3[2]) {
43
+ return "none";
27
44
  }
28
- // 2b. Alternating pattern detection: catch A→B→A→B→A→B death spirals (e.g. read→edit→read→edit)
29
- if (opts.recentToolUses.length >= 6) {
30
- const last6 = opts.recentToolUses.slice(-6);
31
- const isRepeatingPair = last6[2] === last6[0] && last6[3] === last6[1] &&
32
- last6[4] === last6[0] && last6[5] === last6[1];
33
- if (isRepeatingPair)
34
- return "none";
35
- }
36
- // 3. Keyword matching: check if the user message mentions a specific tool name
37
- // Only on the first turn (avoids false positives on multi-turn conversations)
38
- if (opts.turnCount === 1 && opts.userMessage && opts.availableToolNames.length > 0) {
39
- const msgLower = opts.userMessage.toLowerCase();
40
- for (const toolName of opts.availableToolNames) {
41
- // Match tool name as a whole word (e.g. "blender_do" not "do")
42
- // Only consider tool names >= 4 chars to avoid false positives
43
- if (toolName.length >= 4 && msgLower.includes(toolName.toLowerCase())) {
44
- return { type: "tool", name: toolName };
45
- }
46
- }
45
+ }
46
+
47
+ // 2b. Alternating pattern detection: catch A→B→A→B→A→B death spirals (e.g. read→edit→read→edit)
48
+ if (opts.recentToolUses.length >= 6) {
49
+ const last6 = opts.recentToolUses.slice(-6);
50
+ const isRepeatingPair = last6[2] === last6[0] && last6[3] === last6[1] && last6[4] === last6[0] && last6[5] === last6[1];
51
+ if (isRepeatingPair) return "none";
52
+ }
53
+
54
+ // 3. Keyword matching: check if the user message mentions a specific tool name
55
+ // Only on the first turn (avoids false positives on multi-turn conversations)
56
+ if (opts.turnCount === 1 && opts.userMessage && opts.availableToolNames.length > 0) {
57
+ const msgLower = opts.userMessage.toLowerCase();
58
+ for (const toolName of opts.availableToolNames) {
59
+ // Match tool name as a whole word (e.g. "blender_do" not "do")
60
+ // Only consider tool names >= 4 chars to avoid false positives
61
+ if (toolName.length >= 4 && msgLower.includes(toolName.toLowerCase())) {
62
+ return {
63
+ type: "tool",
64
+ name: toolName
65
+ };
66
+ }
47
67
  }
48
- // 4. Default
49
- return "auto";
68
+ }
69
+
70
+ // 4. Default
71
+ return "auto";
50
72
  }
73
+
74
+ /** Overrides from ai_agent_config.context_config JSONB — all optional, falls back to defaults */
75
+
51
76
  // ============================================================================
52
77
  // MODEL-AWARE CONTEXT MANAGEMENT
53
78
  // ============================================================================
54
- /** Legacy compaction trigger — used by getCompactionConfig() for non-Anthropic providers.
55
- * For Anthropic models, getContextManagement() with DB overrides takes precedence. */
56
- export const COMPACTION_TRIGGER_TOKENS = 120_000;
57
- /** Max cumulative tokens before forcing wrap-up (prevents runaway compaction cost) */
79
+
80
+ // These re-export from AGENT_DEFAULTS so there's exactly one place to change.
81
+ // DB context_config always overrides these via resolveAgentLoopConfig().
82
+
83
+ /** Legacy compaction trigger — used by getCompactionConfig() for non-Anthropic providers. */
84
+ export const COMPACTION_TRIGGER_TOKENS = 167_000;
85
+ /** Max cumulative tokens before forcing wrap-up */
58
86
  export const COMPACTION_TOTAL_BUDGET = 2_000_000;
59
- /** Default session cost budget in USD hard cap to prevent runaway spending */
60
- export const DEFAULT_SESSION_COST_BUDGET_USD = 5.00;
87
+ /** Session cost safety capDB context_config.session_cost_budget_usd overrides */
88
+ export const DEFAULT_SESSION_COST_BUDGET_USD = 25.00;
89
+
90
+ /**
91
+ * Provider-aware compaction configuration.
92
+ * - Anthropic/Bedrock: native server-side compaction via compact_20260112
93
+ * - OpenAI/Gemini: Haiku-based summarization (same instructions, same format)
94
+ */
95
+
61
96
  export function getCompactionConfig(model) {
62
- const provider = getProvider(model);
63
- switch (provider) {
64
- case "gemini":
65
- return { triggerTokens: 700_000, totalBudget: 4_000_000, isNative: false };
66
- case "openai":
67
- return { triggerTokens: 120_000, totalBudget: 2_000_000, isNative: false };
68
- case "bedrock":
69
- case "anthropic":
70
- default:
71
- return { triggerTokens: COMPACTION_TRIGGER_TOKENS, totalBudget: COMPACTION_TOTAL_BUDGET, isNative: true };
72
- }
97
+ const provider = getProvider(model);
98
+ switch (provider) {
99
+ case "gemini":
100
+ return {
101
+ triggerTokens: 700_000,
102
+ totalBudget: 4_000_000,
103
+ isNative: false
104
+ };
105
+ case "openai":
106
+ return {
107
+ triggerTokens: 120_000,
108
+ totalBudget: 2_000_000,
109
+ isNative: false
110
+ };
111
+ case "bedrock":
112
+ case "anthropic":
113
+ default:
114
+ return {
115
+ triggerTokens: COMPACTION_TRIGGER_TOKENS,
116
+ totalBudget: COMPACTION_TOTAL_BUDGET,
117
+ isNative: true
118
+ };
119
+ }
73
120
  }
121
+
74
122
  /**
75
123
  * Returns Anthropic beta flags and context_management config for the given model.
76
124
  * - Opus 4.6 / Sonnet 4.6: compact at 120K (pause after) + clear thinking + clear tools at 80K/keep 3
@@ -78,45 +126,71 @@ export function getCompactionConfig(model) {
78
126
  * - Non-Anthropic models (Gemini, OpenAI): no betas, no context management
79
127
  */
80
128
  export function getContextManagement(model, overrides) {
81
- // Non-Anthropic models don't use Anthropic betas or context management
82
- const provider = getProvider(model);
83
- if (provider === "gemini" || provider === "openai") {
84
- return { betas: [], config: { edits: [] } };
129
+ // Non-Anthropic models don't use Anthropic betas or context management
130
+ const provider = getProvider(model);
131
+ if (provider === "gemini" || provider === "openai") {
132
+ return {
133
+ betas: [],
134
+ config: {
135
+ edits: []
136
+ }
137
+ };
138
+ }
139
+ const edits = [];
140
+ const betas = ["context-management-2025-06-27"];
141
+
142
+ // Thinking block clearing — must come FIRST in edits array (API requirement).
143
+ // Default: keep 1 thinking turn (matches Claude Code / Anthropic API defaults).
144
+ const clearThinkingKeep = overrides?.clear_thinking_keep ?? 1;
145
+ edits.push({
146
+ type: "clear_thinking_20251015",
147
+ keep: {
148
+ type: "thinking_turns",
149
+ value: clearThinkingKeep
85
150
  }
86
- const edits = [];
87
- const betas = ["context-management-2025-06-27"];
88
- // Thinking block clearing must come FIRST in edits array (API requirement).
89
- // Default: keep 1 thinking turn (matches Claude Code / Anthropic API defaults).
90
- const clearThinkingKeep = overrides?.clear_thinking_keep ?? 1;
151
+ });
152
+
153
+ // Server-side compaction for models that support compact_20260112.
154
+ // Default trigger: 150K tokens (matches Anthropic API default).
155
+ // pause_after_compaction: true enables the loop to preserve recent messages
156
+ // and track compaction count for budget enforcement.
157
+ const supportsCompaction = model.includes("opus-4-6") || model.includes("sonnet-4-6");
158
+ const compactionTrigger = overrides?.compaction_trigger_tokens ?? AGENT_DEFAULTS.compactionTriggerTokens;
159
+ if (supportsCompaction) {
91
160
  edits.push({
92
- type: "clear_thinking_20251015",
93
- keep: { type: "thinking_turns", value: clearThinkingKeep },
161
+ type: "compact_20260112",
162
+ trigger: {
163
+ type: "input_tokens",
164
+ value: compactionTrigger
165
+ },
166
+ pause_after_compaction: true,
167
+ instructions: "Summarize the conversation preserving: (1) task goals and constraints, (2) files created/modified with paths, (3) decisions made and rationale, (4) errors encountered and resolutions, (5) exact next steps. Be concise but preserve all state needed to continue work without repeating mistakes."
94
168
  });
95
- // Server-side compaction for models that support compact_20260112.
96
- // Default trigger: 150K tokens (matches Anthropic API default).
97
- // pause_after_compaction: true enables the loop to preserve recent messages
98
- // and track compaction count for budget enforcement.
99
- const supportsCompaction = model.includes("opus-4-6") || model.includes("sonnet-4-6");
100
- const compactionTrigger = overrides?.compaction_trigger_tokens ?? 150_000;
101
- if (supportsCompaction) {
102
- edits.push({
103
- type: "compact_20260112",
104
- trigger: { type: "input_tokens", value: compactionTrigger },
105
- pause_after_compaction: true,
106
- instructions: "Summarize the conversation preserving: (1) task goals and constraints, (2) files created/modified with paths, (3) decisions made and rationale, (4) errors encountered and resolutions, (5) exact next steps. Be concise but preserve all state needed to continue work without repeating mistakes.",
107
- });
108
- betas.push("compact-2026-01-12");
169
+ betas.push("compact-2026-01-12");
170
+ }
171
+
172
+ // Clear tool uses default: trigger at 100K, keep 3 (matches Anthropic API defaults).
173
+ const clearToolUsesTrigger = overrides?.clear_tool_uses_trigger ?? 100_000;
174
+ const clearToolUsesKeep = overrides?.clear_tool_uses_keep ?? 3;
175
+ edits.push({
176
+ type: "clear_tool_uses_20250919",
177
+ trigger: {
178
+ type: "input_tokens",
179
+ value: clearToolUsesTrigger
180
+ },
181
+ keep: {
182
+ type: "tool_uses",
183
+ value: clearToolUsesKeep
109
184
  }
110
- // Clear tool uses — default: trigger at 100K, keep 3 (matches Anthropic API defaults).
111
- const clearToolUsesTrigger = overrides?.clear_tool_uses_trigger ?? 100_000;
112
- const clearToolUsesKeep = overrides?.clear_tool_uses_keep ?? 3;
113
- edits.push({
114
- type: "clear_tool_uses_20250919",
115
- trigger: { type: "input_tokens", value: clearToolUsesTrigger },
116
- keep: { type: "tool_uses", value: clearToolUsesKeep },
117
- });
118
- return { betas, config: { edits } };
185
+ });
186
+ return {
187
+ betas,
188
+ config: {
189
+ edits
190
+ }
191
+ };
119
192
  }
193
+
120
194
  /**
121
195
  * Model-aware max output tokens.
122
196
  * Agent config max_tokens takes priority but is capped at model maximum.
@@ -124,50 +198,62 @@ export function getContextManagement(model, overrides) {
124
198
  * DEFAULT_OUTPUT_TOKENS is the sensible per-response cap (like Claude Code's ~16K).
125
199
  * The full MODEL_MAX is only used when explicitly requested via agentMax.
126
200
  */
127
- const DEFAULT_OUTPUT_TOKENS = 16384; // 16K sane default, prevents single-response burns
201
+ // Fallback only when DB agent.max_tokens is null/0. DB value (ai_agent_config.max_tokens) takes priority.
202
+ const DEFAULT_OUTPUT_TOKENS = 32000;
128
203
  const MODEL_MAX_OUTPUT_TOKENS = {
129
- // Anthropic — current models (actual API-enforced limits)
130
- "claude-opus-4-6": 128000, // 128K
131
- "claude-sonnet-4-6": 64000, // 64K (API enforces 64000, not 65536)
132
- "claude-haiku-4-5-20251001": 64000, // 64K
133
- // Anthropic legacy models
134
- "claude-sonnet-4-5-20250929": 64000, // 64K (API enforces 64000)
135
- "claude-opus-4-5-20251101": 64000, // 64K
136
- "claude-opus-4-1-20250805": 32768, // 32K
137
- "claude-sonnet-4-20250514": 64000, // 64K
138
- "claude-opus-4-20250514": 32768, // 32K
139
- "claude-3-7-sonnet-20250219": 64000, // 64K
140
- "claude-3-haiku-20240307": 4096, // 4K
141
- // Bedrock — same limits as direct API
142
- "anthropic.claude-sonnet-4-6": 64000,
143
- "us.anthropic.claude-sonnet-4-20250514-v1:0": 64000,
144
- "us.anthropic.claude-sonnet-4-5-20250929-v1:0": 64000,
145
- "us.anthropic.claude-haiku-4-5-20251001-v1:0": 64000,
146
- // Google Gemini
147
- "gemini-3-pro-preview": 65536,
148
- "gemini-3-flash-preview": 65536,
149
- "gemini-2.5-pro": 65536,
150
- "gemini-2.5-flash": 65536,
151
- "gemini-2.5-flash-lite": 65536,
152
- // OpenAI — GPT-5 family: 128K max output, o-series: 100K
153
- "gpt-5": 128000,
154
- "gpt-5-mini": 128000,
155
- "gpt-5-nano": 128000,
156
- "o3": 100000,
157
- "o4-mini": 100000,
158
- "gpt-4o": 16384,
204
+ // Anthropic — current models (actual API-enforced limits)
205
+ "claude-opus-4-6": 128000,
206
+ // 128K
207
+ "claude-sonnet-4-6": 64000,
208
+ // 64K (API enforces 64000, not 65536)
209
+ "claude-haiku-4-5-20251001": 64000,
210
+ // 64K
211
+ // Anthropic legacy models
212
+ "claude-sonnet-4-5-20250929": 64000,
213
+ // 64K (API enforces 64000)
214
+ "claude-opus-4-5-20251101": 64000,
215
+ // 64K
216
+ "claude-opus-4-1-20250805": 32768,
217
+ // 32K
218
+ "claude-sonnet-4-20250514": 64000,
219
+ // 64K
220
+ "claude-opus-4-20250514": 32768,
221
+ // 32K
222
+ "claude-3-7-sonnet-20250219": 64000,
223
+ // 64K
224
+ "claude-3-haiku-20240307": 4096,
225
+ // 4K
226
+ // Bedrock — same limits as direct API
227
+ "anthropic.claude-sonnet-4-6": 64000,
228
+ "us.anthropic.claude-sonnet-4-20250514-v1:0": 64000,
229
+ "us.anthropic.claude-sonnet-4-5-20250929-v1:0": 64000,
230
+ "us.anthropic.claude-haiku-4-5-20251001-v1:0": 64000,
231
+ // Google Gemini
232
+ "gemini-3-pro-preview": 65536,
233
+ "gemini-3-flash-preview": 65536,
234
+ "gemini-2.5-pro": 65536,
235
+ "gemini-2.5-flash": 65536,
236
+ "gemini-2.5-flash-lite": 65536,
237
+ // OpenAI — GPT-5 family: 128K max output, o-series: 100K
238
+ "gpt-5": 128000,
239
+ "gpt-5-mini": 128000,
240
+ "gpt-5-nano": 128000,
241
+ "o3": 100000,
242
+ "o4-mini": 100000,
243
+ "gpt-4o": 16384
159
244
  };
160
245
  export function getMaxOutputTokens(model, agentMax) {
161
- const modelMax = MODEL_MAX_OUTPUT_TOKENS[model] ?? DEFAULT_OUTPUT_TOKENS;
162
- // If caller explicitly sets agentMax, respect it (capped at model max).
163
- // Otherwise use sane default — never auto-request 128K output.
164
- if (agentMax)
165
- return Math.min(agentMax, modelMax);
166
- return Math.min(DEFAULT_OUTPUT_TOKENS, modelMax);
246
+ const modelMax = MODEL_MAX_OUTPUT_TOKENS[model] ?? DEFAULT_OUTPUT_TOKENS;
247
+ // If caller explicitly sets agentMax, respect it (capped at model max).
248
+ // Otherwise use sane default — never auto-request 128K output.
249
+ if (agentMax) return Math.min(agentMax, modelMax);
250
+ return Math.min(DEFAULT_OUTPUT_TOKENS, modelMax);
167
251
  }
252
+
168
253
  // ============================================================================
169
254
  // MULTI-BREAKPOINT PROMPT CACHING
170
255
  // ============================================================================
256
+
171
257
  /**
172
258
  * Add prompt cache breakpoints to tools and messages.
173
259
  * Uses 2 of 4 allowed breakpoints:
@@ -176,204 +262,293 @@ export function getMaxOutputTokens(model, agentMax) {
176
262
  * System prompt caching is handled by the caller.
177
263
  */
178
264
  export function addPromptCaching(tools, messages) {
179
- const cachedTools = tools.length > 0
180
- ? [...tools.slice(0, -1), { ...tools[tools.length - 1], cache_control: { type: "ephemeral" } }]
181
- : [...tools];
182
- const cachedMessages = [...messages];
183
- if (cachedMessages.length >= 2) {
184
- const idx = cachedMessages.length - 2;
185
- const msg = cachedMessages[idx];
186
- if (typeof msg.content === "string") {
187
- cachedMessages[idx] = {
188
- ...msg,
189
- content: [{ type: "text", text: msg.content, cache_control: { type: "ephemeral" } }],
190
- };
191
- }
192
- else if (Array.isArray(msg.content)) {
193
- const blocks = [...msg.content];
194
- blocks[blocks.length - 1] = { ...blocks[blocks.length - 1], cache_control: { type: "ephemeral" } };
195
- cachedMessages[idx] = { ...msg, content: blocks };
265
+ const cachedTools = tools.length > 0 ? [...tools.slice(0, -1), {
266
+ ...tools[tools.length - 1],
267
+ cache_control: {
268
+ type: "ephemeral"
269
+ }
270
+ }] : [...tools];
271
+ const cachedMessages = [...messages];
272
+ if (cachedMessages.length >= 2) {
273
+ const idx = cachedMessages.length - 2;
274
+ const msg = cachedMessages[idx];
275
+ if (typeof msg.content === "string") {
276
+ cachedMessages[idx] = {
277
+ ...msg,
278
+ content: [{
279
+ type: "text",
280
+ text: msg.content,
281
+ cache_control: {
282
+ type: "ephemeral"
283
+ }
284
+ }]
285
+ };
286
+ } else if (Array.isArray(msg.content)) {
287
+ const blocks = [...msg.content];
288
+ blocks[blocks.length - 1] = {
289
+ ...blocks[blocks.length - 1],
290
+ cache_control: {
291
+ type: "ephemeral"
196
292
  }
293
+ };
294
+ cachedMessages[idx] = {
295
+ ...msg,
296
+ content: blocks
297
+ };
197
298
  }
198
- return { tools: cachedTools, messages: cachedMessages };
299
+ }
300
+ return {
301
+ tools: cachedTools,
302
+ messages: cachedMessages
303
+ };
199
304
  }
305
+
200
306
  // ============================================================================
201
307
  // LOOP DETECTION
202
308
  // ============================================================================
309
+
203
310
  /** djb2 string hash — fast, deterministic, no dependencies */
204
311
  export function djb2Hash(str) {
205
- let hash = 5381;
206
- for (let i = 0; i < str.length; i++) {
207
- hash = ((hash << 5) + hash + str.charCodeAt(i)) & 0xffffffff;
208
- }
209
- return hash.toString(36);
312
+ let hash = 5381;
313
+ for (let i = 0; i < str.length; i++) {
314
+ hash = (hash << 5) + hash + str.charCodeAt(i) & 0xffffffff;
315
+ }
316
+ return hash.toString(36);
210
317
  }
211
318
  export class LoopDetector {
212
- history = [];
213
- consecutiveErrors = new Map();
214
- turnErrors = 0;
215
- turnHadErrors = false;
216
- sessionErrors = new Map();
217
- failedStrategies = new Set();
218
- consecutiveFailedTurns = 0;
219
- totalSessionErrors = 0;
220
- /** Tracks how many times the same file path has been read this session */
221
- fileReadCounts = new Map();
222
- static IDENTICAL_CALL_LIMIT = 4;
223
- static CONSECUTIVE_ERROR_LIMIT = 3;
224
- static TURN_ERROR_LIMIT = 5;
225
- static WINDOW = 20;
226
- static SESSION_TOOL_ERROR_LIMIT = 10;
227
- static CONSECUTIVE_FAILED_TURN_LIMIT = 3;
228
- static FILE_READ_LIMIT = 3;
229
- /** Get the error-tracking key for a tool call. Tools with an `action` param
230
- * are tracked per-action so e.g. voice/speak failing won't block voice/music_compose. */
231
- errorKey(name, input) {
232
- if (input && typeof input.action === "string")
233
- return `${name}:${input.action}`;
234
- return name;
319
+ history = [];
320
+ consecutiveErrors = new Map();
321
+ turnErrors = 0;
322
+ turnHadErrors = false;
323
+ sessionErrors = new Map();
324
+ failedStrategies = new Set();
325
+ consecutiveFailedTurns = 0;
326
+ totalSessionErrors = 0;
327
+
328
+ /** Tracks how many times the same file path has been read this session */
329
+ fileReadCounts = new Map();
330
+
331
+ /** Resolved config — accepts DB overrides, falls back to AGENT_DEFAULTS */
332
+
333
+ constructor(config) {
334
+ this.config = {
335
+ identicalCallLimit: config?.identicalCallLimit ?? AGENT_DEFAULTS.loopIdenticalCallLimit,
336
+ consecutiveErrorLimit: config?.consecutiveErrorLimit ?? AGENT_DEFAULTS.loopConsecutiveErrorLimit,
337
+ turnErrorLimit: config?.turnErrorLimit ?? AGENT_DEFAULTS.loopTurnErrorLimit,
338
+ window: config?.window ?? AGENT_DEFAULTS.loopWindow,
339
+ sessionToolErrorLimit: config?.sessionToolErrorLimit ?? AGENT_DEFAULTS.loopSessionToolErrorLimit,
340
+ consecutiveFailedTurnLimit: config?.consecutiveFailedTurnLimit ?? AGENT_DEFAULTS.loopConsecutiveFailedTurnLimit,
341
+ fileReadLimit: config?.fileReadLimit ?? AGENT_DEFAULTS.loopFileReadLimit
342
+ };
343
+ }
344
+
345
+ /** Create a LoopDetector from a ResolvedAgentLoopConfig */
346
+ static fromResolved(resolved) {
347
+ return new LoopDetector({
348
+ identicalCallLimit: resolved.loopIdenticalCallLimit,
349
+ consecutiveErrorLimit: resolved.loopConsecutiveErrorLimit,
350
+ turnErrorLimit: resolved.loopTurnErrorLimit,
351
+ window: resolved.loopWindow,
352
+ sessionToolErrorLimit: resolved.loopSessionToolErrorLimit,
353
+ consecutiveFailedTurnLimit: resolved.loopConsecutiveFailedTurnLimit,
354
+ fileReadLimit: resolved.loopFileReadLimit
355
+ });
356
+ }
357
+
358
+ /** Get the error-tracking key for a tool call. Tools with an `action` param
359
+ * are tracked per-action so e.g. voice/speak failing won't block voice/music_compose. */
360
+ errorKey(name, input) {
361
+ if (input && typeof input.action === "string") return `${name}:${input.action}`;
362
+ return name;
363
+ }
364
+ recordCall(name, input) {
365
+ const inputHash = djb2Hash(JSON.stringify({
366
+ name,
367
+ ...input
368
+ }));
369
+ const eKey = this.errorKey(name, input);
370
+ if (this.failedStrategies.has(inputHash)) {
371
+ return {
372
+ blocked: true,
373
+ reason: `Blocked: this exact "${name}" call failed in a previous turn. Try a fundamentally different approach.`
374
+ };
235
375
  }
236
- recordCall(name, input) {
237
- const inputHash = djb2Hash(JSON.stringify({ name, ...input }));
238
- const eKey = this.errorKey(name, input);
239
- if (this.failedStrategies.has(inputHash)) {
240
- return {
241
- blocked: true,
242
- reason: `Blocked: this exact "${name}" call failed in a previous turn. Try a fundamentally different approach.`,
243
- };
244
- }
245
- const sessionErrorCount = this.sessionErrors.get(eKey) || 0;
246
- if (sessionErrorCount >= LoopDetector.SESSION_TOOL_ERROR_LIMIT) {
247
- return {
248
- blocked: true,
249
- reason: `Tool "${name}" (action: ${input.action || "default"}) has failed ${sessionErrorCount} times this session. Stop using this tool and try a different approach.`,
250
- };
251
- }
252
- if (this.turnErrors >= LoopDetector.TURN_ERROR_LIMIT) {
253
- return {
254
- blocked: true,
255
- reason: `${this.turnErrors} errors this turn. Stop and re-assess your approach.`,
256
- };
257
- }
258
- const errorCount = this.consecutiveErrors.get(eKey) || 0;
259
- if (errorCount >= LoopDetector.CONSECUTIVE_ERROR_LIMIT) {
260
- return {
261
- blocked: true,
262
- reason: `Tool "${name}" (action: ${input.action || "default"}) blocked: failed ${errorCount} times consecutively. Try a different approach or action.`,
263
- };
264
- }
265
- const windowSlice = this.history.slice(-LoopDetector.WINDOW);
266
- const identicalCount = windowSlice.filter((h) => h.inputHash === inputHash).length;
267
- if (identicalCount >= LoopDetector.IDENTICAL_CALL_LIMIT) {
268
- return {
269
- blocked: true,
270
- reason: `Tool "${name}" blocked: identical call made ${identicalCount} times. Try different parameters.`,
271
- };
272
- }
273
- this.history.push({ name, inputHash });
274
- if (this.history.length > LoopDetector.WINDOW * 2) {
275
- this.history = this.history.slice(-LoopDetector.WINDOW);
276
- }
277
- return { blocked: false };
376
+ const sessionErrorCount = this.sessionErrors.get(eKey) || 0;
377
+ if (sessionErrorCount >= this.config.sessionToolErrorLimit) {
378
+ return {
379
+ blocked: true,
380
+ reason: `Tool "${name}" (action: ${input.action || "default"}) has failed ${sessionErrorCount} times this session. Stop using this tool and try a different approach.`
381
+ };
278
382
  }
279
- /**
280
- * Track file read frequency — call when the tool is known to be a file read.
281
- * Blocks re-reading the same path more than FILE_READ_LIMIT times per session.
282
- */
283
- trackRead(path) {
284
- const readCount = (this.fileReadCounts.get(path) || 0) + 1;
285
- this.fileReadCounts.set(path, readCount);
286
- if (readCount > LoopDetector.FILE_READ_LIMIT) {
287
- return {
288
- blocked: true,
289
- reason: `File "${path}" already read ${readCount - 1} times this session. Use the content from a previous read instead of re-reading.`,
290
- };
291
- }
292
- return { blocked: false };
383
+ if (this.turnErrors >= this.config.turnErrorLimit) {
384
+ return {
385
+ blocked: true,
386
+ reason: `${this.turnErrors} errors this turn. Stop and re-assess your approach.`
387
+ };
293
388
  }
294
- recordResult(name, success, input) {
295
- const eKey = this.errorKey(name, input);
296
- if (success) {
297
- this.consecutiveErrors.delete(eKey);
298
- }
299
- else {
300
- const current = this.consecutiveErrors.get(eKey) || 0;
301
- this.consecutiveErrors.set(eKey, current + 1);
302
- this.turnErrors++;
303
- this.turnHadErrors = true;
304
- const sessionCount = this.sessionErrors.get(eKey) || 0;
305
- this.sessionErrors.set(eKey, sessionCount + 1);
306
- this.totalSessionErrors++;
307
- if (input) {
308
- const inputHash = djb2Hash(JSON.stringify({ name, ...input }));
309
- this.failedStrategies.add(inputHash);
310
- if (this.failedStrategies.size > 200) {
311
- const arr = Array.from(this.failedStrategies);
312
- this.failedStrategies = new Set(arr.slice(-100));
313
- }
314
- }
315
- }
389
+ const errorCount = this.consecutiveErrors.get(eKey) || 0;
390
+ if (errorCount >= this.config.consecutiveErrorLimit) {
391
+ return {
392
+ blocked: true,
393
+ reason: `Tool "${name}" (action: ${input.action || "default"}) blocked: failed ${errorCount} times consecutively. Try a different approach or action.`
394
+ };
316
395
  }
317
- endTurn() {
318
- if (this.turnHadErrors) {
319
- this.consecutiveFailedTurns++;
320
- }
321
- else {
322
- this.consecutiveFailedTurns = 0;
323
- // A clean turn means the agent has recovered — unblock previously failed strategies
324
- // so it can retry calls that failed due to bad params (e.g., wrong UUID format)
325
- this.failedStrategies.clear();
326
- // Decay session error counts on clean turns so tools aren't permanently blocked.
327
- // Each clean turn halves all session error counts, allowing recovery from
328
- // transient issues while still blocking persistently broken tools.
329
- if (this.sessionErrors.size > 0) {
330
- for (const [key, count] of this.sessionErrors) {
331
- const decayed = Math.floor(count / 2);
332
- if (decayed <= 0) {
333
- this.sessionErrors.delete(key);
334
- }
335
- else {
336
- this.sessionErrors.set(key, decayed);
337
- }
338
- }
339
- }
340
- }
341
- // Reset turn-level counters so the NEXT dispatch batch starts fresh.
342
- // Session-level counters (sessionErrors, consecutiveFailedTurns) persist.
343
- this.turnErrors = 0;
344
- this.turnHadErrors = false;
345
- if (this.consecutiveFailedTurns >= LoopDetector.CONSECUTIVE_FAILED_TURN_LIMIT) {
346
- return {
347
- shouldBail: true,
348
- message: `You have had errors in ${this.consecutiveFailedTurns} consecutive turns (${this.totalSessionErrors} total errors). Your approach is not working. STOP and explain to the user what's failing.`,
349
- };
396
+ const windowSlice = this.history.slice(-this.config.window);
397
+ const identicalCount = windowSlice.filter(h => h.inputHash === inputHash).length;
398
+ if (identicalCount >= this.config.identicalCallLimit) {
399
+ return {
400
+ blocked: true,
401
+ reason: `Tool "${name}" blocked: identical call made ${identicalCount} times. Try different parameters.`
402
+ };
403
+ }
404
+ this.history.push({
405
+ name,
406
+ inputHash
407
+ });
408
+ if (this.history.length > this.config.window * 2) {
409
+ this.history = this.history.slice(-this.config.window);
410
+ }
411
+ return {
412
+ blocked: false
413
+ };
414
+ }
415
+
416
+ /**
417
+ * Track file read frequency — call when the tool is known to be a file read.
418
+ * Blocks re-reading the same path more than FILE_READ_LIMIT times per session.
419
+ */
420
+ trackRead(path) {
421
+ const readCount = (this.fileReadCounts.get(path) || 0) + 1;
422
+ this.fileReadCounts.set(path, readCount);
423
+ if (readCount > this.config.fileReadLimit) {
424
+ return {
425
+ blocked: true,
426
+ reason: `File "${path}" already read ${readCount - 1} times this session. Use the content from a previous read instead of re-reading.`
427
+ };
428
+ }
429
+ return {
430
+ blocked: false
431
+ };
432
+ }
433
+
434
+ /**
435
+ * Record a tool execution result.
436
+ * @param transient - If true, the failure is transient (timeout, rate limit)
437
+ * and should NOT be added to failedStrategies. Transient failures are
438
+ * retryable with the exact same inputs — e.g., a task_output poll that
439
+ * timed out because the task is still running.
440
+ */
441
+ recordResult(name, success, input, transient) {
442
+ const eKey = this.errorKey(name, input);
443
+ if (success) {
444
+ this.consecutiveErrors.delete(eKey);
445
+ } else {
446
+ const current = this.consecutiveErrors.get(eKey) || 0;
447
+ this.consecutiveErrors.set(eKey, current + 1);
448
+ this.turnErrors++;
449
+ this.turnHadErrors = true;
450
+ const sessionCount = this.sessionErrors.get(eKey) || 0;
451
+ this.sessionErrors.set(eKey, sessionCount + 1);
452
+ this.totalSessionErrors++;
453
+
454
+ // Only add to failedStrategies for non-transient errors.
455
+ // Transient errors (timeouts, rate limits) should be retryable with
456
+ // the exact same inputs — blocking them creates a deadlock for polling
457
+ // tools like task_output where the input (task_id) never changes.
458
+ if (input && !transient) {
459
+ const inputHash = djb2Hash(JSON.stringify({
460
+ name,
461
+ ...input
462
+ }));
463
+ this.failedStrategies.add(inputHash);
464
+ if (this.failedStrategies.size > 200) {
465
+ const arr = Array.from(this.failedStrategies);
466
+ this.failedStrategies = new Set(arr.slice(-100));
350
467
  }
351
- return { shouldBail: false };
468
+ }
352
469
  }
353
- resetTurn() {
354
- // Only reset per-turn counters — history and consecutiveErrors persist
355
- // for cross-turn detection. The full reset() clears everything for new sessions.
356
- this.turnErrors = 0;
357
- this.turnHadErrors = false;
470
+ }
471
+ endTurn() {
472
+ if (this.turnHadErrors) {
473
+ this.consecutiveFailedTurns++;
474
+ } else {
475
+ this.consecutiveFailedTurns = 0;
476
+ // A clean turn means the agent has recovered — unblock previously failed strategies
477
+ // so it can retry calls that failed due to bad params (e.g., wrong UUID format)
478
+ this.failedStrategies.clear();
479
+ // Decay session error counts on clean turns so tools aren't permanently blocked.
480
+ // Each clean turn halves all session error counts, allowing recovery from
481
+ // transient issues while still blocking persistently broken tools.
482
+ if (this.sessionErrors.size > 0) {
483
+ for (const [key, count] of this.sessionErrors) {
484
+ const decayed = Math.floor(count / 2);
485
+ if (decayed <= 0) {
486
+ this.sessionErrors.delete(key);
487
+ } else {
488
+ this.sessionErrors.set(key, decayed);
489
+ }
490
+ }
491
+ }
358
492
  }
359
- reset() {
360
- this.resetTurn();
361
- this.history = [];
362
- this.consecutiveErrors.clear();
363
- this.sessionErrors.clear();
364
- this.failedStrategies.clear();
365
- this.fileReadCounts.clear();
366
- this.consecutiveFailedTurns = 0;
367
- this.totalSessionErrors = 0;
493
+
494
+ // Cap consecutiveErrors so a single bad batch (parallel Promise.all) can't
495
+ // permanently brick a tool. Without this, N parallel failures push
496
+ // consecutiveErrors to N, which exceeds consecutiveErrorLimit and creates
497
+ // a deadlock: the tool is blocked because it failed, but can't succeed to
498
+ // unblock itself because it's blocked. Capping to (limit - 1) gives the
499
+ // tool one retry on the next turn. Only permanently block after multiple
500
+ // consecutive failed turns (handled by the bail-out check below).
501
+ if (this.consecutiveFailedTurns < this.config.consecutiveFailedTurnLimit) {
502
+ for (const [key, count] of this.consecutiveErrors) {
503
+ if (count >= this.config.consecutiveErrorLimit) {
504
+ this.consecutiveErrors.set(key, this.config.consecutiveErrorLimit - 1);
505
+ }
506
+ }
368
507
  }
369
- getSessionStats() {
370
- return {
371
- totalErrors: this.totalSessionErrors,
372
- failedStrategies: this.failedStrategies.size,
373
- consecutiveFailedTurns: this.consecutiveFailedTurns,
374
- };
508
+
509
+ // Reset turn-level counters so the NEXT dispatch batch starts fresh.
510
+ // Session-level counters (sessionErrors, consecutiveFailedTurns) persist.
511
+ this.turnErrors = 0;
512
+ this.turnHadErrors = false;
513
+ if (this.consecutiveFailedTurns >= this.config.consecutiveFailedTurnLimit) {
514
+ return {
515
+ shouldBail: true,
516
+ message: `You have had errors in ${this.consecutiveFailedTurns} consecutive turns (${this.totalSessionErrors} total errors). Your approach is not working. STOP and explain to the user what's failing.`
517
+ };
375
518
  }
519
+ return {
520
+ shouldBail: false
521
+ };
522
+ }
523
+ resetTurn() {
524
+ // Only reset per-turn counters — history and consecutiveErrors persist
525
+ // for cross-turn detection. The full reset() clears everything for new sessions.
526
+ this.turnErrors = 0;
527
+ this.turnHadErrors = false;
528
+ }
529
+ reset() {
530
+ this.resetTurn();
531
+ this.history = [];
532
+ this.consecutiveErrors.clear();
533
+ this.sessionErrors.clear();
534
+ this.failedStrategies.clear();
535
+ this.fileReadCounts.clear();
536
+ this.consecutiveFailedTurns = 0;
537
+ this.totalSessionErrors = 0;
538
+ }
539
+ getSessionStats() {
540
+ return {
541
+ totalErrors: this.totalSessionErrors,
542
+ failedStrategies: this.failedStrategies.size,
543
+ consecutiveFailedTurns: this.consecutiveFailedTurns
544
+ };
545
+ }
376
546
  }
547
+
548
+ // ============================================================================
549
+ // EXTENDED THINKING
550
+ // ============================================================================
551
+
377
552
  /**
378
553
  * Returns the thinking configuration and required beta string for the given model.
379
554
  * - Opus 4.6: adaptive thinking (no budget needed)
@@ -381,184 +556,365 @@ export class LoopDetector {
381
556
  * - budget_tokens must be strictly < max_tokens
382
557
  */
383
558
  export function getThinkingConfig(model, enabled) {
384
- if (!enabled) {
385
- return { thinking: { type: "disabled" }, beta: "" };
386
- }
387
- const provider = getProvider(model);
388
- // Gemini models: thinking is always-on for 2.5+/3.x — signal pass-through
389
- if (provider === "gemini") {
390
- return { thinking: { type: "enabled" }, beta: "" };
391
- }
392
- // OpenAI models: reasoning models (o-series) have built-in reasoning, GPT models don't support thinking
393
- if (provider === "openai") {
394
- const isReasoning = /^o\d/.test(model);
395
- return { thinking: { type: isReasoning ? "enabled" : "disabled" }, beta: "" };
396
- }
397
- if (model.includes("opus-4-6") || model.includes("sonnet-4-6")) {
398
- return {
399
- thinking: { type: "adaptive" },
400
- beta: "adaptive-thinking-2026-01-28",
401
- };
402
- }
403
- // Sonnet 4.5/4.0 / Haiku: fixed budget
559
+ if (!enabled) {
404
560
  return {
405
- thinking: { type: "enabled", budget_tokens: 10_000 },
406
- beta: "interleaved-thinking-2025-05-14",
561
+ thinking: {
562
+ type: "disabled"
563
+ },
564
+ beta: ""
407
565
  };
566
+ }
567
+ const provider = getProvider(model);
568
+
569
+ // Gemini models: thinking is always-on for 2.5+/3.x — signal pass-through
570
+ if (provider === "gemini") {
571
+ return {
572
+ thinking: {
573
+ type: "enabled"
574
+ },
575
+ beta: ""
576
+ };
577
+ }
578
+
579
+ // OpenAI models: reasoning models (o-series) have built-in reasoning, GPT models don't support thinking
580
+ if (provider === "openai") {
581
+ const isReasoning = /^o\d/.test(model);
582
+ return {
583
+ thinking: {
584
+ type: isReasoning ? "enabled" : "disabled"
585
+ },
586
+ beta: ""
587
+ };
588
+ }
589
+ if (model.includes("opus-4-6") || model.includes("sonnet-4-6")) {
590
+ return {
591
+ thinking: {
592
+ type: "adaptive"
593
+ },
594
+ beta: "adaptive-thinking-2026-01-28"
595
+ };
596
+ }
597
+
598
+ // Sonnet 4.5/4.0 / Haiku: fixed budget (matches Claude Code's 31,999 default)
599
+ return {
600
+ thinking: {
601
+ type: "enabled",
602
+ budget_tokens: 31_999
603
+ },
604
+ beta: "interleaved-thinking-2025-05-14"
605
+ };
408
606
  }
607
+
409
608
  // ============================================================================
410
609
  // COST TRACKING
411
610
  // ============================================================================
611
+
412
612
  export const MODEL_PRICING = {
413
- // Anthropic direct — Claude 4.x
414
- "claude-sonnet-4-6": { inputPer1M: 3.0, outputPer1M: 15.0, thinkingPer1M: 15.0 },
415
- "claude-sonnet-4-20250514": { inputPer1M: 3.0, outputPer1M: 15.0, thinkingPer1M: 15.0 },
416
- "claude-sonnet-4-5-20250929": { inputPer1M: 3.0, outputPer1M: 15.0, thinkingPer1M: 15.0 },
417
- "claude-opus-4-6": { inputPer1M: 5.0, outputPer1M: 25.0, thinkingPer1M: 25.0 },
418
- "claude-opus-4-20250514": { inputPer1M: 5.0, outputPer1M: 25.0, thinkingPer1M: 25.0 },
419
- "claude-opus-4-5-20251101": { inputPer1M: 5.0, outputPer1M: 25.0, thinkingPer1M: 25.0 },
420
- "claude-haiku-4-20250514": { inputPer1M: 1.0, outputPer1M: 5.0, thinkingPer1M: 5.0 },
421
- "claude-haiku-4-5-20251001": { inputPer1M: 1.0, outputPer1M: 5.0, thinkingPer1M: 5.0 },
422
- // Anthropic direct — Claude 3.5
423
- "claude-3-5-sonnet-20241022": { inputPer1M: 3.0, outputPer1M: 15.0 },
424
- "claude-3-5-haiku-20241022": { inputPer1M: 0.80, outputPer1M: 4.0 },
425
- // Bedrock — Claude 4.x
426
- "anthropic.claude-sonnet-4-6": { inputPer1M: 3.0, outputPer1M: 15.0, thinkingPer1M: 15.0 },
427
- "us.anthropic.claude-sonnet-4-20250514-v1:0": { inputPer1M: 3.0, outputPer1M: 15.0, thinkingPer1M: 15.0 },
428
- "us.anthropic.claude-sonnet-4-5-20250929-v1:0": { inputPer1M: 3.0, outputPer1M: 15.0, thinkingPer1M: 15.0 },
429
- "us.anthropic.claude-haiku-4-5-20251001-v1:0": { inputPer1M: 1.0, outputPer1M: 5.0, thinkingPer1M: 5.0 },
430
- // Bedrock — Claude 3.5
431
- "us.anthropic.claude-3-5-haiku-20241022-v1:0": { inputPer1M: 0.80, outputPer1M: 4.0 },
432
- // Bedrock — Llama & Nova
433
- "us.meta.llama3-1-70b-instruct-v1:0": { inputPer1M: 0.72, outputPer1M: 0.72 },
434
- "us.amazon.nova-pro-v1:0": { inputPer1M: 0.80, outputPer1M: 3.20 },
435
- // Gemini (thinking tokens are cheaper than output)
436
- "gemini-3-pro-preview": { inputPer1M: 1.25, outputPer1M: 10.0, thinkingPer1M: 2.50 },
437
- "gemini-3-flash-preview": { inputPer1M: 0.15, outputPer1M: 0.60, thinkingPer1M: 0.15 },
438
- "gemini-2.5-pro": { inputPer1M: 1.25, outputPer1M: 10.0, thinkingPer1M: 2.50 },
439
- "gemini-2.5-flash": { inputPer1M: 0.15, outputPer1M: 0.60, thinkingPer1M: 0.15 },
440
- "gemini-2.5-flash-lite": { inputPer1M: 0.075, outputPer1M: 0.30, thinkingPer1M: 0.075 },
441
- "gemini-2.0-flash": { inputPer1M: 0.10, outputPer1M: 0.40 },
442
- "gemini-2.0-flash-lite": { inputPer1M: 0.075, outputPer1M: 0.30 },
443
- // OpenAI — GPT
444
- "gpt-5": { inputPer1M: 1.25, outputPer1M: 10.0 },
445
- "gpt-5-mini": { inputPer1M: 0.25, outputPer1M: 2.0 },
446
- "gpt-5-nano": { inputPer1M: 0.05, outputPer1M: 0.40 },
447
- "gpt-4o": { inputPer1M: 2.50, outputPer1M: 10.0 },
448
- "gpt-4o-mini": { inputPer1M: 0.15, outputPer1M: 0.60 },
449
- "gpt-4-turbo": { inputPer1M: 10.0, outputPer1M: 30.0 },
450
- // OpenAI — reasoning models
451
- "o1": { inputPer1M: 15.0, outputPer1M: 60.0, thinkingPer1M: 60.0 },
452
- "o1-mini": { inputPer1M: 3.0, outputPer1M: 12.0, thinkingPer1M: 12.0 },
453
- "o3": { inputPer1M: 2.0, outputPer1M: 8.0, thinkingPer1M: 8.0 },
454
- "o3-mini": { inputPer1M: 1.10, outputPer1M: 4.40, thinkingPer1M: 4.40 },
455
- "o4-mini": { inputPer1M: 1.10, outputPer1M: 4.40, thinkingPer1M: 4.40 },
613
+ // Anthropic direct — Claude 4.x
614
+ "claude-sonnet-4-6": {
615
+ inputPer1M: 3.0,
616
+ outputPer1M: 15.0,
617
+ thinkingPer1M: 15.0
618
+ },
619
+ "claude-sonnet-4-20250514": {
620
+ inputPer1M: 3.0,
621
+ outputPer1M: 15.0,
622
+ thinkingPer1M: 15.0
623
+ },
624
+ "claude-sonnet-4-5-20250929": {
625
+ inputPer1M: 3.0,
626
+ outputPer1M: 15.0,
627
+ thinkingPer1M: 15.0
628
+ },
629
+ "claude-opus-4-6": {
630
+ inputPer1M: 5.0,
631
+ outputPer1M: 25.0,
632
+ thinkingPer1M: 25.0
633
+ },
634
+ "claude-opus-4-20250514": {
635
+ inputPer1M: 5.0,
636
+ outputPer1M: 25.0,
637
+ thinkingPer1M: 25.0
638
+ },
639
+ "claude-opus-4-5-20251101": {
640
+ inputPer1M: 5.0,
641
+ outputPer1M: 25.0,
642
+ thinkingPer1M: 25.0
643
+ },
644
+ "claude-haiku-4-20250514": {
645
+ inputPer1M: 1.0,
646
+ outputPer1M: 5.0,
647
+ thinkingPer1M: 5.0
648
+ },
649
+ "claude-haiku-4-5-20251001": {
650
+ inputPer1M: 1.0,
651
+ outputPer1M: 5.0,
652
+ thinkingPer1M: 5.0
653
+ },
654
+ // Anthropic direct Claude 3.5
655
+ "claude-3-5-sonnet-20241022": {
656
+ inputPer1M: 3.0,
657
+ outputPer1M: 15.0
658
+ },
659
+ "claude-3-5-haiku-20241022": {
660
+ inputPer1M: 0.80,
661
+ outputPer1M: 4.0
662
+ },
663
+ // Bedrock — Claude 4.x
664
+ "anthropic.claude-sonnet-4-6": {
665
+ inputPer1M: 3.0,
666
+ outputPer1M: 15.0,
667
+ thinkingPer1M: 15.0
668
+ },
669
+ "us.anthropic.claude-sonnet-4-20250514-v1:0": {
670
+ inputPer1M: 3.0,
671
+ outputPer1M: 15.0,
672
+ thinkingPer1M: 15.0
673
+ },
674
+ "us.anthropic.claude-sonnet-4-5-20250929-v1:0": {
675
+ inputPer1M: 3.0,
676
+ outputPer1M: 15.0,
677
+ thinkingPer1M: 15.0
678
+ },
679
+ "us.anthropic.claude-haiku-4-5-20251001-v1:0": {
680
+ inputPer1M: 1.0,
681
+ outputPer1M: 5.0,
682
+ thinkingPer1M: 5.0
683
+ },
684
+ // Bedrock — Claude 3.5
685
+ "us.anthropic.claude-3-5-haiku-20241022-v1:0": {
686
+ inputPer1M: 0.80,
687
+ outputPer1M: 4.0
688
+ },
689
+ // Bedrock — Llama & Nova
690
+ "us.meta.llama3-1-70b-instruct-v1:0": {
691
+ inputPer1M: 0.72,
692
+ outputPer1M: 0.72
693
+ },
694
+ "us.amazon.nova-pro-v1:0": {
695
+ inputPer1M: 0.80,
696
+ outputPer1M: 3.20
697
+ },
698
+ // Gemini (thinking tokens are cheaper than output)
699
+ "gemini-3-pro-preview": {
700
+ inputPer1M: 1.25,
701
+ outputPer1M: 10.0,
702
+ thinkingPer1M: 2.50
703
+ },
704
+ "gemini-3-flash-preview": {
705
+ inputPer1M: 0.15,
706
+ outputPer1M: 0.60,
707
+ thinkingPer1M: 0.15
708
+ },
709
+ "gemini-2.5-pro": {
710
+ inputPer1M: 1.25,
711
+ outputPer1M: 10.0,
712
+ thinkingPer1M: 2.50
713
+ },
714
+ "gemini-2.5-flash": {
715
+ inputPer1M: 0.15,
716
+ outputPer1M: 0.60,
717
+ thinkingPer1M: 0.15
718
+ },
719
+ "gemini-2.5-flash-lite": {
720
+ inputPer1M: 0.075,
721
+ outputPer1M: 0.30,
722
+ thinkingPer1M: 0.075
723
+ },
724
+ "gemini-2.0-flash": {
725
+ inputPer1M: 0.10,
726
+ outputPer1M: 0.40
727
+ },
728
+ "gemini-2.0-flash-lite": {
729
+ inputPer1M: 0.075,
730
+ outputPer1M: 0.30
731
+ },
732
+ // OpenAI — GPT
733
+ "gpt-5": {
734
+ inputPer1M: 1.25,
735
+ outputPer1M: 10.0
736
+ },
737
+ "gpt-5-mini": {
738
+ inputPer1M: 0.25,
739
+ outputPer1M: 2.0
740
+ },
741
+ "gpt-5-nano": {
742
+ inputPer1M: 0.05,
743
+ outputPer1M: 0.40
744
+ },
745
+ "gpt-4o": {
746
+ inputPer1M: 2.50,
747
+ outputPer1M: 10.0
748
+ },
749
+ "gpt-4o-mini": {
750
+ inputPer1M: 0.15,
751
+ outputPer1M: 0.60
752
+ },
753
+ "gpt-4-turbo": {
754
+ inputPer1M: 10.0,
755
+ outputPer1M: 30.0
756
+ },
757
+ // OpenAI — reasoning models
758
+ "o1": {
759
+ inputPer1M: 15.0,
760
+ outputPer1M: 60.0,
761
+ thinkingPer1M: 60.0
762
+ },
763
+ "o1-mini": {
764
+ inputPer1M: 3.0,
765
+ outputPer1M: 12.0,
766
+ thinkingPer1M: 12.0
767
+ },
768
+ "o3": {
769
+ inputPer1M: 2.0,
770
+ outputPer1M: 8.0,
771
+ thinkingPer1M: 8.0
772
+ },
773
+ "o3-mini": {
774
+ inputPer1M: 1.10,
775
+ outputPer1M: 4.40,
776
+ thinkingPer1M: 4.40
777
+ },
778
+ "o4-mini": {
779
+ inputPer1M: 1.10,
780
+ outputPer1M: 4.40,
781
+ thinkingPer1M: 4.40
782
+ }
456
783
  };
784
+
457
785
  /**
458
786
  * Emit graduated cost warnings at 25%, 50%, 75% thresholds.
459
787
  * Single source of truth — replaces copy-pasted blocks in server + CLI.
460
788
  */
461
789
  export function emitCostWarningIfNeeded(sessionCostUsd, maxCostUsd, costWarningsEmitted, onText) {
462
- if (!isFinite(maxCostUsd) || !onText)
463
- return;
464
- for (const pct of [25, 50, 75]) {
465
- if (!costWarningsEmitted.has(pct) && sessionCostUsd >= maxCostUsd * (pct / 100)) {
466
- costWarningsEmitted.add(pct);
467
- onText(`\n[Cost warning: ${pct}% of budget used ($${sessionCostUsd.toFixed(2)}/$${maxCostUsd.toFixed(2)}).${pct >= 75 ? " Wrap up soon." : ""}]`);
468
- }
790
+ if (!isFinite(maxCostUsd) || !onText) return;
791
+ for (const pct of [25, 50, 75]) {
792
+ if (!costWarningsEmitted.has(pct) && sessionCostUsd >= maxCostUsd * (pct / 100)) {
793
+ costWarningsEmitted.add(pct);
794
+ onText(`\n[Cost warning: ${pct}% of budget used ($${sessionCostUsd.toFixed(2)}/$${maxCostUsd.toFixed(2)}).${pct >= 75 ? " Wrap up soon." : ""}]`);
469
795
  }
796
+ }
470
797
  }
471
798
  export function estimateCostUsd(inputTokens, outputTokens, model, thinkingTokens = 0, cacheReadTokens = 0, cacheCreationTokens = 0) {
472
- // Exact match first, then find a pricing key that is a prefix of the model ID
473
- const pricing = MODEL_PRICING[model]
474
- || MODEL_PRICING[Object.keys(MODEL_PRICING).find((k) => model.startsWith(k)) ?? ""]
475
- || MODEL_PRICING["claude-sonnet-4-6"];
476
- const thinkingRate = pricing.thinkingPer1M || pricing.outputPer1M;
477
- const inputRate = pricing.inputPer1M;
478
- // Base cost
479
- let cost = (inputTokens / 1_000_000) * inputRate
480
- + (outputTokens / 1_000_000) * pricing.outputPer1M
481
- + (thinkingTokens / 1_000_000) * thinkingRate;
482
- // Cache pricing subtract savings for cached tokens
483
- // Anthropic/Bedrock: cache reads 90% cheaper, cache creation 25% surcharge
484
- // OpenAI: cache reads 50% cheaper, no creation surcharge
485
- // Gemini: cache reads 75% cheaper
486
- if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
487
- const provider = getProvider(model);
488
- if (provider === "anthropic" || provider === "bedrock") {
489
- cost -= (cacheReadTokens / 1_000_000) * inputRate * 0.9;
490
- cost += (cacheCreationTokens / 1_000_000) * inputRate * 0.25;
491
- }
492
- else if (provider === "openai") {
493
- cost -= (cacheReadTokens / 1_000_000) * inputRate * 0.5;
494
- }
495
- else if (provider === "gemini") {
496
- cost -= (cacheReadTokens / 1_000_000) * inputRate * 0.75;
497
- }
799
+ // Exact match first, then find a pricing key that is a prefix of the model ID
800
+ const pricing = MODEL_PRICING[model] || MODEL_PRICING[Object.keys(MODEL_PRICING).find(k => model.startsWith(k)) ?? ""] || MODEL_PRICING["claude-sonnet-4-6"];
801
+ const thinkingRate = pricing.thinkingPer1M || pricing.outputPer1M;
802
+ const inputRate = pricing.inputPer1M;
803
+
804
+ // Base cost
805
+ let cost = inputTokens / 1_000_000 * inputRate + outputTokens / 1_000_000 * pricing.outputPer1M + thinkingTokens / 1_000_000 * thinkingRate;
806
+
807
+ // Cache pricing subtract savings for cached tokens
808
+ // Anthropic/Bedrock: cache reads 90% cheaper, cache creation 25% surcharge
809
+ // OpenAI: cache reads 50% cheaper, no creation surcharge
810
+ // Gemini: cache reads 75% cheaper
811
+ if (cacheReadTokens > 0 || cacheCreationTokens > 0) {
812
+ const provider = getProvider(model);
813
+ if (provider === "anthropic" || provider === "bedrock") {
814
+ cost -= cacheReadTokens / 1_000_000 * inputRate * 0.9;
815
+ cost += cacheCreationTokens / 1_000_000 * inputRate * 0.25;
816
+ } else if (provider === "openai") {
817
+ cost -= cacheReadTokens / 1_000_000 * inputRate * 0.5;
818
+ } else if (provider === "gemini") {
819
+ cost -= cacheReadTokens / 1_000_000 * inputRate * 0.75;
498
820
  }
499
- return cost;
821
+ }
822
+ return cost;
500
823
  }
824
+
501
825
  // ============================================================================
502
826
  // MODEL ROUTING BY TASK COMPLEXITY
503
827
  // ============================================================================
828
+
504
829
  /**
505
830
  * Route to cheaper model when the task is simple enough.
506
831
  * Returns the model to actually use.
507
832
  */
508
833
  export function routeModel(message, requestedModel, forceModel) {
509
- // If user explicitly picked a model, respect it
510
- if (forceModel)
511
- return requestedModel;
512
- // Estimate token count (rough: 1 token ~= 4 chars)
513
- const estimatedTokens = Math.ceil(message.length / 4);
514
- // Simple queries → Haiku (30x cheaper than Opus)
515
- const simplePatterns = /^(what|who|when|where|show|list|get|find|look ?up|check)\b/i;
516
- const complexPatterns = /\b(analyze|implement|refactor|design|architect|debug|explain why|compare|evaluate|write|create|build|fix)\b/i;
517
- if (estimatedTokens < 50 && simplePatterns.test(message) && !complexPatterns.test(message)) {
518
- return "claude-haiku-4-5-20251001";
519
- }
520
- // Medium queries → Sonnet
521
- if (estimatedTokens < 200 && !complexPatterns.test(message)) {
522
- return "claude-sonnet-4-5-20250929";
523
- }
524
- // Complex → honor requested model
525
- return requestedModel;
834
+ // If user explicitly picked a model, respect it
835
+ if (forceModel) return requestedModel;
836
+
837
+ // Estimate token count (rough: 1 token ~= 4 chars)
838
+ const estimatedTokens = Math.ceil(message.length / 4);
839
+
840
+ // Simple queries → Haiku (30x cheaper than Opus)
841
+ const simplePatterns = /^(what|who|when|where|show|list|get|find|look ?up|check)\b/i;
842
+ const complexPatterns = /\b(analyze|implement|refactor|design|architect|debug|explain why|compare|evaluate|write|create|build|fix)\b/i;
843
+ if (estimatedTokens < 50 && simplePatterns.test(message) && !complexPatterns.test(message)) {
844
+ return "claude-haiku-4-5-20251001";
845
+ }
846
+
847
+ // Medium queries → Sonnet
848
+ if (estimatedTokens < 200 && !complexPatterns.test(message)) {
849
+ return "claude-sonnet-4-5-20250929";
850
+ }
851
+
852
+ // Complex → honor requested model
853
+ return requestedModel;
526
854
  }
855
+
856
+ // ============================================================================
857
+ // ERROR CATEGORIZATION
858
+ // ============================================================================
859
+
527
860
  export function categorizeError(err) {
528
- const e = err;
529
- const status = e?.status || e?.statusCode;
530
- const msg = String(e?.message || "").toLowerCase();
531
- if (status === 429 || msg.includes("rate limit")) {
532
- return { category: "RATE_LIMIT", retryable: true };
533
- }
534
- if (status === 401 || status === 403 || msg.includes("unauthorized") || msg.includes("forbidden") || msg.includes("invalid api key")) {
535
- return { category: "AUTH", retryable: false };
536
- }
537
- if (status === 400 || msg.includes("malformed") || msg.includes("invalid") || msg.includes("validation")) {
538
- return { category: "MALFORMED", retryable: false };
539
- }
540
- if (status === 500 || status === 502 || status === 503 || status === 529 || msg.includes("overloaded") || msg.includes("internal server error")) {
541
- return { category: "PROVIDER_DOWN", retryable: true };
542
- }
543
- if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("deadline") || msg.includes("econnreset")) {
544
- return { category: "TIMEOUT", retryable: true };
545
- }
546
- if (msg.includes("econnrefused") || msg.includes("enetunreach") || msg.includes("enotfound") || msg.includes("fetch failed") || msg.includes("network")) {
547
- return { category: "NETWORK", retryable: true };
548
- }
549
- return { category: "UNKNOWN", retryable: false };
861
+ const e = err;
862
+ const status = e?.status || e?.statusCode;
863
+ const msg = String(e?.message || "").toLowerCase();
864
+ if (status === 429 || msg.includes("rate limit")) {
865
+ return {
866
+ category: "RATE_LIMIT",
867
+ retryable: true
868
+ };
869
+ }
870
+ if (status === 401 || status === 403 || msg.includes("unauthorized") || msg.includes("forbidden") || msg.includes("invalid api key")) {
871
+ return {
872
+ category: "AUTH",
873
+ retryable: false
874
+ };
875
+ }
876
+ if (status === 400 || msg.includes("malformed") || msg.includes("invalid") || msg.includes("validation")) {
877
+ return {
878
+ category: "MALFORMED",
879
+ retryable: false
880
+ };
881
+ }
882
+ if (status === 500 || status === 502 || status === 503 || status === 529 || msg.includes("overloaded") || msg.includes("internal server error")) {
883
+ return {
884
+ category: "PROVIDER_DOWN",
885
+ retryable: true
886
+ };
887
+ }
888
+ if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("deadline") || msg.includes("econnreset") || msg.includes("stream stalled")) {
889
+ return {
890
+ category: "TIMEOUT",
891
+ retryable: true
892
+ };
893
+ }
894
+ if (msg.includes("econnrefused") || msg.includes("enetunreach") || msg.includes("enotfound") || msg.includes("fetch failed") || msg.includes("network")) {
895
+ return {
896
+ category: "NETWORK",
897
+ retryable: true
898
+ };
899
+ }
900
+ return {
901
+ category: "UNKNOWN",
902
+ retryable: false
903
+ };
550
904
  }
905
+
551
906
  // ============================================================================
552
907
  // RETRY LOGIC
553
908
  // ============================================================================
909
+
554
910
  export function isRetryableError(err) {
555
- return categorizeError(err).retryable;
911
+ return categorizeError(err).retryable;
556
912
  }
913
+
557
914
  // ============================================================================
558
- // TOOL RESULT TRUNCATION (deprecated Anthropic context_management handles limits)
559
- // ============================================================================
560
- // UTILITY — sanitize errors (strip API keys, passwords)
915
+ // UTILITYmodel demotion, sanitize errors
561
916
  // ============================================================================
917
+
562
918
  /**
563
919
  * Demote subagent model requests — single source of truth for server + CLI.
564
920
  * - explore/research: always haiku
@@ -566,35 +922,101 @@ export function isRetryableError(err) {
566
922
  * - sonnet: kept for plan, demoted to haiku for others
567
923
  * - default/undefined: haiku
568
924
  */
925
+ /**
926
+ * Resolve subagent model based on agent type and request.
927
+ *
928
+ * Claude Code behavior: general-purpose and plan subagents inherit the parent
929
+ * model (they do real work / need full reasoning). Only explore and research
930
+ * are demoted to haiku (fast, focused tasks).
931
+ */
569
932
  export function demoteSubagentModel(requested, agentType) {
570
- if (agentType === "explore" || agentType === "research")
571
- return "haiku";
572
- if (!requested)
573
- return "haiku";
574
- if (requested === "opus")
575
- return "sonnet";
576
- if (requested === "sonnet")
577
- return agentType === "plan" ? "sonnet" : "haiku";
578
- return "haiku";
933
+ // Fast, focused agent types always use haiku regardless of request
934
+ if (agentType === "explore" || agentType === "research") return "haiku";
935
+
936
+ // General-purpose and plan inherit the requested model (Claude Code parity)
937
+ if (agentType === "general-purpose" || agentType === "plan") {
938
+ if (requested === "opus") return "opus";
939
+ if (requested === "sonnet") return "sonnet";
940
+ return "sonnet"; // default to sonnet if no model specified
941
+ }
942
+
943
+ // Unknown/custom agent types — default to haiku for safety
944
+ if (!requested) return "haiku";
945
+ return requested === "opus" ? "sonnet" : requested === "sonnet" ? "sonnet" : "haiku";
579
946
  }
580
- /** Documented defaults — replaces scattered magic numbers across call paths */
947
+
948
+ // ============================================================================
949
+ // AGENT LOOP CONFIG RESOLVER — single source of truth for all call paths
950
+ // ============================================================================
951
+
952
+ /**
953
+ * EMERGENCY FALLBACK DEFAULTS — used ONLY when ai_agent_config DB is unreachable.
954
+ *
955
+ * The SINGLE SOURCE OF TRUTH is the ai_agent_config table (Supabase), specifically
956
+ * the row for Whale Code (id: 72d7aaa8-2e8b-48a0-a38d-f332f69600bb).
957
+ * All behavioral knobs are stored in `context_config` JSONB.
958
+ *
959
+ * These values MUST mirror what's in the DB. If you change a value, update the DB
960
+ * first (via Supabase dashboard or migration), then mirror it here.
961
+ *
962
+ * DB → resolveAgentLoopConfig() → code reads resolved values.
963
+ * AGENT_DEFAULTS → code reads ONLY if DB fetch returns null.
964
+ */
581
965
  export const AGENT_DEFAULTS = {
582
- maxTurns: 10,
583
- temperature: 0.7,
584
- maxConcurrentTools: 7,
585
- enableDelegation: true,
586
- maxDurationMs: 900_000, // 15 minutes (SSE default)
587
- maxDurationMsWorkflow: 120_000, // 2 minutes (workflow/channel)
588
- enableModelRouting: true,
589
- subagentMaxTokens: 8192,
590
- subagentMaxTurns: 6,
591
- subagentTemperature: 0.3,
592
- maxMessageChars: 100_000,
593
- maxHistoryChars: 400_000,
594
- compactionTriggerTokens: 150_000,
595
- compactionTotalBudget: 2_000_000,
596
- sessionCostBudgetUsd: 5.00,
966
+ // Mirrors ai_agent_config.max_tool_calls / temperature
967
+ maxTurns: 0,
968
+ // 0 = no limit (agent self-regulates via end_turn, Claude Code parity)
969
+ temperature: 1.0,
970
+ // Mirrors ai_agent_config.context_config JSONB fields
971
+ maxConcurrentTools: 7,
972
+ enableDelegation: true,
973
+ maxDurationMs: 900_000,
974
+ maxDurationMsWorkflow: 120_000,
975
+ enableModelRouting: true,
976
+ subagentMaxTokens: 32000,
977
+ subagentMaxTurns: 0,
978
+ // 0 = no limit (agent self-regulates via end_turn, Claude Code parity)
979
+ subagentTemperature: 1.0,
980
+ subagentMaxRetries: 2,
981
+ // 1 retry (2 total attempts) — proxy already handles auth refresh, avoid double backoff
982
+ maxContinuations: 10,
983
+ subagentMaxContinuations: 5,
984
+ maxMessageChars: 100_000,
985
+ maxHistoryChars: 400_000,
986
+ maxToolResultChars: 2048,
987
+ compactionTriggerTokens: 167_000,
988
+ compactionTotalBudget: 2_000_000,
989
+ sessionCostBudgetUsd: 25.00,
990
+ // Team / teammate behavioral defaults
991
+ teammateMaxTotalTurns: 0,
992
+ // 0 = no limit (teammate self-regulates, Claude Code parity)
993
+ teamTimeoutMs: 600_000,
994
+ // 10 min global safety cap — prevents runaway team runs (DB overridable)
995
+ workerStallMs: 90_000,
996
+ // 90s no-message stall detection (API timeout is 90s, so 90s silence = truly stalled)
997
+ teamReviewMaxTokens: 1024,
998
+ // Max tokens for team review synthesis
999
+ // Infrastructure timeouts for teammates (DB overridable, not hardcoded)
1000
+ apiTimeoutMs: 90_000,
1001
+ // 90s timeout on proxy/API fetch calls
1002
+ toolTimeoutMs: 60_000,
1003
+ // 60s timeout on individual tool execution
1004
+ // Per-tool-result truncation cap (different from maxToolResultChars which is for preCompact)
1005
+ toolResultTruncateChars: 30_000,
1006
+ // Match SAFETY_MAX_CHARS from tool-dispatch.ts — 500K was blowing context windows
1007
+ // Loop detector thresholds (DB overridable via context_config)
1008
+ loopIdenticalCallLimit: 4,
1009
+ loopConsecutiveErrorLimit: 3,
1010
+ loopTurnErrorLimit: 5,
1011
+ loopWindow: 20,
1012
+ loopSessionToolErrorLimit: 10,
1013
+ loopConsecutiveFailedTurnLimit: 3,
1014
+ loopFileReadLimit: 3,
1015
+ loopBatchErrorLimit: 3 // Max errors from single parallel batch before abort
597
1016
  };
1017
+
1018
+ /** Context config shape from ai_agent_config.context_config JSONB */
1019
+
598
1020
  /**
599
1021
  * Resolve all agent loop behavioral knobs from DB config.
600
1022
  * All 3 call paths MUST use this — structurally prevents hardcoded constants.
@@ -604,67 +1026,79 @@ export const AGENT_DEFAULTS = {
604
1026
  * @param workflowMaxTurns - Optional cap from workflow step config (workflow path only)
605
1027
  */
606
1028
  export function resolveAgentLoopConfig(agent, callPath, workflowMaxTurns) {
607
- const cc = agent.context_config;
608
- const defaultsUsed = [];
609
- function resolve(dbValue, defaultValue, name) {
610
- if (dbValue != null)
611
- return dbValue;
612
- defaultsUsed.push(name);
613
- return defaultValue;
614
- }
615
- // Core agent behavior
616
- const agentMaxTurns = agent.max_tool_calls || AGENT_DEFAULTS.maxTurns;
617
- if (!agent.max_tool_calls)
618
- defaultsUsed.push("maxTurns");
619
- const temperature = agent.temperature ?? AGENT_DEFAULTS.temperature;
620
- if (agent.temperature == null)
621
- defaultsUsed.push("temperature");
622
- const maxTokens = getMaxOutputTokens(agent.model || "claude-sonnet-4-6", agent.max_tokens);
623
- if (!agent.max_tokens)
624
- defaultsUsed.push("maxTokens");
625
- // Call-path-specific duration defaults
626
- const durationDefault = callPath === "sse"
627
- ? AGENT_DEFAULTS.maxDurationMs
628
- : AGENT_DEFAULTS.maxDurationMsWorkflow;
629
- // Call-path-specific turn caps
630
- let maxTurns = agentMaxTurns;
631
- if (callPath === "channel")
632
- maxTurns = Math.min(agentMaxTurns, 15);
1029
+ const cc = agent.context_config;
1030
+ const defaultsUsed = [];
1031
+ function resolve(dbValue, defaultValue, name) {
1032
+ if (dbValue != null) return dbValue;
1033
+ defaultsUsed.push(name);
1034
+ return defaultValue;
1035
+ }
1036
+
1037
+ // Core agent behavior
1038
+ const agentMaxTurns = agent.max_tool_calls || AGENT_DEFAULTS.maxTurns;
1039
+ if (!agent.max_tool_calls) defaultsUsed.push("maxTurns");
1040
+ const temperature = agent.temperature ?? AGENT_DEFAULTS.temperature;
1041
+ if (agent.temperature == null) defaultsUsed.push("temperature");
1042
+ const maxTokens = getMaxOutputTokens(agent.model || "claude-sonnet-4-6", agent.max_tokens);
1043
+ if (!agent.max_tokens) defaultsUsed.push("maxTokens");
1044
+
1045
+ // Call-path-specific duration defaults
1046
+ const durationDefault = callPath === "sse" ? AGENT_DEFAULTS.maxDurationMs : AGENT_DEFAULTS.maxDurationMsWorkflow;
1047
+
1048
+ // Call-path-specific turn caps (0 = no limit, Claude Code parity)
1049
+ let maxTurns = agentMaxTurns;
1050
+ if (maxTurns > 0) {
1051
+ if (callPath === "channel") maxTurns = Math.min(agentMaxTurns, 15);
633
1052
  if (callPath === "workflow" && workflowMaxTurns != null) {
634
- maxTurns = Math.min(agentMaxTurns, workflowMaxTurns);
1053
+ maxTurns = Math.min(agentMaxTurns, workflowMaxTurns);
635
1054
  }
636
- return {
637
- maxTurns,
638
- temperature,
639
- maxTokens,
640
- maxConcurrentTools: resolve(cc?.max_concurrent_tools, AGENT_DEFAULTS.maxConcurrentTools, "maxConcurrentTools"),
641
- enableDelegation: resolve(cc?.enable_delegation, AGENT_DEFAULTS.enableDelegation, "enableDelegation"),
642
- maxDurationMs: resolve(cc?.max_duration_ms, durationDefault, "maxDurationMs"),
643
- enableModelRouting: resolve(cc?.enable_model_routing, AGENT_DEFAULTS.enableModelRouting, "enableModelRouting"),
644
- maxMessageChars: resolve(cc?.max_message_chars, AGENT_DEFAULTS.maxMessageChars, "maxMessageChars"),
645
- maxHistoryChars: resolve(cc?.max_history_chars, AGENT_DEFAULTS.maxHistoryChars, "maxHistoryChars"),
646
- contextOverrides: {
647
- compaction_trigger_tokens: cc?.compaction_trigger_tokens ?? undefined,
648
- compaction_total_budget: cc?.compaction_total_budget ?? undefined,
649
- clear_thinking_keep: cc?.clear_thinking_keep ?? undefined,
650
- clear_tool_uses_trigger: cc?.clear_tool_uses_trigger ?? undefined,
651
- clear_tool_uses_keep: cc?.clear_tool_uses_keep ?? undefined,
652
- session_cost_budget_usd: cc?.session_cost_budget_usd ?? undefined,
653
- },
654
- subagentMaxTokens: resolve(cc?.subagent_max_tokens, AGENT_DEFAULTS.subagentMaxTokens, "subagentMaxTokens"),
655
- subagentMaxTurns: resolve(cc?.subagent_max_turns, AGENT_DEFAULTS.subagentMaxTurns, "subagentMaxTurns"),
656
- subagentTemperature: resolve(cc?.subagent_temperature, AGENT_DEFAULTS.subagentTemperature, "subagentTemperature"),
657
- defaultsUsed,
658
- };
1055
+ }
1056
+ return {
1057
+ maxTurns,
1058
+ temperature,
1059
+ maxTokens,
1060
+ maxConcurrentTools: resolve(cc?.max_concurrent_tools, AGENT_DEFAULTS.maxConcurrentTools, "maxConcurrentTools"),
1061
+ enableDelegation: resolve(cc?.enable_delegation, AGENT_DEFAULTS.enableDelegation, "enableDelegation"),
1062
+ maxDurationMs: resolve(cc?.max_duration_ms, durationDefault, "maxDurationMs"),
1063
+ enableModelRouting: resolve(cc?.enable_model_routing, AGENT_DEFAULTS.enableModelRouting, "enableModelRouting"),
1064
+ maxMessageChars: resolve(cc?.max_message_chars, AGENT_DEFAULTS.maxMessageChars, "maxMessageChars"),
1065
+ maxHistoryChars: resolve(cc?.max_history_chars, AGENT_DEFAULTS.maxHistoryChars, "maxHistoryChars"),
1066
+ contextOverrides: {
1067
+ compaction_trigger_tokens: cc?.compaction_trigger_tokens ?? undefined,
1068
+ compaction_total_budget: cc?.compaction_total_budget ?? undefined,
1069
+ clear_thinking_keep: cc?.clear_thinking_keep ?? undefined,
1070
+ clear_tool_uses_trigger: cc?.clear_tool_uses_trigger ?? undefined,
1071
+ clear_tool_uses_keep: cc?.clear_tool_uses_keep ?? undefined,
1072
+ session_cost_budget_usd: cc?.session_cost_budget_usd ?? undefined
1073
+ },
1074
+ subagentMaxTokens: resolve(cc?.subagent_max_tokens, AGENT_DEFAULTS.subagentMaxTokens, "subagentMaxTokens"),
1075
+ subagentMaxTurns: resolve(cc?.subagent_max_turns, AGENT_DEFAULTS.subagentMaxTurns, "subagentMaxTurns"),
1076
+ subagentTemperature: resolve(cc?.subagent_temperature, AGENT_DEFAULTS.subagentTemperature, "subagentTemperature"),
1077
+ maxContinuations: resolve(cc?.max_continuations, AGENT_DEFAULTS.maxContinuations, "maxContinuations"),
1078
+ subagentMaxContinuations: resolve(cc?.subagent_max_continuations, AGENT_DEFAULTS.subagentMaxContinuations, "subagentMaxContinuations"),
1079
+ subagentMaxRetries: resolve(cc?.subagent_max_retries, AGENT_DEFAULTS.subagentMaxRetries, "subagentMaxRetries"),
1080
+ maxToolResultChars: resolve(cc?.max_tool_result_chars, AGENT_DEFAULTS.maxToolResultChars, "maxToolResultChars"),
1081
+ teammateMaxTotalTurns: resolve(cc?.teammate_max_total_turns, AGENT_DEFAULTS.teammateMaxTotalTurns, "teammateMaxTotalTurns"),
1082
+ teamTimeoutMs: resolve(cc?.team_timeout_ms, AGENT_DEFAULTS.teamTimeoutMs, "teamTimeoutMs"),
1083
+ workerStallMs: resolve(cc?.worker_stall_ms, AGENT_DEFAULTS.workerStallMs, "workerStallMs"),
1084
+ teamReviewMaxTokens: resolve(cc?.team_review_max_tokens, AGENT_DEFAULTS.teamReviewMaxTokens, "teamReviewMaxTokens"),
1085
+ apiTimeoutMs: resolve(cc?.api_timeout_ms, AGENT_DEFAULTS.apiTimeoutMs, "apiTimeoutMs"),
1086
+ toolTimeoutMs: resolve(cc?.tool_timeout_ms, AGENT_DEFAULTS.toolTimeoutMs, "toolTimeoutMs"),
1087
+ toolResultTruncateChars: resolve(cc?.tool_result_truncate_chars, AGENT_DEFAULTS.toolResultTruncateChars, "toolResultTruncateChars"),
1088
+ // Loop detector thresholds
1089
+ loopIdenticalCallLimit: resolve(cc?.loop_identical_call_limit, AGENT_DEFAULTS.loopIdenticalCallLimit, "loopIdenticalCallLimit"),
1090
+ loopConsecutiveErrorLimit: resolve(cc?.loop_consecutive_error_limit, AGENT_DEFAULTS.loopConsecutiveErrorLimit, "loopConsecutiveErrorLimit"),
1091
+ loopTurnErrorLimit: resolve(cc?.loop_turn_error_limit, AGENT_DEFAULTS.loopTurnErrorLimit, "loopTurnErrorLimit"),
1092
+ loopWindow: resolve(cc?.loop_window, AGENT_DEFAULTS.loopWindow, "loopWindow"),
1093
+ loopSessionToolErrorLimit: resolve(cc?.loop_session_tool_error_limit, AGENT_DEFAULTS.loopSessionToolErrorLimit, "loopSessionToolErrorLimit"),
1094
+ loopConsecutiveFailedTurnLimit: resolve(cc?.loop_consecutive_failed_turn_limit, AGENT_DEFAULTS.loopConsecutiveFailedTurnLimit, "loopConsecutiveFailedTurnLimit"),
1095
+ loopFileReadLimit: resolve(cc?.loop_file_read_limit, AGENT_DEFAULTS.loopFileReadLimit, "loopFileReadLimit"),
1096
+ loopBatchErrorLimit: resolve(cc?.loop_batch_error_limit, AGENT_DEFAULTS.loopBatchErrorLimit, "loopBatchErrorLimit"),
1097
+ defaultsUsed
1098
+ };
659
1099
  }
660
1100
  export function sanitizeError(err) {
661
- const msg = String(err);
662
- return msg
663
- .replace(/sk-[a-zA-Z0-9_-]+/g, "sk-***")
664
- .replace(/AIzaSy[a-zA-Z0-9_-]+/g, "AIzaSy***")
665
- .replace(/AKIA[A-Z0-9]{16}/g, "AKIA***")
666
- .replace(/key[=:]\s*["']?[a-zA-Z0-9_-]{20,}["']?/gi, "key=***")
667
- .replace(/password[=:]\s*["']?[^\s"']+["']?/gi, "password=***")
668
- .replace(/\n\s+at\s+.*/g, "")
669
- .substring(0, 500);
1101
+ const msg = String(err);
1102
+ return msg.replace(/sk-[a-zA-Z0-9_-]+/g, "sk-***").replace(/AIzaSy[a-zA-Z0-9_-]+/g, "AIzaSy***").replace(/AKIA[A-Z0-9]{16}/g, "AKIA***").replace(/key[=:]\s*["']?[a-zA-Z0-9_-]{20,}["']?/gi, "key=***").replace(/password[=:]\s*["']?[^\s"']+["']?/gi, "password=***").replace(/\n\s+at\s+.*/g, "").substring(0, 500);
670
1103
  }
1104
+ //# sourceMappingURL=agent-core.js.map