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