profclaw 2.0.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (519) hide show
  1. package/.env.example +14 -2
  2. package/CHANGELOG.md +52 -0
  3. package/CONTRIBUTING.md +20 -0
  4. package/Dockerfile +39 -23
  5. package/README.md +178 -41
  6. package/config/pricing.yml +26 -2
  7. package/dist/agents/agent-summary.d.ts +44 -0
  8. package/dist/agents/agent-summary.js +176 -0
  9. package/dist/agents/auto-memory.d.ts +59 -0
  10. package/dist/agents/auto-memory.js +310 -0
  11. package/dist/agents/checkpoint-manager.d.ts +76 -0
  12. package/dist/agents/checkpoint-manager.js +156 -0
  13. package/dist/agents/circuit-breaker.d.ts +54 -0
  14. package/dist/agents/circuit-breaker.js +153 -0
  15. package/dist/agents/command-sandbox.d.ts +93 -0
  16. package/dist/agents/command-sandbox.js +235 -0
  17. package/dist/agents/context-compactor.d.ts +70 -0
  18. package/dist/agents/context-compactor.js +361 -0
  19. package/dist/agents/conversation-branch.d.ts +55 -0
  20. package/dist/agents/conversation-branch.js +115 -0
  21. package/dist/agents/error-recovery.d.ts +44 -0
  22. package/dist/agents/error-recovery.js +197 -0
  23. package/dist/agents/events.d.ts +76 -0
  24. package/dist/agents/events.js +8 -0
  25. package/dist/agents/executor-runner.d.ts +135 -0
  26. package/dist/agents/executor-runner.js +303 -0
  27. package/dist/agents/executor.d.ts +37 -1
  28. package/dist/agents/executor.js +606 -124
  29. package/dist/agents/file-snapshots.d.ts +72 -0
  30. package/dist/agents/file-snapshots.js +182 -0
  31. package/dist/agents/index.d.ts +2 -0
  32. package/dist/agents/orchestrator.d.ts +183 -0
  33. package/dist/agents/orchestrator.js +495 -0
  34. package/dist/agents/output-truncator.d.ts +59 -0
  35. package/dist/agents/output-truncator.js +128 -0
  36. package/dist/agents/permissions.d.ts +63 -0
  37. package/dist/agents/permissions.js +138 -0
  38. package/dist/agents/plan-mode.d.ts +71 -0
  39. package/dist/agents/plan-mode.js +186 -0
  40. package/dist/agents/prompt-suggestions.d.ts +33 -0
  41. package/dist/agents/prompt-suggestions.js +208 -0
  42. package/dist/agents/rate-limit-monitor.d.ts +56 -0
  43. package/dist/agents/rate-limit-monitor.js +224 -0
  44. package/dist/agents/receipt/receipt-cli.d.ts +43 -0
  45. package/dist/agents/receipt/receipt-cli.js +82 -0
  46. package/dist/agents/receipt/receipt-types.d.ts +136 -0
  47. package/dist/agents/receipt/receipt-types.js +19 -0
  48. package/dist/agents/receipt/receipt-verify.d.ts +19 -0
  49. package/dist/agents/receipt/receipt-verify.js +176 -0
  50. package/dist/agents/receipt/receipt-view.d.ts +29 -0
  51. package/dist/agents/receipt/receipt-view.js +227 -0
  52. package/dist/agents/receipt/receipt-writer.d.ts +47 -0
  53. package/dist/agents/receipt/receipt-writer.js +186 -0
  54. package/dist/agents/result-store.d.ts +43 -0
  55. package/dist/agents/result-store.js +145 -0
  56. package/dist/agents/session-diff.d.ts +49 -0
  57. package/dist/agents/session-diff.js +249 -0
  58. package/dist/agents/tool-loader.d.ts +65 -0
  59. package/dist/agents/tool-loader.js +273 -0
  60. package/dist/agents/tool-selector.d.ts +123 -0
  61. package/dist/agents/tool-selector.js +321 -0
  62. package/dist/agents/transcript.d.ts +96 -0
  63. package/dist/agents/transcript.js +267 -0
  64. package/dist/agents/verified-run-git.d.ts +49 -0
  65. package/dist/agents/verified-run-git.js +82 -0
  66. package/dist/agents/verified-run.d.ts +149 -0
  67. package/dist/agents/verified-run.js +402 -0
  68. package/dist/agents/verifier.d.ts +64 -0
  69. package/dist/agents/verifier.js +186 -0
  70. package/dist/agents/worktree-manager.d.ts +80 -0
  71. package/dist/agents/worktree-manager.js +203 -0
  72. package/dist/agents/worktree-tools.d.ts +47 -0
  73. package/dist/agents/worktree-tools.js +246 -0
  74. package/dist/auth/middleware.js +14 -0
  75. package/dist/chat/agentic-executor.d.ts +7 -0
  76. package/dist/chat/agentic-executor.js +263 -32
  77. package/dist/chat/conversations.d.ts +2 -0
  78. package/dist/chat/conversations.js +8 -0
  79. package/dist/chat/execution/executor.d.ts +8 -0
  80. package/dist/chat/execution/executor.js +157 -103
  81. package/dist/chat/execution/index.js +5 -1
  82. package/dist/chat/execution/sandbox.d.ts +8 -0
  83. package/dist/chat/execution/sandbox.js +25 -1
  84. package/dist/chat/execution/tool-router.js +40 -14
  85. package/dist/chat/execution/tools/canvas.d.ts +2 -2
  86. package/dist/chat/execution/tools/code-tools.d.ts +66 -0
  87. package/dist/chat/execution/tools/code-tools.js +353 -0
  88. package/dist/chat/execution/tools/complete-task.d.ts +2 -2
  89. package/dist/chat/execution/tools/cron-tool.d.ts +26 -10
  90. package/dist/chat/execution/tools/cron-tool.js +48 -3
  91. package/dist/chat/execution/tools/decompose-task.d.ts +58 -0
  92. package/dist/chat/execution/tools/decompose-task.js +166 -0
  93. package/dist/chat/execution/tools/exec.d.ts +5 -2
  94. package/dist/chat/execution/tools/exec.js +294 -155
  95. package/dist/chat/execution/tools/feed-tools.d.ts +77 -0
  96. package/dist/chat/execution/tools/feed-tools.js +142 -0
  97. package/dist/chat/execution/tools/file-ops.d.ts +1 -1
  98. package/dist/chat/execution/tools/github.d.ts +2 -2
  99. package/dist/chat/execution/tools/index.d.ts +14 -2
  100. package/dist/chat/execution/tools/index.js +86 -12
  101. package/dist/chat/execution/tools/integrations.d.ts +8 -8
  102. package/dist/chat/execution/tools/multi-patch.d.ts +53 -0
  103. package/dist/chat/execution/tools/multi-patch.js +373 -0
  104. package/dist/chat/execution/tools/openai-image-gen.d.ts +2 -2
  105. package/dist/chat/execution/tools/plan-tools.d.ts +80 -0
  106. package/dist/chat/execution/tools/plan-tools.js +134 -0
  107. package/dist/chat/execution/tools/profclaw-ops.d.ts +6 -6
  108. package/dist/chat/execution/tools/repl-tool.d.ts +46 -0
  109. package/dist/chat/execution/tools/repl-tool.js +207 -0
  110. package/dist/chat/execution/tools/sessions-send.d.ts +2 -2
  111. package/dist/chat/execution/tools/slack-actions.d.ts +2 -2
  112. package/dist/chat/execution/tools/system.d.ts +4 -4
  113. package/dist/chat/execution/tools/todo-tool.d.ts +72 -0
  114. package/dist/chat/execution/tools/todo-tool.js +152 -0
  115. package/dist/chat/execution/tools/tool-search.d.ts +50 -0
  116. package/dist/chat/execution/tools/tool-search.js +155 -0
  117. package/dist/chat/execution/tools/tts-speak.d.ts +2 -2
  118. package/dist/chat/execution/types.d.ts +21 -14
  119. package/dist/chat/execution/workflows/executor.d.ts +11 -0
  120. package/dist/chat/execution/workflows/executor.js +99 -1
  121. package/dist/chat/execution/workflows/types.d.ts +35 -2
  122. package/dist/chat/format/index.d.ts +1 -0
  123. package/dist/chat/format/index.js +1 -0
  124. package/dist/chat/format/markdown-convert.d.ts +23 -0
  125. package/dist/chat/format/markdown-convert.js +149 -0
  126. package/dist/chat/index.d.ts +1 -1
  127. package/dist/chat/index.js +1 -1
  128. package/dist/chat/message-handler.js +58 -6
  129. package/dist/chat/meta-tool-handlers.d.ts +18 -0
  130. package/dist/chat/meta-tool-handlers.js +51 -0
  131. package/dist/chat/proactive/index.d.ts +62 -0
  132. package/dist/chat/proactive/index.js +147 -0
  133. package/dist/chat/prompt-adapter.js +2 -0
  134. package/dist/chat/providers/irc/index.d.ts +2 -2
  135. package/dist/chat/providers/telegram/index.d.ts +2 -0
  136. package/dist/chat/providers/telegram/index.js +21 -2
  137. package/dist/chat/system-prompts.d.ts +3 -3
  138. package/dist/chat/system-prompts.js +121 -61
  139. package/dist/chat/tool-handler.d.ts +2 -0
  140. package/dist/chat/tool-handler.js +47 -3
  141. package/dist/chat/tools.d.ts +6 -6
  142. package/dist/cli/commands/auth.js +64 -1
  143. package/dist/cli/commands/chat.js +1327 -138
  144. package/dist/cli/commands/doctor.js +222 -16
  145. package/dist/cli/commands/history.d.ts +3 -0
  146. package/dist/cli/commands/history.js +138 -0
  147. package/dist/cli/commands/import.d.ts +44 -0
  148. package/dist/cli/commands/import.js +526 -0
  149. package/dist/cli/commands/init.d.ts +13 -0
  150. package/dist/cli/commands/init.js +381 -0
  151. package/dist/cli/commands/onboard.js +210 -30
  152. package/dist/cli/commands/plan.d.ts +13 -0
  153. package/dist/cli/commands/plan.js +184 -0
  154. package/dist/cli/commands/receipt.d.ts +7 -0
  155. package/dist/cli/commands/receipt.js +90 -0
  156. package/dist/cli/commands/run.d.ts +28 -0
  157. package/dist/cli/commands/run.js +204 -0
  158. package/dist/cli/commands/serve.d.ts +7 -0
  159. package/dist/cli/commands/serve.js +77 -18
  160. package/dist/cli/commands/setup.js +84 -3
  161. package/dist/cli/commands/status.js +54 -0
  162. package/dist/cli/commands/tools.js +13 -13
  163. package/dist/cli/commands/tui.js +26 -1
  164. package/dist/cli/index.js +23 -0
  165. package/dist/cli/ink/App.d.ts +13 -0
  166. package/dist/cli/ink/App.js +6 -0
  167. package/dist/cli/ink/ChatApp.d.ts +60 -0
  168. package/dist/cli/ink/ChatApp.js +325 -0
  169. package/dist/cli/ink/DashboardApp.d.ts +3 -0
  170. package/dist/cli/ink/DashboardApp.js +143 -0
  171. package/dist/cli/ink/components/AgentStatus.d.ts +17 -0
  172. package/dist/cli/ink/components/AgentStatus.js +33 -0
  173. package/dist/cli/ink/components/ChannelList.d.ts +17 -0
  174. package/dist/cli/ink/components/ChannelList.js +33 -0
  175. package/dist/cli/ink/components/ConnectionStatus.d.ts +19 -0
  176. package/dist/cli/ink/components/ConnectionStatus.js +50 -0
  177. package/dist/cli/ink/components/CostBar.d.ts +19 -0
  178. package/dist/cli/ink/components/CostBar.js +35 -0
  179. package/dist/cli/ink/components/HookStatus.d.ts +15 -0
  180. package/dist/cli/ink/components/HookStatus.js +7 -0
  181. package/dist/cli/ink/components/PermissionPrompt.d.ts +21 -0
  182. package/dist/cli/ink/components/PermissionPrompt.js +51 -0
  183. package/dist/cli/ink/components/PlanView.d.ts +23 -0
  184. package/dist/cli/ink/components/PlanView.js +26 -0
  185. package/dist/cli/ink/components/ProviderList.d.ts +16 -0
  186. package/dist/cli/ink/components/ProviderList.js +16 -0
  187. package/dist/cli/ink/components/SessionHeader.d.ts +15 -0
  188. package/dist/cli/ink/components/SessionHeader.js +15 -0
  189. package/dist/cli/ink/components/StreamingMessage.d.ts +20 -0
  190. package/dist/cli/ink/components/StreamingMessage.js +27 -0
  191. package/dist/cli/ink/components/SuggestionBar.d.ts +15 -0
  192. package/dist/cli/ink/components/SuggestionBar.js +28 -0
  193. package/dist/cli/ink/components/SystemHealth.d.ts +20 -0
  194. package/dist/cli/ink/components/SystemHealth.js +39 -0
  195. package/dist/cli/ink/components/TaskList.d.ts +17 -0
  196. package/dist/cli/ink/components/TaskList.js +59 -0
  197. package/dist/cli/ink/components/ToolCall.d.ts +17 -0
  198. package/dist/cli/ink/components/ToolCall.js +43 -0
  199. package/dist/cli/ink/index.d.ts +23 -0
  200. package/dist/cli/ink/index.js +15 -0
  201. package/dist/cli/ink/keybindings.d.ts +35 -0
  202. package/dist/cli/ink/keybindings.js +105 -0
  203. package/dist/cli/ink/markdown-renderer.d.ts +47 -0
  204. package/dist/cli/ink/markdown-renderer.js +380 -0
  205. package/dist/cli/ink/output-styles.d.ts +39 -0
  206. package/dist/cli/ink/output-styles.js +119 -0
  207. package/dist/cli/interactive/auto-serve.d.ts +38 -0
  208. package/dist/cli/interactive/auto-serve.js +209 -0
  209. package/dist/cli/interactive/index.d.ts +25 -0
  210. package/dist/cli/interactive/index.js +23 -0
  211. package/dist/cli/interactive/picker.d.ts +28 -0
  212. package/dist/cli/interactive/picker.js +153 -0
  213. package/dist/cli/interactive/renderer.d.ts +26 -0
  214. package/dist/cli/interactive/renderer.js +555 -0
  215. package/dist/cli/interactive/repl.d.ts +14 -0
  216. package/dist/cli/interactive/repl.js +1516 -0
  217. package/dist/cli/interactive/stream-client.d.ts +59 -0
  218. package/dist/cli/interactive/stream-client.js +506 -0
  219. package/dist/cli/interactive/types.d.ts +121 -0
  220. package/dist/cli/interactive/types.js +10 -0
  221. package/dist/cli/utils/api.d.ts +9 -0
  222. package/dist/cli/utils/api.js +58 -2
  223. package/dist/costs/token-tracker.d.ts +10 -1
  224. package/dist/costs/token-tracker.js +37 -5
  225. package/dist/cron/natural-language.d.ts +54 -0
  226. package/dist/cron/natural-language.js +569 -0
  227. package/dist/cron/scheduler.d.ts +34 -4
  228. package/dist/cron/scheduler.js +141 -9
  229. package/dist/cron/templates.d.ts +1 -1
  230. package/dist/cron/templates.js +219 -0
  231. package/dist/feeds/feed-engine.d.ts +149 -0
  232. package/dist/feeds/feed-engine.js +600 -0
  233. package/dist/feeds/index.d.ts +9 -0
  234. package/dist/feeds/index.js +8 -0
  235. package/dist/gateway/router.js +6 -1
  236. package/dist/hooks/built-in/audit-log.d.ts +11 -0
  237. package/dist/hooks/built-in/audit-log.js +84 -0
  238. package/dist/hooks/built-in/cost-warning.d.ts +10 -0
  239. package/dist/hooks/built-in/cost-warning.js +59 -0
  240. package/dist/hooks/built-in/dangerous-tool.d.ts +32 -0
  241. package/dist/hooks/built-in/dangerous-tool.js +80 -0
  242. package/dist/hooks/built-in/index.d.ts +14 -0
  243. package/dist/hooks/built-in/index.js +20 -0
  244. package/dist/hooks/index.d.ts +3 -0
  245. package/dist/hooks/index.js +6 -0
  246. package/dist/hooks/loader.d.ts +17 -0
  247. package/dist/hooks/loader.js +142 -0
  248. package/dist/hooks/registry.d.ts +62 -0
  249. package/dist/hooks/registry.js +127 -0
  250. package/dist/integrations/web-search.js +6 -3
  251. package/dist/memory/index.d.ts +1 -0
  252. package/dist/memory/index.js +2 -0
  253. package/dist/memory/memory-service.js +14 -13
  254. package/dist/memory/observational.d.ts +62 -0
  255. package/dist/memory/observational.js +396 -0
  256. package/dist/middleware/content-filter.d.ts +22 -0
  257. package/dist/middleware/content-filter.js +69 -0
  258. package/dist/middleware/request-validator.d.ts +159 -0
  259. package/dist/middleware/request-validator.js +93 -0
  260. package/dist/plugins/sdk.d.ts +22 -0
  261. package/dist/plugins/sdk.js +17 -1
  262. package/dist/projects/types.d.ts +10 -10
  263. package/dist/providers/ai-sdk.d.ts +11 -0
  264. package/dist/providers/ai-sdk.js +111 -56
  265. package/dist/providers/core/models.js +114 -6
  266. package/dist/providers/core/types.d.ts +7 -0
  267. package/dist/providers/index.d.ts +1 -0
  268. package/dist/providers/index.js +1 -0
  269. package/dist/providers/prompt-cache.d.ts +68 -0
  270. package/dist/providers/prompt-cache.js +165 -0
  271. package/dist/providers/smart-router.d.ts +118 -0
  272. package/dist/providers/smart-router.js +693 -0
  273. package/dist/providers/types.d.ts +16 -16
  274. package/dist/routes/agents.js +50 -0
  275. package/dist/routes/auth.js +8 -1
  276. package/dist/routes/chat.js +280 -18
  277. package/dist/routes/costs.js +32 -0
  278. package/dist/routes/cron.js +80 -5
  279. package/dist/routes/feeds.d.ts +10 -0
  280. package/dist/routes/feeds.js +168 -0
  281. package/dist/routes/mcp.js +21 -0
  282. package/dist/routes/memory.js +130 -0
  283. package/dist/routes/skills.js +129 -0
  284. package/dist/routes/teams.d.ts +9 -0
  285. package/dist/routes/teams.js +210 -0
  286. package/dist/routes/tools.js +14 -0
  287. package/dist/routes/users.js +2 -0
  288. package/dist/server/route-loader.js +3 -1
  289. package/dist/server/stream-bridge.d.ts +19 -0
  290. package/dist/server/stream-bridge.js +38 -0
  291. package/dist/server.js +313 -36
  292. package/dist/skills/marketplace.d.ts +87 -0
  293. package/dist/skills/marketplace.js +268 -0
  294. package/dist/storage/index.d.ts +14 -0
  295. package/dist/storage/index.js +64 -3
  296. package/dist/storage/schema.d.ts +4 -4
  297. package/dist/storage/schema.js +1 -1
  298. package/dist/teams/index.d.ts +110 -0
  299. package/dist/teams/index.js +365 -0
  300. package/dist/tickets/types.d.ts +39 -39
  301. package/dist/types/summary.d.ts +5 -5
  302. package/dist/utils/auto-update.d.ts +23 -0
  303. package/dist/utils/auto-update.js +157 -0
  304. package/dist/utils/offline-detect.d.ts +55 -0
  305. package/dist/utils/offline-detect.js +121 -0
  306. package/dist/utils/pid-file.d.ts +36 -0
  307. package/dist/utils/pid-file.js +125 -0
  308. package/dist/utils/prevent-sleep.d.ts +27 -0
  309. package/dist/utils/prevent-sleep.js +95 -0
  310. package/dist/utils/sanitizer.d.ts +57 -0
  311. package/dist/utils/sanitizer.js +174 -0
  312. package/docker-compose.yml +13 -137
  313. package/package.json +31 -6
  314. package/skills/deploy-cloudflare/SKILL.md +62 -0
  315. package/skills/deploy-vercel/SKILL.md +67 -0
  316. package/skills/docker-deploy/SKILL.md +158 -0
  317. package/skills/full-stack-builder/SKILL.md +92 -0
  318. package/skills/humanizer/SKILL.md +488 -0
  319. package/skills/profclaw-assistant/SKILL.md +85 -56
  320. package/ui/dist/assets/ActivityView-Da6HQ8ws.js +1 -0
  321. package/ui/dist/assets/AgentList-H58R0kX3.js +1 -0
  322. package/ui/dist/assets/AnalyticsDashboard-B28AeRsc.js +1 -0
  323. package/ui/dist/assets/AreaChart-DwLzeAQ8.js +1 -0
  324. package/ui/dist/assets/CartesianChart-piKQsTAR.js +36 -0
  325. package/ui/dist/assets/ChatView-Dbj8rxU5.js +10 -0
  326. package/ui/dist/assets/CostsDashboard-C6F5df0F.js +1 -0
  327. package/ui/dist/assets/EstimateSelect-wga0rUKX.js +1 -0
  328. package/ui/dist/assets/FeedDashboard-Ef6FEzEf.js +1 -0
  329. package/ui/dist/assets/FloatingChatbot-0yhkUeCq.js +2 -0
  330. package/ui/dist/assets/InviteCodeManagement-tUXfx4Bc.js +2 -0
  331. package/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  332. package/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  333. package/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  334. package/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  335. package/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  336. package/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  337. package/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  338. package/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  339. package/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  340. package/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  341. package/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  342. package/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  343. package/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  344. package/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  345. package/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  346. package/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  347. package/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  348. package/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  349. package/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  350. package/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  351. package/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  352. package/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  353. package/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  354. package/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  355. package/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  356. package/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  357. package/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  358. package/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  359. package/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  360. package/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  361. package/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  362. package/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  363. package/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  364. package/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  365. package/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  366. package/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  367. package/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  368. package/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  369. package/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  370. package/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  371. package/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  372. package/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  373. package/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  374. package/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  375. package/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  376. package/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  377. package/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  378. package/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  379. package/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  380. package/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  381. package/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  382. package/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  383. package/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  384. package/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  385. package/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  386. package/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  387. package/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  388. package/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  389. package/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  390. package/ui/dist/assets/MarketplacePage-DGrLtolR.js +1 -0
  391. package/ui/dist/assets/{ProjectDetail--gPfvATB.js → ProjectDetail-BgWvA6UP.js} +2 -2
  392. package/ui/dist/assets/ProjectIcon-TDuliqwg.js +1 -0
  393. package/ui/dist/assets/ProjectList-DXgM4187.js +1 -0
  394. package/ui/dist/assets/{Settings-1kaf7VHE.js → Settings-xA8Zhi3p.js} +3 -3
  395. package/ui/dist/assets/StatusIndicator-B8vfFAxg.js +1 -0
  396. package/ui/dist/assets/{SummaryDetail-DV3AmONk.js → SummaryDetail-eedRfTtF.js} +2 -2
  397. package/ui/dist/assets/SummaryList-CLNX2P84.js +1 -0
  398. package/ui/dist/assets/TaskDetail-BtWclNiR.js +1 -0
  399. package/ui/dist/assets/TaskList-JjODAgSc.js +1 -0
  400. package/ui/dist/assets/TeamsPage-CBK5iAyx.js +1 -0
  401. package/ui/dist/assets/TicketBoard-C9aJNNYp.js +1 -0
  402. package/ui/dist/assets/TicketDetail-CV5JmL31.js +1 -0
  403. package/ui/dist/assets/TicketList-68V4lzUz.js +1 -0
  404. package/ui/dist/assets/UserManagement-DKTb6UpE.js +2 -0
  405. package/ui/dist/assets/ViewSwitcher-BvdQht2Y.js +1 -0
  406. package/ui/dist/assets/alert-dialog-O6qBOv_f.js +1 -0
  407. package/ui/dist/assets/{archive-BsLa7brF.js → archive-CX7UvZpf.js} +1 -1
  408. package/ui/dist/assets/badge-BbfnwDJP.js +1 -0
  409. package/ui/dist/assets/{bug-CmZI7jqM.js → bug-3WX0394-.js} +1 -1
  410. package/ui/dist/assets/{calendar-Bf0t2B82.js → calendar-buq77TaS.js} +1 -1
  411. package/ui/dist/assets/{chevron-up-CoUsOvZj.js → chevron-up-4ymsBJRo.js} +1 -1
  412. package/ui/dist/assets/{circle-x-Dgw11LgT.js → circle-x-ByXtwR6Y.js} +1 -1
  413. package/ui/dist/assets/constants-CVdDh7p0.js +1 -0
  414. package/ui/dist/assets/{cpu-DiPMQICV.js → cpu-CiuoCeDY.js} +1 -1
  415. package/ui/dist/assets/{database-BwTfupDi.js → database-BWXSBg5a.js} +1 -1
  416. package/ui/dist/assets/dialog-lDg4NvMV.js +1 -0
  417. package/ui/dist/assets/dollar-sign-Dmijd6DP.js +1 -0
  418. package/ui/dist/assets/{ellipsis-UJx4Xnf6.js → ellipsis-vT-5SVIp.js} +1 -1
  419. package/ui/dist/assets/{ellipsis-vertical-DoULYEKn.js → ellipsis-vertical-B4tAX_bL.js} +1 -1
  420. package/ui/dist/assets/feature-markdown-DBo5Q7uq.js +289 -0
  421. package/ui/dist/assets/{file-code-B2UrJLwi.js → file-code-ChOWdKXf.js} +1 -1
  422. package/ui/dist/assets/{folder-open-BJi577JH.js → folder-open-CkOUbIiP.js} +1 -1
  423. package/ui/dist/assets/{funnel-PkaD_HSR.js → funnel-uZkoSPP-.js} +1 -1
  424. package/ui/dist/assets/{git-branch-C_K30am0.js → git-branch-CwvUxj7C.js} +1 -1
  425. package/ui/dist/assets/{git-commit-horizontal-IT6ecxWQ.js → git-commit-horizontal-lxPzCvhD.js} +1 -1
  426. package/ui/dist/assets/{globe-f-jjCa_g.js → globe-D_WpJdsj.js} +1 -1
  427. package/ui/dist/assets/{hash-DNEv8Elo.js → hash-CA0hJ7vh.js} +1 -1
  428. package/ui/dist/assets/{history-BQSBo_1Q.js → history-CEWMLELs.js} +1 -1
  429. package/ui/dist/assets/inbox-ehtOptTV.js +1 -0
  430. package/ui/dist/assets/{index-nS3EErDg.js → index-C1rhbml4.js} +3 -3
  431. package/ui/dist/assets/index-CR8gfCHv.js +1 -0
  432. package/ui/dist/assets/index-DVXMpWai.js +1 -0
  433. package/ui/dist/assets/index-DaDJMM2v.js +1 -0
  434. package/ui/dist/assets/index-Djdq_0xu.js +1 -0
  435. package/ui/dist/assets/index-M46Gcb8K.css +1 -0
  436. package/ui/dist/assets/index-sEBN7w8J.js +109 -0
  437. package/ui/dist/assets/layers-C6Mhf8Nk.js +1 -0
  438. package/ui/dist/assets/{layout-dashboard-CcKt1hXw.js → layout-dashboard-BRUM0kpT.js} +1 -1
  439. package/ui/dist/assets/{lightbulb-Jhp7FvbU.js → lightbulb-CN2q1O5l.js} +1 -1
  440. package/ui/dist/assets/{link-2-DdO7ostF.js → link-2-CC4E28yJ.js} +1 -1
  441. package/ui/dist/assets/markdown-renderer-C6ENbB0u.js +10 -0
  442. package/ui/dist/assets/markdown-renderer-CfVKi3_s.css +1 -0
  443. package/ui/dist/assets/{message-square-CBgH65X7.js → message-square-Bbb241am.js} +1 -1
  444. package/ui/dist/assets/package-CwT3IzFx.js +1 -0
  445. package/ui/dist/assets/{pencil-CYXCEPQh.js → pencil-CDmiHzoj.js} +1 -1
  446. package/ui/dist/assets/{play-d1ONaH0-.js → play-tjy5jMQX.js} +1 -1
  447. package/ui/dist/assets/popover-CFHZf3pE.js +1 -0
  448. package/ui/dist/assets/progress-BboUHuLf.js +1 -0
  449. package/ui/dist/assets/{rocket-DhvUetsk.js → rocket--8ZHgdXJ.js} +1 -1
  450. package/ui/dist/assets/select-n108rXny.js +1 -0
  451. package/ui/dist/assets/{send-P0r5D7td.js → send-Cu7MR2Qh.js} +1 -1
  452. package/ui/dist/assets/server-DmodxZp-.js +1 -0
  453. package/ui/dist/assets/{settings-2-ocj5uHGx.js → settings-2-CkRNqkxj.js} +1 -1
  454. package/ui/dist/assets/sheet-7aUJkyzU.js +1 -0
  455. package/ui/dist/assets/{shield-check-DfVdE34l.js → shield-check-ViI3nMKE.js} +1 -1
  456. package/ui/dist/assets/{shield-off-8l0J6R-8.js → shield-off-DN3tagkn.js} +1 -1
  457. package/ui/dist/assets/skeleton-C0E1Nfro.js +1 -0
  458. package/ui/dist/assets/{smartphone-77_g3SQn.js → smartphone-5FghiXpA.js} +1 -1
  459. package/ui/dist/assets/{square-Ckzsr3Rn.js → square-DiNSx8K7.js} +1 -1
  460. package/ui/dist/assets/star-DhdFVidS.js +1 -0
  461. package/ui/dist/assets/switch-CIgVbZqQ.js +1 -0
  462. package/ui/dist/assets/table-BC56FVMV.js +1 -0
  463. package/ui/dist/assets/{tag-C35mgoEv.js → tag-CH_vQliw.js} +1 -1
  464. package/ui/dist/assets/textarea-CxDiKFXZ.js +1 -0
  465. package/ui/dist/assets/{timer-DHJBS2w1.js → timer-CdGVTb60.js} +1 -1
  466. package/ui/dist/assets/tooltip-BuW9A5UO.js +1 -0
  467. package/ui/dist/assets/{trash-2-keO5tKPE.js → trash-2-CucZJL0N.js} +1 -1
  468. package/ui/dist/assets/trending-down-BCezC1z2.js +1 -0
  469. package/ui/dist/assets/{trending-up-BBv8KbrY.js → trending-up-C5OYX2k2.js} +1 -1
  470. package/ui/dist/assets/vendor-query-C0p7b53x.js +4 -0
  471. package/ui/dist/assets/vendor-react-Mc5_kfYG.js +12 -0
  472. package/ui/dist/assets/vendor-ui-CXPAUBFv.js +51 -0
  473. package/ui/dist/assets/{wand-sparkles-BusQ52ZK.js → wand-sparkles-BaH6pJnc.js} +1 -1
  474. package/ui/dist/assets/{wrench-02YaOSiK.js → wrench-CjxjP6ok.js} +1 -1
  475. package/ui/dist/index.html +5 -2
  476. package/ui/dist/assets/ActivityView-BeshZXmE.js +0 -1
  477. package/ui/dist/assets/AgentList-QVHeldPi.js +0 -1
  478. package/ui/dist/assets/AnalyticsDashboard-C9R97dXE.js +0 -1
  479. package/ui/dist/assets/AreaChart-B73gaiVQ.js +0 -1
  480. package/ui/dist/assets/CartesianChart-CXYL2R-A.js +0 -36
  481. package/ui/dist/assets/ChatView-qjZErlrp.js +0 -10
  482. package/ui/dist/assets/CostsDashboard-O4DCLy1i.js +0 -1
  483. package/ui/dist/assets/EstimateSelect-1hQf4Osk.js +0 -1
  484. package/ui/dist/assets/FloatingChatbot-BZBzrJxd.js +0 -2
  485. package/ui/dist/assets/InviteCodeManagement-LEoGqYeA.js +0 -2
  486. package/ui/dist/assets/ProjectIcon-Chd_ofsw.js +0 -1
  487. package/ui/dist/assets/ProjectList-BvUfVB6c.js +0 -4
  488. package/ui/dist/assets/StatusIndicator-pRfkNcdV.js +0 -1
  489. package/ui/dist/assets/SummaryList-B6kXiTxL.js +0 -1
  490. package/ui/dist/assets/TaskDetail-CV6CzbOS.js +0 -1
  491. package/ui/dist/assets/TaskList-DL7brQKd.js +0 -1
  492. package/ui/dist/assets/TicketBoard-CrkkFj7C.js +0 -1
  493. package/ui/dist/assets/TicketDetail-hnnYclpD.js +0 -1
  494. package/ui/dist/assets/TicketList-CsDAyQCL.js +0 -1
  495. package/ui/dist/assets/UserManagement-BGFQyTSr.js +0 -2
  496. package/ui/dist/assets/ViewSwitcher-CnL0OqA8.js +0 -1
  497. package/ui/dist/assets/alert-dialog-SKM6Gjz4.js +0 -7
  498. package/ui/dist/assets/badge-CVHH1a-v.js +0 -1
  499. package/ui/dist/assets/brain-6o_RHVpe.js +0 -1
  500. package/ui/dist/assets/constants-Q5Zivl-a.js +0 -1
  501. package/ui/dist/assets/dialog-BUqN9Psj.js +0 -1
  502. package/ui/dist/assets/index-BUmnwPQr.js +0 -1
  503. package/ui/dist/assets/index-BfF5G4Cw.js +0 -1
  504. package/ui/dist/assets/index-C8N375c2.js +0 -1
  505. package/ui/dist/assets/index-CuxnqVVz.css +0 -1
  506. package/ui/dist/assets/index-CzMM3QOk.js +0 -1
  507. package/ui/dist/assets/index-lJlNPFVJ.js +0 -67
  508. package/ui/dist/assets/layers-jFqVrWMD.js +0 -1
  509. package/ui/dist/assets/markdown-renderer-n1ToC4XQ.js +0 -36
  510. package/ui/dist/assets/popover-CrmZgoWu.js +0 -1
  511. package/ui/dist/assets/progress-uv4SPkL5.js +0 -1
  512. package/ui/dist/assets/select-CeQ8AHGy.js +0 -1
  513. package/ui/dist/assets/server-CVHTZB72.js +0 -1
  514. package/ui/dist/assets/sheet-DuQExSho.js +0 -1
  515. package/ui/dist/assets/skeleton-TFiFJ3nB.js +0 -1
  516. package/ui/dist/assets/switch-CAePkd6k.js +0 -1
  517. package/ui/dist/assets/table-ZjAZ7hkt.js +0 -1
  518. package/ui/dist/assets/textarea-DsVPnSgR.js +0 -1
  519. package/ui/dist/assets/tooltip-BYmQ331W.js +0 -1
