agent-nuvira 1.14.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/LICENSE +21 -0
- package/README.md +891 -0
- package/dist/agent-sdk/src/agent.d.ts +118 -0
- package/dist/agent-sdk/src/agent.d.ts.map +1 -0
- package/dist/agent-sdk/src/agent.js +88 -0
- package/dist/agent-sdk/src/agent.js.map +1 -0
- package/dist/agent-sdk/src/index.d.ts +33 -0
- package/dist/agent-sdk/src/index.d.ts.map +1 -0
- package/dist/agent-sdk/src/index.js +32 -0
- package/dist/agent-sdk/src/index.js.map +1 -0
- package/dist/agent-sdk/src/register.d.ts +70 -0
- package/dist/agent-sdk/src/register.d.ts.map +1 -0
- package/dist/agent-sdk/src/register.js +181 -0
- package/dist/agent-sdk/src/register.js.map +1 -0
- package/dist/agent-sdk/src/scaffold.d.ts +50 -0
- package/dist/agent-sdk/src/scaffold.d.ts.map +1 -0
- package/dist/agent-sdk/src/scaffold.js +291 -0
- package/dist/agent-sdk/src/scaffold.js.map +1 -0
- package/dist/agent-sdk/src/testing.d.ts +187 -0
- package/dist/agent-sdk/src/testing.d.ts.map +1 -0
- package/dist/agent-sdk/src/testing.js +243 -0
- package/dist/agent-sdk/src/testing.js.map +1 -0
- package/dist/agent-sdk/src/types.d.ts +202 -0
- package/dist/agent-sdk/src/types.d.ts.map +1 -0
- package/dist/agent-sdk/src/types.js +11 -0
- package/dist/agent-sdk/src/types.js.map +1 -0
- package/dist/agents/agent.d.ts +132 -0
- package/dist/agents/agent.d.ts.map +1 -0
- package/dist/agents/agent.js +19 -0
- package/dist/agents/agent.js.map +1 -0
- package/dist/agents/agents/context-gatherer.d.ts +42 -0
- package/dist/agents/agents/context-gatherer.d.ts.map +1 -0
- package/dist/agents/agents/context-gatherer.js +366 -0
- package/dist/agents/agents/context-gatherer.js.map +1 -0
- package/dist/agents/agents/debugger.d.ts +58 -0
- package/dist/agents/agents/debugger.d.ts.map +1 -0
- package/dist/agents/agents/debugger.js +257 -0
- package/dist/agents/agents/debugger.js.map +1 -0
- package/dist/agents/agents/git-agent.d.ts +34 -0
- package/dist/agents/agents/git-agent.d.ts.map +1 -0
- package/dist/agents/agents/git-agent.js +200 -0
- package/dist/agents/agents/git-agent.js.map +1 -0
- package/dist/agents/agents/github-release-agent.d.ts +65 -0
- package/dist/agents/agents/github-release-agent.d.ts.map +1 -0
- package/dist/agents/agents/github-release-agent.js +439 -0
- package/dist/agents/agents/github-release-agent.js.map +1 -0
- package/dist/agents/agents/package-agent.d.ts +33 -0
- package/dist/agents/agents/package-agent.d.ts.map +1 -0
- package/dist/agents/agents/package-agent.js +233 -0
- package/dist/agents/agents/package-agent.js.map +1 -0
- package/dist/agents/agents/planner.d.ts +26 -0
- package/dist/agents/agents/planner.d.ts.map +1 -0
- package/dist/agents/agents/planner.js +222 -0
- package/dist/agents/agents/planner.js.map +1 -0
- package/dist/agents/agents/reviewer.d.ts +34 -0
- package/dist/agents/agents/reviewer.d.ts.map +1 -0
- package/dist/agents/agents/reviewer.js +159 -0
- package/dist/agents/agents/reviewer.js.map +1 -0
- package/dist/agents/agents/runner.d.ts +73 -0
- package/dist/agents/agents/runner.d.ts.map +1 -0
- package/dist/agents/agents/runner.js +299 -0
- package/dist/agents/agents/runner.js.map +1 -0
- package/dist/agents/agents/security-agent.d.ts +33 -0
- package/dist/agents/agents/security-agent.d.ts.map +1 -0
- package/dist/agents/agents/security-agent.js +184 -0
- package/dist/agents/agents/security-agent.js.map +1 -0
- package/dist/agents/agents/tester.d.ts +96 -0
- package/dist/agents/agents/tester.d.ts.map +1 -0
- package/dist/agents/agents/tester.js +410 -0
- package/dist/agents/agents/tester.js.map +1 -0
- package/dist/agents/agents/writer.d.ts +51 -0
- package/dist/agents/agents/writer.d.ts.map +1 -0
- package/dist/agents/agents/writer.js +384 -0
- package/dist/agents/agents/writer.js.map +1 -0
- package/dist/agents/context-vault.d.ts +49 -0
- package/dist/agents/context-vault.d.ts.map +1 -0
- package/dist/agents/context-vault.js +134 -0
- package/dist/agents/context-vault.js.map +1 -0
- package/dist/agents/orchestrator.d.ts +97 -0
- package/dist/agents/orchestrator.d.ts.map +1 -0
- package/dist/agents/orchestrator.js +696 -0
- package/dist/agents/orchestrator.js.map +1 -0
- package/dist/agents/utils/file-tree.d.ts +28 -0
- package/dist/agents/utils/file-tree.d.ts.map +1 -0
- package/dist/agents/utils/file-tree.js +93 -0
- package/dist/agents/utils/file-tree.js.map +1 -0
- package/dist/cli/agent.d.ts +25 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +374 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/benchmark.d.ts +24 -0
- package/dist/cli/benchmark.d.ts.map +1 -0
- package/dist/cli/benchmark.js +235 -0
- package/dist/cli/benchmark.js.map +1 -0
- package/dist/cli/cache.d.ts +12 -0
- package/dist/cli/cache.d.ts.map +1 -0
- package/dist/cli/cache.js +58 -0
- package/dist/cli/cache.js.map +1 -0
- package/dist/cli/chat.d.ts +37 -0
- package/dist/cli/chat.d.ts.map +1 -0
- package/dist/cli/chat.js +393 -0
- package/dist/cli/chat.js.map +1 -0
- package/dist/cli/commands.d.ts +24 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +18 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/config.d.ts +19 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +162 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/dashboard.d.ts +34 -0
- package/dist/cli/dashboard.d.ts.map +1 -0
- package/dist/cli/dashboard.js +126 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/cli/doctor.d.ts +68 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +585 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/edit.d.ts +11 -0
- package/dist/cli/edit.d.ts.map +1 -0
- package/dist/cli/edit.js +86 -0
- package/dist/cli/edit.js.map +1 -0
- package/dist/cli/execute.d.ts +25 -0
- package/dist/cli/execute.d.ts.map +1 -0
- package/dist/cli/execute.js +186 -0
- package/dist/cli/execute.js.map +1 -0
- package/dist/cli/federation.d.ts +31 -0
- package/dist/cli/federation.d.ts.map +1 -0
- package/dist/cli/federation.js +387 -0
- package/dist/cli/federation.js.map +1 -0
- package/dist/cli/history.d.ts +22 -0
- package/dist/cli/history.d.ts.map +1 -0
- package/dist/cli/history.js +140 -0
- package/dist/cli/history.js.map +1 -0
- package/dist/cli/init.d.ts +49 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +423 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/learn.d.ts +31 -0
- package/dist/cli/learn.d.ts.map +1 -0
- package/dist/cli/learn.js +320 -0
- package/dist/cli/learn.js.map +1 -0
- package/dist/cli/memory.d.ts +38 -0
- package/dist/cli/memory.d.ts.map +1 -0
- package/dist/cli/memory.js +295 -0
- package/dist/cli/memory.js.map +1 -0
- package/dist/cli/model-picker.d.ts +18 -0
- package/dist/cli/model-picker.d.ts.map +1 -0
- package/dist/cli/model-picker.js +225 -0
- package/dist/cli/model-picker.js.map +1 -0
- package/dist/cli/models.d.ts +11 -0
- package/dist/cli/models.d.ts.map +1 -0
- package/dist/cli/models.js +132 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/plan.d.ts +11 -0
- package/dist/cli/plan.d.ts.map +1 -0
- package/dist/cli/plan.js +94 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/plugins.d.ts +15 -0
- package/dist/cli/plugins.d.ts.map +1 -0
- package/dist/cli/plugins.js +123 -0
- package/dist/cli/plugins.js.map +1 -0
- package/dist/cli/router.d.ts +20 -0
- package/dist/cli/router.d.ts.map +1 -0
- package/dist/cli/router.js +142 -0
- package/dist/cli/router.js.map +1 -0
- package/dist/cli/run.d.ts +22 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +110 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/sandbox.d.ts +27 -0
- package/dist/cli/sandbox.d.ts.map +1 -0
- package/dist/cli/sandbox.js +264 -0
- package/dist/cli/sandbox.js.map +1 -0
- package/dist/cli/sdk.d.ts +27 -0
- package/dist/cli/sdk.d.ts.map +1 -0
- package/dist/cli/sdk.js +204 -0
- package/dist/cli/sdk.js.map +1 -0
- package/dist/cli/stats.d.ts +18 -0
- package/dist/cli/stats.d.ts.map +1 -0
- package/dist/cli/stats.js +78 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/team.d.ts +42 -0
- package/dist/cli/team.d.ts.map +1 -0
- package/dist/cli/team.js +473 -0
- package/dist/cli/team.js.map +1 -0
- package/dist/cli/workflow.d.ts +27 -0
- package/dist/cli/workflow.d.ts.map +1 -0
- package/dist/cli/workflow.js +347 -0
- package/dist/cli/workflow.js.map +1 -0
- package/dist/config/manager.d.ts +37 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +147 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/types.d.ts +53 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/context/cache.d.ts +27 -0
- package/dist/context/cache.d.ts.map +1 -0
- package/dist/context/cache.js +116 -0
- package/dist/context/cache.js.map +1 -0
- package/dist/context/history.d.ts +87 -0
- package/dist/context/history.d.ts.map +1 -0
- package/dist/context/history.js +249 -0
- package/dist/context/history.js.map +1 -0
- package/dist/context/parser.d.ts +61 -0
- package/dist/context/parser.d.ts.map +1 -0
- package/dist/context/parser.js +194 -0
- package/dist/context/parser.js.map +1 -0
- package/dist/federation/client.d.ts +49 -0
- package/dist/federation/client.d.ts.map +1 -0
- package/dist/federation/client.js +239 -0
- package/dist/federation/client.js.map +1 -0
- package/dist/federation/protocol.d.ts +155 -0
- package/dist/federation/protocol.d.ts.map +1 -0
- package/dist/federation/protocol.js +57 -0
- package/dist/federation/protocol.js.map +1 -0
- package/dist/federation/server.d.ts +25 -0
- package/dist/federation/server.d.ts.map +1 -0
- package/dist/federation/server.js +401 -0
- package/dist/federation/server.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/inference/factory.d.ts +20 -0
- package/dist/inference/factory.d.ts.map +1 -0
- package/dist/inference/factory.js +46 -0
- package/dist/inference/factory.js.map +1 -0
- package/dist/inference/gemini-adapter.d.ts +17 -0
- package/dist/inference/gemini-adapter.d.ts.map +1 -0
- package/dist/inference/gemini-adapter.js +176 -0
- package/dist/inference/gemini-adapter.js.map +1 -0
- package/dist/inference/groq-adapter.d.ts +17 -0
- package/dist/inference/groq-adapter.d.ts.map +1 -0
- package/dist/inference/groq-adapter.js +103 -0
- package/dist/inference/groq-adapter.js.map +1 -0
- package/dist/inference/interface.d.ts +49 -0
- package/dist/inference/interface.d.ts.map +1 -0
- package/dist/inference/interface.js +2 -0
- package/dist/inference/interface.js.map +1 -0
- package/dist/inference/local-adapter.d.ts +35 -0
- package/dist/inference/local-adapter.d.ts.map +1 -0
- package/dist/inference/local-adapter.js +311 -0
- package/dist/inference/local-adapter.js.map +1 -0
- package/dist/inference/model-catalog.d.ts +53 -0
- package/dist/inference/model-catalog.d.ts.map +1 -0
- package/dist/inference/model-catalog.js +306 -0
- package/dist/inference/model-catalog.js.map +1 -0
- package/dist/inference/nim-adapter.d.ts +17 -0
- package/dist/inference/nim-adapter.d.ts.map +1 -0
- package/dist/inference/nim-adapter.js +103 -0
- package/dist/inference/nim-adapter.js.map +1 -0
- package/dist/inference/openrouter-adapter.d.ts +17 -0
- package/dist/inference/openrouter-adapter.d.ts.map +1 -0
- package/dist/inference/openrouter-adapter.js +105 -0
- package/dist/inference/openrouter-adapter.js.map +1 -0
- package/dist/inference/sse.d.ts +20 -0
- package/dist/inference/sse.d.ts.map +1 -0
- package/dist/inference/sse.js +91 -0
- package/dist/inference/sse.js.map +1 -0
- package/dist/learning/agent-stats.d.ts +109 -0
- package/dist/learning/agent-stats.d.ts.map +1 -0
- package/dist/learning/agent-stats.js +240 -0
- package/dist/learning/agent-stats.js.map +1 -0
- package/dist/learning/benchmark.d.ts +161 -0
- package/dist/learning/benchmark.d.ts.map +1 -0
- package/dist/learning/benchmark.js +589 -0
- package/dist/learning/benchmark.js.map +1 -0
- package/dist/learning/cost-tracker.d.ts +101 -0
- package/dist/learning/cost-tracker.d.ts.map +1 -0
- package/dist/learning/cost-tracker.js +224 -0
- package/dist/learning/cost-tracker.js.map +1 -0
- package/dist/learning/feedback.d.ts +88 -0
- package/dist/learning/feedback.d.ts.map +1 -0
- package/dist/learning/feedback.js +169 -0
- package/dist/learning/feedback.js.map +1 -0
- package/dist/learning/hybrid-router.d.ts +201 -0
- package/dist/learning/hybrid-router.d.ts.map +1 -0
- package/dist/learning/hybrid-router.js +450 -0
- package/dist/learning/hybrid-router.js.map +1 -0
- package/dist/learning/model-compare.d.ts +76 -0
- package/dist/learning/model-compare.d.ts.map +1 -0
- package/dist/learning/model-compare.js +252 -0
- package/dist/learning/model-compare.js.map +1 -0
- package/dist/learning/model-router.d.ts +68 -0
- package/dist/learning/model-router.d.ts.map +1 -0
- package/dist/learning/model-router.js +140 -0
- package/dist/learning/model-router.js.map +1 -0
- package/dist/learning/pattern-extractor.d.ts +99 -0
- package/dist/learning/pattern-extractor.d.ts.map +1 -0
- package/dist/learning/pattern-extractor.js +310 -0
- package/dist/learning/pattern-extractor.js.map +1 -0
- package/dist/learning/scorer.d.ts +51 -0
- package/dist/learning/scorer.d.ts.map +1 -0
- package/dist/learning/scorer.js +64 -0
- package/dist/learning/scorer.js.map +1 -0
- package/dist/learning/self-improver.d.ts +48 -0
- package/dist/learning/self-improver.d.ts.map +1 -0
- package/dist/learning/self-improver.js +161 -0
- package/dist/learning/self-improver.js.map +1 -0
- package/dist/memory/embedder.d.ts +65 -0
- package/dist/memory/embedder.d.ts.map +1 -0
- package/dist/memory/embedder.js +424 -0
- package/dist/memory/embedder.js.map +1 -0
- package/dist/memory/memory-integration.d.ts +56 -0
- package/dist/memory/memory-integration.d.ts.map +1 -0
- package/dist/memory/memory-integration.js +95 -0
- package/dist/memory/memory-integration.js.map +1 -0
- package/dist/memory/trajectory-store.d.ts +149 -0
- package/dist/memory/trajectory-store.d.ts.map +1 -0
- package/dist/memory/trajectory-store.js +476 -0
- package/dist/memory/trajectory-store.js.map +1 -0
- package/dist/memory/vector-store.d.ts +78 -0
- package/dist/memory/vector-store.d.ts.map +1 -0
- package/dist/memory/vector-store.js +186 -0
- package/dist/memory/vector-store.js.map +1 -0
- package/dist/plugins/agent-plugin.d.ts +73 -0
- package/dist/plugins/agent-plugin.d.ts.map +1 -0
- package/dist/plugins/agent-plugin.js +199 -0
- package/dist/plugins/agent-plugin.js.map +1 -0
- package/dist/plugins/registry.d.ts +61 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +67 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/sandbox/images.d.ts +31 -0
- package/dist/sandbox/images.d.ts.map +1 -0
- package/dist/sandbox/images.js +129 -0
- package/dist/sandbox/images.js.map +1 -0
- package/dist/sandbox/manager.d.ts +134 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +470 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/types.d.ts +113 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +107 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/security/scanner.d.ts +53 -0
- package/dist/security/scanner.d.ts.map +1 -0
- package/dist/security/scanner.js +271 -0
- package/dist/security/scanner.js.map +1 -0
- package/dist/team/config.d.ts +50 -0
- package/dist/team/config.d.ts.map +1 -0
- package/dist/team/config.js +108 -0
- package/dist/team/config.js.map +1 -0
- package/dist/team/memory.d.ts +63 -0
- package/dist/team/memory.d.ts.map +1 -0
- package/dist/team/memory.js +282 -0
- package/dist/team/memory.js.map +1 -0
- package/dist/team/review.d.ts +123 -0
- package/dist/team/review.d.ts.map +1 -0
- package/dist/team/review.js +293 -0
- package/dist/team/review.js.map +1 -0
- package/dist/utils/env.d.ts +19 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +250 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +45 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/web-dashboard/server.d.ts +59 -0
- package/dist/web-dashboard/server.d.ts.map +1 -0
- package/dist/web-dashboard/server.js +418 -0
- package/dist/web-dashboard/server.js.map +1 -0
- package/dist/workflow/registry.d.ts +127 -0
- package/dist/workflow/registry.d.ts.map +1 -0
- package/dist/workflow/registry.js +482 -0
- package/dist/workflow/registry.js.map +1 -0
- package/dist/workflow/templates.d.ts +93 -0
- package/dist/workflow/templates.d.ts.map +1 -0
- package/dist/workflow/templates.js +481 -0
- package/dist/workflow/templates.js.map +1 -0
- package/package.json +78 -0
- package/src/web-dashboard/public/assets/index-B08nDkSB.css +1 -0
- package/src/web-dashboard/public/assets/index-BKL8YOFD.js +135 -0
- package/src/web-dashboard/public/assets/index-BKL8YOFD.js.map +1 -0
- package/src/web-dashboard/public/index.html +13 -0
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator — The central coordinator of the multi-agent system.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Accept a user goal and optionally a provider/model config
|
|
6
|
+
* 2. Create a ContextVault (shared context bus)
|
|
7
|
+
* 3. Build the project file tree and inject it for the Planner
|
|
8
|
+
* 4. Optionally retrieve memory context from past similar trajectories
|
|
9
|
+
* 5. Run the PlannerAgent to produce an execution plan
|
|
10
|
+
* 6. Execute tasks sequentially, respecting dependencies
|
|
11
|
+
* 7. Spawn the appropriate agent for each task
|
|
12
|
+
* 8. Apply file changes to disk
|
|
13
|
+
* 9. Execute runner commands and capture output
|
|
14
|
+
* 10. Optionally store the trajectory in memory
|
|
15
|
+
* 11. Synthesize and return the final result
|
|
16
|
+
*
|
|
17
|
+
* Called by the `agent-nuvira execute` CLI command.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
20
|
+
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
21
|
+
import inquirer from 'inquirer';
|
|
22
|
+
import { ProviderFactory } from '../inference/factory.js';
|
|
23
|
+
import { ConfigManager } from '../config/manager.js';
|
|
24
|
+
import { showModelPicker } from '../cli/model-picker.js';
|
|
25
|
+
import { logger } from '../utils/logger.js';
|
|
26
|
+
import { ContextVault } from './context-vault.js';
|
|
27
|
+
import { buildProjectFileTree, truncateTree } from './utils/file-tree.js';
|
|
28
|
+
import { PlannerAgent } from './agents/planner.js';
|
|
29
|
+
import { ContextGathererAgent } from './agents/context-gatherer.js';
|
|
30
|
+
import { WriterAgent } from './agents/writer.js';
|
|
31
|
+
import { ReviewerAgent } from './agents/reviewer.js';
|
|
32
|
+
import { RunnerAgent } from './agents/runner.js';
|
|
33
|
+
import { TesterAgent, cleanupSandbox } from './agents/tester.js';
|
|
34
|
+
import { DebuggerAgent } from './agents/debugger.js';
|
|
35
|
+
import { GitAgent } from './agents/git-agent.js';
|
|
36
|
+
import { PackageAgent } from './agents/package-agent.js';
|
|
37
|
+
import { GitHubReleaseAgent } from './agents/github-release-agent.js';
|
|
38
|
+
import { SecurityAgent } from './agents/security-agent.js';
|
|
39
|
+
import { scanForInjections, formatScanReport } from '../security/scanner.js';
|
|
40
|
+
import { buildAgentModelMap } from '../learning/model-router.js';
|
|
41
|
+
import { createReviewFromResult } from '../team/review.js';
|
|
42
|
+
// ─── DAG Integration (optional — dashboard may not be built) ─────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Push a DAG update to the live dashboard, if the server is running.
|
|
45
|
+
* Uses dynamic import so the orchestrator doesn't crash if the dashboard
|
|
46
|
+
* module hasn't been built or isn't available.
|
|
47
|
+
*/
|
|
48
|
+
let dagModule = undefined;
|
|
49
|
+
async function ensureDAGModule() {
|
|
50
|
+
if (dagModule !== undefined)
|
|
51
|
+
return; // already attempted (null = failed, object = loaded)
|
|
52
|
+
try {
|
|
53
|
+
dagModule = await import('../web-dashboard/server.js');
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
dagModule = null; // dashboard module not available — mark as failed
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function tryPushDAG(update) {
|
|
60
|
+
await ensureDAGModule();
|
|
61
|
+
if (dagModule)
|
|
62
|
+
dagModule.pushDAGUpdate(update);
|
|
63
|
+
}
|
|
64
|
+
async function tryUpdateDAGNode(nodeId, update) {
|
|
65
|
+
await ensureDAGModule();
|
|
66
|
+
if (dagModule)
|
|
67
|
+
dagModule.updateDAGNode(nodeId, update);
|
|
68
|
+
}
|
|
69
|
+
async function tryResetDAG() {
|
|
70
|
+
await ensureDAGModule();
|
|
71
|
+
if (dagModule)
|
|
72
|
+
dagModule.resetDAG();
|
|
73
|
+
}
|
|
74
|
+
// ─── Agent Registry ─────────────────────────────────────────────────────────
|
|
75
|
+
// ─── Spinner Icons ─────────────────────────────────────────────────────────
|
|
76
|
+
/** Icons for each agent type, shown in the spinner during execution */
|
|
77
|
+
const AGENT_ICONS = {
|
|
78
|
+
'context-gatherer': '📂',
|
|
79
|
+
'planner': '📋',
|
|
80
|
+
'writer': '✏️',
|
|
81
|
+
'reviewer': '👁️',
|
|
82
|
+
'tester': '🧪',
|
|
83
|
+
'debugger': '🐛',
|
|
84
|
+
'runner': '▶️',
|
|
85
|
+
'git': '🔀',
|
|
86
|
+
'package': '📦',
|
|
87
|
+
'github-release': '🏷️',
|
|
88
|
+
'security': '🔒',
|
|
89
|
+
};
|
|
90
|
+
function createAgent(agentType, _options) {
|
|
91
|
+
switch (agentType) {
|
|
92
|
+
case 'context-gatherer':
|
|
93
|
+
return new ContextGathererAgent();
|
|
94
|
+
case 'planner':
|
|
95
|
+
return new PlannerAgent();
|
|
96
|
+
case 'writer':
|
|
97
|
+
return new WriterAgent();
|
|
98
|
+
case 'reviewer':
|
|
99
|
+
return new ReviewerAgent();
|
|
100
|
+
case 'runner':
|
|
101
|
+
return new RunnerAgent();
|
|
102
|
+
case 'tester':
|
|
103
|
+
return new TesterAgent();
|
|
104
|
+
case 'debugger':
|
|
105
|
+
return new DebuggerAgent();
|
|
106
|
+
case 'git':
|
|
107
|
+
return new GitAgent();
|
|
108
|
+
case 'package':
|
|
109
|
+
return new PackageAgent();
|
|
110
|
+
case 'github-release':
|
|
111
|
+
return new GitHubReleaseAgent();
|
|
112
|
+
case 'security':
|
|
113
|
+
return new SecurityAgent();
|
|
114
|
+
default:
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// ─── Orchestrator ───────────────────────────────────────────────────────────
|
|
119
|
+
export class Orchestrator {
|
|
120
|
+
configManager;
|
|
121
|
+
constructor(configManager) {
|
|
122
|
+
this.configManager = configManager ?? new ConfigManager();
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Execute a multi-agent pipeline for the given goal.
|
|
126
|
+
*/
|
|
127
|
+
async execute(goal, options = {}) {
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
const vault = new ContextVault(goal, process.cwd());
|
|
130
|
+
const defaultCallLLM = this.createLLMProvider(options);
|
|
131
|
+
const agentResults = [];
|
|
132
|
+
const contextFiles = [];
|
|
133
|
+
// ── 2b. Build project file tree and inject for Planner ────────────────
|
|
134
|
+
if (options.verbose)
|
|
135
|
+
logger.highlight('\n📂 Scanning project structure...');
|
|
136
|
+
try {
|
|
137
|
+
const fullTree = await buildProjectFileTree(process.cwd());
|
|
138
|
+
// Truncate to 100 lines max to avoid blowing token limits
|
|
139
|
+
const treeForPlanner = truncateTree(fullTree, 100);
|
|
140
|
+
vault.setMeta('projectFileTree', treeForPlanner);
|
|
141
|
+
if (options.verbose) {
|
|
142
|
+
const fileCount = fullTree.split('\n').filter((l) => l.includes('📄')).length;
|
|
143
|
+
logger.info(` Found ${fileCount} source files in project`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
logger.debug(`File tree build failed (non-critical): ${err}`);
|
|
148
|
+
vault.setMeta('projectFileTree', '');
|
|
149
|
+
}
|
|
150
|
+
// ── 3. Memory Retrieval ──────────────────────────────────────────────
|
|
151
|
+
let memoryContext = '';
|
|
152
|
+
if (options.useMemory) {
|
|
153
|
+
if (options.verbose)
|
|
154
|
+
logger.highlight('\n🔍 Searching memory for similar past tasks...');
|
|
155
|
+
let patternContext = '';
|
|
156
|
+
try {
|
|
157
|
+
const { retrieveMemoryContext } = await import('../memory/memory-integration.js');
|
|
158
|
+
const memoryResult = await retrieveMemoryContext(goal, defaultCallLLM, 3);
|
|
159
|
+
memoryContext = memoryResult.fewShotContext;
|
|
160
|
+
// Also inject coding patterns if available
|
|
161
|
+
patternContext = memoryResult.patternContext || '';
|
|
162
|
+
if (options.verbose) {
|
|
163
|
+
if (memoryResult.trajectories.length > 0) {
|
|
164
|
+
logger.info(` Found ${memoryResult.trajectories.length} similar past trajectories`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
logger.info(' No similar past tasks found in memory');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
logger.debug(`Memory retrieval failed: ${err}`);
|
|
173
|
+
}
|
|
174
|
+
// Inject memory context and patterns into vault for agents
|
|
175
|
+
if (memoryContext) {
|
|
176
|
+
vault.setMeta('memoryContext', memoryContext);
|
|
177
|
+
}
|
|
178
|
+
if (patternContext) {
|
|
179
|
+
vault.setMeta('patternContext', patternContext);
|
|
180
|
+
memoryContext += `\n${patternContext}`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ── 3b. Auto-route models ─────────────────────────────────────────────
|
|
184
|
+
if (options.autoRouteModels && !options.agentModels) {
|
|
185
|
+
const autoModels = buildAgentModelMap();
|
|
186
|
+
options.agentModels = autoModels;
|
|
187
|
+
if (options.verbose) {
|
|
188
|
+
logger.info(' Auto-routing models based on task type');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// ── 4. Planner (or pre-built plan from workflow template) ────────────
|
|
192
|
+
if (options.prefillPlan && options.prefillPlan.length > 0) {
|
|
193
|
+
for (const step of options.prefillPlan) {
|
|
194
|
+
vault.context.taskPlan.push({ ...step });
|
|
195
|
+
}
|
|
196
|
+
agentResults.push({ agent: 'Planner', success: true, summary: `Using pre-built '${options.prefillPlan.length}-step' workflow plan` });
|
|
197
|
+
if (options.verbose) {
|
|
198
|
+
logger.highlight('\n📋 Using workflow template plan...');
|
|
199
|
+
logger.info(` Using ${options.prefillPlan.length} pre-defined steps`);
|
|
200
|
+
for (const step of options.prefillPlan) {
|
|
201
|
+
logger.info(` [${step.agentType}] ${step.description}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
if (options.verbose)
|
|
207
|
+
logger.highlight('\n📋 Planning...');
|
|
208
|
+
const planResult = await this.runAgent(new PlannerAgent(), vault, defaultCallLLM, options);
|
|
209
|
+
agentResults.push({ agent: 'Planner', success: planResult.success, summary: planResult.summary });
|
|
210
|
+
if (!planResult.success) {
|
|
211
|
+
return this.buildResult(false, goal, agentResults, vault, {
|
|
212
|
+
error: planResult.error || 'Planning failed',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (vault.context.taskPlan.length === 0) {
|
|
216
|
+
return this.buildResult(false, goal, agentResults, vault, {
|
|
217
|
+
error: 'Planner did not produce a valid task plan',
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (options.verbose) {
|
|
221
|
+
logger.info(` Created ${vault.context.taskPlan.length} task steps`);
|
|
222
|
+
for (const step of vault.context.taskPlan) {
|
|
223
|
+
logger.info(` [${step.agentType}] ${step.description}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ── 4b. Push initial DAG state to dashboard ─────────────────────────
|
|
228
|
+
if (vault.context.taskPlan.length > 0) {
|
|
229
|
+
await tryResetDAG();
|
|
230
|
+
const nodes = vault.context.taskPlan.map((step) => ({
|
|
231
|
+
id: step.id,
|
|
232
|
+
agentType: step.agentType,
|
|
233
|
+
status: 'pending',
|
|
234
|
+
description: step.description,
|
|
235
|
+
}));
|
|
236
|
+
const edges = [];
|
|
237
|
+
for (const step of vault.context.taskPlan) {
|
|
238
|
+
for (const dep of step.dependsOn) {
|
|
239
|
+
edges.push({ from: dep, to: step.id });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
await tryPushDAG({
|
|
243
|
+
pipelineId: goal,
|
|
244
|
+
pipelineDescription: goal.slice(0, 80),
|
|
245
|
+
nodes,
|
|
246
|
+
edges,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// ── 5. Execute tasks ─────────────────────────────────────────────────
|
|
250
|
+
if (options.verbose)
|
|
251
|
+
logger.highlight('\n⚡ Executing tasks...');
|
|
252
|
+
// Update spinner to show we've moved past planning into execution
|
|
253
|
+
if (options.spinner && vault.context.taskPlan.length > 0) {
|
|
254
|
+
const total = vault.context.taskPlan.length;
|
|
255
|
+
options.spinner.start(`⚡ Executing ${total} task${total !== 1 ? 's' : ''}...`);
|
|
256
|
+
}
|
|
257
|
+
for (let iteration = 0; iteration < 50; iteration++) {
|
|
258
|
+
if (vault.isComplete)
|
|
259
|
+
break;
|
|
260
|
+
const runnableTasks = vault.getRunnableTasks();
|
|
261
|
+
if (runnableTasks.length === 0 && !vault.isComplete) {
|
|
262
|
+
const stuck = vault.context.taskPlan.filter((s) => s.status === 'pending');
|
|
263
|
+
for (const s of stuck) {
|
|
264
|
+
const failedDep = vault.context.taskPlan.find((d) => s.dependsOn.includes(d.id) && d.status === 'failed');
|
|
265
|
+
const reason = failedDep
|
|
266
|
+
? `Dependency failed: ${failedDep.id} (${failedDep.description.slice(0, 60)})`
|
|
267
|
+
: 'Deadlocked: dependencies could not be satisfied';
|
|
268
|
+
vault.updateTaskStatus(s.id, 'failed', reason);
|
|
269
|
+
}
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
// Runner and sandbox agents need exclusive access (no parallel)
|
|
273
|
+
const exclusiveAgentTypes = ['tester', 'debugger', 'runner'];
|
|
274
|
+
const canParallel = runnableTasks.length > 1 &&
|
|
275
|
+
!runnableTasks.some((t) => exclusiveAgentTypes.includes(t.agentType));
|
|
276
|
+
if (canParallel) {
|
|
277
|
+
for (const task of runnableTasks) {
|
|
278
|
+
vault.updateTaskStatus(task.id, 'running');
|
|
279
|
+
}
|
|
280
|
+
if (options.verbose) {
|
|
281
|
+
logger.info(`\n ⚡ Running ${runnableTasks.length} tasks in parallel...`);
|
|
282
|
+
}
|
|
283
|
+
const taskPromises = runnableTasks.map((task) => this.executeSingleTask(task, vault, options, agentResults, contextFiles, defaultCallLLM));
|
|
284
|
+
await Promise.all(taskPromises);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
for (const task of runnableTasks) {
|
|
288
|
+
await this.executeSingleTask(task, vault, options, agentResults, contextFiles, defaultCallLLM);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// ── 6. Clean up sandbox if any ────────────────────────────────────────
|
|
293
|
+
const sandboxPath = vault.getMeta('sandboxPath');
|
|
294
|
+
if (sandboxPath) {
|
|
295
|
+
try {
|
|
296
|
+
cleanupSandbox(sandboxPath);
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// Best-effort cleanup
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// ── 6b. Review mode — create a review bundle instead of applying changes
|
|
303
|
+
let reviewId;
|
|
304
|
+
if (options.reviewMode && vault.context.fileChanges.filter(c => c.newContent || c.status === 'deleted').length > 0) {
|
|
305
|
+
const fileChanges = vault.context.fileChanges.map((c) => ({
|
|
306
|
+
path: c.path,
|
|
307
|
+
originalContent: c.originalContent,
|
|
308
|
+
newContent: c.newContent,
|
|
309
|
+
status: c.status,
|
|
310
|
+
}));
|
|
311
|
+
// Build a summary from agent results
|
|
312
|
+
const summaryLines = agentResults.map((r) => `${r.success ? '✅' : '❌'} ${r.agent}: ${r.summary.slice(0, 120)}`);
|
|
313
|
+
summaryLines.push('');
|
|
314
|
+
summaryLines.push(vault.getDiffSummary());
|
|
315
|
+
const fullSummary = summaryLines.join('\n');
|
|
316
|
+
const review = createReviewFromResult(goal, fileChanges, fullSummary, {
|
|
317
|
+
provider: options.provider,
|
|
318
|
+
model: options.model,
|
|
319
|
+
author: process.env.USER || 'agent-nuvira',
|
|
320
|
+
});
|
|
321
|
+
reviewId = review.id;
|
|
322
|
+
if (options.verbose) {
|
|
323
|
+
logger.highlight(`\n📋 Created review bundle: ${review.id}`);
|
|
324
|
+
logger.info(` Run \`buff team review show ${review.id}\` to view`);
|
|
325
|
+
logger.info(` Run \`buff team review approve ${review.id}\` then \`buff team review merge ${review.id}\` to apply`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// ── 6c. Apply file changes ────────────────────────────────────────────
|
|
329
|
+
if (!options.reviewMode && !options.dryRun) {
|
|
330
|
+
const applied = this.applyFileChanges(vault);
|
|
331
|
+
if (applied > 0 && options.verbose) {
|
|
332
|
+
logger.success(`\n 💾 Applied ${applied} file change${applied !== 1 ? 's' : ''} to disk`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else if (options.verbose && options.reviewMode) {
|
|
336
|
+
logger.info(' 📋 Review mode — changes saved as review bundle instead of written to disk');
|
|
337
|
+
}
|
|
338
|
+
// ── 6d. Collect runner output for display ────────────────────────────
|
|
339
|
+
let runOutput;
|
|
340
|
+
const runResult = vault.getMeta('runResult');
|
|
341
|
+
if (runResult) {
|
|
342
|
+
const lines = [];
|
|
343
|
+
lines.push(`$ ${runResult.command}`);
|
|
344
|
+
lines.push(`Exit code: ${runResult.exitCode} | Duration: ${runResult.duration}ms`);
|
|
345
|
+
if (runResult.stdout) {
|
|
346
|
+
lines.push('');
|
|
347
|
+
lines.push(runResult.stdout.slice(0, 2000)); // Limit displayed output
|
|
348
|
+
if (runResult.stdout.length > 2000) {
|
|
349
|
+
lines.push('... (output truncated)');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (runResult.stderr && runResult.exitCode !== 0) {
|
|
353
|
+
lines.push('');
|
|
354
|
+
lines.push('stderr:');
|
|
355
|
+
lines.push(runResult.stderr.slice(0, 1000));
|
|
356
|
+
}
|
|
357
|
+
runOutput = lines.join('\n');
|
|
358
|
+
}
|
|
359
|
+
// ── 7. Store trajectory in memory + self-improvement loop ───────────
|
|
360
|
+
let trajectoryId = '';
|
|
361
|
+
if (options.useMemory) {
|
|
362
|
+
try {
|
|
363
|
+
const orchestrationSummary = {
|
|
364
|
+
success: !vault.hasFailedTasks,
|
|
365
|
+
goal,
|
|
366
|
+
summary: '',
|
|
367
|
+
tasksCompleted: vault.context.taskPlan.filter((s) => s.status === 'completed').length,
|
|
368
|
+
tasksTotal: vault.context.taskPlan.length,
|
|
369
|
+
agentResults,
|
|
370
|
+
fileChanges: vault.getDiffSummary(),
|
|
371
|
+
};
|
|
372
|
+
const { storeExecutionTrajectory } = await import('../memory/memory-integration.js');
|
|
373
|
+
trajectoryId = await storeExecutionTrajectory(orchestrationSummary, defaultCallLLM, vault.context.taskPlan, contextFiles, options.verbose);
|
|
374
|
+
// Self-improvement
|
|
375
|
+
try {
|
|
376
|
+
const { getSelfImprover } = await import('../learning/self-improver.js');
|
|
377
|
+
const improver = getSelfImprover();
|
|
378
|
+
await improver.processRun({ ...orchestrationSummary, trajectoryId }, defaultCallLLM, options.agentModels, options.verbose);
|
|
379
|
+
if (options.verbose && trajectoryId) {
|
|
380
|
+
logger.info(' Self-improvement stats saved. Run `buff learn optimize` to see recommendations.');
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
catch (err) {
|
|
384
|
+
logger.debug(`Self-improvement loop failed: ${err}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
logger.debug(`Trajectory storage failed: ${err}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// ── 8. Synthesize result ─────────────────────────────────────────────
|
|
392
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
393
|
+
const completed = vault.context.taskPlan.filter((s) => s.status === 'completed').length;
|
|
394
|
+
const total = vault.context.taskPlan.length;
|
|
395
|
+
const hasFailures = vault.hasFailedTasks;
|
|
396
|
+
const summaryLines = [];
|
|
397
|
+
summaryLines.push(hasFailures
|
|
398
|
+
? `Completed ${completed}/${total} tasks with some failures in ${elapsed}s`
|
|
399
|
+
: `Completed all ${completed} tasks successfully in ${elapsed}s`);
|
|
400
|
+
summaryLines.push('');
|
|
401
|
+
summaryLines.push('Changes:');
|
|
402
|
+
summaryLines.push(vault.getDiffSummary());
|
|
403
|
+
return this.buildResult(!hasFailures, goal, agentResults, vault, {
|
|
404
|
+
summary: summaryLines.join('\n'),
|
|
405
|
+
tasksCompleted: completed,
|
|
406
|
+
tasksTotal: total,
|
|
407
|
+
trajectoryId,
|
|
408
|
+
reviewId,
|
|
409
|
+
runOutput,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
// ─── Private Helpers ──────────────────────────────────────────────────
|
|
413
|
+
createLLMProvider(options) {
|
|
414
|
+
const providerType = (options.provider ||
|
|
415
|
+
this.configManager.getAll().defaultProvider);
|
|
416
|
+
const { config } = this.configManager.getProviderConfig(providerType);
|
|
417
|
+
const provider = ProviderFactory.createProvider(providerType, config);
|
|
418
|
+
return async (prompt, inferenceOptions) => {
|
|
419
|
+
// Runtime injection guardrail
|
|
420
|
+
const injectionFindings = scanForInjections(prompt);
|
|
421
|
+
if (injectionFindings.length > 0) {
|
|
422
|
+
const report = formatScanReport({
|
|
423
|
+
passed: false,
|
|
424
|
+
findings: injectionFindings,
|
|
425
|
+
summary: 'Prompt injection detected — call blocked',
|
|
426
|
+
});
|
|
427
|
+
throw new Error(`Injection guardrail blocked LLM call:\n${report}`);
|
|
428
|
+
}
|
|
429
|
+
const mergedOptions = {
|
|
430
|
+
...inferenceOptions,
|
|
431
|
+
model: options.model || inferenceOptions?.model || config.model,
|
|
432
|
+
temperature: inferenceOptions?.temperature ?? config.temperature ?? 0.7,
|
|
433
|
+
maxTokens: inferenceOptions?.maxTokens ?? config.maxTokens ?? 4096,
|
|
434
|
+
};
|
|
435
|
+
return provider.generate(prompt, mergedOptions);
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
async runAgent(agent, vault, callLLM, _options) {
|
|
439
|
+
try {
|
|
440
|
+
return await agent.execute(vault.context, callLLM);
|
|
441
|
+
}
|
|
442
|
+
catch (err) {
|
|
443
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
444
|
+
return { success: false, summary: `${agent.name} errored`, error: msg };
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Create the onRateLimit callback that prompts the user.
|
|
449
|
+
* Returns undefined if we're in non-interactive mode (no TTY or dry-run).
|
|
450
|
+
*/
|
|
451
|
+
createRateLimitHandler(options, currentModel) {
|
|
452
|
+
// Don't prompt in non-interactive or dry-run mode — just use auto-retry
|
|
453
|
+
if (options.dryRun || !process.stdout.isTTY) {
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
456
|
+
return async (info) => {
|
|
457
|
+
// ── Stop the CLI spinner before showing interactive prompts ──────
|
|
458
|
+
const spl = options.spinner;
|
|
459
|
+
if (spl)
|
|
460
|
+
spl.stop();
|
|
461
|
+
const waitSeconds = (info.retryAfterMs / 1000).toFixed(1);
|
|
462
|
+
const modelStr = info.modelName
|
|
463
|
+
? `Model: ${info.modelName}`
|
|
464
|
+
: currentModel
|
|
465
|
+
? `Model: ${currentModel}`
|
|
466
|
+
: '';
|
|
467
|
+
console.log('');
|
|
468
|
+
logger.warn(`\u26A0\uFE0F Rate limit hit for ${info.agentName}`);
|
|
469
|
+
logger.info(` ${modelStr}`);
|
|
470
|
+
logger.info(` Please wait ${waitSeconds}s before next request`);
|
|
471
|
+
console.log('');
|
|
472
|
+
const { action } = await inquirer.prompt([
|
|
473
|
+
{
|
|
474
|
+
type: 'list',
|
|
475
|
+
name: 'action',
|
|
476
|
+
message: `What would you like to do?`,
|
|
477
|
+
prefix: '\u{1F504}',
|
|
478
|
+
choices: [
|
|
479
|
+
{ name: `\u23F3 Wait ${waitSeconds}s and retry`, value: 'retry' },
|
|
480
|
+
{ name: '\u{1F500} Switch to a different model', value: 'switch-model' },
|
|
481
|
+
{ name: '\u23ED Skip this step', value: 'skip' },
|
|
482
|
+
{ name: '\u274C Abort the pipeline', value: 'abort' },
|
|
483
|
+
],
|
|
484
|
+
},
|
|
485
|
+
]);
|
|
486
|
+
console.log('');
|
|
487
|
+
// Helper to restart the spinner before returning
|
|
488
|
+
const restartSpinner = () => {
|
|
489
|
+
if (spl)
|
|
490
|
+
spl.start();
|
|
491
|
+
};
|
|
492
|
+
if (action === 'retry') {
|
|
493
|
+
logger.info(`Waiting ${waitSeconds}s as requested...`);
|
|
494
|
+
restartSpinner();
|
|
495
|
+
return { action: 'retry' };
|
|
496
|
+
}
|
|
497
|
+
if (action === 'skip') {
|
|
498
|
+
logger.info('Skipping this step.');
|
|
499
|
+
restartSpinner();
|
|
500
|
+
return { action: 'skip' };
|
|
501
|
+
}
|
|
502
|
+
if (action === 'abort') {
|
|
503
|
+
logger.error('Pipeline aborted by user.');
|
|
504
|
+
// Don't restart spinner — pipeline is ending
|
|
505
|
+
return { action: 'abort' };
|
|
506
|
+
}
|
|
507
|
+
if (action === 'switch-model') {
|
|
508
|
+
// Show the categorized model picker so the user can choose visually
|
|
509
|
+
const picked = await showModelPicker(this.configManager);
|
|
510
|
+
if (!picked) {
|
|
511
|
+
logger.info('Model selection cancelled — retrying with current model.');
|
|
512
|
+
restartSpinner();
|
|
513
|
+
return { action: 'retry' };
|
|
514
|
+
}
|
|
515
|
+
console.log('');
|
|
516
|
+
logger.info(`Switching to model: ${picked.model} (provider: ${picked.provider})`);
|
|
517
|
+
// Create a new LLM provider with the switched model
|
|
518
|
+
const newOptions = {
|
|
519
|
+
...options,
|
|
520
|
+
provider: picked.provider,
|
|
521
|
+
model: picked.model,
|
|
522
|
+
};
|
|
523
|
+
const newCallLLM = this.createLLMProvider(newOptions);
|
|
524
|
+
restartSpinner();
|
|
525
|
+
return { action: 'switch-model', callLLM: newCallLLM };
|
|
526
|
+
}
|
|
527
|
+
// Fallback: retry
|
|
528
|
+
restartSpinner();
|
|
529
|
+
return { action: 'retry' };
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
async executeSingleTask(task, vault, options, agentResults, contextFiles, defaultCallLLM) {
|
|
533
|
+
vault.updateTaskStatus(task.id, 'running');
|
|
534
|
+
await tryUpdateDAGNode(task.id, { status: 'running' });
|
|
535
|
+
// Update spinner text to show which task is currently executing
|
|
536
|
+
if (options.spinner) {
|
|
537
|
+
const agentIcon = AGENT_ICONS[task.agentType] || '⚙️';
|
|
538
|
+
const shortDesc = task.description.slice(0, 60);
|
|
539
|
+
options.spinner.start(`${agentIcon} ${shortDesc}${task.description.length > 60 ? '...' : ''}`);
|
|
540
|
+
}
|
|
541
|
+
if (options.verbose) {
|
|
542
|
+
logger.info(`\n ▶️ ${task.agentType}: ${task.description.slice(0, 80)}${task.description.length > 80 ? '...' : ''}`);
|
|
543
|
+
}
|
|
544
|
+
try {
|
|
545
|
+
const agentModel = options.model || options.agentModels?.[task.agentType];
|
|
546
|
+
const agentCallLLM = agentModel
|
|
547
|
+
? this.createLLMProvider({ ...options, model: agentModel })
|
|
548
|
+
: defaultCallLLM;
|
|
549
|
+
// Skip runner tasks in dry-run mode (no commands executed)
|
|
550
|
+
if (task.agentType === 'runner' && options.dryRun) {
|
|
551
|
+
vault.updateTaskStatus(task.id, 'completed', 'Skipped (dry-run mode)');
|
|
552
|
+
agentResults.push({
|
|
553
|
+
agent: 'runner',
|
|
554
|
+
success: true,
|
|
555
|
+
summary: 'Skipped (dry-run mode — no commands executed)',
|
|
556
|
+
});
|
|
557
|
+
if (options.verbose) {
|
|
558
|
+
logger.info(' ⏭️ Skipped (dry-run — no commands executed)');
|
|
559
|
+
}
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
const agent = createAgent(task.agentType, options);
|
|
563
|
+
if (!agent) {
|
|
564
|
+
vault.updateTaskStatus(task.id, 'failed', `Unknown agent type: ${task.agentType}`);
|
|
565
|
+
agentResults.push({
|
|
566
|
+
agent: task.agentType,
|
|
567
|
+
success: false,
|
|
568
|
+
summary: `Unknown agent type: ${task.agentType}`,
|
|
569
|
+
});
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
// Wire up the rate-limit handler so agents can prompt the user
|
|
573
|
+
vault.context.onRateLimit = this.createRateLimitHandler(options, agentModel || options.model);
|
|
574
|
+
const result = await agent.execute(vault.context, agentCallLLM);
|
|
575
|
+
vault.updateTaskStatus(task.id, result.success ? 'completed' : 'failed', result.summary);
|
|
576
|
+
await tryUpdateDAGNode(task.id, {
|
|
577
|
+
status: result.success ? 'completed' : 'failed',
|
|
578
|
+
summary: result.summary,
|
|
579
|
+
});
|
|
580
|
+
agentResults.push({ agent: task.agentType, success: result.success, summary: result.summary });
|
|
581
|
+
// Track sandbox path for cleanup
|
|
582
|
+
if (result.success && task.agentType === 'tester') {
|
|
583
|
+
const testResult = vault.getMeta('testResult');
|
|
584
|
+
if (testResult?.sandboxPath) {
|
|
585
|
+
vault.setMeta('sandboxPath', testResult.sandboxPath);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// After debugger step: write debugger's fixes to disk immediately
|
|
589
|
+
// The DebuggerAgent's syncChangesToContext() updates context.fileChanges
|
|
590
|
+
// with LLM-generated fixes. If a runner step follows the debugger, those
|
|
591
|
+
// fixes must be on disk before the runner executes.
|
|
592
|
+
if (task.agentType === 'debugger' && result.success && !options.dryRun) {
|
|
593
|
+
const applied = this.applyFileChanges(vault);
|
|
594
|
+
if (applied > 0 && options.verbose) {
|
|
595
|
+
logger.info(` 💾 Applied ${applied} debug fix(es) to disk`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// After writer step: write files to disk immediately and sync into artifacts
|
|
599
|
+
// IMPORTANT: files MUST be on disk before the RunnerAgent tries to execute them
|
|
600
|
+
if (task.agentType === 'writer' && result.success) {
|
|
601
|
+
if (!options.dryRun) {
|
|
602
|
+
const applied = this.applyFileChanges(vault);
|
|
603
|
+
if (applied > 0 && options.verbose) {
|
|
604
|
+
logger.info(` 💾 Applied ${applied} file change${applied !== 1 ? 's' : ''} to disk`);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
const newArtifacts = vault.context.fileChanges
|
|
608
|
+
.filter((c) => c.status === 'created' || c.status === 'modified')
|
|
609
|
+
.filter((c) => c.newContent)
|
|
610
|
+
.map((c) => ({
|
|
611
|
+
path: c.path,
|
|
612
|
+
content: c.newContent,
|
|
613
|
+
description: `${c.status} by WriterAgent (${task.description.slice(0, 60)})`,
|
|
614
|
+
}));
|
|
615
|
+
for (const artifact of newArtifacts) {
|
|
616
|
+
const existing = vault.context.artifacts.findIndex((a) => a.path === artifact.path);
|
|
617
|
+
if (existing >= 0) {
|
|
618
|
+
vault.context.artifacts[existing] = artifact;
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
vault.context.artifacts.push(artifact);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
// After runner step: refresh artifacts with any files created during execution
|
|
626
|
+
if (task.agentType === 'runner' && result.success) {
|
|
627
|
+
const runResult = vault.getMeta('runResult');
|
|
628
|
+
if (runResult?.stdout) {
|
|
629
|
+
vault.setMeta('runOutput', runResult.stdout);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// Track context file paths for memory storage
|
|
633
|
+
if (task.agentType === 'context-gatherer' && result.success) {
|
|
634
|
+
for (const artifact of vault.context.artifacts) {
|
|
635
|
+
if (!contextFiles.includes(artifact.path)) {
|
|
636
|
+
contextFiles.push(artifact.path);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (options.verbose) {
|
|
641
|
+
const icon = result.success ? '✅' : '⚠️';
|
|
642
|
+
logger.info(` ${icon} ${result.summary}`);
|
|
643
|
+
// If it's a runner, show the output inline
|
|
644
|
+
if (task.agentType === 'runner' && result.success && result.details) {
|
|
645
|
+
const outputLines = result.details.split('\n').filter((l) => l.startsWith('stdout:') || l.startsWith('Command:'));
|
|
646
|
+
for (const line of outputLines) {
|
|
647
|
+
logger.info(` ${line}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
catch (err) {
|
|
653
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
654
|
+
vault.updateTaskStatus(task.id, 'failed', msg);
|
|
655
|
+
await tryUpdateDAGNode(task.id, { status: 'failed', summary: msg });
|
|
656
|
+
agentResults.push({ agent: task.agentType, success: false, summary: `Error: ${msg}` });
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
applyFileChanges(vault) {
|
|
660
|
+
let count = 0;
|
|
661
|
+
for (const change of vault.context.fileChanges) {
|
|
662
|
+
if (change.status === 'deleted')
|
|
663
|
+
continue;
|
|
664
|
+
if (!change.newContent)
|
|
665
|
+
continue;
|
|
666
|
+
const absolutePath = isAbsolute(change.path)
|
|
667
|
+
? change.path
|
|
668
|
+
: resolve(process.cwd(), change.path);
|
|
669
|
+
const dir = dirname(absolutePath);
|
|
670
|
+
if (!existsSync(dir)) {
|
|
671
|
+
mkdirSync(dir, { recursive: true });
|
|
672
|
+
}
|
|
673
|
+
writeFileSync(absolutePath, change.newContent, 'utf-8');
|
|
674
|
+
count++;
|
|
675
|
+
}
|
|
676
|
+
return count;
|
|
677
|
+
}
|
|
678
|
+
buildResult(success, goal, agentResults, vault, overrides = {}) {
|
|
679
|
+
const completed = overrides.tasksCompleted ?? agentResults.filter((r) => r.success).length;
|
|
680
|
+
const total = overrides.tasksTotal ?? agentResults.length;
|
|
681
|
+
return {
|
|
682
|
+
success,
|
|
683
|
+
goal,
|
|
684
|
+
summary: overrides.summary || `Execution completed with status: ${success ? 'success' : 'failure'}`,
|
|
685
|
+
tasksCompleted: completed,
|
|
686
|
+
tasksTotal: total,
|
|
687
|
+
agentResults,
|
|
688
|
+
fileChanges: vault.getDiffSummary(),
|
|
689
|
+
runOutput: overrides.runOutput,
|
|
690
|
+
error: overrides.error,
|
|
691
|
+
trajectoryId: overrides.trajectoryId,
|
|
692
|
+
reviewId: overrides.reviewId,
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
//# sourceMappingURL=orchestrator.js.map
|