agentic-orchestrator 0.1.13 → 0.1.15
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/AGENTS.md +139 -0
- package/CLAUDE.md +12 -0
- package/agentic/orchestrator/agents.yaml +3 -0
- package/agentic/orchestrator/defaults/policy.defaults.yaml +3 -0
- package/agentic/orchestrator/policy.yaml +3 -0
- package/agentic/orchestrator/schemas/agents.schema.json +15 -0
- package/agentic/orchestrator/schemas/policy.schema.json +14 -0
- package/apps/control-plane/src/cli/cli-argument-parser.ts +7 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +8 -0
- package/apps/control-plane/src/cli/init-command-handler.ts +6 -0
- package/apps/control-plane/src/cli/resume-command-handler.ts +31 -2
- package/apps/control-plane/src/cli/run-command-handler.ts +31 -3
- package/apps/control-plane/src/cli/types.ts +1 -0
- package/apps/control-plane/src/core/error-codes.ts +4 -0
- package/apps/control-plane/src/core/kernel.ts +3 -0
- package/apps/control-plane/src/index.ts +14 -0
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +25 -3
- package/apps/control-plane/src/providers/api-worker-provider.ts +115 -0
- package/apps/control-plane/src/providers/cli-worker-provider.ts +385 -0
- package/apps/control-plane/src/providers/output-parsers/generic-output-parser.ts +100 -0
- package/apps/control-plane/src/providers/output-parsers/index.ts +11 -0
- package/apps/control-plane/src/providers/output-parsers/types.ts +23 -0
- package/apps/control-plane/src/providers/providers.ts +19 -0
- package/apps/control-plane/src/providers/worker-provider-factory.ts +198 -0
- package/apps/control-plane/src/supervisor/build-wave-executor.ts +140 -3
- package/apps/control-plane/src/supervisor/planning-wave-executor.ts +125 -5
- package/apps/control-plane/src/supervisor/qa-wave-executor.ts +144 -2
- package/apps/control-plane/src/supervisor/runtime.ts +24 -0
- package/apps/control-plane/src/supervisor/worker-decision-loop.ts +134 -12
- package/apps/control-plane/test/cli.unit.spec.ts +36 -0
- package/apps/control-plane/test/dashboard-api.integration.spec.ts +2 -2
- package/apps/control-plane/test/resume-command.spec.ts +31 -1
- package/apps/control-plane/test/worker-decision-loop.spec.ts +3 -0
- package/apps/control-plane/test/worker-execution-policy.spec.ts +284 -0
- package/apps/control-plane/test/worker-provider-adapters.spec.ts +440 -0
- package/apps/control-plane/test/worker-provider-factory.spec.ts +151 -0
- package/config/agentic/orchestrator/agents.yaml +3 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js +7 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/help-command-handler.js +8 -0
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.js +6 -0
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/resume-command-handler.d.ts +3 -0
- package/dist/apps/control-plane/cli/resume-command-handler.js +18 -2
- package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/run-command-handler.d.ts +3 -1
- package/dist/apps/control-plane/cli/run-command-handler.js +17 -3
- package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/types.d.ts +1 -0
- package/dist/apps/control-plane/core/error-codes.d.ts +4 -0
- package/dist/apps/control-plane/core/error-codes.js +4 -0
- package/dist/apps/control-plane/core/error-codes.js.map +1 -1
- package/dist/apps/control-plane/core/kernel.d.ts +3 -0
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/index.d.ts +2 -0
- package/dist/apps/control-plane/index.js +1 -0
- package/dist/apps/control-plane/index.js.map +1 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +14 -2
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/providers/api-worker-provider.d.ts +31 -0
- package/dist/apps/control-plane/providers/api-worker-provider.js +73 -0
- package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -0
- package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +46 -0
- package/dist/apps/control-plane/providers/cli-worker-provider.js +274 -0
- package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -0
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.d.ts +10 -0
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js +79 -0
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js.map +1 -0
- package/dist/apps/control-plane/providers/output-parsers/index.d.ts +2 -0
- package/dist/apps/control-plane/providers/output-parsers/index.js +2 -0
- package/dist/apps/control-plane/providers/output-parsers/index.js.map +1 -0
- package/dist/apps/control-plane/providers/output-parsers/types.d.ts +21 -0
- package/dist/apps/control-plane/providers/output-parsers/types.js +2 -0
- package/dist/apps/control-plane/providers/output-parsers/types.js.map +1 -0
- package/dist/apps/control-plane/providers/providers.d.ts +4 -0
- package/dist/apps/control-plane/providers/providers.js +15 -0
- package/dist/apps/control-plane/providers/providers.js.map +1 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +41 -0
- package/dist/apps/control-plane/providers/worker-provider-factory.js +104 -0
- package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -0
- package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +13 -0
- package/dist/apps/control-plane/supervisor/build-wave-executor.js +92 -3
- package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/planning-wave-executor.d.ts +12 -0
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js +83 -5
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +13 -0
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js +91 -2
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/runtime.js +19 -0
- package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +10 -0
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js +113 -12
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
- package/package.json +2 -2
- package/packages/web-dashboard/next-env.d.ts +2 -1
- package/packages/web-dashboard/src/app/api/features/[id]/checkout/route.ts +4 -3
- package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +6 -2
- package/packages/web-dashboard/src/app/api/features/[id]/evidence/[artifact]/route.ts +6 -5
- package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +5 -4
- package/packages/web-dashboard/src/app/api/features/[id]/route.ts +7 -3
- package/packages/web-dashboard/src/lib/aop-client.ts +2 -2
- package/packages/web-dashboard/src/lib/orchestrator-tools.ts +1 -1
- package/packages/web-dashboard/tsconfig.json +1 -0
- package/spec-files/outstanding/agentic_orchestrator_human_input_interaction_protocol_spec.md +590 -0
- package/spec-files/outstanding/agentic_orchestrator_real_worker_provider_execution_spec.md +616 -0
- package/spec-files/progress.md +91 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to coding agents operating in this repository.
|
|
4
|
+
|
|
5
|
+
## Build & Development Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run build # Lint + TypeScript compile
|
|
9
|
+
npm run typecheck # tsc --noEmit (type-check only)
|
|
10
|
+
npm run lint # ESLint with --max-warnings 0
|
|
11
|
+
npm run lint:fix # ESLint with auto-fix
|
|
12
|
+
npm run test # Vitest with coverage (via Nx)
|
|
13
|
+
npm run run # Run CLI: tsx apps/control-plane/src/cli/aop.ts
|
|
14
|
+
|
|
15
|
+
# Run a single test file
|
|
16
|
+
npx vitest run apps/control-plane/test/<file>.spec.ts
|
|
17
|
+
|
|
18
|
+
# Run tests matching a pattern
|
|
19
|
+
npx vitest run -t "pattern"
|
|
20
|
+
|
|
21
|
+
# Validation scripts (also run in CI)
|
|
22
|
+
npm run validate:mcp-contracts
|
|
23
|
+
npm run validate:architecture
|
|
24
|
+
npm run validate:docker-mcp
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
This is an MCP-first, multi-agent orchestrator control plane. The codebase lives in an Nx monorepo with a single application at `apps/control-plane/`.
|
|
30
|
+
|
|
31
|
+
### Layer Overview
|
|
32
|
+
|
|
33
|
+
**CLI** (`apps/control-plane/src/cli/`) -> **Supervisor** (`supervisor/`) -> **Kernel** (`core/kernel.ts`) -> **Services** (`application/services/`)
|
|
34
|
+
|
|
35
|
+
- **CLI**: Entry point at `cli/aop.ts` -> delegates to `interfaces/cli/bootstrap.ts`. Commands: `run`, `status`, `resume`, `stop`, `delete`, `cleanup`, `init`, `dashboard`, `retry`, `send`, `attach`, `help`. All responses are structured JSON with `{ ok, data/error }`. Run `aop --help` or `aop help <command>` for usage details.
|
|
36
|
+
- **Kernel** (`core/kernel.ts`, ~900 lines): Deterministic orchestration engine. Manages schema validation, state, locks, plans, patches, gates, merges, and reporting. Delegates to 12+ domain services via port interfaces.
|
|
37
|
+
- **Supervisor** (`supervisor/runtime.ts`): Multi-agent runtime. Resolves providers (codex, claude, gemini, etc.), loads role-specific prompts, orchestrates planning/build/QA waves, and manages lease heartbeats.
|
|
38
|
+
- **MCP Tool Runtime** (`mcp/tool-runtime.ts`): Tool execution pipeline with registry-based dispatch, input/output schema validation, role-based authorization, and idempotency tracking via `operation_id`.
|
|
39
|
+
- **Application Services** (`application/services/`): 12+ focused services (plan, patch, gates, QA, locks, merge, deletion, etc.) implementing port interfaces consumed by the kernel.
|
|
40
|
+
|
|
41
|
+
### Configuration Layer (`config/agentic/orchestrator/`)
|
|
42
|
+
|
|
43
|
+
- `policy.yaml` - Commit/patch/merge policies, lock TTL, RBAC, supervisor iteration limits
|
|
44
|
+
- `gates.yaml` - Gate profiles (fast/full/merge) with commands and coverage thresholds
|
|
45
|
+
- `agents.yaml` - Agent roles (planner/builder/qa), provider defaults, prompt paths
|
|
46
|
+
- `prompts/` - Role-specific system prompts
|
|
47
|
+
- `tools/` - MCP tool contracts: `catalog.json` (33 tools), per-tool `schemas/input/` and `schemas/output/`
|
|
48
|
+
- `schemas/` - JSON schemas for policy, state, plan, index, gates, agents, qa_test_index
|
|
49
|
+
|
|
50
|
+
### Runtime Artifacts (`.aop/`)
|
|
51
|
+
|
|
52
|
+
- `.aop/features/index.json` - Global feature index (active/blocked/merged features, locks, sessions)
|
|
53
|
+
- `.aop/features/<id>/state.md` - Per-feature state (YAML frontmatter + markdown)
|
|
54
|
+
- `.aop/features/<id>/plan.json` - Versioned plan with optimistic concurrency
|
|
55
|
+
- `.aop/features/<id>/evidence/` - Gate evidence artifacts
|
|
56
|
+
|
|
57
|
+
## Key Patterns
|
|
58
|
+
|
|
59
|
+
- **Port-based DI**: Services define interface ports; the kernel implements them. This decouples domain logic from infrastructure.
|
|
60
|
+
- **Schema-driven validation**: All configs and artifacts validated via AJV against JSON schemas. Validation failures return structured errors with retry hints.
|
|
61
|
+
- **Atomic state management**: File locks, version guards, and optimistic concurrency for all state mutations.
|
|
62
|
+
- **Structured error codes**: 45+ error codes with `{ code, message, details: { retryable, requires_human, suggestions } }`.
|
|
63
|
+
- **Tool registry dispatch**: `catalog.json` metadata drives tool routing, replacing switch-based dispatch. Mutating tools require `operation_id` for idempotency.
|
|
64
|
+
|
|
65
|
+
## Design Principles
|
|
66
|
+
|
|
67
|
+
- **KISS (Keep It Simple, Stupid)**: Prefer the simplest design that satisfies requirements and preserves deterministic behavior.
|
|
68
|
+
- **SRP (Single Responsibility Principle)**: Each class/module should have one clear reason to change.
|
|
69
|
+
- **SOLID (pragmatic application)**:
|
|
70
|
+
- Open/Closed: Extend by adding adapters/services instead of modifying unrelated orchestrator flow.
|
|
71
|
+
- Interface Segregation: Keep interfaces focused (avoid broad "do everything" contracts).
|
|
72
|
+
- Dependency Inversion: Depend on ports/interfaces, not concrete infrastructure.
|
|
73
|
+
- **Hexagonal Architecture**: Domain/application layers must not depend directly on provider CLI/SDK details; keep those in adapter boundaries.
|
|
74
|
+
- **Composition over Inheritance**: Build behavior through composed collaborators (factory + adapter + parser + service) rather than deep class hierarchies.
|
|
75
|
+
- **High Cohesion, Low Coupling**: Keep CLI parsing, provider execution, orchestration logic, and persistence concerns in separate modules.
|
|
76
|
+
|
|
77
|
+
## Lint Rules to Know
|
|
78
|
+
|
|
79
|
+
- `no-explicit-any` is **enforced** in source, relaxed in tests
|
|
80
|
+
- `no-floating-promises` and `no-misused-promises` are errors
|
|
81
|
+
- `require-await` is enforced in source, relaxed in tests
|
|
82
|
+
- `consistent-type-imports` is required (use `import type` for type-only imports)
|
|
83
|
+
- `no-console` is an error in source (except `warn`/`error`); allowed in scripts and CLI entry point
|
|
84
|
+
- Unused variables must be prefixed with `_`
|
|
85
|
+
- Zero warnings allowed (`--max-warnings 0`)
|
|
86
|
+
|
|
87
|
+
## Adding a New CLI Command or Flag
|
|
88
|
+
|
|
89
|
+
When adding a new command or flag to the CLI, update **all** of the following in the same change:
|
|
90
|
+
|
|
91
|
+
1. **`apps/control-plane/src/cli/types.ts`** - add the command to the `CliCommand` enum.
|
|
92
|
+
2. **`apps/control-plane/src/cli/cli-argument-parser.ts`** - parse the new flag/command token.
|
|
93
|
+
3. **`apps/control-plane/src/interfaces/cli/bootstrap.ts`** - dispatch the new command.
|
|
94
|
+
4. **`apps/control-plane/src/cli/help-command-handler.ts`** - add or update the entry in `COMMAND_HELP` (both the command summary and its flags list). This is the source of truth for `aop --help` output.
|
|
95
|
+
5. **`CLAUDE.md` and `AGENTS.md`** - update command lists/documentation to keep both assistant guides aligned.
|
|
96
|
+
|
|
97
|
+
## Coverage Thresholds
|
|
98
|
+
|
|
99
|
+
Lines: 90% | Branches: 90% | Functions: 90% | Statements: 90%
|
|
100
|
+
|
|
101
|
+
## Updating progress.md
|
|
102
|
+
|
|
103
|
+
`spec-files/progress.md` is the versioned work log for this repository. **After completing any meaningful code change** (new feature, bug fix, refactor, test coverage improvement, validator change, etc.), append a new numbered entry to the **Completed Tasks** section of `progress.md`.
|
|
104
|
+
|
|
105
|
+
### Entry format
|
|
106
|
+
|
|
107
|
+
Each entry must include:
|
|
108
|
+
|
|
109
|
+
- A sequential number (increment from the last entry)
|
|
110
|
+
- A short title describing what was done
|
|
111
|
+
- **Goal** - one sentence on why the change was made
|
|
112
|
+
- **Changes made** - bullet list of files modified and what changed; be specific (function names, test counts, metric deltas)
|
|
113
|
+
- **Result** - outcome verification (e.g. `npm test [PASS]`, `npm run lint [PASS]`, validator output)
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
Entry N - Short Title
|
|
117
|
+
- **Goal:** One-sentence description of the problem or objective.
|
|
118
|
+
- **Changes made:**
|
|
119
|
+
- `path/to/file.ts` - description of what changed and why.
|
|
120
|
+
- `apps/control-plane/test/foo.spec.ts` - X tests added covering Y branches.
|
|
121
|
+
- **Result:** `npm test` [PASS] (N test files / M tests passing). `npm run lint` [PASS].
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Rules
|
|
125
|
+
|
|
126
|
+
- **One entry per logical unit of work.** Don't bundle unrelated changes into one entry.
|
|
127
|
+
- **Do not edit or renumber past entries.** The log is append-only.
|
|
128
|
+
- Entries go in the **Completed Tasks** section (before the `## Next Tasks:` heading).
|
|
129
|
+
- The `## Next Tasks:` section lists only work that has **not yet been done**. Move items out of it once completed.
|
|
130
|
+
- After completing work from a spec file, update the **Spec Gap Tracker** table (if present) to mark the item as complete.
|
|
131
|
+
|
|
132
|
+
## Executing a Spec
|
|
133
|
+
|
|
134
|
+
When beginning work from a spec file (for example `spec-files/agentic_orchestrator_*.md`):
|
|
135
|
+
|
|
136
|
+
1. **Before writing any code**, read the spec and add all planned tasks to the `## Next Tasks:` section of `progress.md`. Use the spec's section numbers as identifiers (for example `Section 3.1 - Add mutating cross-check`).
|
|
137
|
+
2. **As each task completes**, move it out of `## Next Tasks:` and into a new numbered `Entry N - ...` in the Completed Tasks section.
|
|
138
|
+
3. **Never leave a completed task in `## Next Tasks:`**. The section must only contain work that hasn't started or isn't finished.
|
|
139
|
+
4. If a task is blocked or deferred, leave it in `## Next Tasks:` with a `[BLOCKED]` or `[DEFERRED]` annotation and a one-line reason.
|
package/CLAUDE.md
CHANGED
|
@@ -62,6 +62,18 @@ This is an MCP-first, multi-agent orchestrator control plane. The codebase lives
|
|
|
62
62
|
- **Structured error codes**: 45+ error codes with `{ code, message, details: { retryable, requires_human, suggestions } }`.
|
|
63
63
|
- **Tool registry dispatch**: `catalog.json` metadata drives tool routing, replacing switch-based dispatch. Mutating tools require `operation_id` for idempotency.
|
|
64
64
|
|
|
65
|
+
## Design Principles
|
|
66
|
+
|
|
67
|
+
- **KISS (Keep It Simple, Stupid)**: Prefer the simplest design that satisfies requirements and preserves deterministic behavior.
|
|
68
|
+
- **SRP (Single Responsibility Principle)**: Each class/module should have one clear reason to change.
|
|
69
|
+
- **SOLID (pragmatic application)**:
|
|
70
|
+
- Open/Closed: Extend by adding adapters/services instead of modifying unrelated orchestrator flow.
|
|
71
|
+
- Interface Segregation: Keep interfaces focused (avoid broad "do everything" contracts).
|
|
72
|
+
- Dependency Inversion: Depend on ports/interfaces, not concrete infrastructure.
|
|
73
|
+
- **Hexagonal Architecture**: Domain/application layers must not depend directly on provider CLI/SDK details; keep those in adapter boundaries.
|
|
74
|
+
- **Composition over Inheritance**: Build behavior through composed collaborators (factory + adapter + parser + service) rather than deep class hierarchies.
|
|
75
|
+
- **High Cohesion, Low Coupling**: Keep CLI parsing, provider execution, orchestration logic, and persistence concerns in separate modules.
|
|
76
|
+
|
|
65
77
|
## Lint Rules to Know
|
|
66
78
|
|
|
67
79
|
- `no-explicit-any` is **enforced** in source, relaxed in tests
|
|
@@ -10,6 +10,9 @@ missing_prompt_behavior: ignore
|
|
|
10
10
|
runtime:
|
|
11
11
|
default_provider: custom
|
|
12
12
|
default_model: local-default
|
|
13
|
+
worker_provider_mode: live
|
|
14
|
+
worker_response_timeout_ms: 120000
|
|
15
|
+
max_consecutive_no_progress_iterations: 2
|
|
13
16
|
provider_config_env: AOP_PROVIDER_CONFIG_ENV
|
|
14
17
|
provider_configs:
|
|
15
18
|
kiro-cli:
|
|
@@ -48,6 +48,9 @@ path_rules:
|
|
|
48
48
|
allow_symlink_traversal: false
|
|
49
49
|
execution:
|
|
50
50
|
default_step_timeout_seconds: 600
|
|
51
|
+
require_live_provider_for_run: true
|
|
52
|
+
malformed_worker_output_action: block_feature
|
|
53
|
+
no_progress_action: block_feature
|
|
51
54
|
retry_policy:
|
|
52
55
|
transient_max_retries: 1
|
|
53
56
|
transient_error_codes:
|
|
@@ -48,6 +48,9 @@ path_rules:
|
|
|
48
48
|
allow_symlink_traversal: false
|
|
49
49
|
execution:
|
|
50
50
|
default_step_timeout_seconds: 600
|
|
51
|
+
require_live_provider_for_run: true
|
|
52
|
+
malformed_worker_output_action: block_feature
|
|
53
|
+
no_progress_action: block_feature
|
|
51
54
|
retry_policy:
|
|
52
55
|
transient_max_retries: 1
|
|
53
56
|
transient_error_codes:
|
|
@@ -48,6 +48,21 @@
|
|
|
48
48
|
"type": "string",
|
|
49
49
|
"description": "Default model string passed to the provider SDK. Overridden by --agent-model CLI flag or AOP_AGENT_MODEL env var."
|
|
50
50
|
},
|
|
51
|
+
"worker_provider_mode": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"description": "Execution mode for worker providers. 'live' uses provider-backed execution, 'stub' uses NullWorkerProvider.",
|
|
54
|
+
"enum": ["live", "stub"]
|
|
55
|
+
},
|
|
56
|
+
"worker_response_timeout_ms": {
|
|
57
|
+
"type": "number",
|
|
58
|
+
"description": "Timeout in milliseconds for a single worker execution request.",
|
|
59
|
+
"minimum": 1
|
|
60
|
+
},
|
|
61
|
+
"max_consecutive_no_progress_iterations": {
|
|
62
|
+
"type": "number",
|
|
63
|
+
"description": "Consecutive no-progress worker iterations allowed before no-progress policy action is triggered.",
|
|
64
|
+
"minimum": 1
|
|
65
|
+
},
|
|
51
66
|
"default_agent_config": {
|
|
52
67
|
"type": "object",
|
|
53
68
|
"description": "Default agent configuration object forwarded to the provider SDK when no provider-specific entry exists in provider_configs."
|
|
@@ -206,6 +206,20 @@
|
|
|
206
206
|
"minimum": 1,
|
|
207
207
|
"description": "Default execution timeout applied to each gate step that does not declare its own timeout_seconds."
|
|
208
208
|
},
|
|
209
|
+
"require_live_provider_for_run": {
|
|
210
|
+
"type": "boolean",
|
|
211
|
+
"description": "When true, run/resume reject stub worker providers and require live provider execution."
|
|
212
|
+
},
|
|
213
|
+
"malformed_worker_output_action": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"description": "Action taken when worker output cannot be parsed or contains unsupported output types.",
|
|
216
|
+
"enum": ["block_feature", "fail_run"]
|
|
217
|
+
},
|
|
218
|
+
"no_progress_action": {
|
|
219
|
+
"type": "string",
|
|
220
|
+
"description": "Action taken when a live worker repeatedly produces no actionable outputs.",
|
|
221
|
+
"enum": ["block_feature", "fail_run"]
|
|
222
|
+
},
|
|
209
223
|
"retry_policy": {
|
|
210
224
|
"type": "object",
|
|
211
225
|
"description": "Governs automatic retries for transient gate execution failures.",
|
|
@@ -99,6 +99,13 @@ export class CliArgumentParser {
|
|
|
99
99
|
index += 1;
|
|
100
100
|
continue;
|
|
101
101
|
}
|
|
102
|
+
if (token === '--worker-provider-mode') {
|
|
103
|
+
if (next === 'live' || next === 'stub') {
|
|
104
|
+
options.worker_provider_mode = next;
|
|
105
|
+
index += 1;
|
|
106
|
+
}
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
102
109
|
if (token === '--transport') {
|
|
103
110
|
options.transport = next;
|
|
104
111
|
index += 1;
|
|
@@ -27,6 +27,10 @@ const COMMAND_HELP: Record<CliCommand, CommandHelp> = {
|
|
|
27
27
|
flag: '--provider-config-env <var>',
|
|
28
28
|
description: 'Env var name used for API-backed provider auth/config',
|
|
29
29
|
},
|
|
30
|
+
{
|
|
31
|
+
flag: '--worker-provider-mode <live|stub>',
|
|
32
|
+
description: 'Worker execution mode override (default: live for run/resume)',
|
|
33
|
+
},
|
|
30
34
|
{ flag: '--transport <inprocess|mcp>', description: 'Tool transport layer (default: mcp)' },
|
|
31
35
|
{ flag: '--takeover-stale-run', description: 'Take over a stale run lease' },
|
|
32
36
|
{ flag: '--project <name>', description: 'Select project from multi-project.yaml' },
|
|
@@ -47,6 +51,10 @@ const COMMAND_HELP: Record<CliCommand, CommandHelp> = {
|
|
|
47
51
|
flags: [
|
|
48
52
|
{ flag: '--feature-id <id>', description: 'Resume a specific feature' },
|
|
49
53
|
{ flag: '--force', description: 'Force-resume even if the feature is not blocked' },
|
|
54
|
+
{
|
|
55
|
+
flag: '--worker-provider-mode <live|stub>',
|
|
56
|
+
description: 'Worker execution mode override (default: live)',
|
|
57
|
+
},
|
|
50
58
|
{ flag: '--transport <inprocess|mcp>', description: 'Tool transport layer (default: mcp)' },
|
|
51
59
|
],
|
|
52
60
|
},
|
|
@@ -259,6 +259,9 @@ path_rules:
|
|
|
259
259
|
allow_symlink_traversal: false
|
|
260
260
|
execution:
|
|
261
261
|
default_step_timeout_seconds: 600
|
|
262
|
+
require_live_provider_for_run: true
|
|
263
|
+
malformed_worker_output_action: block_feature
|
|
264
|
+
no_progress_action: block_feature
|
|
262
265
|
retry_policy:
|
|
263
266
|
transient_max_retries: 1
|
|
264
267
|
transient_error_codes:
|
|
@@ -420,6 +423,9 @@ missing_prompt_behavior: ignore
|
|
|
420
423
|
runtime:
|
|
421
424
|
default_provider: ${wizard.defaultProvider}
|
|
422
425
|
default_model: ${wizard.defaultModel}
|
|
426
|
+
worker_provider_mode: live
|
|
427
|
+
worker_response_timeout_ms: 120000
|
|
428
|
+
max_consecutive_no_progress_iterations: 2
|
|
423
429
|
${providerConfigEnvLine} role_provider_overrides: {}
|
|
424
430
|
`;
|
|
425
431
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { STATUS } from '../core/constants.js';
|
|
2
|
-
import { resolveProviderSelection
|
|
2
|
+
import { resolveProviderSelection } from '../providers/providers.js';
|
|
3
|
+
import {
|
|
4
|
+
DefaultWorkerProviderFactory,
|
|
5
|
+
resolveWorkerProviderMode,
|
|
6
|
+
resolveWorkerProviderPolicy,
|
|
7
|
+
resolveWorkerProviderRuntime,
|
|
8
|
+
type WorkerProviderFactory,
|
|
9
|
+
} from '../providers/worker-provider-factory.js';
|
|
3
10
|
import { SupervisorRuntime } from '../supervisor/runtime.js';
|
|
4
11
|
import type { AopKernel } from '../core/kernel.js';
|
|
5
12
|
import type { ToolClient } from '../mcp/tool-client.js';
|
|
@@ -84,6 +91,12 @@ interface ResumePlan {
|
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
export class ResumeCommandHandler {
|
|
94
|
+
private readonly workerProviderFactory: WorkerProviderFactory;
|
|
95
|
+
|
|
96
|
+
constructor(workerProviderFactory: WorkerProviderFactory = new DefaultWorkerProviderFactory()) {
|
|
97
|
+
this.workerProviderFactory = workerProviderFactory;
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
async execute(context: ResumeCommandContext): Promise<unknown> {
|
|
88
101
|
const { env, runId, transport, options, kernel, toolClient } = context;
|
|
89
102
|
const recovery = await kernel.recoverFromState();
|
|
@@ -108,7 +121,23 @@ export class ResumeCommandHandler {
|
|
|
108
121
|
agentsConfig: kernel.getAgentsConfig(),
|
|
109
122
|
});
|
|
110
123
|
|
|
111
|
-
const
|
|
124
|
+
const runtimeConfig = resolveWorkerProviderRuntime(kernel.getAgentsConfig().runtime);
|
|
125
|
+
const policySnapshot = kernel.getPolicySnapshot();
|
|
126
|
+
const executionPolicy =
|
|
127
|
+
policySnapshot.execution && typeof policySnapshot.execution === 'object'
|
|
128
|
+
? (policySnapshot.execution as Record<string, unknown>)
|
|
129
|
+
: null;
|
|
130
|
+
const provider = this.workerProviderFactory.create({
|
|
131
|
+
selection,
|
|
132
|
+
mode: resolveWorkerProviderMode(
|
|
133
|
+
options.worker_provider_mode,
|
|
134
|
+
kernel.getAgentsConfig().runtime?.worker_provider_mode,
|
|
135
|
+
'live',
|
|
136
|
+
),
|
|
137
|
+
context: 'resume',
|
|
138
|
+
policy: resolveWorkerProviderPolicy(executionPolicy),
|
|
139
|
+
runtime: runtimeConfig,
|
|
140
|
+
});
|
|
112
141
|
const supervisor = new SupervisorRuntime(kernel, provider, toolClient, {
|
|
113
142
|
max_active_features: 5,
|
|
114
143
|
max_parallel_gate_runs: 3,
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { resolveProviderSelection
|
|
3
|
+
import { resolveProviderSelection } from '../providers/providers.js';
|
|
4
|
+
import {
|
|
5
|
+
DefaultWorkerProviderFactory,
|
|
6
|
+
resolveWorkerProviderMode,
|
|
7
|
+
resolveWorkerProviderPolicy,
|
|
8
|
+
resolveWorkerProviderRuntime,
|
|
9
|
+
type WorkerProviderFactory,
|
|
10
|
+
} from '../providers/worker-provider-factory.js';
|
|
4
11
|
import { SupervisorRuntime } from '../supervisor/runtime.js';
|
|
5
12
|
import { TOOLS } from '../core/constants.js';
|
|
6
13
|
import type { AopKernel } from '../core/kernel.js';
|
|
@@ -36,9 +43,14 @@ interface FeatureIndex {
|
|
|
36
43
|
|
|
37
44
|
export class RunCommandHandler {
|
|
38
45
|
private readonly spawnDelayMs: number;
|
|
46
|
+
private readonly workerProviderFactory: WorkerProviderFactory;
|
|
39
47
|
|
|
40
|
-
constructor(
|
|
48
|
+
constructor(
|
|
49
|
+
spawnDelayMs = 500,
|
|
50
|
+
workerProviderFactory: WorkerProviderFactory = new DefaultWorkerProviderFactory(),
|
|
51
|
+
) {
|
|
41
52
|
this.spawnDelayMs = spawnDelayMs;
|
|
53
|
+
this.workerProviderFactory = workerProviderFactory;
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
async execute(context: RunCommandContext): Promise<unknown> {
|
|
@@ -70,7 +82,23 @@ export class RunCommandHandler {
|
|
|
70
82
|
agentsConfig: kernel.getAgentsConfig(),
|
|
71
83
|
});
|
|
72
84
|
|
|
73
|
-
const
|
|
85
|
+
const runtimeConfig = resolveWorkerProviderRuntime(kernel.getAgentsConfig().runtime);
|
|
86
|
+
const policySnapshot = kernel.getPolicySnapshot();
|
|
87
|
+
const executionPolicy =
|
|
88
|
+
policySnapshot.execution && typeof policySnapshot.execution === 'object'
|
|
89
|
+
? (policySnapshot.execution as Record<string, unknown>)
|
|
90
|
+
: null;
|
|
91
|
+
const provider = this.workerProviderFactory.create({
|
|
92
|
+
selection,
|
|
93
|
+
mode: resolveWorkerProviderMode(
|
|
94
|
+
options.worker_provider_mode,
|
|
95
|
+
kernel.getAgentsConfig().runtime?.worker_provider_mode,
|
|
96
|
+
'live',
|
|
97
|
+
),
|
|
98
|
+
context: 'run',
|
|
99
|
+
policy: resolveWorkerProviderPolicy(executionPolicy),
|
|
100
|
+
runtime: runtimeConfig,
|
|
101
|
+
});
|
|
74
102
|
const supervisor = new SupervisorRuntime(kernel, provider, toolClient, {
|
|
75
103
|
max_active_features: maxActiveFeatures ?? 5,
|
|
76
104
|
max_parallel_gate_runs: maxParallelGateRuns ?? 3,
|
|
@@ -31,6 +31,10 @@ export const ERROR_CODES = {
|
|
|
31
31
|
AGENT_PROVIDER_NOT_CONFIGURED: 'agent_provider_not_configured',
|
|
32
32
|
UNSUPPORTED_AGENT_PROVIDER: 'unsupported_agent_provider',
|
|
33
33
|
PROVIDER_AUTH_MISSING: 'provider_auth_missing',
|
|
34
|
+
PROVIDER_STUB_DISALLOWED: 'provider_stub_disallowed',
|
|
35
|
+
PROVIDER_RUNTIME_UNAVAILABLE: 'provider_runtime_unavailable',
|
|
36
|
+
PROVIDER_OUTPUT_INVALID: 'provider_output_invalid',
|
|
37
|
+
PROVIDER_NO_PROGRESS: 'provider_no_progress',
|
|
34
38
|
UNAUTHENTICATED: 'unauthenticated',
|
|
35
39
|
INVALID_ACTOR_CLAIM: 'invalid_actor_claim',
|
|
36
40
|
OPERATION_ID_REQUIRED: 'operation_id_required',
|
|
@@ -95,6 +95,9 @@ export interface AgentsRuntimeConfig {
|
|
|
95
95
|
provider_config_env?: string;
|
|
96
96
|
default_agent_config?: Record<string, unknown>;
|
|
97
97
|
provider_configs?: Record<string, Record<string, unknown>>;
|
|
98
|
+
worker_provider_mode?: 'live' | 'stub' | string;
|
|
99
|
+
worker_response_timeout_ms?: number;
|
|
100
|
+
max_consecutive_no_progress_iterations?: number;
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
export interface AgentsConfigSnapshot {
|
|
@@ -3,6 +3,20 @@ export type { AgentsConfigSnapshot } from './core/kernel.js';
|
|
|
3
3
|
export { SupervisorRuntime } from './supervisor/runtime.js';
|
|
4
4
|
export { resolveProviderSelection, NullWorkerProvider } from './providers/providers.js';
|
|
5
5
|
export type { WorkerProvider, ProviderSelectionResolver } from './providers/providers.js';
|
|
6
|
+
export {
|
|
7
|
+
DefaultWorkerProviderFactory,
|
|
8
|
+
resolveWorkerProviderMode,
|
|
9
|
+
resolveWorkerProviderRuntime,
|
|
10
|
+
resolveWorkerProviderPolicy,
|
|
11
|
+
resolveMalformedWorkerOutputAction,
|
|
12
|
+
resolveNoProgressAction,
|
|
13
|
+
} from './providers/worker-provider-factory.js';
|
|
14
|
+
export type {
|
|
15
|
+
WorkerProviderMode,
|
|
16
|
+
ProviderCommandContext,
|
|
17
|
+
WorkerProviderFactory,
|
|
18
|
+
CreateWorkerProviderInput,
|
|
19
|
+
} from './providers/worker-provider-factory.js';
|
|
6
20
|
export { createToolingRuntime, resolveToolClient } from './mcp/runtime-factory.js';
|
|
7
21
|
export type { ToolingKernelPort, CreateToolingRuntimeOptions } from './mcp/runtime-factory.js';
|
|
8
22
|
export { InProcessToolClient, McpToolClient, createOperationId } from './mcp/tool-client.js';
|
|
@@ -26,7 +26,13 @@ import { AttachCommandHandler } from '../../cli/attach-command-handler.js';
|
|
|
26
26
|
import { HelpCommandHandler } from '../../cli/help-command-handler.js';
|
|
27
27
|
import { readEnvFileValues } from '../../cli/env-file.js';
|
|
28
28
|
import { MultiProjectLoader } from '../../application/multi-project-loader.js';
|
|
29
|
-
import {
|
|
29
|
+
import { resolveProviderSelection } from '../../providers/providers.js';
|
|
30
|
+
import {
|
|
31
|
+
DefaultWorkerProviderFactory,
|
|
32
|
+
resolveWorkerProviderMode,
|
|
33
|
+
resolveWorkerProviderPolicy,
|
|
34
|
+
resolveWorkerProviderRuntime,
|
|
35
|
+
} from '../../providers/worker-provider-factory.js';
|
|
30
36
|
import type { RuntimeContext } from '../../cli/types.js';
|
|
31
37
|
import type { ProjectConfig } from '../../application/multi-project-loader.js';
|
|
32
38
|
|
|
@@ -315,7 +321,7 @@ export async function runCli(
|
|
|
315
321
|
const tooling = await createToolingRuntime(repoRoot, kernel);
|
|
316
322
|
const toolClient = resolveToolClient(transport, tooling);
|
|
317
323
|
|
|
318
|
-
let commandProvider
|
|
324
|
+
let commandProvider = null;
|
|
319
325
|
if (options.command === CliCommand.Send || options.command === CliCommand.Attach) {
|
|
320
326
|
let selection;
|
|
321
327
|
try {
|
|
@@ -332,7 +338,23 @@ export async function runCli(
|
|
|
332
338
|
provider_config_ref: null,
|
|
333
339
|
};
|
|
334
340
|
}
|
|
335
|
-
|
|
341
|
+
const workerProviderFactory = new DefaultWorkerProviderFactory();
|
|
342
|
+
const policySnapshot = kernel.getPolicySnapshot();
|
|
343
|
+
const executionPolicy =
|
|
344
|
+
policySnapshot.execution && typeof policySnapshot.execution === 'object'
|
|
345
|
+
? (policySnapshot.execution as Record<string, unknown>)
|
|
346
|
+
: null;
|
|
347
|
+
commandProvider = workerProviderFactory.create({
|
|
348
|
+
selection,
|
|
349
|
+
mode: resolveWorkerProviderMode(
|
|
350
|
+
options.worker_provider_mode,
|
|
351
|
+
kernel.getAgentsConfig().runtime?.worker_provider_mode,
|
|
352
|
+
'stub',
|
|
353
|
+
),
|
|
354
|
+
context: options.command === CliCommand.Send ? 'send' : 'attach',
|
|
355
|
+
policy: resolveWorkerProviderPolicy(executionPolicy),
|
|
356
|
+
runtime: resolveWorkerProviderRuntime(kernel.getAgentsConfig().runtime),
|
|
357
|
+
});
|
|
336
358
|
kernel.setProvider(commandProvider);
|
|
337
359
|
}
|
|
338
360
|
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { ERROR_CODES } from '../core/error-codes.js';
|
|
3
|
+
import type { AppError, ProviderSelection, WorkerProvider, WorkerSession } from './providers.js';
|
|
4
|
+
import type { ProviderOutputParser } from './output-parsers/types.js';
|
|
5
|
+
|
|
6
|
+
interface ApiWorkerProviderOptions {
|
|
7
|
+
outputParser: ProviderOutputParser;
|
|
8
|
+
workerResponseTimeoutMs: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function providerError(code: string, message: string, details: Record<string, unknown>): AppError {
|
|
12
|
+
const error = new Error(message) as AppError;
|
|
13
|
+
error.code = code;
|
|
14
|
+
error.details = details;
|
|
15
|
+
return error;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
19
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ApiWorkerProvider implements WorkerProvider {
|
|
23
|
+
readonly mode = 'live' as const;
|
|
24
|
+
readonly selection: ProviderSelection;
|
|
25
|
+
|
|
26
|
+
private readonly outputParser: ProviderOutputParser;
|
|
27
|
+
private readonly workerResponseTimeoutMs: number;
|
|
28
|
+
|
|
29
|
+
constructor(selection: ProviderSelection, options: ApiWorkerProviderOptions) {
|
|
30
|
+
this.selection = selection;
|
|
31
|
+
this.outputParser = options.outputParser;
|
|
32
|
+
this.workerResponseTimeoutMs = options.workerResponseTimeoutMs;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
createSession(
|
|
36
|
+
role: string,
|
|
37
|
+
featureId: string,
|
|
38
|
+
systemPrompt: string | null,
|
|
39
|
+
): Promise<WorkerSession> {
|
|
40
|
+
return Promise.resolve({
|
|
41
|
+
session_id: `${role}-${featureId}-${crypto.randomUUID()}`,
|
|
42
|
+
role,
|
|
43
|
+
feature_id: featureId,
|
|
44
|
+
system_prompt_loaded: Boolean(systemPrompt),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
reattachSession(sessionId: string): Promise<WorkerSession | null> {
|
|
49
|
+
if (!sessionId || sessionId === 'unknown') {
|
|
50
|
+
return Promise.resolve(null);
|
|
51
|
+
}
|
|
52
|
+
return Promise.resolve({
|
|
53
|
+
session_id: sessionId,
|
|
54
|
+
role: 'orchestrator',
|
|
55
|
+
feature_id: 'global',
|
|
56
|
+
system_prompt_loaded: false,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
closeSession(_sessionId: string): Promise<{ closed: true }> {
|
|
61
|
+
return Promise.resolve({ closed: true });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
runWorker(input: {
|
|
65
|
+
role: string;
|
|
66
|
+
feature_id: string;
|
|
67
|
+
context_bundle?: Record<string, unknown>;
|
|
68
|
+
instructions?: string;
|
|
69
|
+
last_tool_results?: Array<Record<string, unknown>>;
|
|
70
|
+
runtime_selection?: {
|
|
71
|
+
provider: string;
|
|
72
|
+
model: string;
|
|
73
|
+
provider_config_ref: string | null;
|
|
74
|
+
};
|
|
75
|
+
}): Promise<Record<string, unknown>> {
|
|
76
|
+
// API-backed providers (gemini) require explicit adapter wiring. Until that is configured,
|
|
77
|
+
// fail deterministically instead of silently producing NOTE-only progress.
|
|
78
|
+
if (!this.selection.provider_config_ref) {
|
|
79
|
+
throw providerError(
|
|
80
|
+
ERROR_CODES.PROVIDER_RUNTIME_UNAVAILABLE,
|
|
81
|
+
'API-backed provider credentials are not available',
|
|
82
|
+
{
|
|
83
|
+
provider: this.selection.provider,
|
|
84
|
+
reason: 'missing_provider_config_ref',
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const mockResponse = isRecord(this.selection.agent_config)
|
|
90
|
+
? this.selection.agent_config.mock_response
|
|
91
|
+
: null;
|
|
92
|
+
if (!isRecord(mockResponse)) {
|
|
93
|
+
throw providerError(
|
|
94
|
+
ERROR_CODES.PROVIDER_RUNTIME_UNAVAILABLE,
|
|
95
|
+
'API-backed worker adapter is not configured for this provider',
|
|
96
|
+
{
|
|
97
|
+
provider: this.selection.provider,
|
|
98
|
+
reason: 'missing_api_adapter_configuration',
|
|
99
|
+
timeout_ms: this.workerResponseTimeoutMs,
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const sessionId = `${input.role}-${input.feature_id}-api`;
|
|
105
|
+
return Promise.resolve(
|
|
106
|
+
this.outputParser.parse(JSON.stringify(mockResponse), {
|
|
107
|
+
sessionId,
|
|
108
|
+
role: input.role,
|
|
109
|
+
featureId: input.feature_id,
|
|
110
|
+
provider: this.selection.provider,
|
|
111
|
+
model: this.selection.model,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|