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.
- package/.env.example +14 -2
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTING.md +20 -0
- package/Dockerfile +39 -23
- package/README.md +174 -40
- package/dist/agents/agent-summary.d.ts +44 -0
- package/dist/agents/agent-summary.js +176 -0
- package/dist/agents/auto-memory.d.ts +59 -0
- package/dist/agents/auto-memory.js +310 -0
- package/dist/agents/checkpoint-manager.d.ts +76 -0
- package/dist/agents/checkpoint-manager.js +156 -0
- package/dist/agents/circuit-breaker.d.ts +54 -0
- package/dist/agents/circuit-breaker.js +153 -0
- package/dist/agents/context-compactor.d.ts +70 -0
- package/dist/agents/context-compactor.js +361 -0
- package/dist/agents/conversation-branch.d.ts +55 -0
- package/dist/agents/conversation-branch.js +115 -0
- package/dist/agents/error-recovery.d.ts +44 -0
- package/dist/agents/error-recovery.js +197 -0
- package/dist/agents/events.d.ts +76 -0
- package/dist/agents/events.js +8 -0
- package/dist/agents/executor.d.ts +35 -1
- package/dist/agents/executor.js +573 -124
- package/dist/agents/file-snapshots.d.ts +72 -0
- package/dist/agents/file-snapshots.js +182 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/orchestrator.d.ts +183 -0
- package/dist/agents/orchestrator.js +495 -0
- package/dist/agents/permissions.d.ts +63 -0
- package/dist/agents/permissions.js +138 -0
- package/dist/agents/plan-mode.d.ts +71 -0
- package/dist/agents/plan-mode.js +186 -0
- package/dist/agents/prompt-suggestions.d.ts +33 -0
- package/dist/agents/prompt-suggestions.js +208 -0
- package/dist/agents/rate-limit-monitor.d.ts +56 -0
- package/dist/agents/rate-limit-monitor.js +224 -0
- package/dist/agents/result-store.d.ts +37 -0
- package/dist/agents/result-store.js +104 -0
- package/dist/agents/session-diff.d.ts +43 -0
- package/dist/agents/session-diff.js +258 -0
- package/dist/agents/tool-loader.d.ts +65 -0
- package/dist/agents/tool-loader.js +273 -0
- package/dist/agents/transcript.d.ts +96 -0
- package/dist/agents/transcript.js +267 -0
- package/dist/agents/worktree-manager.d.ts +80 -0
- package/dist/agents/worktree-manager.js +203 -0
- package/dist/auth/middleware.js +14 -0
- package/dist/chat/agentic-executor.d.ts +7 -0
- package/dist/chat/agentic-executor.js +253 -30
- package/dist/chat/conversations.d.ts +2 -0
- package/dist/chat/conversations.js +8 -0
- package/dist/chat/execution/executor.d.ts +8 -0
- package/dist/chat/execution/executor.js +157 -103
- package/dist/chat/execution/index.js +5 -1
- package/dist/chat/execution/tool-router.js +40 -14
- package/dist/chat/execution/tools/canvas.d.ts +2 -2
- package/dist/chat/execution/tools/code-tools.d.ts +66 -0
- package/dist/chat/execution/tools/code-tools.js +353 -0
- package/dist/chat/execution/tools/complete-task.d.ts +2 -2
- package/dist/chat/execution/tools/cron-tool.d.ts +26 -10
- package/dist/chat/execution/tools/cron-tool.js +48 -3
- package/dist/chat/execution/tools/decompose-task.d.ts +58 -0
- package/dist/chat/execution/tools/decompose-task.js +166 -0
- package/dist/chat/execution/tools/exec.d.ts +5 -2
- package/dist/chat/execution/tools/exec.js +294 -155
- package/dist/chat/execution/tools/feed-tools.d.ts +77 -0
- package/dist/chat/execution/tools/feed-tools.js +142 -0
- package/dist/chat/execution/tools/file-ops.d.ts +1 -1
- package/dist/chat/execution/tools/github.d.ts +2 -2
- package/dist/chat/execution/tools/index.d.ts +14 -2
- package/dist/chat/execution/tools/index.js +86 -12
- package/dist/chat/execution/tools/integrations.d.ts +8 -8
- package/dist/chat/execution/tools/multi-patch.d.ts +53 -0
- package/dist/chat/execution/tools/multi-patch.js +373 -0
- package/dist/chat/execution/tools/openai-image-gen.d.ts +2 -2
- package/dist/chat/execution/tools/plan-tools.d.ts +80 -0
- package/dist/chat/execution/tools/plan-tools.js +134 -0
- package/dist/chat/execution/tools/profclaw-ops.d.ts +6 -6
- package/dist/chat/execution/tools/repl-tool.d.ts +46 -0
- package/dist/chat/execution/tools/repl-tool.js +207 -0
- package/dist/chat/execution/tools/sessions-send.d.ts +2 -2
- package/dist/chat/execution/tools/slack-actions.d.ts +2 -2
- package/dist/chat/execution/tools/system.d.ts +4 -4
- package/dist/chat/execution/tools/todo-tool.d.ts +72 -0
- package/dist/chat/execution/tools/todo-tool.js +152 -0
- package/dist/chat/execution/tools/tool-search.d.ts +50 -0
- package/dist/chat/execution/tools/tool-search.js +155 -0
- package/dist/chat/execution/types.d.ts +21 -14
- package/dist/chat/execution/workflows/executor.d.ts +11 -0
- package/dist/chat/execution/workflows/executor.js +99 -1
- package/dist/chat/execution/workflows/types.d.ts +35 -2
- package/dist/chat/format/index.d.ts +1 -0
- package/dist/chat/format/index.js +1 -0
- package/dist/chat/format/markdown-convert.d.ts +23 -0
- package/dist/chat/format/markdown-convert.js +149 -0
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +1 -1
- package/dist/chat/message-handler.js +58 -6
- package/dist/chat/proactive/index.d.ts +62 -0
- package/dist/chat/proactive/index.js +147 -0
- package/dist/chat/prompt-adapter.js +2 -0
- package/dist/chat/providers/irc/index.d.ts +2 -2
- package/dist/chat/providers/telegram/index.d.ts +2 -0
- package/dist/chat/providers/telegram/index.js +21 -2
- package/dist/chat/system-prompts.d.ts +3 -3
- package/dist/chat/system-prompts.js +116 -61
- package/dist/chat/tools.d.ts +6 -6
- package/dist/cli/commands/auth.js +64 -1
- package/dist/cli/commands/chat.js +1327 -138
- package/dist/cli/commands/doctor.js +222 -16
- package/dist/cli/commands/history.d.ts +3 -0
- package/dist/cli/commands/history.js +138 -0
- package/dist/cli/commands/import.d.ts +44 -0
- package/dist/cli/commands/import.js +526 -0
- package/dist/cli/commands/init.d.ts +13 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/onboard.js +210 -30
- package/dist/cli/commands/plan.d.ts +13 -0
- package/dist/cli/commands/plan.js +184 -0
- package/dist/cli/commands/serve.d.ts +7 -0
- package/dist/cli/commands/serve.js +77 -18
- package/dist/cli/commands/setup.js +84 -3
- package/dist/cli/commands/status.js +54 -0
- package/dist/cli/commands/tools.js +13 -13
- package/dist/cli/commands/tui.js +26 -1
- package/dist/cli/index.js +19 -0
- package/dist/cli/ink/App.d.ts +13 -0
- package/dist/cli/ink/App.js +6 -0
- package/dist/cli/ink/ChatApp.d.ts +60 -0
- package/dist/cli/ink/ChatApp.js +325 -0
- package/dist/cli/ink/DashboardApp.d.ts +3 -0
- package/dist/cli/ink/DashboardApp.js +143 -0
- package/dist/cli/ink/components/AgentStatus.d.ts +17 -0
- package/dist/cli/ink/components/AgentStatus.js +33 -0
- package/dist/cli/ink/components/ChannelList.d.ts +17 -0
- package/dist/cli/ink/components/ChannelList.js +33 -0
- package/dist/cli/ink/components/ConnectionStatus.d.ts +19 -0
- package/dist/cli/ink/components/ConnectionStatus.js +50 -0
- package/dist/cli/ink/components/CostBar.d.ts +19 -0
- package/dist/cli/ink/components/CostBar.js +35 -0
- package/dist/cli/ink/components/HookStatus.d.ts +15 -0
- package/dist/cli/ink/components/HookStatus.js +7 -0
- package/dist/cli/ink/components/PermissionPrompt.d.ts +21 -0
- package/dist/cli/ink/components/PermissionPrompt.js +51 -0
- package/dist/cli/ink/components/PlanView.d.ts +23 -0
- package/dist/cli/ink/components/PlanView.js +26 -0
- package/dist/cli/ink/components/ProviderList.d.ts +16 -0
- package/dist/cli/ink/components/ProviderList.js +16 -0
- package/dist/cli/ink/components/SessionHeader.d.ts +15 -0
- package/dist/cli/ink/components/SessionHeader.js +15 -0
- package/dist/cli/ink/components/StreamingMessage.d.ts +20 -0
- package/dist/cli/ink/components/StreamingMessage.js +27 -0
- package/dist/cli/ink/components/SuggestionBar.d.ts +15 -0
- package/dist/cli/ink/components/SuggestionBar.js +28 -0
- package/dist/cli/ink/components/SystemHealth.d.ts +20 -0
- package/dist/cli/ink/components/SystemHealth.js +39 -0
- package/dist/cli/ink/components/TaskList.d.ts +17 -0
- package/dist/cli/ink/components/TaskList.js +59 -0
- package/dist/cli/ink/components/ToolCall.d.ts +17 -0
- package/dist/cli/ink/components/ToolCall.js +43 -0
- package/dist/cli/ink/index.d.ts +23 -0
- package/dist/cli/ink/index.js +15 -0
- package/dist/cli/ink/keybindings.d.ts +35 -0
- package/dist/cli/ink/keybindings.js +105 -0
- package/dist/cli/ink/markdown-renderer.d.ts +47 -0
- package/dist/cli/ink/markdown-renderer.js +380 -0
- package/dist/cli/ink/output-styles.d.ts +39 -0
- package/dist/cli/ink/output-styles.js +119 -0
- package/dist/cli/interactive/auto-serve.d.ts +38 -0
- package/dist/cli/interactive/auto-serve.js +209 -0
- package/dist/cli/interactive/index.d.ts +25 -0
- package/dist/cli/interactive/index.js +23 -0
- package/dist/cli/interactive/picker.d.ts +28 -0
- package/dist/cli/interactive/picker.js +153 -0
- package/dist/cli/interactive/renderer.d.ts +26 -0
- package/dist/cli/interactive/renderer.js +555 -0
- package/dist/cli/interactive/repl.d.ts +14 -0
- package/dist/cli/interactive/repl.js +1516 -0
- package/dist/cli/interactive/stream-client.d.ts +59 -0
- package/dist/cli/interactive/stream-client.js +506 -0
- package/dist/cli/interactive/types.d.ts +121 -0
- package/dist/cli/interactive/types.js +10 -0
- package/dist/cli/utils/api.d.ts +9 -0
- package/dist/cli/utils/api.js +58 -2
- package/dist/cron/natural-language.d.ts +54 -0
- package/dist/cron/natural-language.js +569 -0
- package/dist/cron/scheduler.d.ts +34 -4
- package/dist/cron/scheduler.js +141 -9
- package/dist/cron/templates.d.ts +1 -1
- package/dist/cron/templates.js +219 -0
- package/dist/feeds/feed-engine.d.ts +149 -0
- package/dist/feeds/feed-engine.js +600 -0
- package/dist/feeds/index.d.ts +9 -0
- package/dist/feeds/index.js +8 -0
- package/dist/gateway/router.js +6 -1
- package/dist/hooks/built-in/audit-log.d.ts +11 -0
- package/dist/hooks/built-in/audit-log.js +84 -0
- package/dist/hooks/built-in/cost-warning.d.ts +10 -0
- package/dist/hooks/built-in/cost-warning.js +59 -0
- package/dist/hooks/built-in/dangerous-tool.d.ts +32 -0
- package/dist/hooks/built-in/dangerous-tool.js +80 -0
- package/dist/hooks/built-in/index.d.ts +14 -0
- package/dist/hooks/built-in/index.js +20 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/loader.d.ts +17 -0
- package/dist/hooks/loader.js +142 -0
- package/dist/hooks/registry.d.ts +62 -0
- package/dist/hooks/registry.js +127 -0
- package/dist/integrations/web-search.js +6 -3
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/memory-service.js +14 -13
- package/dist/memory/observational.d.ts +62 -0
- package/dist/memory/observational.js +396 -0
- package/dist/middleware/content-filter.d.ts +22 -0
- package/dist/middleware/content-filter.js +69 -0
- package/dist/middleware/request-validator.d.ts +159 -0
- package/dist/middleware/request-validator.js +93 -0
- package/dist/plugins/sdk.d.ts +22 -0
- package/dist/plugins/sdk.js +17 -1
- package/dist/projects/types.d.ts +10 -10
- package/dist/providers/ai-sdk.d.ts +11 -0
- package/dist/providers/ai-sdk.js +78 -19
- package/dist/providers/core/models.js +67 -1
- package/dist/providers/core/types.d.ts +3 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/smart-router.d.ts +118 -0
- package/dist/providers/smart-router.js +685 -0
- package/dist/providers/types.d.ts +16 -16
- package/dist/routes/agents.js +50 -0
- package/dist/routes/auth.js +8 -1
- package/dist/routes/chat.js +259 -14
- package/dist/routes/costs.js +32 -0
- package/dist/routes/cron.js +80 -5
- package/dist/routes/feeds.d.ts +10 -0
- package/dist/routes/feeds.js +168 -0
- package/dist/routes/mcp.js +21 -0
- package/dist/routes/memory.js +130 -0
- package/dist/routes/skills.js +129 -0
- package/dist/routes/teams.d.ts +9 -0
- package/dist/routes/teams.js +210 -0
- package/dist/routes/tools.js +14 -0
- package/dist/routes/users.js +2 -0
- package/dist/server/route-loader.js +3 -1
- package/dist/server/stream-bridge.d.ts +19 -0
- package/dist/server/stream-bridge.js +38 -0
- package/dist/server.js +310 -36
- package/dist/skills/marketplace.d.ts +87 -0
- package/dist/skills/marketplace.js +268 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.js +64 -3
- package/dist/storage/schema.d.ts +4 -4
- package/dist/storage/schema.js +1 -1
- package/dist/teams/index.d.ts +110 -0
- package/dist/teams/index.js +365 -0
- package/dist/tickets/types.d.ts +39 -39
- package/dist/types/summary.d.ts +5 -5
- package/dist/utils/auto-update.d.ts +23 -0
- package/dist/utils/auto-update.js +157 -0
- package/dist/utils/offline-detect.d.ts +55 -0
- package/dist/utils/offline-detect.js +121 -0
- package/dist/utils/pid-file.d.ts +36 -0
- package/dist/utils/pid-file.js +125 -0
- package/dist/utils/prevent-sleep.d.ts +27 -0
- package/dist/utils/prevent-sleep.js +95 -0
- package/dist/utils/sanitizer.d.ts +57 -0
- package/dist/utils/sanitizer.js +174 -0
- package/docker-compose.yml +13 -137
- package/package.json +31 -6
- package/skills/deploy-cloudflare/SKILL.md +62 -0
- package/skills/deploy-vercel/SKILL.md +67 -0
- package/skills/docker-deploy/SKILL.md +158 -0
- package/skills/full-stack-builder/SKILL.md +92 -0
- package/skills/humanizer/SKILL.md +488 -0
- package/skills/profclaw-assistant/SKILL.md +85 -56
- package/ui/dist/assets/ActivityView-Da6HQ8ws.js +1 -0
- package/ui/dist/assets/AgentList-H58R0kX3.js +1 -0
- package/ui/dist/assets/AnalyticsDashboard-B28AeRsc.js +1 -0
- package/ui/dist/assets/AreaChart-DwLzeAQ8.js +1 -0
- package/ui/dist/assets/CartesianChart-piKQsTAR.js +36 -0
- package/ui/dist/assets/ChatView-Dbj8rxU5.js +10 -0
- package/ui/dist/assets/CostsDashboard-C6F5df0F.js +1 -0
- package/ui/dist/assets/EstimateSelect-wga0rUKX.js +1 -0
- package/ui/dist/assets/FeedDashboard-Ef6FEzEf.js +1 -0
- package/ui/dist/assets/FloatingChatbot-0yhkUeCq.js +2 -0
- package/ui/dist/assets/InviteCodeManagement-tUXfx4Bc.js +2 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/ui/dist/assets/MarketplacePage-DGrLtolR.js +1 -0
- package/ui/dist/assets/{ProjectDetail--gPfvATB.js → ProjectDetail-BgWvA6UP.js} +2 -2
- package/ui/dist/assets/ProjectIcon-TDuliqwg.js +1 -0
- package/ui/dist/assets/ProjectList-DXgM4187.js +1 -0
- package/ui/dist/assets/{Settings-1kaf7VHE.js → Settings-xA8Zhi3p.js} +3 -3
- package/ui/dist/assets/StatusIndicator-B8vfFAxg.js +1 -0
- package/ui/dist/assets/{SummaryDetail-DV3AmONk.js → SummaryDetail-eedRfTtF.js} +2 -2
- package/ui/dist/assets/SummaryList-CLNX2P84.js +1 -0
- package/ui/dist/assets/TaskDetail-BtWclNiR.js +1 -0
- package/ui/dist/assets/TaskList-JjODAgSc.js +1 -0
- package/ui/dist/assets/TeamsPage-CBK5iAyx.js +1 -0
- package/ui/dist/assets/TicketBoard-C9aJNNYp.js +1 -0
- package/ui/dist/assets/TicketDetail-CV5JmL31.js +1 -0
- package/ui/dist/assets/TicketList-68V4lzUz.js +1 -0
- package/ui/dist/assets/UserManagement-DKTb6UpE.js +2 -0
- package/ui/dist/assets/ViewSwitcher-BvdQht2Y.js +1 -0
- package/ui/dist/assets/alert-dialog-O6qBOv_f.js +1 -0
- package/ui/dist/assets/{archive-BsLa7brF.js → archive-CX7UvZpf.js} +1 -1
- package/ui/dist/assets/badge-BbfnwDJP.js +1 -0
- package/ui/dist/assets/{bug-CmZI7jqM.js → bug-3WX0394-.js} +1 -1
- package/ui/dist/assets/{calendar-Bf0t2B82.js → calendar-buq77TaS.js} +1 -1
- package/ui/dist/assets/{chevron-up-CoUsOvZj.js → chevron-up-4ymsBJRo.js} +1 -1
- package/ui/dist/assets/{circle-x-Dgw11LgT.js → circle-x-ByXtwR6Y.js} +1 -1
- package/ui/dist/assets/constants-CVdDh7p0.js +1 -0
- package/ui/dist/assets/{cpu-DiPMQICV.js → cpu-CiuoCeDY.js} +1 -1
- package/ui/dist/assets/{database-BwTfupDi.js → database-BWXSBg5a.js} +1 -1
- package/ui/dist/assets/dialog-lDg4NvMV.js +1 -0
- package/ui/dist/assets/dollar-sign-Dmijd6DP.js +1 -0
- package/ui/dist/assets/{ellipsis-UJx4Xnf6.js → ellipsis-vT-5SVIp.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-DoULYEKn.js → ellipsis-vertical-B4tAX_bL.js} +1 -1
- package/ui/dist/assets/feature-markdown-DBo5Q7uq.js +289 -0
- package/ui/dist/assets/{file-code-B2UrJLwi.js → file-code-ChOWdKXf.js} +1 -1
- package/ui/dist/assets/{folder-open-BJi577JH.js → folder-open-CkOUbIiP.js} +1 -1
- package/ui/dist/assets/{funnel-PkaD_HSR.js → funnel-uZkoSPP-.js} +1 -1
- package/ui/dist/assets/{git-branch-C_K30am0.js → git-branch-CwvUxj7C.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-IT6ecxWQ.js → git-commit-horizontal-lxPzCvhD.js} +1 -1
- package/ui/dist/assets/{globe-f-jjCa_g.js → globe-D_WpJdsj.js} +1 -1
- package/ui/dist/assets/{hash-DNEv8Elo.js → hash-CA0hJ7vh.js} +1 -1
- package/ui/dist/assets/{history-BQSBo_1Q.js → history-CEWMLELs.js} +1 -1
- package/ui/dist/assets/inbox-ehtOptTV.js +1 -0
- package/ui/dist/assets/{index-nS3EErDg.js → index-C1rhbml4.js} +3 -3
- package/ui/dist/assets/index-CR8gfCHv.js +1 -0
- package/ui/dist/assets/index-DVXMpWai.js +1 -0
- package/ui/dist/assets/index-DaDJMM2v.js +1 -0
- package/ui/dist/assets/index-Djdq_0xu.js +1 -0
- package/ui/dist/assets/index-M46Gcb8K.css +1 -0
- package/ui/dist/assets/index-sEBN7w8J.js +109 -0
- package/ui/dist/assets/layers-C6Mhf8Nk.js +1 -0
- package/ui/dist/assets/{layout-dashboard-CcKt1hXw.js → layout-dashboard-BRUM0kpT.js} +1 -1
- package/ui/dist/assets/{lightbulb-Jhp7FvbU.js → lightbulb-CN2q1O5l.js} +1 -1
- package/ui/dist/assets/{link-2-DdO7ostF.js → link-2-CC4E28yJ.js} +1 -1
- package/ui/dist/assets/markdown-renderer-C6ENbB0u.js +10 -0
- package/ui/dist/assets/markdown-renderer-CfVKi3_s.css +1 -0
- package/ui/dist/assets/{message-square-CBgH65X7.js → message-square-Bbb241am.js} +1 -1
- package/ui/dist/assets/package-CwT3IzFx.js +1 -0
- package/ui/dist/assets/{pencil-CYXCEPQh.js → pencil-CDmiHzoj.js} +1 -1
- package/ui/dist/assets/{play-d1ONaH0-.js → play-tjy5jMQX.js} +1 -1
- package/ui/dist/assets/popover-CFHZf3pE.js +1 -0
- package/ui/dist/assets/progress-BboUHuLf.js +1 -0
- package/ui/dist/assets/{rocket-DhvUetsk.js → rocket--8ZHgdXJ.js} +1 -1
- package/ui/dist/assets/select-n108rXny.js +1 -0
- package/ui/dist/assets/{send-P0r5D7td.js → send-Cu7MR2Qh.js} +1 -1
- package/ui/dist/assets/server-DmodxZp-.js +1 -0
- package/ui/dist/assets/{settings-2-ocj5uHGx.js → settings-2-CkRNqkxj.js} +1 -1
- package/ui/dist/assets/sheet-7aUJkyzU.js +1 -0
- package/ui/dist/assets/{shield-check-DfVdE34l.js → shield-check-ViI3nMKE.js} +1 -1
- package/ui/dist/assets/{shield-off-8l0J6R-8.js → shield-off-DN3tagkn.js} +1 -1
- package/ui/dist/assets/skeleton-C0E1Nfro.js +1 -0
- package/ui/dist/assets/{smartphone-77_g3SQn.js → smartphone-5FghiXpA.js} +1 -1
- package/ui/dist/assets/{square-Ckzsr3Rn.js → square-DiNSx8K7.js} +1 -1
- package/ui/dist/assets/star-DhdFVidS.js +1 -0
- package/ui/dist/assets/switch-CIgVbZqQ.js +1 -0
- package/ui/dist/assets/table-BC56FVMV.js +1 -0
- package/ui/dist/assets/{tag-C35mgoEv.js → tag-CH_vQliw.js} +1 -1
- package/ui/dist/assets/textarea-CxDiKFXZ.js +1 -0
- package/ui/dist/assets/{timer-DHJBS2w1.js → timer-CdGVTb60.js} +1 -1
- package/ui/dist/assets/tooltip-BuW9A5UO.js +1 -0
- package/ui/dist/assets/{trash-2-keO5tKPE.js → trash-2-CucZJL0N.js} +1 -1
- package/ui/dist/assets/trending-down-BCezC1z2.js +1 -0
- package/ui/dist/assets/{trending-up-BBv8KbrY.js → trending-up-C5OYX2k2.js} +1 -1
- package/ui/dist/assets/vendor-query-C0p7b53x.js +4 -0
- package/ui/dist/assets/vendor-react-Mc5_kfYG.js +12 -0
- package/ui/dist/assets/vendor-ui-CXPAUBFv.js +51 -0
- package/ui/dist/assets/{wand-sparkles-BusQ52ZK.js → wand-sparkles-BaH6pJnc.js} +1 -1
- package/ui/dist/assets/{wrench-02YaOSiK.js → wrench-CjxjP6ok.js} +1 -1
- package/ui/dist/index.html +5 -2
- package/ui/dist/assets/ActivityView-BeshZXmE.js +0 -1
- package/ui/dist/assets/AgentList-QVHeldPi.js +0 -1
- package/ui/dist/assets/AnalyticsDashboard-C9R97dXE.js +0 -1
- package/ui/dist/assets/AreaChart-B73gaiVQ.js +0 -1
- package/ui/dist/assets/CartesianChart-CXYL2R-A.js +0 -36
- package/ui/dist/assets/ChatView-qjZErlrp.js +0 -10
- package/ui/dist/assets/CostsDashboard-O4DCLy1i.js +0 -1
- package/ui/dist/assets/EstimateSelect-1hQf4Osk.js +0 -1
- package/ui/dist/assets/FloatingChatbot-BZBzrJxd.js +0 -2
- package/ui/dist/assets/InviteCodeManagement-LEoGqYeA.js +0 -2
- package/ui/dist/assets/ProjectIcon-Chd_ofsw.js +0 -1
- package/ui/dist/assets/ProjectList-BvUfVB6c.js +0 -4
- package/ui/dist/assets/StatusIndicator-pRfkNcdV.js +0 -1
- package/ui/dist/assets/SummaryList-B6kXiTxL.js +0 -1
- package/ui/dist/assets/TaskDetail-CV6CzbOS.js +0 -1
- package/ui/dist/assets/TaskList-DL7brQKd.js +0 -1
- package/ui/dist/assets/TicketBoard-CrkkFj7C.js +0 -1
- package/ui/dist/assets/TicketDetail-hnnYclpD.js +0 -1
- package/ui/dist/assets/TicketList-CsDAyQCL.js +0 -1
- package/ui/dist/assets/UserManagement-BGFQyTSr.js +0 -2
- package/ui/dist/assets/ViewSwitcher-CnL0OqA8.js +0 -1
- package/ui/dist/assets/alert-dialog-SKM6Gjz4.js +0 -7
- package/ui/dist/assets/badge-CVHH1a-v.js +0 -1
- package/ui/dist/assets/brain-6o_RHVpe.js +0 -1
- package/ui/dist/assets/constants-Q5Zivl-a.js +0 -1
- package/ui/dist/assets/dialog-BUqN9Psj.js +0 -1
- package/ui/dist/assets/index-BUmnwPQr.js +0 -1
- package/ui/dist/assets/index-BfF5G4Cw.js +0 -1
- package/ui/dist/assets/index-C8N375c2.js +0 -1
- package/ui/dist/assets/index-CuxnqVVz.css +0 -1
- package/ui/dist/assets/index-CzMM3QOk.js +0 -1
- package/ui/dist/assets/index-lJlNPFVJ.js +0 -67
- package/ui/dist/assets/layers-jFqVrWMD.js +0 -1
- package/ui/dist/assets/markdown-renderer-n1ToC4XQ.js +0 -36
- package/ui/dist/assets/popover-CrmZgoWu.js +0 -1
- package/ui/dist/assets/progress-uv4SPkL5.js +0 -1
- package/ui/dist/assets/select-CeQ8AHGy.js +0 -1
- package/ui/dist/assets/server-CVHTZB72.js +0 -1
- package/ui/dist/assets/sheet-DuQExSho.js +0 -1
- package/ui/dist/assets/skeleton-TFiFJ3nB.js +0 -1
- package/ui/dist/assets/switch-CAePkd6k.js +0 -1
- package/ui/dist/assets/table-ZjAZ7hkt.js +0 -1
- package/ui/dist/assets/textarea-DsVPnSgR.js +0 -1
- package/ui/dist/assets/tooltip-BYmQ331W.js +0 -1
package/dist/agents/executor.js
CHANGED
|
@@ -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
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
243
|
-
|
|
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
|
|
247
|
-
this.emit("
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
276
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
this.
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
|
|
301
|
-
|
|
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
|
-
|
|
304
|
-
|
|
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
|
|
381
|
-
|
|
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
|
-
|
|
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 ||
|