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
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Agent Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Enables spawning, managing, and merging results from sub-agents.
|
|
5
|
+
* Supports orchestration patterns:
|
|
6
|
+
* - Fan-out: N parallel workers + 1 synthesizer
|
|
7
|
+
* - Pipeline: sequential agent chain (A -> B -> C)
|
|
8
|
+
* - Debate: 2+ agents argue, 1 judges
|
|
9
|
+
*
|
|
10
|
+
* Each sub-agent gets an isolated session with scoped tool access.
|
|
11
|
+
* Parent can set token budgets, timeouts, and tool policies per child.
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from 'node:crypto';
|
|
14
|
+
import { createContextualLogger } from '../utils/logger.js';
|
|
15
|
+
const log = createContextualLogger('Orchestrator');
|
|
16
|
+
// Active orchestrations for cancellation
|
|
17
|
+
const activeOrchestrations = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* Run a sub-agent in an isolated session.
|
|
20
|
+
*/
|
|
21
|
+
async function runSubAgent(config, contextInput, signal) {
|
|
22
|
+
const startTime = Date.now();
|
|
23
|
+
try {
|
|
24
|
+
const { executeAgenticChat } = await import('../chat/agentic-executor.js');
|
|
25
|
+
const { createChatToolHandler } = await import('../chat/tool-handler.js');
|
|
26
|
+
const conversationId = `orchestrator-${config.id}-${randomUUID()}`;
|
|
27
|
+
const toolHandler = await createChatToolHandler({
|
|
28
|
+
conversationId,
|
|
29
|
+
securityMode: 'full',
|
|
30
|
+
});
|
|
31
|
+
// Filter tools if restricted
|
|
32
|
+
const allTools = toolHandler.getTools();
|
|
33
|
+
const tools = config.allowedTools?.length
|
|
34
|
+
? allTools.filter((t) => config.allowedTools.includes(t.name))
|
|
35
|
+
: allTools;
|
|
36
|
+
// Build the prompt - inject pipeline context if provided
|
|
37
|
+
let fullPrompt = config.prompt;
|
|
38
|
+
if (contextInput) {
|
|
39
|
+
fullPrompt = `Context from previous step:\n${contextInput}\n\nYour task:\n${config.prompt}`;
|
|
40
|
+
}
|
|
41
|
+
const response = await Promise.race([
|
|
42
|
+
executeAgenticChat({
|
|
43
|
+
conversationId,
|
|
44
|
+
messages: [{
|
|
45
|
+
id: randomUUID(),
|
|
46
|
+
role: 'user',
|
|
47
|
+
content: fullPrompt,
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
}],
|
|
50
|
+
systemPrompt: config.systemPrompt || 'You are a focused AI agent working on a specific sub-task. Be concise and thorough.',
|
|
51
|
+
model: config.model,
|
|
52
|
+
effort: config.effort || 'medium',
|
|
53
|
+
toolHandler,
|
|
54
|
+
tools: tools.map((t) => ({
|
|
55
|
+
name: t.name,
|
|
56
|
+
description: t.description,
|
|
57
|
+
parameters: t.parameters,
|
|
58
|
+
})),
|
|
59
|
+
}),
|
|
60
|
+
new Promise((_, reject) => {
|
|
61
|
+
const timeout = config.timeoutMs || 300000;
|
|
62
|
+
const timer = setTimeout(() => reject(new Error(`Sub-agent "${config.name}" timed out after ${timeout}ms`)), timeout);
|
|
63
|
+
signal?.addEventListener('abort', () => {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
reject(new Error(`Sub-agent "${config.name}" cancelled`));
|
|
66
|
+
});
|
|
67
|
+
}),
|
|
68
|
+
]);
|
|
69
|
+
return {
|
|
70
|
+
agentId: config.id,
|
|
71
|
+
agentName: config.name,
|
|
72
|
+
success: true,
|
|
73
|
+
output: response.content,
|
|
74
|
+
durationMs: Date.now() - startTime,
|
|
75
|
+
tokensUsed: response.usage?.totalTokens,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
agentId: config.id,
|
|
81
|
+
agentName: config.name,
|
|
82
|
+
success: false,
|
|
83
|
+
output: '',
|
|
84
|
+
error: error instanceof Error ? error.message : String(error),
|
|
85
|
+
durationMs: Date.now() - startTime,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Execute a fan-out orchestration: run N agents in parallel, then synthesize.
|
|
91
|
+
*/
|
|
92
|
+
async function executeFanOut(config, signal) {
|
|
93
|
+
const startTime = Date.now();
|
|
94
|
+
// Run all agents in parallel
|
|
95
|
+
const results = await Promise.allSettled(config.agents.map((agent) => runSubAgent(agent, undefined, signal)));
|
|
96
|
+
const agentResults = results.map((r, i) => {
|
|
97
|
+
if (r.status === 'fulfilled')
|
|
98
|
+
return r.value;
|
|
99
|
+
return {
|
|
100
|
+
agentId: config.agents[i].id,
|
|
101
|
+
agentName: config.agents[i].name,
|
|
102
|
+
success: false,
|
|
103
|
+
output: '',
|
|
104
|
+
error: r.reason instanceof Error ? r.reason.message : String(r.reason),
|
|
105
|
+
durationMs: Date.now() - startTime,
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
// Synthesize results
|
|
109
|
+
let finalOutput = '';
|
|
110
|
+
if (config.synthesizerPrompt) {
|
|
111
|
+
const synthesisInput = agentResults
|
|
112
|
+
.filter((r) => r.success)
|
|
113
|
+
.map((r) => `[${r.agentName}]:\n${r.output}`)
|
|
114
|
+
.join('\n\n---\n\n');
|
|
115
|
+
const synthesisResult = await runSubAgent({
|
|
116
|
+
id: 'synthesizer',
|
|
117
|
+
name: 'Synthesizer',
|
|
118
|
+
prompt: `${config.synthesizerPrompt}\n\nResults from ${agentResults.filter((r) => r.success).length} agents:\n\n${synthesisInput}`,
|
|
119
|
+
model: config.agents[0]?.model,
|
|
120
|
+
effort: 'medium',
|
|
121
|
+
}, undefined, signal);
|
|
122
|
+
agentResults.push(synthesisResult);
|
|
123
|
+
finalOutput = synthesisResult.output;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
finalOutput = agentResults
|
|
127
|
+
.filter((r) => r.success)
|
|
128
|
+
.map((r) => `## ${r.agentName}\n${r.output}`)
|
|
129
|
+
.join('\n\n');
|
|
130
|
+
}
|
|
131
|
+
const totalTokens = agentResults.reduce((sum, r) => sum + (r.tokensUsed || 0), 0);
|
|
132
|
+
return {
|
|
133
|
+
id: config.id,
|
|
134
|
+
pattern: 'fan_out',
|
|
135
|
+
success: agentResults.some((r) => r.success),
|
|
136
|
+
agentResults,
|
|
137
|
+
finalOutput,
|
|
138
|
+
totalDurationMs: Date.now() - startTime,
|
|
139
|
+
totalTokens,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Execute a pipeline orchestration: A -> B -> C
|
|
144
|
+
* Output of each agent becomes context for the next.
|
|
145
|
+
*/
|
|
146
|
+
async function executePipeline(config, signal) {
|
|
147
|
+
const startTime = Date.now();
|
|
148
|
+
const agentResults = [];
|
|
149
|
+
let lastOutput = '';
|
|
150
|
+
for (const agent of config.agents) {
|
|
151
|
+
if (signal.aborted)
|
|
152
|
+
break;
|
|
153
|
+
const result = await runSubAgent(agent, lastOutput || undefined, signal);
|
|
154
|
+
agentResults.push(result);
|
|
155
|
+
if (!result.success && config.failFast) {
|
|
156
|
+
return {
|
|
157
|
+
id: config.id,
|
|
158
|
+
pattern: 'pipeline',
|
|
159
|
+
success: false,
|
|
160
|
+
agentResults,
|
|
161
|
+
finalOutput: '',
|
|
162
|
+
totalDurationMs: Date.now() - startTime,
|
|
163
|
+
totalTokens: agentResults.reduce((sum, r) => sum + (r.tokensUsed || 0), 0),
|
|
164
|
+
error: `Pipeline failed at step "${agent.name}": ${result.error}`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (result.success) {
|
|
168
|
+
lastOutput = result.output;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
id: config.id,
|
|
173
|
+
pattern: 'pipeline',
|
|
174
|
+
success: agentResults.some((r) => r.success),
|
|
175
|
+
agentResults,
|
|
176
|
+
finalOutput: lastOutput,
|
|
177
|
+
totalDurationMs: Date.now() - startTime,
|
|
178
|
+
totalTokens: agentResults.reduce((sum, r) => sum + (r.tokensUsed || 0), 0),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Execute a debate orchestration: agents argue, judge decides.
|
|
183
|
+
*/
|
|
184
|
+
async function executeDebate(config, signal) {
|
|
185
|
+
const startTime = Date.now();
|
|
186
|
+
// Run debaters in parallel
|
|
187
|
+
const debaterResults = await Promise.allSettled(config.agents.map((agent) => runSubAgent(agent, undefined, signal)));
|
|
188
|
+
const agentResults = debaterResults.map((r, i) => {
|
|
189
|
+
if (r.status === 'fulfilled')
|
|
190
|
+
return r.value;
|
|
191
|
+
return {
|
|
192
|
+
agentId: config.agents[i].id,
|
|
193
|
+
agentName: config.agents[i].name,
|
|
194
|
+
success: false,
|
|
195
|
+
output: '',
|
|
196
|
+
error: r.reason instanceof Error ? r.reason.message : String(r.reason),
|
|
197
|
+
durationMs: Date.now() - startTime,
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
// Judge the debate
|
|
201
|
+
let finalOutput = '';
|
|
202
|
+
if (config.judgePrompt) {
|
|
203
|
+
const debateInput = agentResults
|
|
204
|
+
.filter((r) => r.success)
|
|
205
|
+
.map((r) => `[${r.agentName}] argues:\n${r.output}`)
|
|
206
|
+
.join('\n\n---\n\n');
|
|
207
|
+
const judgeResult = await runSubAgent({
|
|
208
|
+
id: 'judge',
|
|
209
|
+
name: 'Judge',
|
|
210
|
+
prompt: `${config.judgePrompt}\n\nArguments:\n\n${debateInput}`,
|
|
211
|
+
model: config.agents[0]?.model,
|
|
212
|
+
effort: 'high',
|
|
213
|
+
}, undefined, signal);
|
|
214
|
+
agentResults.push(judgeResult);
|
|
215
|
+
finalOutput = judgeResult.output;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
finalOutput = agentResults.filter((r) => r.success).map((r) => r.output).join('\n\n');
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
id: config.id,
|
|
222
|
+
pattern: 'debate',
|
|
223
|
+
success: agentResults.some((r) => r.success),
|
|
224
|
+
agentResults,
|
|
225
|
+
finalOutput,
|
|
226
|
+
totalDurationMs: Date.now() - startTime,
|
|
227
|
+
totalTokens: agentResults.reduce((sum, r) => sum + (r.tokensUsed || 0), 0),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
// Public API
|
|
231
|
+
/**
|
|
232
|
+
* Execute an orchestration.
|
|
233
|
+
*/
|
|
234
|
+
export async function orchestrate(config) {
|
|
235
|
+
const abortController = new AbortController();
|
|
236
|
+
activeOrchestrations.set(config.id, abortController);
|
|
237
|
+
// Overall timeout
|
|
238
|
+
let timeoutHandle;
|
|
239
|
+
if (config.timeoutMs) {
|
|
240
|
+
timeoutHandle = setTimeout(() => abortController.abort(), config.timeoutMs);
|
|
241
|
+
}
|
|
242
|
+
log.info(`Starting orchestration: ${config.name} (${config.pattern}) with ${config.agents.length} agents`);
|
|
243
|
+
try {
|
|
244
|
+
let result;
|
|
245
|
+
switch (config.pattern) {
|
|
246
|
+
case 'fan_out':
|
|
247
|
+
result = await executeFanOut(config, abortController.signal);
|
|
248
|
+
break;
|
|
249
|
+
case 'pipeline':
|
|
250
|
+
result = await executePipeline(config, abortController.signal);
|
|
251
|
+
break;
|
|
252
|
+
case 'debate':
|
|
253
|
+
result = await executeDebate(config, abortController.signal);
|
|
254
|
+
break;
|
|
255
|
+
case 'custom':
|
|
256
|
+
// Custom: just run all in parallel (same as fan_out without synthesis)
|
|
257
|
+
result = await executeFanOut({ ...config, synthesizerPrompt: undefined }, abortController.signal);
|
|
258
|
+
break;
|
|
259
|
+
default:
|
|
260
|
+
throw new Error(`Unknown orchestration pattern: ${config.pattern}`);
|
|
261
|
+
}
|
|
262
|
+
log.info(`Orchestration complete: ${config.name} - ${result.success ? 'success' : 'failed'} in ${result.totalDurationMs}ms (${result.totalTokens} tokens)`);
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
finally {
|
|
266
|
+
if (timeoutHandle)
|
|
267
|
+
clearTimeout(timeoutHandle);
|
|
268
|
+
activeOrchestrations.delete(config.id);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Cancel a running orchestration.
|
|
273
|
+
*/
|
|
274
|
+
export function cancelOrchestration(id) {
|
|
275
|
+
const controller = activeOrchestrations.get(id);
|
|
276
|
+
if (controller) {
|
|
277
|
+
controller.abort();
|
|
278
|
+
activeOrchestrations.delete(id);
|
|
279
|
+
log.info(`Cancelled orchestration: ${id}`);
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* List active orchestrations.
|
|
286
|
+
*/
|
|
287
|
+
export function listActiveOrchestrations() {
|
|
288
|
+
return [...activeOrchestrations.keys()];
|
|
289
|
+
}
|
|
290
|
+
const DEFAULT_ORCHESTRATOR_CONFIG = {
|
|
291
|
+
maxConcurrent: 3,
|
|
292
|
+
timeoutMs: 300_000,
|
|
293
|
+
};
|
|
294
|
+
// Singleton instance
|
|
295
|
+
let _instance;
|
|
296
|
+
/**
|
|
297
|
+
* Class-based orchestrator for fan-out parallel sub-agent tasks.
|
|
298
|
+
*
|
|
299
|
+
* The caller provides an `apiCall` function that wraps the actual LLM API —
|
|
300
|
+
* following the same injected-client pattern used by ContextCompactor.
|
|
301
|
+
*
|
|
302
|
+
* Usage:
|
|
303
|
+
* ```ts
|
|
304
|
+
* const orch = getAgentOrchestrator({ maxConcurrent: 2 });
|
|
305
|
+
* const results = await orch.dispatch([
|
|
306
|
+
* { description: 'Summarise file A', prompt: '...' },
|
|
307
|
+
* { description: 'Summarise file B', prompt: '...' },
|
|
308
|
+
* ], myApiCall);
|
|
309
|
+
* console.log(orch.synthesize(results));
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
export class AgentOrchestrator {
|
|
313
|
+
tasks = new Map();
|
|
314
|
+
config;
|
|
315
|
+
/** Number of tasks currently in the 'running' state. */
|
|
316
|
+
running = 0;
|
|
317
|
+
/** Cancelled task IDs — checked before executing. */
|
|
318
|
+
cancelled = new Set();
|
|
319
|
+
constructor(config) {
|
|
320
|
+
this.config = { ...DEFAULT_ORCHESTRATOR_CONFIG, ...config };
|
|
321
|
+
}
|
|
322
|
+
// -------------------------------------------------------------------------
|
|
323
|
+
// Public API
|
|
324
|
+
// -------------------------------------------------------------------------
|
|
325
|
+
/**
|
|
326
|
+
* Dispatch multiple sub-tasks in parallel, respecting `maxConcurrent`.
|
|
327
|
+
* Resolves when every task has either completed, failed, or timed out.
|
|
328
|
+
*/
|
|
329
|
+
async dispatch(taskDefs, apiCall) {
|
|
330
|
+
// Build task objects
|
|
331
|
+
const newTasks = taskDefs.map((def) => ({
|
|
332
|
+
id: randomUUID(),
|
|
333
|
+
description: def.description,
|
|
334
|
+
prompt: def.prompt,
|
|
335
|
+
status: 'pending',
|
|
336
|
+
tokensUsed: 0,
|
|
337
|
+
}));
|
|
338
|
+
for (const task of newTasks) {
|
|
339
|
+
this.tasks.set(task.id, task);
|
|
340
|
+
}
|
|
341
|
+
// Semaphore: release a "slot" whenever a task finishes so the next one starts.
|
|
342
|
+
const queue = [...newTasks];
|
|
343
|
+
const workers = [];
|
|
344
|
+
const next = () => {
|
|
345
|
+
const task = queue.shift();
|
|
346
|
+
if (!task)
|
|
347
|
+
return Promise.resolve();
|
|
348
|
+
if (this.cancelled.has(task.id)) {
|
|
349
|
+
task.status = 'failed';
|
|
350
|
+
task.error = 'Task was cancelled before it started';
|
|
351
|
+
return next();
|
|
352
|
+
}
|
|
353
|
+
this.running++;
|
|
354
|
+
return this.runTask(task, apiCall).then(() => {
|
|
355
|
+
this.running--;
|
|
356
|
+
return next();
|
|
357
|
+
});
|
|
358
|
+
};
|
|
359
|
+
// Seed up to maxConcurrent workers.
|
|
360
|
+
const concurrency = Math.min(this.config.maxConcurrent, newTasks.length);
|
|
361
|
+
for (let i = 0; i < concurrency; i++) {
|
|
362
|
+
workers.push(next());
|
|
363
|
+
}
|
|
364
|
+
await Promise.all(workers);
|
|
365
|
+
return newTasks;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Run a single sub-agent task with timeout and cancellation support.
|
|
369
|
+
* Mutates `task` in place and returns it.
|
|
370
|
+
*/
|
|
371
|
+
async runTask(task, apiCall) {
|
|
372
|
+
if (this.cancelled.has(task.id)) {
|
|
373
|
+
task.status = 'failed';
|
|
374
|
+
task.error = 'Task was cancelled';
|
|
375
|
+
task.completedAt = Date.now();
|
|
376
|
+
return task;
|
|
377
|
+
}
|
|
378
|
+
task.status = 'running';
|
|
379
|
+
task.startedAt = Date.now();
|
|
380
|
+
const timeoutMs = this.config.timeoutMs;
|
|
381
|
+
try {
|
|
382
|
+
const result = await Promise.race([
|
|
383
|
+
apiCall(task.prompt),
|
|
384
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Task "${task.description}" timed out after ${timeoutMs}ms`)), timeoutMs)),
|
|
385
|
+
]);
|
|
386
|
+
// Re-check cancellation — task may have been cancelled while the API call was in flight.
|
|
387
|
+
if (this.cancelled.has(task.id)) {
|
|
388
|
+
task.status = 'failed';
|
|
389
|
+
task.error = 'Task was cancelled';
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
task.status = 'completed';
|
|
393
|
+
task.result = result;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
task.status = 'failed';
|
|
398
|
+
task.error = error instanceof Error ? error.message : String(error);
|
|
399
|
+
log.warn(`Sub-agent task failed: ${task.description} — ${task.error}`);
|
|
400
|
+
}
|
|
401
|
+
finally {
|
|
402
|
+
task.completedAt = Date.now();
|
|
403
|
+
}
|
|
404
|
+
return task;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Return a snapshot of all tasks tracked by this orchestrator.
|
|
408
|
+
*/
|
|
409
|
+
getStatus() {
|
|
410
|
+
return [...this.tasks.values()];
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Mark a task as cancelled. If it is still pending it will be skipped
|
|
414
|
+
* entirely; if it is already running the next post-API-call check will
|
|
415
|
+
* mark it failed.
|
|
416
|
+
*/
|
|
417
|
+
cancel(taskId) {
|
|
418
|
+
this.cancelled.add(taskId);
|
|
419
|
+
const task = this.tasks.get(taskId);
|
|
420
|
+
if (task && task.status === 'pending') {
|
|
421
|
+
task.status = 'failed';
|
|
422
|
+
task.error = 'Task was cancelled';
|
|
423
|
+
task.completedAt = Date.now();
|
|
424
|
+
log.info(`Cancelled pending task: ${taskId}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Build a markdown summary of completed task results.
|
|
429
|
+
*
|
|
430
|
+
* ```markdown
|
|
431
|
+
* ## Task Results
|
|
432
|
+
* ### 1. Summarise file A ✓
|
|
433
|
+
* <result text>
|
|
434
|
+
* ### 2. Summarise file B ✗
|
|
435
|
+
* Error: timed out after 300000ms
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
synthesize(tasks) {
|
|
439
|
+
const lines = ['## Task Results', ''];
|
|
440
|
+
tasks.forEach((task, index) => {
|
|
441
|
+
const marker = task.status === 'completed' ? '✓' : '✗';
|
|
442
|
+
lines.push(`### ${index + 1}. ${task.description} ${marker}`);
|
|
443
|
+
if (task.status === 'completed' && task.result) {
|
|
444
|
+
lines.push(task.result);
|
|
445
|
+
}
|
|
446
|
+
else if (task.status === 'failed') {
|
|
447
|
+
lines.push(`Error: ${task.error ?? 'Unknown error'}`);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
lines.push(`Status: ${task.status}`);
|
|
451
|
+
}
|
|
452
|
+
lines.push('');
|
|
453
|
+
});
|
|
454
|
+
return lines.join('\n').trimEnd();
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Wait until all currently-tracked tasks have left the 'pending' or
|
|
458
|
+
* 'running' state, or until the optional `timeoutMs` elapses.
|
|
459
|
+
*
|
|
460
|
+
* Resolves with the current task snapshot once settled.
|
|
461
|
+
*/
|
|
462
|
+
async waitAll(timeoutMs) {
|
|
463
|
+
const poll = () => [...this.tasks.values()].every((t) => t.status === 'completed' || t.status === 'failed');
|
|
464
|
+
if (poll())
|
|
465
|
+
return this.getStatus();
|
|
466
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : Infinity;
|
|
467
|
+
const INTERVAL = 50;
|
|
468
|
+
return new Promise((resolve) => {
|
|
469
|
+
const check = () => {
|
|
470
|
+
if (poll()) {
|
|
471
|
+
resolve(this.getStatus());
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (Date.now() >= deadline) {
|
|
475
|
+
resolve(this.getStatus());
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
setTimeout(check, INTERVAL);
|
|
479
|
+
};
|
|
480
|
+
setTimeout(check, INTERVAL);
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Return a lazily-created singleton `AgentOrchestrator`.
|
|
486
|
+
* Pass `config` on first call to customise defaults; subsequent calls with
|
|
487
|
+
* a different config will replace the singleton.
|
|
488
|
+
*/
|
|
489
|
+
export function getAgentOrchestrator(config) {
|
|
490
|
+
if (!_instance || config) {
|
|
491
|
+
_instance = new AgentOrchestrator(config);
|
|
492
|
+
}
|
|
493
|
+
return _instance;
|
|
494
|
+
}
|
|
495
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Output Truncator
|
|
3
|
+
*
|
|
4
|
+
* Caps large tool results (file reads, command output, logs, web content) to a
|
|
5
|
+
* configurable char budget before they reach the model. The head and the tail
|
|
6
|
+
* are kept (errors and summaries usually live at the end), the middle is
|
|
7
|
+
* replaced by an explicit marker, and the full result is kept in the
|
|
8
|
+
* ResultStore so the model can fetch a range with `fetch_result`.
|
|
9
|
+
*/
|
|
10
|
+
import type { ResultStore } from './result-store.js';
|
|
11
|
+
export interface TruncationConfig {
|
|
12
|
+
/** Max chars of a result sent to the model */
|
|
13
|
+
maxChars: number;
|
|
14
|
+
/** Fraction of the budget spent on the head (rest goes to the tail) */
|
|
15
|
+
headRatio: number;
|
|
16
|
+
/** Max chars returned by a single fetch_result call */
|
|
17
|
+
fetchMaxChars: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function getTruncationConfig(): TruncationConfig;
|
|
20
|
+
/** Truncation is on unless PROFCLAW_TOOL_OUTPUT_TRUNCATION is off/0/false/no. */
|
|
21
|
+
export declare function isTruncationEnabled(): boolean;
|
|
22
|
+
export interface TruncatedText {
|
|
23
|
+
text: string;
|
|
24
|
+
truncated: boolean;
|
|
25
|
+
/** Number of chars removed from the middle */
|
|
26
|
+
omitted: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Keep the head and tail of `text`, replacing the middle with a marker.
|
|
30
|
+
*/
|
|
31
|
+
export declare function truncateText(text: string, maxChars: number, headRatio?: number, hint?: string): TruncatedText;
|
|
32
|
+
export interface TruncatedResult {
|
|
33
|
+
/** Value to hand to the model (original reference when nothing was cut) */
|
|
34
|
+
value: unknown;
|
|
35
|
+
truncated: boolean;
|
|
36
|
+
omitted: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Truncate an arbitrary tool result. Long string fields are shortened in place
|
|
40
|
+
* so the object shape survives; if the whole payload is still over budget
|
|
41
|
+
* (e.g. a huge array), it falls back to truncating the JSON text.
|
|
42
|
+
*/
|
|
43
|
+
export declare function truncateResult(result: unknown, config?: TruncationConfig, hint?: string): TruncatedResult;
|
|
44
|
+
/**
|
|
45
|
+
* Truncate `result` if needed. When truncation happens the FULL result is
|
|
46
|
+
* saved in `store` under `toolCallId` so `fetch_result` can page through it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function truncateAndStore(store: ResultStore, toolCallId: string, result: unknown, config?: TruncationConfig): Promise<TruncatedResult>;
|
|
49
|
+
export interface ResultRange {
|
|
50
|
+
resultId: string;
|
|
51
|
+
offset: number;
|
|
52
|
+
length: number;
|
|
53
|
+
totalChars: number;
|
|
54
|
+
content: string;
|
|
55
|
+
hasMore: boolean;
|
|
56
|
+
}
|
|
57
|
+
/** Read a char range of a stored full result (JSON text of the original). */
|
|
58
|
+
export declare function readStoredRange(store: ResultStore, resultId: string, offset: number, length: number, config?: TruncationConfig): Promise<ResultRange | null>;
|
|
59
|
+
//# sourceMappingURL=output-truncator.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Output Truncator
|
|
3
|
+
*
|
|
4
|
+
* Caps large tool results (file reads, command output, logs, web content) to a
|
|
5
|
+
* configurable char budget before they reach the model. The head and the tail
|
|
6
|
+
* are kept (errors and summaries usually live at the end), the middle is
|
|
7
|
+
* replaced by an explicit marker, and the full result is kept in the
|
|
8
|
+
* ResultStore so the model can fetch a range with `fetch_result`.
|
|
9
|
+
*/
|
|
10
|
+
import { readFile } from 'node:fs/promises';
|
|
11
|
+
const DEFAULT_MAX_CHARS = 12_000;
|
|
12
|
+
const DEFAULT_HEAD_RATIO = 0.7;
|
|
13
|
+
function readPositiveInt(name, fallback) {
|
|
14
|
+
const raw = process.env[name];
|
|
15
|
+
if (!raw)
|
|
16
|
+
return fallback;
|
|
17
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
19
|
+
}
|
|
20
|
+
export function getTruncationConfig() {
|
|
21
|
+
const maxChars = readPositiveInt('PROFCLAW_TOOL_OUTPUT_MAX_CHARS', DEFAULT_MAX_CHARS);
|
|
22
|
+
const rawRatio = Number.parseFloat(process.env.PROFCLAW_TOOL_OUTPUT_HEAD_RATIO ?? '');
|
|
23
|
+
const headRatio = Number.isFinite(rawRatio) && rawRatio > 0 && rawRatio < 1 ? rawRatio : DEFAULT_HEAD_RATIO;
|
|
24
|
+
return {
|
|
25
|
+
maxChars,
|
|
26
|
+
headRatio,
|
|
27
|
+
fetchMaxChars: readPositiveInt('PROFCLAW_TOOL_FETCH_MAX_CHARS', maxChars),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Truncation is on unless PROFCLAW_TOOL_OUTPUT_TRUNCATION is off/0/false/no. */
|
|
31
|
+
export function isTruncationEnabled() {
|
|
32
|
+
const flag = (process.env.PROFCLAW_TOOL_OUTPUT_TRUNCATION ?? '').toLowerCase();
|
|
33
|
+
return !['off', '0', 'false', 'no'].includes(flag);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Keep the head and tail of `text`, replacing the middle with a marker.
|
|
37
|
+
*/
|
|
38
|
+
export function truncateText(text, maxChars, headRatio = DEFAULT_HEAD_RATIO, hint = '') {
|
|
39
|
+
if (text.length <= maxChars) {
|
|
40
|
+
return { text, truncated: false, omitted: 0 };
|
|
41
|
+
}
|
|
42
|
+
const headLen = Math.floor(maxChars * headRatio);
|
|
43
|
+
const tailLen = Math.max(0, maxChars - headLen);
|
|
44
|
+
const omitted = text.length - headLen - tailLen;
|
|
45
|
+
const marker = `\n[truncated ${omitted} chars${hint ? `. ${hint}` : ''}]\n`;
|
|
46
|
+
const tail = tailLen > 0 ? text.slice(text.length - tailLen) : '';
|
|
47
|
+
return { text: text.slice(0, headLen) + marker + tail, truncated: true, omitted };
|
|
48
|
+
}
|
|
49
|
+
function shrinkStrings(value, maxChars, headRatio, hint, stats, depth) {
|
|
50
|
+
if (typeof value === 'string') {
|
|
51
|
+
const t = truncateText(value, maxChars, headRatio, hint);
|
|
52
|
+
stats.omitted += t.omitted;
|
|
53
|
+
return t.text;
|
|
54
|
+
}
|
|
55
|
+
if (depth > 6 || value === null || typeof value !== 'object')
|
|
56
|
+
return value;
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
return value.map((v) => shrinkStrings(v, maxChars, headRatio, hint, stats, depth + 1));
|
|
59
|
+
}
|
|
60
|
+
const out = {};
|
|
61
|
+
for (const [k, v] of Object.entries(value)) {
|
|
62
|
+
out[k] = shrinkStrings(v, maxChars, headRatio, hint, stats, depth + 1);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function safeStringify(value) {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.stringify(value) ?? '';
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return String(value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Truncate an arbitrary tool result. Long string fields are shortened in place
|
|
76
|
+
* so the object shape survives; if the whole payload is still over budget
|
|
77
|
+
* (e.g. a huge array), it falls back to truncating the JSON text.
|
|
78
|
+
*/
|
|
79
|
+
export function truncateResult(result, config = getTruncationConfig(), hint = '') {
|
|
80
|
+
const serialized = typeof result === 'string' ? result : safeStringify(result);
|
|
81
|
+
if (serialized.length <= config.maxChars) {
|
|
82
|
+
return { value: result, truncated: false, omitted: 0 };
|
|
83
|
+
}
|
|
84
|
+
if (typeof result === 'string') {
|
|
85
|
+
const t = truncateText(result, config.maxChars, config.headRatio, hint);
|
|
86
|
+
return { value: t.text, truncated: true, omitted: t.omitted };
|
|
87
|
+
}
|
|
88
|
+
const stats = { omitted: 0 };
|
|
89
|
+
const shrunk = shrinkStrings(result, config.maxChars, config.headRatio, hint, stats, 0);
|
|
90
|
+
const shrunkSerialized = safeStringify(shrunk);
|
|
91
|
+
if (shrunkSerialized.length <= config.maxChars * 1.25 + 256 && stats.omitted > 0) {
|
|
92
|
+
return { value: shrunk, truncated: true, omitted: stats.omitted };
|
|
93
|
+
}
|
|
94
|
+
const t = truncateText(serialized, config.maxChars, config.headRatio, hint);
|
|
95
|
+
return { value: t.text, truncated: true, omitted: t.omitted };
|
|
96
|
+
}
|
|
97
|
+
// Store integration
|
|
98
|
+
/**
|
|
99
|
+
* Truncate `result` if needed. When truncation happens the FULL result is
|
|
100
|
+
* saved in `store` under `toolCallId` so `fetch_result` can page through it.
|
|
101
|
+
*/
|
|
102
|
+
export async function truncateAndStore(store, toolCallId, result, config = getTruncationConfig()) {
|
|
103
|
+
const hint = `full output saved as result_id "${toolCallId}", call fetch_result with offset/length`;
|
|
104
|
+
const truncated = truncateResult(result, config, hint);
|
|
105
|
+
if (truncated.truncated) {
|
|
106
|
+
await store.store(toolCallId, result);
|
|
107
|
+
}
|
|
108
|
+
return truncated;
|
|
109
|
+
}
|
|
110
|
+
/** Read a char range of a stored full result (JSON text of the original). */
|
|
111
|
+
export async function readStoredRange(store, resultId, offset, length, config = getTruncationConfig()) {
|
|
112
|
+
const stored = store.retrieve(resultId);
|
|
113
|
+
if (!stored)
|
|
114
|
+
return null;
|
|
115
|
+
const full = stored.fullPath ? await readFile(stored.fullPath, 'utf8') : stored.inline;
|
|
116
|
+
const start = Math.max(0, Math.min(offset, full.length));
|
|
117
|
+
const len = Math.max(1, Math.min(length, config.fetchMaxChars));
|
|
118
|
+
const content = full.slice(start, start + len);
|
|
119
|
+
return {
|
|
120
|
+
resultId,
|
|
121
|
+
offset: start,
|
|
122
|
+
length: content.length,
|
|
123
|
+
totalChars: full.length,
|
|
124
|
+
content,
|
|
125
|
+
hasMore: start + content.length < full.length,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=output-truncator.js.map
|