profclaw 2.0.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -2
- package/CHANGELOG.md +52 -0
- package/CONTRIBUTING.md +20 -0
- package/Dockerfile +39 -23
- package/README.md +178 -41
- package/config/pricing.yml +26 -2
- 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/command-sandbox.d.ts +93 -0
- package/dist/agents/command-sandbox.js +235 -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-runner.d.ts +135 -0
- package/dist/agents/executor-runner.js +303 -0
- package/dist/agents/executor.d.ts +37 -1
- package/dist/agents/executor.js +606 -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/output-truncator.d.ts +59 -0
- package/dist/agents/output-truncator.js +128 -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/receipt/receipt-cli.d.ts +43 -0
- package/dist/agents/receipt/receipt-cli.js +82 -0
- package/dist/agents/receipt/receipt-types.d.ts +136 -0
- package/dist/agents/receipt/receipt-types.js +19 -0
- package/dist/agents/receipt/receipt-verify.d.ts +19 -0
- package/dist/agents/receipt/receipt-verify.js +176 -0
- package/dist/agents/receipt/receipt-view.d.ts +29 -0
- package/dist/agents/receipt/receipt-view.js +227 -0
- package/dist/agents/receipt/receipt-writer.d.ts +47 -0
- package/dist/agents/receipt/receipt-writer.js +186 -0
- package/dist/agents/result-store.d.ts +43 -0
- package/dist/agents/result-store.js +145 -0
- package/dist/agents/session-diff.d.ts +49 -0
- package/dist/agents/session-diff.js +249 -0
- package/dist/agents/tool-loader.d.ts +65 -0
- package/dist/agents/tool-loader.js +273 -0
- package/dist/agents/tool-selector.d.ts +123 -0
- package/dist/agents/tool-selector.js +321 -0
- package/dist/agents/transcript.d.ts +96 -0
- package/dist/agents/transcript.js +267 -0
- package/dist/agents/verified-run-git.d.ts +49 -0
- package/dist/agents/verified-run-git.js +82 -0
- package/dist/agents/verified-run.d.ts +149 -0
- package/dist/agents/verified-run.js +402 -0
- package/dist/agents/verifier.d.ts +64 -0
- package/dist/agents/verifier.js +186 -0
- package/dist/agents/worktree-manager.d.ts +80 -0
- package/dist/agents/worktree-manager.js +203 -0
- package/dist/agents/worktree-tools.d.ts +47 -0
- package/dist/agents/worktree-tools.js +246 -0
- package/dist/auth/middleware.js +14 -0
- package/dist/chat/agentic-executor.d.ts +7 -0
- package/dist/chat/agentic-executor.js +263 -32
- 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/sandbox.d.ts +8 -0
- package/dist/chat/execution/sandbox.js +25 -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/tools/tts-speak.d.ts +2 -2
- 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/meta-tool-handlers.d.ts +18 -0
- package/dist/chat/meta-tool-handlers.js +51 -0
- 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 +121 -61
- package/dist/chat/tool-handler.d.ts +2 -0
- package/dist/chat/tool-handler.js +47 -3
- 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/receipt.d.ts +7 -0
- package/dist/cli/commands/receipt.js +90 -0
- package/dist/cli/commands/run.d.ts +28 -0
- package/dist/cli/commands/run.js +204 -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 +23 -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/costs/token-tracker.d.ts +10 -1
- package/dist/costs/token-tracker.js +37 -5
- 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 +111 -56
- package/dist/providers/core/models.js +114 -6
- package/dist/providers/core/types.d.ts +7 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/prompt-cache.d.ts +68 -0
- package/dist/providers/prompt-cache.js +165 -0
- package/dist/providers/smart-router.d.ts +118 -0
- package/dist/providers/smart-router.js +693 -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 +280 -18
- 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 +313 -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,16 @@ import { randomUUID } from "node:crypto";
|
|
|
11
11
|
import { EventEmitter } from "node:events";
|
|
12
12
|
import { EFFORT_BUDGET_MAP } from "./types.js";
|
|
13
13
|
import { defaultStopConditions, taskCompleted } from "./stop-conditions.js";
|
|
14
|
+
import { ToolCircuitBreaker } from "./circuit-breaker.js";
|
|
14
15
|
import { logger } from "../utils/logger.js";
|
|
16
|
+
import { applyAnthropicMessageCache, applyAnthropicToolCache, extractCacheUsage, } from "../providers/prompt-cache.js";
|
|
17
|
+
import { trackChatUsage } from "../costs/token-tracker.js";
|
|
18
|
+
import { ResultStore } from "./result-store.js";
|
|
19
|
+
import { getAgentSummaryTracker } from "./agent-summary.js";
|
|
20
|
+
import { getHookRegistry } from "../hooks/registry.js";
|
|
21
|
+
import { ContextCompactor } from "./context-compactor.js";
|
|
22
|
+
import { getSleepPreventer } from "../utils/prevent-sleep.js";
|
|
23
|
+
import { getCheckpointManager } from "./checkpoint-manager.js";
|
|
15
24
|
// Default Configuration
|
|
16
25
|
const DEFAULT_CONFIG = {
|
|
17
26
|
maxSteps: 100,
|
|
@@ -123,10 +132,21 @@ export class AgentExecutor extends EventEmitter {
|
|
|
123
132
|
config;
|
|
124
133
|
abortController;
|
|
125
134
|
isRunning = false;
|
|
135
|
+
resultStore;
|
|
136
|
+
circuitBreaker = new ToolCircuitBreaker();
|
|
137
|
+
hooks;
|
|
138
|
+
compactor;
|
|
139
|
+
checkpointManager = getCheckpointManager();
|
|
126
140
|
constructor(sessionId, conversationId, goal, config = {}) {
|
|
127
141
|
super();
|
|
128
142
|
this.abortController = new AbortController();
|
|
129
143
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
144
|
+
this.resultStore = new ResultStore(sessionId);
|
|
145
|
+
this.hooks = getHookRegistry();
|
|
146
|
+
this.compactor = new ContextCompactor({
|
|
147
|
+
maxContextTokens: this.config.maxBudget,
|
|
148
|
+
compactionThreshold: Math.floor(this.config.maxBudget * 0.7),
|
|
149
|
+
});
|
|
130
150
|
// Ensure taskCompleted is always included in stop conditions
|
|
131
151
|
if (!this.config.stopConditions.some((c) => c.name === "taskCompleted")) {
|
|
132
152
|
this.config.stopConditions.push(taskCompleted());
|
|
@@ -154,14 +174,20 @@ export class AgentExecutor extends EventEmitter {
|
|
|
154
174
|
maxSteps: this.config.maxSteps,
|
|
155
175
|
maxBudget: this.config.maxBudget,
|
|
156
176
|
});
|
|
177
|
+
// Register this session with the summary tracker
|
|
178
|
+
getAgentSummaryTracker().start(sessionId);
|
|
157
179
|
}
|
|
158
180
|
// Public API
|
|
159
181
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
182
|
+
* Async generator that streams agent events as they happen.
|
|
183
|
+
*
|
|
184
|
+
* Yields AgentEvent values in real time: session:start, step:start,
|
|
185
|
+
* tool:call, tool:result/tool:error, content, cost:update, step:complete,
|
|
186
|
+
* and finally session:complete, session:error, or session:abort.
|
|
187
|
+
*
|
|
188
|
+
* This is the canonical implementation; run() delegates here.
|
|
163
189
|
*/
|
|
164
|
-
async
|
|
190
|
+
async *stream(model, messages, tools, onToolExecute, providerHint) {
|
|
165
191
|
if (this.isRunning) {
|
|
166
192
|
throw new Error("Agent is already running");
|
|
167
193
|
}
|
|
@@ -169,140 +195,343 @@ export class AgentExecutor extends EventEmitter {
|
|
|
169
195
|
this.state.status = "running";
|
|
170
196
|
this.state.updatedAt = Date.now();
|
|
171
197
|
this.emit("start", this.state);
|
|
172
|
-
|
|
198
|
+
getSleepPreventer().start();
|
|
199
|
+
logger.info("[AgentExecutor] Starting agent stream", {
|
|
173
200
|
sessionId: this.state.sessionId,
|
|
174
201
|
goal: this.state.goal,
|
|
175
202
|
});
|
|
176
|
-
|
|
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
|
-
|
|
203
|
+
// --- Async event channel ---
|
|
204
|
+
// onStepFinish is a synchronous callback inside generateText. We bridge it
|
|
205
|
+
// into the async generator by queuing events and signalling the consumer.
|
|
206
|
+
const queue = [];
|
|
207
|
+
let resolveNext;
|
|
208
|
+
let generateDone = false;
|
|
209
|
+
let generateError;
|
|
210
|
+
const push = (event) => {
|
|
211
|
+
queue.push(event);
|
|
212
|
+
if (resolveNext) {
|
|
213
|
+
const r = resolveNext;
|
|
214
|
+
resolveNext = undefined;
|
|
215
|
+
r();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
// Yield session:start immediately
|
|
219
|
+
push({
|
|
220
|
+
type: 'session:start',
|
|
221
|
+
sessionId: this.state.sessionId,
|
|
222
|
+
config: {
|
|
223
|
+
maxSteps: this.config.maxSteps,
|
|
224
|
+
maxBudget: this.config.maxBudget,
|
|
225
|
+
effort: this.config.effort,
|
|
226
|
+
securityMode: this.config.securityMode,
|
|
227
|
+
stepTimeoutMs: this.config.stepTimeoutMs,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
// Run generateText in the background, pushing events via push()
|
|
231
|
+
const generatePromise = (async () => {
|
|
232
|
+
try {
|
|
233
|
+
// Fire onSessionStart hook
|
|
234
|
+
await this.hooks.run('onSessionStart', {
|
|
235
|
+
hookPoint: 'onSessionStart',
|
|
236
|
+
sessionId: this.state.sessionId,
|
|
237
|
+
metadata: {},
|
|
238
|
+
});
|
|
239
|
+
this.injectFailureHint(messages);
|
|
240
|
+
// Use the streaming-aware wrapper so tool events are pushed in real time
|
|
241
|
+
const executableTools = this.wrapToolsWithExecuteAndEvents(tools, onToolExecute, push);
|
|
242
|
+
// Compact context before the API call if messages are large
|
|
243
|
+
const compactionResult = await this.compactor.compact(messages);
|
|
244
|
+
if (compactionResult.compacted) {
|
|
245
|
+
logger.info("[AgentExecutor] Context compacted before API call", {
|
|
246
|
+
originalTokens: compactionResult.originalTokens,
|
|
247
|
+
compactedTokens: compactionResult.compactedTokens,
|
|
248
|
+
turnsCompacted: compactionResult.turnsCompacted,
|
|
249
|
+
});
|
|
250
|
+
messages = compactionResult.messages;
|
|
251
|
+
}
|
|
252
|
+
const hasTools = Object.keys(executableTools).length > 0;
|
|
253
|
+
const providerOptions = this.buildProviderOptions(providerHint);
|
|
254
|
+
const result = await generateText({
|
|
255
|
+
model,
|
|
256
|
+
messages: applyAnthropicMessageCache(messages, providerHint ?? ''),
|
|
257
|
+
tools: hasTools ? applyAnthropicToolCache(executableTools, providerHint ?? '') : undefined,
|
|
258
|
+
...(providerOptions ? { providerOptions } : {}),
|
|
259
|
+
stopWhen: [
|
|
260
|
+
sdkStepCountIs(this.config.maxSteps),
|
|
261
|
+
sdkHasToolCall("complete_task"),
|
|
262
|
+
],
|
|
263
|
+
abortSignal: this.abortController.signal,
|
|
264
|
+
onStepFinish: (step) => {
|
|
265
|
+
const stepIndex = this.state.currentStep;
|
|
266
|
+
push({ type: 'step:start', stepIndex });
|
|
267
|
+
this.state.currentStep++;
|
|
268
|
+
this.state.updatedAt = Date.now();
|
|
269
|
+
const stepInput = getUsageInputTokens(step.usage);
|
|
270
|
+
const stepOutput = getUsageOutputTokens(step.usage);
|
|
271
|
+
const tokensUsed = stepInput + stepOutput;
|
|
272
|
+
this.state.usedBudget += tokensUsed;
|
|
273
|
+
this.state.inputTokensUsed += stepInput;
|
|
274
|
+
this.state.outputTokensUsed += stepOutput;
|
|
275
|
+
const cacheUsage = extractCacheUsage(step.usage);
|
|
276
|
+
this.trackStepUsage(model, stepInput, stepOutput, cacheUsage);
|
|
277
|
+
if (cacheUsage.cacheReadTokens > 0 || cacheUsage.cacheWriteTokens > 0) {
|
|
278
|
+
logger.debug("[AgentExecutor] Prompt cache usage", {
|
|
279
|
+
sessionId: this.state.sessionId,
|
|
280
|
+
cacheReadTokens: cacheUsage.cacheReadTokens,
|
|
281
|
+
cacheWriteTokens: cacheUsage.cacheWriteTokens,
|
|
282
|
+
promptTokens: cacheUsage.promptTokens,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// Update summary tracker with step progress
|
|
286
|
+
getAgentSummaryTracker().update(this.state.sessionId, {
|
|
287
|
+
status: 'thinking',
|
|
288
|
+
stepCount: this.state.currentStep,
|
|
289
|
+
tokensUsed: this.state.usedBudget,
|
|
290
|
+
});
|
|
291
|
+
push({
|
|
292
|
+
type: 'cost:update',
|
|
293
|
+
inputTokens: this.state.inputTokensUsed,
|
|
294
|
+
outputTokens: this.state.outputTokensUsed,
|
|
295
|
+
estimatedCost: 0,
|
|
296
|
+
});
|
|
297
|
+
if (step.text) {
|
|
298
|
+
this.state.context.lastTextResponse = step.text;
|
|
299
|
+
push({ type: 'content', text: step.text, delta: step.text });
|
|
300
|
+
}
|
|
301
|
+
let stepToolCalls = 0;
|
|
302
|
+
for (const tc of step.toolCalls ?? []) {
|
|
303
|
+
stepToolCalls++;
|
|
304
|
+
const record = {
|
|
305
|
+
id: tc.toolCallId ?? randomUUID(),
|
|
306
|
+
name: tc.toolName,
|
|
307
|
+
args: getToolCallInput(tc),
|
|
308
|
+
status: "pending",
|
|
309
|
+
startedAt: Date.now(),
|
|
310
|
+
};
|
|
311
|
+
const tr = (step.toolResults ?? []).find((toolResult) => toolResult.toolCallId === tc.toolCallId);
|
|
312
|
+
if (tr) {
|
|
313
|
+
record.result = getToolResultOutput(tr);
|
|
314
|
+
record.completedAt = Date.now();
|
|
315
|
+
if (typeof record.result === "object" && record.result !== null) {
|
|
316
|
+
const resultObj = record.result;
|
|
317
|
+
const isPending = resultObj.pending === true;
|
|
318
|
+
const hasError = Boolean(resultObj.error);
|
|
319
|
+
const isFailure = resultObj.success === false || hasError;
|
|
320
|
+
if (isPending) {
|
|
321
|
+
record.status = "pending";
|
|
322
|
+
}
|
|
323
|
+
else if (isFailure) {
|
|
324
|
+
record.status = "failed";
|
|
325
|
+
record.error =
|
|
326
|
+
resultObj.error ||
|
|
327
|
+
"Tool returned unsuccessful result";
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
record.status = "executed";
|
|
331
|
+
}
|
|
237
332
|
}
|
|
238
333
|
else {
|
|
239
334
|
record.status = "executed";
|
|
240
335
|
}
|
|
241
336
|
}
|
|
242
|
-
|
|
243
|
-
|
|
337
|
+
this.state.toolCallHistory.push(record);
|
|
338
|
+
this.emit("tool:call", this.state, record);
|
|
339
|
+
this.extractContext(record);
|
|
340
|
+
if (record.status === "executed") {
|
|
341
|
+
this.emit("tool:result", this.state, record);
|
|
244
342
|
}
|
|
245
343
|
}
|
|
246
|
-
this.state
|
|
247
|
-
this.emit("
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
344
|
+
this.emit("step:start", this.state);
|
|
345
|
+
this.emit("step:complete", this.state, step);
|
|
346
|
+
push({
|
|
347
|
+
type: 'step:complete',
|
|
348
|
+
stepIndex: this.state.currentStep,
|
|
349
|
+
toolCalls: stepToolCalls,
|
|
350
|
+
hasContent: Boolean(step.text),
|
|
351
|
+
});
|
|
352
|
+
logger.debug("[AgentExecutor] Step completed", {
|
|
353
|
+
step: this.state.currentStep,
|
|
354
|
+
toolCalls: step.toolCalls?.length ?? 0,
|
|
355
|
+
tokensUsed,
|
|
356
|
+
text: step.text?.substring(0, 100),
|
|
357
|
+
});
|
|
358
|
+
this.checkCustomStopConditions(step);
|
|
359
|
+
// Emit a budget warning when 80% of the token budget is consumed
|
|
360
|
+
const usedPercent = this.state.maxBudget > 0
|
|
361
|
+
? (this.state.usedBudget / this.state.maxBudget) * 100
|
|
362
|
+
: 0;
|
|
363
|
+
if (usedPercent >= 80 && usedPercent < 100) {
|
|
364
|
+
push({
|
|
365
|
+
type: 'budget:warning',
|
|
366
|
+
usedPercent: Math.round(usedPercent),
|
|
367
|
+
tokensUsed: this.state.usedBudget,
|
|
368
|
+
tokensMax: this.state.maxBudget,
|
|
369
|
+
});
|
|
252
370
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
371
|
+
// Save a checkpoint every 5 steps so the session can be resumed
|
|
372
|
+
// (re-use stepIndex which was declared at the top of onStepFinish)
|
|
373
|
+
const currentStepForCheckpoint = this.state.currentStep;
|
|
374
|
+
if (currentStepForCheckpoint > 0 && currentStepForCheckpoint % 5 === 0) {
|
|
375
|
+
const checkpoint = {
|
|
376
|
+
sessionId: this.state.sessionId,
|
|
377
|
+
taskDescription: this.state.goal,
|
|
378
|
+
currentStep: currentStepForCheckpoint,
|
|
379
|
+
totalSteps: this.config.maxSteps,
|
|
380
|
+
messages: [...messages],
|
|
381
|
+
tokensUsed: this.state.usedBudget,
|
|
382
|
+
estimatedCost: 0,
|
|
383
|
+
toolCallHistory: this.state.toolCallHistory.map((tc) => ({
|
|
384
|
+
name: tc.name,
|
|
385
|
+
success: tc.status === 'executed',
|
|
386
|
+
step: currentStepForCheckpoint,
|
|
387
|
+
})),
|
|
388
|
+
completedFiles: (this.state.context.modifiedFiles ?? []).slice(),
|
|
389
|
+
createdAt: this.state.createdAt,
|
|
390
|
+
updatedAt: Date.now(),
|
|
391
|
+
};
|
|
392
|
+
void this.checkpointManager.save(checkpoint).then(() => {
|
|
393
|
+
push({ type: 'checkpoint:saved', sessionId: this.state.sessionId, step: currentStepForCheckpoint });
|
|
394
|
+
}).catch((err) => {
|
|
395
|
+
logger.warn("[AgentExecutor] Failed to save checkpoint", { err });
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (this.state.usedBudget >= this.state.maxBudget) {
|
|
399
|
+
logger.info("[AgentExecutor] Budget exceeded, aborting", {
|
|
400
|
+
used: this.state.usedBudget,
|
|
401
|
+
max: this.state.maxBudget,
|
|
402
|
+
});
|
|
403
|
+
this.abortController.abort();
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
const totalUsage = result.totalUsage;
|
|
408
|
+
if (totalUsage) {
|
|
409
|
+
const totalInput = getUsageInputTokens(totalUsage);
|
|
410
|
+
const totalOutput = getUsageOutputTokens(totalUsage);
|
|
411
|
+
this.state.usedBudget = totalInput + totalOutput;
|
|
412
|
+
this.state.inputTokensUsed = totalInput;
|
|
413
|
+
this.state.outputTokensUsed = totalOutput;
|
|
414
|
+
}
|
|
415
|
+
if (result.text) {
|
|
416
|
+
this.state.context.lastTextResponse = result.text;
|
|
417
|
+
}
|
|
418
|
+
this.finalize();
|
|
419
|
+
// Fire onSessionEnd hook after finalization
|
|
420
|
+
await this.hooks.run('onSessionEnd', {
|
|
421
|
+
hookPoint: 'onSessionEnd',
|
|
422
|
+
sessionId: this.state.sessionId,
|
|
423
|
+
metadata: {},
|
|
424
|
+
});
|
|
425
|
+
const finalResult = this.state.finalResult ?? {
|
|
426
|
+
success: false,
|
|
427
|
+
summary: 'No result',
|
|
428
|
+
artifacts: [],
|
|
429
|
+
stopReason: 'unknown',
|
|
430
|
+
totalSteps: this.state.currentStep,
|
|
431
|
+
totalTokens: this.state.usedBudget,
|
|
432
|
+
};
|
|
433
|
+
push({
|
|
434
|
+
type: 'session:complete',
|
|
435
|
+
result: finalResult,
|
|
436
|
+
totalSteps: this.state.currentStep,
|
|
437
|
+
totalTokens: this.state.usedBudget,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
const err = error;
|
|
442
|
+
if (err.name === "AbortError") {
|
|
443
|
+
logger.info("[AgentExecutor] Agent aborted");
|
|
444
|
+
this.finalize();
|
|
445
|
+
// Fire onSessionEnd even on abort
|
|
446
|
+
await this.hooks.run('onSessionEnd', {
|
|
447
|
+
hookPoint: 'onSessionEnd',
|
|
448
|
+
sessionId: this.state.sessionId,
|
|
449
|
+
metadata: { aborted: true },
|
|
262
450
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
451
|
+
push({ type: 'session:abort', reason: 'aborted' });
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
generateError = err;
|
|
455
|
+
// Fire onError hook before emitting the event
|
|
456
|
+
await this.hooks.run('onError', {
|
|
457
|
+
hookPoint: 'onError',
|
|
458
|
+
sessionId: this.state.sessionId,
|
|
459
|
+
error: err,
|
|
460
|
+
metadata: {},
|
|
461
|
+
});
|
|
462
|
+
// Push the event BEFORE handleError so it is always emitted even if
|
|
463
|
+
// the EventEmitter 'error' event throws due to missing listener.
|
|
464
|
+
push({ type: 'session:error', error: err.message, stack: err.stack });
|
|
465
|
+
try {
|
|
466
|
+
this.handleError(err);
|
|
272
467
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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;
|
|
468
|
+
catch {
|
|
469
|
+
// Swallow re-throw from EventEmitter if no 'error' listener is attached
|
|
470
|
+
}
|
|
471
|
+
}
|
|
284
472
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
this.
|
|
473
|
+
finally {
|
|
474
|
+
generateDone = true;
|
|
475
|
+
this.isRunning = false;
|
|
476
|
+
getSleepPreventer().stop();
|
|
477
|
+
if (resolveNext) {
|
|
478
|
+
const r = resolveNext;
|
|
479
|
+
resolveNext = undefined;
|
|
480
|
+
r();
|
|
481
|
+
}
|
|
288
482
|
}
|
|
289
|
-
|
|
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;
|
|
483
|
+
})();
|
|
484
|
+
// Drain the queue; wait for more events when it is empty
|
|
485
|
+
while (true) {
|
|
486
|
+
while (queue.length > 0) {
|
|
487
|
+
yield queue.shift();
|
|
299
488
|
}
|
|
300
|
-
|
|
301
|
-
|
|
489
|
+
if (generateDone)
|
|
490
|
+
break;
|
|
491
|
+
await new Promise((resolve) => {
|
|
492
|
+
resolveNext = resolve;
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
// Drain any remaining events that arrived while we were awaiting
|
|
496
|
+
while (queue.length > 0) {
|
|
497
|
+
yield queue.shift();
|
|
302
498
|
}
|
|
303
|
-
|
|
304
|
-
|
|
499
|
+
// Propagate errors after the consumer has seen all events
|
|
500
|
+
await generatePromise;
|
|
501
|
+
if (generateError) {
|
|
502
|
+
throw generateError;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Run the agent until completion or stop condition.
|
|
507
|
+
* Uses AI SDK's native multi-step execution — a single generateText call
|
|
508
|
+
* with stopWhen + onStepFinish replaces the old manual loop.
|
|
509
|
+
*
|
|
510
|
+
* Backward-compatible: delegates to stream() and returns the final AgentState.
|
|
511
|
+
*/
|
|
512
|
+
async run(model, messages, tools, onToolExecute, providerHint) {
|
|
513
|
+
// Consume the stream — stream() handles all state mutation and error handling
|
|
514
|
+
for await (const _event of this.stream(model, messages, tools, onToolExecute, providerHint)) {
|
|
515
|
+
// Individual events are not needed here; state is updated in-place
|
|
305
516
|
}
|
|
517
|
+
return this.state;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Resume execution from a saved checkpoint.
|
|
521
|
+
*
|
|
522
|
+
* Restores the message history and step counter from the checkpoint, emits a
|
|
523
|
+
* checkpoint:resumed event, then continues with generateText from that point.
|
|
524
|
+
*/
|
|
525
|
+
async *resume(checkpoint, model, tools, onToolExecute, providerHint) {
|
|
526
|
+
// Restore step counter so subsequent checkpoints use the right step index
|
|
527
|
+
this.state.currentStep = checkpoint.currentStep;
|
|
528
|
+
this.state.usedBudget = checkpoint.tokensUsed;
|
|
529
|
+
this.state.goal = checkpoint.taskDescription ?? this.state.goal;
|
|
530
|
+
this.state.createdAt = checkpoint.createdAt;
|
|
531
|
+
// Emit resumed event before the stream starts
|
|
532
|
+
yield { type: 'checkpoint:resumed', sessionId: checkpoint.sessionId, step: checkpoint.currentStep };
|
|
533
|
+
// Delegate to stream() with the restored messages
|
|
534
|
+
yield* this.stream(model, checkpoint.messages, tools, onToolExecute, providerHint);
|
|
306
535
|
}
|
|
307
536
|
/**
|
|
308
537
|
* Cancel the running agent.
|
|
@@ -375,14 +604,67 @@ export class AgentExecutor extends EventEmitter {
|
|
|
375
604
|
for (const [name, toolDef] of Object.entries(tools)) {
|
|
376
605
|
wrapped[name] = {
|
|
377
606
|
...toolDef,
|
|
378
|
-
execute: async (args) => {
|
|
607
|
+
execute: async (args, opts) => {
|
|
608
|
+
// Circuit breaker check — prevent repeated calls to a failing tool
|
|
609
|
+
const cbCheck = this.circuitBreaker.canExecute(name);
|
|
610
|
+
if (!cbCheck.allowed) {
|
|
611
|
+
logger.warn("[AgentExecutor] Circuit breaker blocked tool call", {
|
|
612
|
+
tool: name,
|
|
613
|
+
reason: cbCheck.reason,
|
|
614
|
+
});
|
|
615
|
+
return {
|
|
616
|
+
error: cbCheck.reason ?? `Circuit breaker open for ${name}`,
|
|
617
|
+
success: false,
|
|
618
|
+
canRetry: false,
|
|
619
|
+
suggestion: "Try an alternative approach",
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
const toolCallId = opts?.toolCallId ?? randomUUID();
|
|
623
|
+
const timeoutMs = this.config.stepTimeoutMs;
|
|
624
|
+
// Update summary tracker — tool is now executing
|
|
625
|
+
const summaryTracker = getAgentSummaryTracker();
|
|
626
|
+
const currentAction = summaryTracker.summarizeToolCall(this.state.sessionId, name, args);
|
|
627
|
+
summaryTracker.update(this.state.sessionId, {
|
|
628
|
+
status: 'executing',
|
|
629
|
+
currentAction,
|
|
630
|
+
lastToolName: name,
|
|
631
|
+
lastToolArgs: JSON.stringify(args).substring(0, 100),
|
|
632
|
+
});
|
|
633
|
+
let timeoutHandle;
|
|
634
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
635
|
+
timeoutHandle = setTimeout(() => {
|
|
636
|
+
reject(new Error(`__TOOL_TIMEOUT__:${timeoutMs}`));
|
|
637
|
+
}, timeoutMs);
|
|
638
|
+
});
|
|
379
639
|
try {
|
|
380
|
-
const
|
|
381
|
-
|
|
640
|
+
const raw = await Promise.race([
|
|
641
|
+
onToolExecute(name, args),
|
|
642
|
+
timeoutPromise,
|
|
643
|
+
]);
|
|
644
|
+
clearTimeout(timeoutHandle);
|
|
645
|
+
this.circuitBreaker.recordSuccess(name);
|
|
646
|
+
const stored = await this.resultStore.store(toolCallId, raw);
|
|
647
|
+
// Return the inline representation (summary or full result)
|
|
648
|
+
return JSON.parse(stored.inline);
|
|
382
649
|
}
|
|
383
650
|
catch (error) {
|
|
384
|
-
|
|
651
|
+
clearTimeout(timeoutHandle);
|
|
385
652
|
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
653
|
+
// Timeout path
|
|
654
|
+
if (errorMsg.startsWith("__TOOL_TIMEOUT__:")) {
|
|
655
|
+
const ms = errorMsg.split(":")[1];
|
|
656
|
+
logger.warn("[AgentExecutor] Tool execution timed out", {
|
|
657
|
+
tool: name,
|
|
658
|
+
timeoutMs,
|
|
659
|
+
});
|
|
660
|
+
this.circuitBreaker.recordFailure(name);
|
|
661
|
+
return {
|
|
662
|
+
error: `Tool execution timed out after ${ms}ms`,
|
|
663
|
+
success: false,
|
|
664
|
+
canRetry: true,
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
// Regular error path
|
|
386
668
|
const isPermError = errorMsg.toLowerCase().includes("permission") ||
|
|
387
669
|
errorMsg.toLowerCase().includes("unauthorized") ||
|
|
388
670
|
errorMsg.toLowerCase().includes("forbidden") ||
|
|
@@ -391,12 +673,183 @@ export class AgentExecutor extends EventEmitter {
|
|
|
391
673
|
tool: name,
|
|
392
674
|
error: errorMsg,
|
|
393
675
|
});
|
|
676
|
+
this.circuitBreaker.recordFailure(name);
|
|
677
|
+
return {
|
|
678
|
+
error: errorMsg,
|
|
679
|
+
success: false,
|
|
680
|
+
suggestion: "This tool failed. Consider trying a different approach or asking the user for help.",
|
|
681
|
+
canRetry: !isPermError,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
return wrapped;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Like wrapToolsWithExecute, but additionally pushes tool:call, tool:result,
|
|
691
|
+
* and tool:error AgentEvents via the provided push callback so that the
|
|
692
|
+
* stream() generator can yield them in real time.
|
|
693
|
+
*/
|
|
694
|
+
wrapToolsWithExecuteAndEvents(tools, onToolExecute, push) {
|
|
695
|
+
if (!onToolExecute)
|
|
696
|
+
return tools;
|
|
697
|
+
const wrapped = {};
|
|
698
|
+
for (const [name, toolDef] of Object.entries(tools)) {
|
|
699
|
+
wrapped[name] = {
|
|
700
|
+
...toolDef,
|
|
701
|
+
execute: async (args, opts) => {
|
|
702
|
+
const toolCallId = opts?.toolCallId ?? randomUUID();
|
|
703
|
+
// Circuit breaker check
|
|
704
|
+
const cbCheck = this.circuitBreaker.canExecute(name);
|
|
705
|
+
if (!cbCheck.allowed) {
|
|
706
|
+
const reason = cbCheck.reason ?? `Circuit breaker open for ${name}`;
|
|
707
|
+
logger.warn("[AgentExecutor] Circuit breaker blocked tool call", {
|
|
708
|
+
tool: name,
|
|
709
|
+
reason,
|
|
710
|
+
});
|
|
711
|
+
// Emit circuit:open so the consumer knows the breaker tripped
|
|
712
|
+
push({ type: 'circuit:open', toolName: name, cooldownMs: 0 });
|
|
713
|
+
push({ type: 'tool:error', toolCallId, error: reason });
|
|
394
714
|
return {
|
|
715
|
+
error: reason,
|
|
716
|
+
success: false,
|
|
717
|
+
canRetry: false,
|
|
718
|
+
suggestion: "Try an alternative approach",
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
const timeoutMs = this.config.stepTimeoutMs;
|
|
722
|
+
// Update summary tracker — tool is now executing
|
|
723
|
+
const summaryTracker = getAgentSummaryTracker();
|
|
724
|
+
const currentAction = summaryTracker.summarizeToolCall(this.state.sessionId, name, args);
|
|
725
|
+
summaryTracker.update(this.state.sessionId, {
|
|
726
|
+
status: 'executing',
|
|
727
|
+
currentAction,
|
|
728
|
+
lastToolName: name,
|
|
729
|
+
lastToolArgs: JSON.stringify(args).substring(0, 100),
|
|
730
|
+
});
|
|
731
|
+
// beforeToolCall hook — may abort tool execution
|
|
732
|
+
const beforeResult = await this.hooks.run('beforeToolCall', {
|
|
733
|
+
hookPoint: 'beforeToolCall',
|
|
734
|
+
sessionId: this.state.sessionId,
|
|
735
|
+
toolName: name,
|
|
736
|
+
toolArgs: args,
|
|
737
|
+
metadata: {},
|
|
738
|
+
});
|
|
739
|
+
if (!beforeResult.proceed) {
|
|
740
|
+
const blockReason = `Tool "${name}" blocked by hook`;
|
|
741
|
+
logger.info("[AgentExecutor] Tool blocked by beforeToolCall hook", {
|
|
742
|
+
tool: name,
|
|
743
|
+
});
|
|
744
|
+
push({ type: 'tool:error', toolCallId, error: blockReason });
|
|
745
|
+
const blockedResult = {
|
|
746
|
+
error: blockReason,
|
|
747
|
+
success: false,
|
|
748
|
+
canRetry: false,
|
|
749
|
+
suggestion: 'A lifecycle hook prevented this tool from running.',
|
|
750
|
+
};
|
|
751
|
+
push({
|
|
752
|
+
type: 'tool:result',
|
|
753
|
+
toolCallId,
|
|
754
|
+
result: blockedResult,
|
|
755
|
+
duration: 0,
|
|
756
|
+
success: false,
|
|
757
|
+
});
|
|
758
|
+
return blockedResult;
|
|
759
|
+
}
|
|
760
|
+
// Use potentially modified args from the hook
|
|
761
|
+
const effectiveArgs = beforeResult.modified !== undefined && typeof beforeResult.modified === 'object' && beforeResult.modified !== null
|
|
762
|
+
? beforeResult.modified
|
|
763
|
+
: args;
|
|
764
|
+
// Push tool:call event before execution
|
|
765
|
+
push({ type: 'tool:call', toolName: name, args: effectiveArgs, toolCallId });
|
|
766
|
+
let timeoutHandle;
|
|
767
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
768
|
+
timeoutHandle = setTimeout(() => {
|
|
769
|
+
reject(new Error(`__TOOL_TIMEOUT__:${timeoutMs}`));
|
|
770
|
+
}, timeoutMs);
|
|
771
|
+
});
|
|
772
|
+
const startedAt = Date.now();
|
|
773
|
+
try {
|
|
774
|
+
const raw = await Promise.race([
|
|
775
|
+
onToolExecute(name, effectiveArgs),
|
|
776
|
+
timeoutPromise,
|
|
777
|
+
]);
|
|
778
|
+
clearTimeout(timeoutHandle);
|
|
779
|
+
this.circuitBreaker.recordSuccess(name);
|
|
780
|
+
const stored = await this.resultStore.store(toolCallId, raw);
|
|
781
|
+
const inlineResult = JSON.parse(stored.inline);
|
|
782
|
+
const duration = Date.now() - startedAt;
|
|
783
|
+
// afterToolCall hook — receives the result
|
|
784
|
+
await this.hooks.run('afterToolCall', {
|
|
785
|
+
hookPoint: 'afterToolCall',
|
|
786
|
+
sessionId: this.state.sessionId,
|
|
787
|
+
toolName: name,
|
|
788
|
+
toolArgs: effectiveArgs,
|
|
789
|
+
toolResult: inlineResult,
|
|
790
|
+
metadata: {},
|
|
791
|
+
});
|
|
792
|
+
push({
|
|
793
|
+
type: 'tool:result',
|
|
794
|
+
toolCallId,
|
|
795
|
+
result: inlineResult,
|
|
796
|
+
duration,
|
|
797
|
+
success: true,
|
|
798
|
+
});
|
|
799
|
+
return inlineResult;
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
clearTimeout(timeoutHandle);
|
|
803
|
+
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
804
|
+
const duration = Date.now() - startedAt;
|
|
805
|
+
// Timeout path
|
|
806
|
+
if (errorMsg.startsWith("__TOOL_TIMEOUT__:")) {
|
|
807
|
+
const ms = errorMsg.split(":")[1];
|
|
808
|
+
logger.warn("[AgentExecutor] Tool execution timed out", {
|
|
809
|
+
tool: name,
|
|
810
|
+
timeoutMs,
|
|
811
|
+
});
|
|
812
|
+
this.circuitBreaker.recordFailure(name);
|
|
813
|
+
const timeoutResult = {
|
|
814
|
+
error: `Tool execution timed out after ${ms}ms`,
|
|
815
|
+
success: false,
|
|
816
|
+
canRetry: true,
|
|
817
|
+
};
|
|
818
|
+
push({ type: 'tool:error', toolCallId, error: timeoutResult.error });
|
|
819
|
+
push({
|
|
820
|
+
type: 'tool:result',
|
|
821
|
+
toolCallId,
|
|
822
|
+
result: timeoutResult,
|
|
823
|
+
duration,
|
|
824
|
+
success: false,
|
|
825
|
+
});
|
|
826
|
+
return timeoutResult;
|
|
827
|
+
}
|
|
828
|
+
// Regular error path
|
|
829
|
+
const isPermError = errorMsg.toLowerCase().includes("permission") ||
|
|
830
|
+
errorMsg.toLowerCase().includes("unauthorized") ||
|
|
831
|
+
errorMsg.toLowerCase().includes("forbidden") ||
|
|
832
|
+
errorMsg.toLowerCase().includes("not allowed");
|
|
833
|
+
logger.warn("[AgentExecutor] Tool execution failed", {
|
|
834
|
+
tool: name,
|
|
835
|
+
error: errorMsg,
|
|
836
|
+
});
|
|
837
|
+
this.circuitBreaker.recordFailure(name);
|
|
838
|
+
push({ type: 'tool:error', toolCallId, error: errorMsg });
|
|
839
|
+
const errorResult = {
|
|
395
840
|
error: errorMsg,
|
|
396
841
|
success: false,
|
|
397
842
|
suggestion: "This tool failed. Consider trying a different approach or asking the user for help.",
|
|
398
843
|
canRetry: !isPermError,
|
|
399
844
|
};
|
|
845
|
+
push({
|
|
846
|
+
type: 'tool:result',
|
|
847
|
+
toolCallId,
|
|
848
|
+
result: errorResult,
|
|
849
|
+
duration,
|
|
850
|
+
success: false,
|
|
851
|
+
});
|
|
852
|
+
return errorResult;
|
|
400
853
|
}
|
|
401
854
|
},
|
|
402
855
|
};
|
|
@@ -524,8 +977,37 @@ export class AgentExecutor extends EventEmitter {
|
|
|
524
977
|
}
|
|
525
978
|
}
|
|
526
979
|
}
|
|
980
|
+
/** Route one step's usage (with cache tokens) into the cost tracker. */
|
|
981
|
+
trackStepUsage(model, inputTokens, outputTokens, cache) {
|
|
982
|
+
const total = inputTokens + outputTokens;
|
|
983
|
+
if (total <= 0)
|
|
984
|
+
return;
|
|
985
|
+
const modelId = typeof model === "string" ? model : getRecord(model)?.modelId;
|
|
986
|
+
if (typeof modelId !== "string" || modelId.length === 0)
|
|
987
|
+
return;
|
|
988
|
+
try {
|
|
989
|
+
trackChatUsage(modelId, total, inputTokens, outputTokens, {
|
|
990
|
+
cacheReadTokens: cache.cacheReadTokens,
|
|
991
|
+
cacheWriteTokens: cache.cacheWriteTokens,
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
catch (err) {
|
|
995
|
+
logger.warn("[AgentExecutor] Usage tracking failed", {
|
|
996
|
+
sessionId: this.state.sessionId,
|
|
997
|
+
error: err instanceof Error ? err.message : String(err),
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
527
1001
|
// Finalization
|
|
528
1002
|
finalize() {
|
|
1003
|
+
// Clean up any temp files written by the result store (fire-and-forget)
|
|
1004
|
+
this.resultStore.cleanup().catch((err) => {
|
|
1005
|
+
logger.warn("[AgentExecutor] ResultStore cleanup failed", {
|
|
1006
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
// Remove this session from the summary tracker
|
|
1010
|
+
getAgentSummaryTracker().end(this.state.sessionId);
|
|
529
1011
|
const completedViaTask = this.state.toolCallHistory.some((t) => t.name === "complete_task" && t.status === "executed");
|
|
530
1012
|
// Check if agent completed via text response (no tool calls)
|
|
531
1013
|
const completedViaTextResponse = this.state.toolCallHistory.length === 0 ||
|