@@ -11,7 +11,16 @@ import { randomUUID } from "node:crypto";
11
11
  import { EventEmitter } from "node:events";
12
12
  import { EFFORT_BUDGET_MAP } from "./types.js";
13
13
  import { defaultStopConditions, taskCompleted } from "./stop-conditions.js";
14
+ import { ToolCircuitBreaker } from "./circuit-breaker.js";
14
15
  import { logger } from "../utils/logger.js";
16
+ import { applyAnthropicMessageCache, applyAnthropicToolCache, extractCacheUsage, } from "../providers/prompt-cache.js";
17
+ import { trackChatUsage } from "../costs/token-tracker.js";
18
+ import { ResultStore } from "./result-store.js";
19
+ import { getAgentSummaryTracker } from "./agent-summary.js";
20
+ import { getHookRegistry } from "../hooks/registry.js";
21
+ import { ContextCompactor } from "./context-compactor.js";
22
+ import { getSleepPreventer } from "../utils/prevent-sleep.js";
23
+ import { getCheckpointManager } from "./checkpoint-manager.js";
15
24
  // Default Configuration
16
25
  const DEFAULT_CONFIG = {
17
26
  maxSteps: 100,
@@ -123,10 +132,21 @@ export class AgentExecutor extends EventEmitter {
123
132
  config;
124
133
  abortController;
125
134
  isRunning = false;
135
+ resultStore;
136
+ circuitBreaker = new ToolCircuitBreaker();
137
+ hooks;
138
+ compactor;
139
+ checkpointManager = getCheckpointManager();
126
140
  constructor(sessionId, conversationId, goal, config = {}) {
127
141
  super();
128
142
  this.abortController = new AbortController();
129
143
  this.config = { ...DEFAULT_CONFIG, ...config };
144
+ this.resultStore = new ResultStore(sessionId);
145
+ this.hooks = getHookRegistry();
146
+ this.compactor = new ContextCompactor({
147
+ maxContextTokens: this.config.maxBudget,
148
+ compactionThreshold: Math.floor(this.config.maxBudget * 0.7),
149
+ });
130
150
  // Ensure taskCompleted is always included in stop conditions
131
151
  if (!this.config.stopConditions.some((c) => c.name === "taskCompleted")) {
132
152
  this.config.stopConditions.push(taskCompleted());
@@ -154,14 +174,20 @@ export class AgentExecutor extends EventEmitter {
154
174
  maxSteps: this.config.maxSteps,
155
175
  maxBudget: this.config.maxBudget,
156
176
  });
177
+ // Register this session with the summary tracker
178
+ getAgentSummaryTracker().start(sessionId);
157
179
  }
158
180
  // Public API
159
181
  /**
160
- * Run the agent until completion or stop condition.
161
- * Uses AI SDK's native multi-step execution — a single generateText call
162
- * with stopWhen + onStepFinish replaces the old manual loop.
182
+ * Async generator that streams agent events as they happen.
183
+ *
184
+ * Yields AgentEvent values in real time: session:start, step:start,
185
+ * tool:call, tool:result/tool:error, content, cost:update, step:complete,
186
+ * and finally session:complete, session:error, or session:abort.
187
+ *
188
+ * This is the canonical implementation; run() delegates here.
163
189
  */
164
- async run(model, messages, tools, onToolExecute, providerHint) {
190
+ async *stream(model, messages, tools, onToolExecute, providerHint) {
165
191
  if (this.isRunning) {
166
192
  throw new Error("Agent is already running");
167
193
  }
@@ -169,140 +195,343 @@ export class AgentExecutor extends EventEmitter {
169
195
  this.state.status = "running";
170
196
  this.state.updatedAt = Date.now();
171
197
  this.emit("start", this.state);
172
- logger.info("[AgentExecutor] Starting agent run", {
198
+ getSleepPreventer().start();
199
+ logger.info("[AgentExecutor] Starting agent stream", {
173
200
  sessionId: this.state.sessionId,
174
201
  goal: this.state.goal,
175
202
  });
176
- try {
177
- // Inject failure hint if applicable (from prior runs / retries)
178
- this.injectFailureHint(messages);
179
- // Wire execute functions into tools so the SDK can auto-execute them
180
- const executableTools = this.wrapToolsWithExecute(tools, onToolExecute);
181
- const hasTools = Object.keys(executableTools).length > 0;
182
- // Build provider-specific options (e.g. Anthropic thinking/effort)
183
- const providerOptions = this.buildProviderOptions(providerHint);
184
- // Single generateText call — the SDK handles multi-step chaining
185
- const result = await generateText({
186
- model,
187
- messages,
188
- tools: hasTools ? executableTools : undefined,
189
- ...(providerOptions ? { providerOptions } : {}),
190
- stopWhen: [
191
- sdkStepCountIs(this.config.maxSteps),
192
- sdkHasToolCall("complete_task"),
193
- ],
194
- abortSignal: this.abortController.signal,
195
- onStepFinish: (step) => {
196
- this.state.currentStep++;
197
- this.state.updatedAt = Date.now();
198
- // Track token budget (AI SDK v6 uses inputTokens/outputTokens)
199
- const stepInput = getUsageInputTokens(step.usage);
200
- const stepOutput = getUsageOutputTokens(step.usage);
201
- const tokensUsed = stepInput + stepOutput;
202
- this.state.usedBudget += tokensUsed;
203
- this.state.inputTokensUsed += stepInput;
204
- this.state.outputTokensUsed += stepOutput;
205
- // Store text response for summary extraction
206
- if (step.text) {
207
- this.state.context.lastTextResponse = step.text;
208
- }
209
- // Record tool calls in history
210
- for (const tc of step.toolCalls ?? []) {
211
- const record = {
212
- id: tc.toolCallId ?? randomUUID(),
213
- name: tc.toolName,
214
- args: getToolCallInput(tc),
215
- status: "pending",
216
- startedAt: Date.now(),
217
- };
218
- // Find the matching tool result
219
- const tr = (step.toolResults ?? []).find((toolResult) => toolResult.toolCallId === tc.toolCallId);
220
- if (tr) {
221
- record.result = getToolResultOutput(tr);
222
- record.completedAt = Date.now();
223
- // Check if the tool result indicates a failure
224
- if (typeof record.result === "object" && record.result !== null) {
225
- const resultObj = record.result;
226
- const isPending = resultObj.pending === true;
227
- const hasError = Boolean(resultObj.error);
228
- const isFailure = resultObj.success === false || hasError;
229
- if (isPending) {
230
- record.status = "pending";
231
- }
232
- else if (isFailure) {
233
- record.status = "failed";
234
- record.error =
235
- resultObj.error ||
236
- "Tool returned unsuccessful result";
203
+ // --- Async event channel ---
204
+ // onStepFinish is a synchronous callback inside generateText. We bridge it
205
+ // into the async generator by queuing events and signalling the consumer.
206
+ const queue = [];
207
+ let resolveNext;
208
+ let generateDone = false;
209
+ let generateError;
210
+ const push = (event) => {
211
+ queue.push(event);
212
+ if (resolveNext) {
213
+ const r = resolveNext;
214
+ resolveNext = undefined;
215
+ r();
216
+ }
217
+ };
218
+ // Yield session:start immediately
219
+ push({
220
+ type: 'session:start',
221
+ sessionId: this.state.sessionId,
222
+ config: {
223
+ maxSteps: this.config.maxSteps,
224
+ maxBudget: this.config.maxBudget,
225
+ effort: this.config.effort,
226
+ securityMode: this.config.securityMode,
227
+ stepTimeoutMs: this.config.stepTimeoutMs,
228
+ },
229
+ });
230
+ // Run generateText in the background, pushing events via push()
231
+ const generatePromise = (async () => {
232
+ try {
233
+ // Fire onSessionStart hook
234
+ await this.hooks.run('onSessionStart', {
235
+ hookPoint: 'onSessionStart',
236
+ sessionId: this.state.sessionId,
237
+ metadata: {},
238
+ });
239
+ this.injectFailureHint(messages);
240
+ // Use the streaming-aware wrapper so tool events are pushed in real time
241
+ const executableTools = this.wrapToolsWithExecuteAndEvents(tools, onToolExecute, push);
242
+ // Compact context before the API call if messages are large
243
+ const compactionResult = await this.compactor.compact(messages);
244
+ if (compactionResult.compacted) {
245
+ logger.info("[AgentExecutor] Context compacted before API call", {
246
+ originalTokens: compactionResult.originalTokens,
247
+ compactedTokens: compactionResult.compactedTokens,
248
+ turnsCompacted: compactionResult.turnsCompacted,
249
+ });
250
+ messages = compactionResult.messages;
251
+ }
252
+ const hasTools = Object.keys(executableTools).length > 0;
253
+ const providerOptions = this.buildProviderOptions(providerHint);
254
+ const result = await generateText({
255
+ model,
256
+ messages: applyAnthropicMessageCache(messages, providerHint ?? ''),
257
+ tools: hasTools ? applyAnthropicToolCache(executableTools, providerHint ?? '') : undefined,
258
+ ...(providerOptions ? { providerOptions } : {}),
259
+ stopWhen: [
260
+ sdkStepCountIs(this.config.maxSteps),
261
+ sdkHasToolCall("complete_task"),
262
+ ],
263
+ abortSignal: this.abortController.signal,
264
+ onStepFinish: (step) => {
265
+ const stepIndex = this.state.currentStep;
266
+ push({ type: 'step:start', stepIndex });
267
+ this.state.currentStep++;
268
+ this.state.updatedAt = Date.now();
269
+ const stepInput = getUsageInputTokens(step.usage);
270
+ const stepOutput = getUsageOutputTokens(step.usage);
271
+ const tokensUsed = stepInput + stepOutput;
272
+ this.state.usedBudget += tokensUsed;
273
+ this.state.inputTokensUsed += stepInput;
274
+ this.state.outputTokensUsed += stepOutput;
275
+ const cacheUsage = extractCacheUsage(step.usage);
276
+ this.trackStepUsage(model, stepInput, stepOutput, cacheUsage);
277
+ if (cacheUsage.cacheReadTokens > 0 || cacheUsage.cacheWriteTokens > 0) {
278
+ logger.debug("[AgentExecutor] Prompt cache usage", {
279
+ sessionId: this.state.sessionId,
280
+ cacheReadTokens: cacheUsage.cacheReadTokens,
281
+ cacheWriteTokens: cacheUsage.cacheWriteTokens,
282
+ promptTokens: cacheUsage.promptTokens,
283
+ });
284
+ }
285
+ // Update summary tracker with step progress
286
+ getAgentSummaryTracker().update(this.state.sessionId, {
287
+ status: 'thinking',
288
+ stepCount: this.state.currentStep,
289
+ tokensUsed: this.state.usedBudget,
290
+ });
291
+ push({
292
+ type: 'cost:update',
293
+ inputTokens: this.state.inputTokensUsed,
294
+ outputTokens: this.state.outputTokensUsed,
295
+ estimatedCost: 0,
296
+ });
297
+ if (step.text) {
298
+ this.state.context.lastTextResponse = step.text;
299
+ push({ type: 'content', text: step.text, delta: step.text });
300
+ }
301
+ let stepToolCalls = 0;
302
+ for (const tc of step.toolCalls ?? []) {
303
+ stepToolCalls++;
304
+ const record = {
305
+ id: tc.toolCallId ?? randomUUID(),
306
+ name: tc.toolName,
307
+ args: getToolCallInput(tc),
308
+ status: "pending",
309
+ startedAt: Date.now(),
310
+ };
311
+ const tr = (step.toolResults ?? []).find((toolResult) => toolResult.toolCallId === tc.toolCallId);
312
+ if (tr) {
313
+ record.result = getToolResultOutput(tr);
314
+ record.completedAt = Date.now();
315
+ if (typeof record.result === "object" && record.result !== null) {
316
+ const resultObj = record.result;
317
+ const isPending = resultObj.pending === true;
318
+ const hasError = Boolean(resultObj.error);
319
+ const isFailure = resultObj.success === false || hasError;
320
+ if (isPending) {
321
+ record.status = "pending";
322
+ }
323
+ else if (isFailure) {
324
+ record.status = "failed";
325
+ record.error =
326
+ resultObj.error ||
327
+ "Tool returned unsuccessful result";
328
+ }
329
+ else {
330
+ record.status = "executed";
331
+ }
237
332
  }
238
333
  else {
239
334
  record.status = "executed";
240
335
  }
241
336
  }
242
- else {
243
- record.status = "executed";
337
+ this.state.toolCallHistory.push(record);
338
+ this.emit("tool:call", this.state, record);
339
+ this.extractContext(record);
340
+ if (record.status === "executed") {
341
+ this.emit("tool:result", this.state, record);
244
342
  }
245
343
  }
246
- this.state.toolCallHistory.push(record);
247
- this.emit("tool:call", this.state, record);
248
- // Extract context from tool results (projects, tickets, etc.)
249
- this.extractContext(record);
250
- if (record.status === "executed") {
251
- this.emit("tool:result", this.state, record);
344
+ this.emit("step:start", this.state);
345
+ this.emit("step:complete", this.state, step);
346
+ push({
347
+ type: 'step:complete',
348
+ stepIndex: this.state.currentStep,
349
+ toolCalls: stepToolCalls,
350
+ hasContent: Boolean(step.text),
351
+ });
352
+ logger.debug("[AgentExecutor] Step completed", {
353
+ step: this.state.currentStep,
354
+ toolCalls: step.toolCalls?.length ?? 0,
355
+ tokensUsed,
356
+ text: step.text?.substring(0, 100),
357
+ });
358
+ this.checkCustomStopConditions(step);
359
+ // Emit a budget warning when 80% of the token budget is consumed
360
+ const usedPercent = this.state.maxBudget > 0
361
+ ? (this.state.usedBudget / this.state.maxBudget) * 100
362
+ : 0;
363
+ if (usedPercent >= 80 && usedPercent < 100) {
364
+ push({
365
+ type: 'budget:warning',
366
+ usedPercent: Math.round(usedPercent),
367
+ tokensUsed: this.state.usedBudget,
368
+ tokensMax: this.state.maxBudget,
369
+ });
252
370
  }
253
- }
254
- // Emit step events
255
- this.emit("step:start", this.state);
256
- this.emit("step:complete", this.state, step);
257
- logger.debug("[AgentExecutor] Step completed", {
258
- step: this.state.currentStep,
259
- toolCalls: step.toolCalls?.length ?? 0,
260
- tokensUsed,
261
- text: step.text?.substring(0, 100),
371
+ // Save a checkpoint every 5 steps so the session can be resumed
372
+ // (re-use stepIndex which was declared at the top of onStepFinish)
373
+ const currentStepForCheckpoint = this.state.currentStep;
374
+ if (currentStepForCheckpoint > 0 && currentStepForCheckpoint % 5 === 0) {
375
+ const checkpoint = {
376
+ sessionId: this.state.sessionId,
377
+ taskDescription: this.state.goal,
378
+ currentStep: currentStepForCheckpoint,
379
+ totalSteps: this.config.maxSteps,
380
+ messages: [...messages],
381
+ tokensUsed: this.state.usedBudget,
382
+ estimatedCost: 0,
383
+ toolCallHistory: this.state.toolCallHistory.map((tc) => ({
384
+ name: tc.name,
385
+ success: tc.status === 'executed',
386
+ step: currentStepForCheckpoint,
387
+ })),
388
+ completedFiles: (this.state.context.modifiedFiles ?? []).slice(),
389
+ createdAt: this.state.createdAt,
390
+ updatedAt: Date.now(),
391
+ };
392
+ void this.checkpointManager.save(checkpoint).then(() => {
393
+ push({ type: 'checkpoint:saved', sessionId: this.state.sessionId, step: currentStepForCheckpoint });
394
+ }).catch((err) => {
395
+ logger.warn("[AgentExecutor] Failed to save checkpoint", { err });
396
+ });
397
+ }
398
+ if (this.state.usedBudget >= this.state.maxBudget) {
399
+ logger.info("[AgentExecutor] Budget exceeded, aborting", {
400
+ used: this.state.usedBudget,
401
+ max: this.state.maxBudget,
402
+ });
403
+ this.abortController.abort();
404
+ }
405
+ },
406
+ });
407
+ const totalUsage = result.totalUsage;
408
+ if (totalUsage) {
409
+ const totalInput = getUsageInputTokens(totalUsage);
410
+ const totalOutput = getUsageOutputTokens(totalUsage);
411
+ this.state.usedBudget = totalInput + totalOutput;
412
+ this.state.inputTokensUsed = totalInput;
413
+ this.state.outputTokensUsed = totalOutput;
414
+ }
415
+ if (result.text) {
416
+ this.state.context.lastTextResponse = result.text;
417
+ }
418
+ this.finalize();
419
+ // Fire onSessionEnd hook after finalization
420
+ await this.hooks.run('onSessionEnd', {
421
+ hookPoint: 'onSessionEnd',
422
+ sessionId: this.state.sessionId,
423
+ metadata: {},
424
+ });
425
+ const finalResult = this.state.finalResult ?? {
426
+ success: false,
427
+ summary: 'No result',
428
+ artifacts: [],
429
+ stopReason: 'unknown',
430
+ totalSteps: this.state.currentStep,
431
+ totalTokens: this.state.usedBudget,
432
+ };
433
+ push({
434
+ type: 'session:complete',
435
+ result: finalResult,
436
+ totalSteps: this.state.currentStep,
437
+ totalTokens: this.state.usedBudget,
438
+ });
439
+ }
440
+ catch (error) {
441
+ const err = error;
442
+ if (err.name === "AbortError") {
443
+ logger.info("[AgentExecutor] Agent aborted");
444
+ this.finalize();
445
+ // Fire onSessionEnd even on abort
446
+ await this.hooks.run('onSessionEnd', {
447
+ hookPoint: 'onSessionEnd',
448
+ sessionId: this.state.sessionId,
449
+ metadata: { aborted: true },
262
450
  });
263
- // Check custom stop conditions (consecutive failures, same tool repeated, etc.)
264
- this.checkCustomStopConditions(step);
265
- // Budget abort
266
- if (this.state.usedBudget >= this.state.maxBudget) {
267
- logger.info("[AgentExecutor] Budget exceeded, aborting", {
268
- used: this.state.usedBudget,
269
- max: this.state.maxBudget,
270
- });
271
- this.abortController.abort();
451
+ push({ type: 'session:abort', reason: 'aborted' });
452
+ }
453
+ else {
454
+ generateError = err;
455
+ // Fire onError hook before emitting the event
456
+ await this.hooks.run('onError', {
457
+ hookPoint: 'onError',
458
+ sessionId: this.state.sessionId,
459
+ error: err,
460
+ metadata: {},
461
+ });
462
+ // Push the event BEFORE handleError so it is always emitted even if
463
+ // the EventEmitter 'error' event throws due to missing listener.
464
+ push({ type: 'session:error', error: err.message, stack: err.stack });
465
+ try {
466
+ this.handleError(err);
272
467
  }
273
- },
274
- });
275
- // Update budget from total usage (AI SDK v6 uses inputTokens/outputTokens)
276
- const totalUsage = result.totalUsage;
277
- if (totalUsage) {
278
- const totalInput = getUsageInputTokens(totalUsage);
279
- const totalOutput = getUsageOutputTokens(totalUsage);
280
- // totalUsage is the authoritative sum; overwrite our step-by-step estimate
281
- this.state.usedBudget = totalInput + totalOutput;
282
- this.state.inputTokensUsed = totalInput;
283
- this.state.outputTokensUsed = totalOutput;
468
+ catch {
469
+ // Swallow re-throw from EventEmitter if no 'error' listener is attached
470
+ }
471
+ }
284
472
  }
285
- // Store final text from the result (last step's text)
286
- if (result.text) {
287
- this.state.context.lastTextResponse = result.text;
473
+ finally {
474
+ generateDone = true;
475
+ this.isRunning = false;
476
+ getSleepPreventer().stop();
477
+ if (resolveNext) {
478
+ const r = resolveNext;
479
+ resolveNext = undefined;
480
+ r();
481
+ }
288
482
  }
289
- // Finalize
290
- this.finalize();
291
- return this.state;
292
- }
293
- catch (error) {
294
- if (error.name === "AbortError") {
295
- // Aborted by budget or cancellation — still finalize
296
- logger.info("[AgentExecutor] Agent aborted");
297
- this.finalize();
298
- return this.state;
483
+ })();
484
+ // Drain the queue; wait for more events when it is empty
485
+ while (true) {
486
+ while (queue.length > 0) {
487
+ yield queue.shift();
299
488
  }
300
- this.handleError(error);
301
- throw error;
489
+ if (generateDone)
490
+ break;
491
+ await new Promise((resolve) => {
492
+ resolveNext = resolve;
493
+ });
494
+ }
495
+ // Drain any remaining events that arrived while we were awaiting
496
+ while (queue.length > 0) {
497
+ yield queue.shift();
302
498
  }
303
- finally {
304
- this.isRunning = false;
499
+ // Propagate errors after the consumer has seen all events
500
+ await generatePromise;
501
+ if (generateError) {
502
+ throw generateError;
503
+ }
504
+ }
505
+ /**
506
+ * Run the agent until completion or stop condition.
507
+ * Uses AI SDK's native multi-step execution — a single generateText call
508
+ * with stopWhen + onStepFinish replaces the old manual loop.
509
+ *
510
+ * Backward-compatible: delegates to stream() and returns the final AgentState.
511
+ */
512
+ async run(model, messages, tools, onToolExecute, providerHint) {
513
+ // Consume the stream — stream() handles all state mutation and error handling
514
+ for await (const _event of this.stream(model, messages, tools, onToolExecute, providerHint)) {
515
+ // Individual events are not needed here; state is updated in-place
305
516
  }
517
+ return this.state;
518
+ }
519
+ /**
520
+ * Resume execution from a saved checkpoint.
521
+ *
522
+ * Restores the message history and step counter from the checkpoint, emits a
523
+ * checkpoint:resumed event, then continues with generateText from that point.
524
+ */
525
+ async *resume(checkpoint, model, tools, onToolExecute, providerHint) {
526
+ // Restore step counter so subsequent checkpoints use the right step index
527
+ this.state.currentStep = checkpoint.currentStep;
528
+ this.state.usedBudget = checkpoint.tokensUsed;
529
+ this.state.goal = checkpoint.taskDescription ?? this.state.goal;
530
+ this.state.createdAt = checkpoint.createdAt;
531
+ // Emit resumed event before the stream starts
532
+ yield { type: 'checkpoint:resumed', sessionId: checkpoint.sessionId, step: checkpoint.currentStep };
533
+ // Delegate to stream() with the restored messages
534
+ yield* this.stream(model, checkpoint.messages, tools, onToolExecute, providerHint);
306
535
  }
307
536
  /**
308
537
  * Cancel the running agent.
@@ -375,14 +604,67 @@ export class AgentExecutor extends EventEmitter {
375
604
  for (const [name, toolDef] of Object.entries(tools)) {
376
605
  wrapped[name] = {
377
606
  ...toolDef,
378
- execute: async (args) => {
607
+ execute: async (args, opts) => {
608
+ // Circuit breaker check — prevent repeated calls to a failing tool
609
+ const cbCheck = this.circuitBreaker.canExecute(name);
610
+ if (!cbCheck.allowed) {
611
+ logger.warn("[AgentExecutor] Circuit breaker blocked tool call", {
612
+ tool: name,
613
+ reason: cbCheck.reason,
614
+ });
615
+ return {
616
+ error: cbCheck.reason ?? `Circuit breaker open for ${name}`,
617
+ success: false,
618
+ canRetry: false,
619
+ suggestion: "Try an alternative approach",
620
+ };
621
+ }
622
+ const toolCallId = opts?.toolCallId ?? randomUUID();
623
+ const timeoutMs = this.config.stepTimeoutMs;
624
+ // Update summary tracker — tool is now executing
625
+ const summaryTracker = getAgentSummaryTracker();
626
+ const currentAction = summaryTracker.summarizeToolCall(this.state.sessionId, name, args);
627
+ summaryTracker.update(this.state.sessionId, {
628
+ status: 'executing',
629
+ currentAction,
630
+ lastToolName: name,
631
+ lastToolArgs: JSON.stringify(args).substring(0, 100),
632
+ });
633
+ let timeoutHandle;
634
+ const timeoutPromise = new Promise((_, reject) => {
635
+ timeoutHandle = setTimeout(() => {
636
+ reject(new Error(`__TOOL_TIMEOUT__:${timeoutMs}`));
637
+ }, timeoutMs);
638
+ });
379
639
  try {
380
- const result = await onToolExecute(name, args);
381
- return result;
640
+ const raw = await Promise.race([
641
+ onToolExecute(name, args),
642
+ timeoutPromise,
643
+ ]);
644
+ clearTimeout(timeoutHandle);
645
+ this.circuitBreaker.recordSuccess(name);
646
+ const stored = await this.resultStore.store(toolCallId, raw);
647
+ // Return the inline representation (summary or full result)
648
+ return JSON.parse(stored.inline);
382
649
  }
383
650
  catch (error) {
384
- // Return error as a structured result so the AI can see it and adjust
651
+ clearTimeout(timeoutHandle);
385
652
  const errorMsg = error instanceof Error ? error.message : "Unknown error";
653
+ // Timeout path
654
+ if (errorMsg.startsWith("__TOOL_TIMEOUT__:")) {
655
+ const ms = errorMsg.split(":")[1];
656
+ logger.warn("[AgentExecutor] Tool execution timed out", {
657
+ tool: name,
658
+ timeoutMs,
659
+ });
660
+ this.circuitBreaker.recordFailure(name);
661
+ return {
662
+ error: `Tool execution timed out after ${ms}ms`,
663
+ success: false,
664
+ canRetry: true,
665
+ };
666
+ }
667
+ // Regular error path
386
668
  const isPermError = errorMsg.toLowerCase().includes("permission") ||
387
669
  errorMsg.toLowerCase().includes("unauthorized") ||
388
670
  errorMsg.toLowerCase().includes("forbidden") ||
@@ -391,12 +673,183 @@ export class AgentExecutor extends EventEmitter {
391
673
  tool: name,
392
674
  error: errorMsg,
393
675
  });
676
+ this.circuitBreaker.recordFailure(name);
677
+ return {
678
+ error: errorMsg,
679
+ success: false,
680
+ suggestion: "This tool failed. Consider trying a different approach or asking the user for help.",
681
+ canRetry: !isPermError,
682
+ };
683
+ }
684
+ },
685
+ };
686
+ }
687
+ return wrapped;
688
+ }
689
+ /**
690
+ * Like wrapToolsWithExecute, but additionally pushes tool:call, tool:result,
691
+ * and tool:error AgentEvents via the provided push callback so that the
692
+ * stream() generator can yield them in real time.
693
+ */
694
+ wrapToolsWithExecuteAndEvents(tools, onToolExecute, push) {
695
+ if (!onToolExecute)
696
+ return tools;
697
+ const wrapped = {};
698
+ for (const [name, toolDef] of Object.entries(tools)) {
699
+ wrapped[name] = {
700
+ ...toolDef,
701
+ execute: async (args, opts) => {
702
+ const toolCallId = opts?.toolCallId ?? randomUUID();
703
+ // Circuit breaker check
704
+ const cbCheck = this.circuitBreaker.canExecute(name);
705
+ if (!cbCheck.allowed) {
706
+ const reason = cbCheck.reason ?? `Circuit breaker open for ${name}`;
707
+ logger.warn("[AgentExecutor] Circuit breaker blocked tool call", {
708
+ tool: name,
709
+ reason,
710
+ });
711
+ // Emit circuit:open so the consumer knows the breaker tripped
712
+ push({ type: 'circuit:open', toolName: name, cooldownMs: 0 });
713
+ push({ type: 'tool:error', toolCallId, error: reason });
394
714
  return {
715
+ error: reason,
716
+ success: false,
717
+ canRetry: false,
718
+ suggestion: "Try an alternative approach",
719
+ };
720
+ }
721
+ const timeoutMs = this.config.stepTimeoutMs;
722
+ // Update summary tracker — tool is now executing
723
+ const summaryTracker = getAgentSummaryTracker();
724
+ const currentAction = summaryTracker.summarizeToolCall(this.state.sessionId, name, args);
725
+ summaryTracker.update(this.state.sessionId, {
726
+ status: 'executing',
727
+ currentAction,
728
+ lastToolName: name,
729
+ lastToolArgs: JSON.stringify(args).substring(0, 100),
730
+ });
731
+ // beforeToolCall hook — may abort tool execution
732
+ const beforeResult = await this.hooks.run('beforeToolCall', {
733
+ hookPoint: 'beforeToolCall',
734
+ sessionId: this.state.sessionId,
735
+ toolName: name,
736
+ toolArgs: args,
737
+ metadata: {},
738
+ });
739
+ if (!beforeResult.proceed) {
740
+ const blockReason = `Tool "${name}" blocked by hook`;
741
+ logger.info("[AgentExecutor] Tool blocked by beforeToolCall hook", {
742
+ tool: name,
743
+ });
744
+ push({ type: 'tool:error', toolCallId, error: blockReason });
745
+ const blockedResult = {
746
+ error: blockReason,
747
+ success: false,
748
+ canRetry: false,
749
+ suggestion: 'A lifecycle hook prevented this tool from running.',
750
+ };
751
+ push({
752
+ type: 'tool:result',
753
+ toolCallId,
754
+ result: blockedResult,
755
+ duration: 0,
756
+ success: false,
757
+ });
758
+ return blockedResult;
759
+ }
760
+ // Use potentially modified args from the hook
761
+ const effectiveArgs = beforeResult.modified !== undefined && typeof beforeResult.modified === 'object' && beforeResult.modified !== null
762
+ ? beforeResult.modified
763
+ : args;
764
+ // Push tool:call event before execution
765
+ push({ type: 'tool:call', toolName: name, args: effectiveArgs, toolCallId });
766
+ let timeoutHandle;
767
+ const timeoutPromise = new Promise((_, reject) => {
768
+ timeoutHandle = setTimeout(() => {
769
+ reject(new Error(`__TOOL_TIMEOUT__:${timeoutMs}`));
770
+ }, timeoutMs);
771
+ });
772
+ const startedAt = Date.now();
773
+ try {
774
+ const raw = await Promise.race([
775
+ onToolExecute(name, effectiveArgs),
776
+ timeoutPromise,
777
+ ]);
778
+ clearTimeout(timeoutHandle);
779
+ this.circuitBreaker.recordSuccess(name);
780
+ const stored = await this.resultStore.store(toolCallId, raw);
781
+ const inlineResult = JSON.parse(stored.inline);
782
+ const duration = Date.now() - startedAt;
783
+ // afterToolCall hook — receives the result
784
+ await this.hooks.run('afterToolCall', {
785
+ hookPoint: 'afterToolCall',
786
+ sessionId: this.state.sessionId,
787
+ toolName: name,
788
+ toolArgs: effectiveArgs,
789
+ toolResult: inlineResult,
790
+ metadata: {},
791
+ });
792
+ push({
793
+ type: 'tool:result',
794
+ toolCallId,
795
+ result: inlineResult,
796
+ duration,
797
+ success: true,
798
+ });
799
+ return inlineResult;
800
+ }
801
+ catch (error) {
802
+ clearTimeout(timeoutHandle);
803
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
804
+ const duration = Date.now() - startedAt;
805
+ // Timeout path
806
+ if (errorMsg.startsWith("__TOOL_TIMEOUT__:")) {
807
+ const ms = errorMsg.split(":")[1];
808
+ logger.warn("[AgentExecutor] Tool execution timed out", {
809
+ tool: name,
810
+ timeoutMs,
811
+ });
812
+ this.circuitBreaker.recordFailure(name);
813
+ const timeoutResult = {
814
+ error: `Tool execution timed out after ${ms}ms`,
815
+ success: false,
816
+ canRetry: true,
817
+ };
818
+ push({ type: 'tool:error', toolCallId, error: timeoutResult.error });
819
+ push({
820
+ type: 'tool:result',
821
+ toolCallId,
822
+ result: timeoutResult,
823
+ duration,
824
+ success: false,
825
+ });
826
+ return timeoutResult;
827
+ }
828
+ // Regular error path
829
+ const isPermError = errorMsg.toLowerCase().includes("permission") ||
830
+ errorMsg.toLowerCase().includes("unauthorized") ||
831
+ errorMsg.toLowerCase().includes("forbidden") ||
832
+ errorMsg.toLowerCase().includes("not allowed");
833
+ logger.warn("[AgentExecutor] Tool execution failed", {
834
+ tool: name,
835
+ error: errorMsg,
836
+ });
837
+ this.circuitBreaker.recordFailure(name);
838
+ push({ type: 'tool:error', toolCallId, error: errorMsg });
839
+ const errorResult = {
395
840
  error: errorMsg,
396
841
  success: false,
397
842
  suggestion: "This tool failed. Consider trying a different approach or asking the user for help.",
398
843
  canRetry: !isPermError,
399
844
  };
845
+ push({
846
+ type: 'tool:result',
847
+ toolCallId,
848
+ result: errorResult,
849
+ duration,
850
+ success: false,
851
+ });
852
+ return errorResult;
400
853
  }
401
854
  },
402
855
  };
@@ -524,8 +977,37 @@ export class AgentExecutor extends EventEmitter {
524
977
  }
525
978
  }
526
979
  }
980
+ /** Route one step's usage (with cache tokens) into the cost tracker. */
981
+ trackStepUsage(model, inputTokens, outputTokens, cache) {
982
+ const total = inputTokens + outputTokens;
983
+ if (total <= 0)
984
+ return;
985
+ const modelId = typeof model === "string" ? model : getRecord(model)?.modelId;
986
+ if (typeof modelId !== "string" || modelId.length === 0)
987
+ return;
988
+ try {
989
+ trackChatUsage(modelId, total, inputTokens, outputTokens, {
990
+ cacheReadTokens: cache.cacheReadTokens,
991
+ cacheWriteTokens: cache.cacheWriteTokens,
992
+ });
993
+ }
994
+ catch (err) {
995
+ logger.warn("[AgentExecutor] Usage tracking failed", {
996
+ sessionId: this.state.sessionId,
997
+ error: err instanceof Error ? err.message : String(err),
998
+ });
999
+ }
1000
+ }
527
1001
  // Finalization
528
1002
  finalize() {
1003
+ // Clean up any temp files written by the result store (fire-and-forget)
1004
+ this.resultStore.cleanup().catch((err) => {
1005
+ logger.warn("[AgentExecutor] ResultStore cleanup failed", {
1006
+ error: err instanceof Error ? err.message : String(err),
1007
+ });
1008
+ });
1009
+ // Remove this session from the summary tracker
1010
+ getAgentSummaryTracker().end(this.state.sessionId);
529
1011
  const completedViaTask = this.state.toolCallHistory.some((t) => t.name === "complete_task" && t.status === "executed");
530
1012
  // Check if agent completed via text response (no tool calls)
531
1013
  const completedViaTextResponse = this.state.toolCallHistory.length === 0 ||