@matt82198/aesop 0.1.0 → 0.3.1
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/CHANGELOG.md +117 -2
- package/README.md +59 -218
- package/bin/cli.js +168 -41
- package/daemons/run-watchdog.sh +16 -4
- package/daemons/selfheal.sh +231 -0
- package/docs/ANY-REPO.md +427 -0
- package/docs/CONTRIBUTING.md +72 -0
- package/docs/DEMO.md +334 -0
- package/docs/HOOK-INSTALL.md +15 -56
- package/docs/INSTALL.md +74 -4
- package/docs/PORTING.md +166 -0
- package/docs/README.md +33 -3
- package/docs/TEAM-STATE.md +372 -0
- package/docs/reproduce.md +33 -3
- package/driver/CLAUDE.md +150 -0
- package/driver/README.md +383 -0
- package/driver/aesop.config.example.json +80 -0
- package/driver/agent_driver.py +355 -0
- package/driver/backend_config.py +253 -0
- package/driver/claude_code_driver.py +198 -0
- package/driver/codex_driver.py +673 -0
- package/driver/openai_compatible_driver.py +249 -0
- package/driver/openai_transport.py +179 -0
- package/driver/verification_policy.py +75 -0
- package/driver/wave_bridge.py +254 -0
- package/driver/wave_loop.py +1408 -0
- package/driver/wave_scheduler.py +890 -0
- package/hooks/pre-push-policy.sh +131 -33
- package/mcp/server.mjs +320 -4
- package/monitor/collect-signals.mjs +69 -0
- package/package.json +22 -14
- package/skills/CLAUDE.md +132 -2
- package/skills/buildsystem/SKILL.md +330 -0
- package/skills/buildsystem/wave-flat-dispatch.template.mjs +658 -0
- package/skills/fleet/SKILL.md +113 -0
- package/skills/power/SKILL.md +246 -131
- package/state_store/__init__.py +4 -2
- package/state_store/api.py +19 -4
- package/state_store/coordination.py +209 -0
- package/state_store/identity.py +51 -0
- package/state_store/projections.py +63 -0
- package/state_store/read_api.py +156 -0
- package/state_store/store.py +185 -73
- package/state_store/write_api.py +462 -0
- package/templates/wave-presets/data.json +65 -0
- package/templates/wave-presets/library.json +65 -0
- package/templates/wave-presets/saas.json +64 -0
- package/tools/audit_report.py +388 -0
- package/tools/bench_runner.py +100 -3
- package/tools/ci_merge_wait.py +256 -35
- package/tools/ci_workflow_lint.py +430 -0
- package/tools/claudemd_drift.py +394 -0
- package/tools/claudemd_lint.py +359 -0
- package/tools/common.py +39 -3
- package/tools/cost_ceiling.py +166 -43
- package/tools/cost_econ.py +480 -0
- package/tools/cost_projection.py +559 -0
- package/tools/crossos_drift.py +394 -0
- package/tools/defect_escape.py +252 -0
- package/tools/doctor.js +1 -1
- package/tools/eod_sweep.py +188 -26
- package/tools/fleet.js +260 -0
- package/tools/fleet_ledger.py +209 -7
- package/tools/git_identity_check.py +315 -0
- package/tools/health-score.js +40 -0
- package/tools/health_score.py +361 -0
- package/tools/metrics_gate.py +13 -4
- package/tools/mutation_test.py +523 -0
- package/tools/portability_check.py +206 -0
- package/tools/proposals.mjs +47 -2
- package/tools/reconcile.py +7 -4
- package/tools/reproduce.js +405 -0
- package/tools/secret_scan.py +207 -65
- package/tools/self_stats.py +20 -0
- package/tools/stall_check.py +247 -16
- package/tools/stateapi_lint.py +325 -0
- package/tools/test_battery.py +173 -0
- package/tools/transcript_digest.py +380 -0
- package/tools/verify_activity_filter.py +437 -0
- package/tools/verify_agent_inspector.py +2 -0
- package/tools/verify_cost_panel.py +345 -0
- package/tools/verify_dash.py +2 -0
- package/tools/verify_dispatch_panel.py +301 -0
- package/tools/verify_failure_drilldown.py +188 -0
- package/tools/verify_prboard.py +2 -0
- package/tools/verify_scorecards.py +281 -0
- package/tools/verify_submit_encoding.py +2 -0
- package/tools/verify_ui_trio.py +409 -0
- package/tools/verify_wave_telemetry.py +268 -0
- package/tools/wave_backlog_analyzer.py +490 -0
- package/tools/wave_ledger_hook.py +150 -0
- package/tools/wave_preflight.py +779 -0
- package/tools/wave_resume.py +215 -0
- package/tools/wave_templates.py +340 -0
- package/ui/agents.py +68 -14
- package/ui/collectors.py +81 -55
- package/ui/config.py +7 -2
- package/ui/cost.py +231 -12
- package/ui/handler.py +383 -55
- package/ui/quality_scorecard.py +232 -0
- package/ui/sse.py +3 -3
- package/ui/wave_audit_tail.py +213 -0
- package/ui/wave_dispatch.py +280 -0
- package/ui/wave_failure.py +288 -0
- package/ui/wave_gantt.py +152 -0
- package/ui/wave_reasoning_tail.py +176 -0
- package/ui/wave_telemetry.py +383 -0
- package/ui/web/dist/assets/index-CNQxaiOW.css +1 -0
- package/ui/web/dist/assets/index-CP68RIh3.js +9 -0
- package/ui/web/dist/index.html +2 -2
- package/bin/CLAUDE.md +0 -76
- package/daemons/CLAUDE.md +0 -36
- package/dash/CLAUDE.md +0 -32
- package/docs/archive/README.md +0 -3
- package/docs/archive/spikes/tiered-cognition/ACTIVATION.md +0 -125
- package/docs/archive/spikes/tiered-cognition/DESIGN.md +0 -287
- package/docs/archive/spikes/tiered-cognition/FINDINGS.md +0 -113
- package/docs/archive/spikes/tiered-cognition/README.md +0 -27
- package/docs/archive/spikes/tiered-cognition/aesop-cognition.example.md +0 -32
- package/docs/archive/spikes/tiered-cognition/force-model-policy.merged.mjs +0 -673
- package/docs/archive/spikes/tiered-cognition/strip-tools-hook.mjs +0 -434
- package/hooks/CLAUDE.md +0 -89
- package/mcp/CLAUDE.md +0 -213
- package/monitor/CLAUDE.md +0 -40
- package/scan/CLAUDE.md +0 -30
- package/state_store/CLAUDE.md +0 -39
- package/tools/CLAUDE.md +0 -79
- package/ui/CLAUDE.md +0 -127
- package/ui/web/dist/assets/index-0qQYnvMC.js +0 -9
- package/ui/web/dist/assets/index-BdIlFieV.css +0 -1
package/driver/README.md
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# AgentDriver — multi-model portability for aesop
|
|
2
|
+
|
|
3
|
+
> Run aesop's wave loop on backends other than Claude Code — Codex, and
|
|
4
|
+
> eventually open models — through one narrow interface.
|
|
5
|
+
|
|
6
|
+
This directory contains the **AgentDriver seam** (Phase 1), a working Codex
|
|
7
|
+
implementation (Phase 2), and the wave bridge connecting backends to orchestrator
|
|
8
|
+
dispatch (Phase 3). The phase-1 abstraction seam is the interface; the
|
|
9
|
+
phase-2 Codex driver proves a non-Claude backend can execute a real coding task
|
|
10
|
+
end-to-end and produce orchestrator-verified results, entirely offline (no API
|
|
11
|
+
key, no network in CI tests). Phase 3 routes work items through any backend with
|
|
12
|
+
honest verification (test exit code only) and backend-driven verification tier.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## The problem
|
|
17
|
+
|
|
18
|
+
Aesop's orchestration core — the wave / flat-dispatch cycle — is written against
|
|
19
|
+
Claude Code's Workflow harness. It calls `agent()`, `parallel()`, the
|
|
20
|
+
Read/Write/Bash tools, and `budget.spent()` directly. Those calls only exist
|
|
21
|
+
inside Claude Code, so the wave loop cannot run anywhere else.
|
|
22
|
+
|
|
23
|
+
The spike's finding: ~80% of aesop (daemons, tools, state_store, MCP, UI) is
|
|
24
|
+
already portable. The coupling is concentrated in **how the wave loop talks to
|
|
25
|
+
its execution backend**. Extract that into one interface and the loop becomes
|
|
26
|
+
backend-agnostic.
|
|
27
|
+
|
|
28
|
+
## The abstraction
|
|
29
|
+
|
|
30
|
+
`AgentDriver` (in `agent_driver.py`) is that interface — an abstract base class
|
|
31
|
+
with **five** operations, which are everything the wave loop needs from any
|
|
32
|
+
backend:
|
|
33
|
+
|
|
34
|
+
| # | Operation | What it gives the wave loop |
|
|
35
|
+
|---|-----------------------------------|--------------------------------------------------------------|
|
|
36
|
+
| 1 | `probe_capabilities()` | Honest self-report → drives the whole verification strategy. |
|
|
37
|
+
| 2 | `dispatch_worker(request)` | Spawn one isolated worker (read/write files, run shell, return structured result). |
|
|
38
|
+
| 3 | `worker_status(worker_id)` | Liveness / stall detection for the watchdog. |
|
|
39
|
+
| 4 | `run_command(cmd, cwd, shell)` | Orchestrator-side execution: tests, git, verification. |
|
|
40
|
+
| 5 | `resolve_model(role)` | Abstract role (`worker`/`setup`/`verify`) → concrete model. |
|
|
41
|
+
|
|
42
|
+
Plus one optional op: `get_tokens_spent()`.
|
|
43
|
+
|
|
44
|
+
The wave loop calls **only** these methods. A new backend is a new subclass — no
|
|
45
|
+
changes to the orchestration algorithm. That is the entire point of the seam.
|
|
46
|
+
|
|
47
|
+
### What maps where (Claude Code reference)
|
|
48
|
+
|
|
49
|
+
In Claude Code the actual dispatch runs inside the harness, not in this Python
|
|
50
|
+
process. So the reference adapter (`claude_code_driver.py`) is deliberately thin:
|
|
51
|
+
|
|
52
|
+
| Operation | Claude Code mechanism | Concrete here? |
|
|
53
|
+
|----------------------|------------------------------|:--------------:|
|
|
54
|
+
| `probe_capabilities` | static known-good facts | yes |
|
|
55
|
+
| `resolve_model` | Anthropic model-name map | yes |
|
|
56
|
+
| `run_command` | Bash tool (subprocess out of harness) | yes |
|
|
57
|
+
| `dispatch_worker` | Workflow `agent()`/Task tool | harness-serviced |
|
|
58
|
+
| `worker_status` | harness + heartbeat files | harness-serviced |
|
|
59
|
+
|
|
60
|
+
The two harness-serviced ops raise a clear, explained error out of harness
|
|
61
|
+
rather than fake a Claude agent from plain Python. When the wave-flat-dispatch
|
|
62
|
+
template is refactored onto the driver (Phase 1, below), these become the
|
|
63
|
+
documented handoff points to the harness.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Per-backend capability matrix
|
|
68
|
+
|
|
69
|
+
Encoded honestly in each driver's `probe_capabilities()` — the numbers are the
|
|
70
|
+
spike's findings as data, so the orchestrator can plan **before** any CLI wiring
|
|
71
|
+
exists:
|
|
72
|
+
|
|
73
|
+
| Capability | **claude-code** | **codex** (Phase 2) | open-model (future) |
|
|
74
|
+
|------------------------|:---------------:|:-------------------------:|:--------------------------:|
|
|
75
|
+
| parallel_dispatch | native | no — external event loop | no — external event loop |
|
|
76
|
+
| worker filesystem I/O | yes (tools) | no — orchestrator injects | no — orchestrator injects |
|
|
77
|
+
| worker shell | yes (Bash tool) | no — orchestrator runs | no — orchestrator runs |
|
|
78
|
+
| structured output | yes (~perfect) | yes (JSON schema) | partial — regex recovery |
|
|
79
|
+
| worktree isolation | git-worktree | no — temp-dir | no — temp-dir |
|
|
80
|
+
| native cost tracking | `budget.spent()`| usage metadata (real) | manual (len/4 estimate) |
|
|
81
|
+
| tool-use accuracy | ~0.99 | ~0.90–0.95 | ~0.70–0.85 |
|
|
82
|
+
| **verification tier** | **1** | **2** | **4** |
|
|
83
|
+
|
|
84
|
+
Read the trend down the last row — it is the design's thesis, not an accident.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## The key insight — verification is load-bearing
|
|
89
|
+
|
|
90
|
+
> **Cheaper / weaker workers RAISE the need for the verification layer aesop
|
|
91
|
+
> already built. They do not lower the orchestrator's burden — they shift cost
|
|
92
|
+
> from inference to orchestration.**
|
|
93
|
+
|
|
94
|
+
Aesop's original bet was "Haiku suffices as a subagent because its tool-use
|
|
95
|
+
accuracy is ~99%, so the orchestrator only spot-checks lightly." A weaker
|
|
96
|
+
backend breaks that assumption:
|
|
97
|
+
|
|
98
|
+
- **Codex (gpt-3.5/4-turbo, ~90–95%)** returns 5–10% malformed JSON. The
|
|
99
|
+
orchestrator must validate every output and budget ≥2 repair rounds → **Tier 2**.
|
|
100
|
+
- **Open models (~70–85%)** return 15–30% malformed JSON. Every Build result
|
|
101
|
+
needs validation + strong spot-check (Sonnet-verified), with high triage
|
|
102
|
+
escalation → **Tier 4**.
|
|
103
|
+
|
|
104
|
+
So the money saved on cheap inference is partly re-spent on orchestrator
|
|
105
|
+
verification (the spike models DeepSeek at ~6.7× cheaper than Haiku, not the
|
|
106
|
+
headline 10×, once recovery is counted). This is exactly why aesop's existing
|
|
107
|
+
adversarial-review / mutation / verification tooling is **load-bearing** for
|
|
108
|
+
portability: it is the thing that makes weak-but-cheap backends viable at all.
|
|
109
|
+
`recommended_verification_tier` on every `DriverCapabilities` encodes this
|
|
110
|
+
inverse relationship — lower accuracy, higher tier — and the test suite asserts
|
|
111
|
+
it as an invariant (`TestVerificationThesisEncoded`).
|
|
112
|
+
|
|
113
|
+
The Haiku baseline is **unchanged**: it stays Tier 1. Portability *extends* the
|
|
114
|
+
system; it does not replace the original principle (autonomous fleet work needs
|
|
115
|
+
high-confidence subagents **plus** strong orchestration).
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Phased roadmap
|
|
120
|
+
|
|
121
|
+
| Phase | Scope | Status |
|
|
122
|
+
|-------|--------------------------------------------|----------------------------|
|
|
123
|
+
| **1** | Driver interface + Claude Code parity | **shipped** |
|
|
124
|
+
| | Reference adapter, honest Codex stub, tests| in this directory |
|
|
125
|
+
| | Refactor wave-flat-dispatch onto the driver| next (harness handoff pts) |
|
|
126
|
+
| **2** | Codex OpenAI Chat Completions HTTP backend | **shipped** |
|
|
127
|
+
| | Transport seam (urllib, injectable); dispatch_worker (file injection, JSON validation with retry, full-file replacement); run_command (subprocess); worker_status (in-memory registry); verification_policy mapping; offline test suite with FakeTransport + gated live test | implemented in `codex_driver.py` + `openai_transport.py` + `verification_policy.py` + tests |
|
|
128
|
+
| **3** | Wave bridge + verification policy routing | **shipped** |
|
|
129
|
+
| | Connect AgentDriver backends to wave-flat-dispatch manifest items; honest green (test exit code only); backend-driven verification tier. OpenAI-compatible driver for hosted models (OpenRouter, etc.) and local models (Ollama). | implemented in `wave_bridge.py` + `openai_compatible_driver.py` + tests |
|
|
130
|
+
| **4** | Open-model runner library | future |
|
|
131
|
+
| | Dedicated Ollama/local-model adapter, per-model prompt tuning, error-recovery protocol, Tier-4 enforcement, `bench/` accuracy benchmark | future |
|
|
132
|
+
|
|
133
|
+
**Deployment posture** (from the spike): Claude Code is production. Codex and
|
|
134
|
+
open models stay **experimental / opt-in** until their tiers are proven —
|
|
135
|
+
recommend Haiku for production fleets.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Usage
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import sys
|
|
143
|
+
sys.path.insert(0, "driver") # bare imports within the domain
|
|
144
|
+
|
|
145
|
+
from claude_code_driver import ClaudeCodeDriver
|
|
146
|
+
from codex_driver import CodexDriver
|
|
147
|
+
from verification_policy import verification_policy
|
|
148
|
+
from backend_config import build_driver, load_backend_config, describe_backend
|
|
149
|
+
|
|
150
|
+
for driver in (ClaudeCodeDriver(), CodexDriver()):
|
|
151
|
+
caps = driver.probe_capabilities()
|
|
152
|
+
print(caps.summary()) # ASCII one-liner for logs/dashboards
|
|
153
|
+
print("worker model ->", driver.resolve_model("worker"))
|
|
154
|
+
|
|
155
|
+
# The verification policy is RESOLVED in Python (verification_policy function)
|
|
156
|
+
# and baked into the manifest by build_manifest_item. JS consumes these literal fields;
|
|
157
|
+
# it does NOT recompute the policy (that was the drift trap).
|
|
158
|
+
policy = verification_policy(caps)
|
|
159
|
+
print("verification tier:", caps.recommended_verification_tier)
|
|
160
|
+
print(" repair_cap:", policy['repair_cap'])
|
|
161
|
+
print(" require_adversarial_review:", policy['require_adversarial_review'])
|
|
162
|
+
print(" spot_check_frac:", policy['spot_check_frac'])
|
|
163
|
+
print(" validate_all_json:", policy['validate_all_json'])
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Running other models (OpenAI-compatible backends)
|
|
167
|
+
|
|
168
|
+
Aesop can target any OpenAI Chat Completions-compatible endpoint: OpenRouter,
|
|
169
|
+
Together AI, Ollama (local), or any service offering a compatible API. Use the
|
|
170
|
+
`OpenAICompatibleDriver`:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from openai_compatible_driver import OpenAICompatibleDriver
|
|
174
|
+
|
|
175
|
+
# OpenRouter (hosted model, Tier 2)
|
|
176
|
+
driver = OpenAICompatibleDriver(
|
|
177
|
+
base_url="https://openrouter.ai/api/v1",
|
|
178
|
+
model="openrouter/auto", # or specific model like "openai/gpt-4-turbo"
|
|
179
|
+
api_key_env="OPENAI_API_KEY", # env var name (default)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Local Ollama (small/local model, Tier 3)
|
|
183
|
+
driver = OpenAICompatibleDriver(
|
|
184
|
+
base_url="http://localhost:11434/v1",
|
|
185
|
+
model="neural-chat",
|
|
186
|
+
is_local=True, # Marks as local -> tier 3, higher verification
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Together AI
|
|
190
|
+
driver = OpenAICompatibleDriver(
|
|
191
|
+
base_url="https://api.together.xyz/v1",
|
|
192
|
+
model="meta-llama/Llama-2-70b-chat",
|
|
193
|
+
api_key_env="TOGETHER_API_KEY",
|
|
194
|
+
)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
All OpenAI-compatible backends run through the **Phase 2 orchestrator-managed
|
|
198
|
+
execution contract**: the orchestrator injects file contents, validates JSON
|
|
199
|
+
output, writes files, and runs tests. No backend has native filesystem/shell
|
|
200
|
+
access. The driver reports its honest verification tier (2 for hosted strong
|
|
201
|
+
models, 3 for local/small models), and the wave template enforces the
|
|
202
|
+
appropriate verification policy (validate all JSON, spot-check, repair bounds).
|
|
203
|
+
|
|
204
|
+
To run aesop against a backend:
|
|
205
|
+
|
|
206
|
+
1. Set up the environment (API key, endpoint URL).
|
|
207
|
+
2. Instantiate the driver.
|
|
208
|
+
3. Pass it to your wave orchestration loop:
|
|
209
|
+
```python
|
|
210
|
+
caps = driver.probe_capabilities()
|
|
211
|
+
policy = verification_policy(caps)
|
|
212
|
+
# Proceed with wave dispatch, respecting policy.verification_tier
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Important note**: Non-agentic backends (Ollama, smaller models) run at a higher
|
|
216
|
+
verification tier (3+) because their tool-use accuracy is lower. The cost of
|
|
217
|
+
cheaper inference is re-spent on orchestrator verification. See the verification
|
|
218
|
+
thesis in the README for details.
|
|
219
|
+
|
|
220
|
+
### Configuring a backend
|
|
221
|
+
|
|
222
|
+
Aesop's backend can be configured via an `aesop.config.json` file in the
|
|
223
|
+
repository root (or any other path). This allows dropping a single JSON file to
|
|
224
|
+
switch backends without changing code. The configuration is **offline-safe**:
|
|
225
|
+
building a driver requires no API key; keys are read from environment variables
|
|
226
|
+
at call time during live dispatch.
|
|
227
|
+
|
|
228
|
+
**Configuration schema** (backend block):
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"backend": "claude" | "codex" | "openai-compatible",
|
|
232
|
+
"model": "...", // Required for codex, openai-compatible
|
|
233
|
+
"base_url": "...", // Required for openai-compatible
|
|
234
|
+
"api_key_env": "OPENAI_API_KEY", // Optional (default: OPENAI_API_KEY)
|
|
235
|
+
"is_local": false, // Optional, for openai-compatible only
|
|
236
|
+
"max_owned_bytes": 200000, // Optional file-size limit
|
|
237
|
+
"max_retries": 2, // Optional retry cap for malformed JSON
|
|
238
|
+
"timeout_s": 120.0 // Optional HTTP timeout
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Default**: If no config file exists, aesop uses Claude Code (preserves today's
|
|
243
|
+
behavior).
|
|
244
|
+
|
|
245
|
+
**Example configurations**:
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
# backend_config.py provides helpers to load and build drivers from JSON:
|
|
249
|
+
|
|
250
|
+
from backend_config import load_backend_config, build_driver, describe_backend
|
|
251
|
+
|
|
252
|
+
# Load from aesop.config.json (or default to Claude)
|
|
253
|
+
config = load_backend_config() # path="aesop.config.json" by default
|
|
254
|
+
|
|
255
|
+
# Instantiate the driver (offline-safe; no API key required at build time)
|
|
256
|
+
driver = build_driver(config)
|
|
257
|
+
|
|
258
|
+
# Describe the backend for logging
|
|
259
|
+
print(describe_backend(config))
|
|
260
|
+
# Example output: "claude-code: parallel=1 wfs=1 ... tier=1"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Claude Code** (production):
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"backend": "claude"
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
- Haiku workers, Tier 1 verification
|
|
270
|
+
- No API key needed (Claude Code manages auth)
|
|
271
|
+
- Recommended for production
|
|
272
|
+
|
|
273
|
+
**OpenAI Codex** (experimental):
|
|
274
|
+
```json
|
|
275
|
+
{
|
|
276
|
+
"backend": "codex",
|
|
277
|
+
"model": "gpt-3.5-turbo"
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
- Requires `OPENAI_API_KEY` environment variable set
|
|
281
|
+
- Tier 2 verification (validate all JSON, spot-check, repair budget)
|
|
282
|
+
- Cheaper than Claude but needs higher orchestrator burden
|
|
283
|
+
|
|
284
|
+
**OpenAI-compatible hosted model** (OpenRouter, experimental):
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"backend": "openai-compatible",
|
|
288
|
+
"base_url": "https://openrouter.ai/api/v1",
|
|
289
|
+
"model": "openai/gpt-4-turbo",
|
|
290
|
+
"api_key_env": "OPENROUTER_API_KEY"
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
- Requires the named environment variable set
|
|
294
|
+
- Tier 2 verification (hosted strong model)
|
|
295
|
+
- Supports any OpenAI-compatible endpoint (OpenRouter, Together, etc.)
|
|
296
|
+
|
|
297
|
+
**OpenAI-compatible local model** (Ollama, experimental):
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"backend": "openai-compatible",
|
|
301
|
+
"base_url": "http://localhost:11434/v1",
|
|
302
|
+
"model": "neural-chat",
|
|
303
|
+
"is_local": true
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
- No API key required (uses dummy `local-only` if not set)
|
|
307
|
+
- Tier 3 verification (local small model: validate all, heavy spot-check, adversarial review)
|
|
308
|
+
- Requires `ollama serve` running on localhost:11434
|
|
309
|
+
|
|
310
|
+
**How to run**:
|
|
311
|
+
|
|
312
|
+
1. Copy `driver/aesop.config.example.json` to `aesop.config.json` in the repo root
|
|
313
|
+
2. Edit `aesop.config.json` to select a backend and set any required fields
|
|
314
|
+
3. For non-Claude backends, set the API key environment variable:
|
|
315
|
+
```bash
|
|
316
|
+
export OPENAI_API_KEY=sk-... # for Codex
|
|
317
|
+
export OPENROUTER_API_KEY=sk-... # for OpenRouter
|
|
318
|
+
# Ollama needs no key
|
|
319
|
+
```
|
|
320
|
+
4. Run aesop; the orchestration loop loads the config and instantiates the driver (from backend_config):
|
|
321
|
+
```python
|
|
322
|
+
from backend_config import load_backend_config, build_driver
|
|
323
|
+
|
|
324
|
+
config = load_backend_config()
|
|
325
|
+
driver = build_driver(config)
|
|
326
|
+
# Pass driver to wave orchestration loop
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Testing**: All drivers build offline (no API key required at import or build
|
|
330
|
+
time). Keys are read from `os.environ` only at dispatch time if a live call is
|
|
331
|
+
made. Tests can inject a `FakeTransport` to avoid network entirely.
|
|
332
|
+
|
|
333
|
+
### Wiring verification tier into a wave manifest
|
|
334
|
+
|
|
335
|
+
When building a manifest for `wave-flat-dispatch.template.mjs`, the backend's
|
|
336
|
+
verification policy is RESOLVED in Python (via `build_manifest_item`) and baked
|
|
337
|
+
into the manifest as literal fields:
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
from wave_bridge import build_manifest_item
|
|
341
|
+
|
|
342
|
+
item = {
|
|
343
|
+
"slug": "fix-test",
|
|
344
|
+
"ownsFiles": ["test.py"],
|
|
345
|
+
"prompt": "Fix the test",
|
|
346
|
+
"testCmd": "python -m unittest test",
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
# build_manifest_item resolves ALL FOUR policy knobs from the driver's tier
|
|
350
|
+
# and includes them in the manifest as literal fields (no JS recomputation).
|
|
351
|
+
manifest_item = build_manifest_item(driver, item)
|
|
352
|
+
|
|
353
|
+
# Result includes:
|
|
354
|
+
# "model": "haiku" (from driver.resolve_model)
|
|
355
|
+
# "verificationTier": 1 (from driver.probe_capabilities)
|
|
356
|
+
# "repairCap": 1 (from verification_policy)
|
|
357
|
+
# "requireAdversarialReview": false (from verification_policy)
|
|
358
|
+
# "spotCheckFrac": 0.10 (from verification_policy)
|
|
359
|
+
# "validateAllJson": false (from verification_policy)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
The wave template **consumes these literal fields directly** — it does NOT
|
|
363
|
+
recompute the policy. This eliminates the JS/Python drift trap: the single source
|
|
364
|
+
of truth is Python's `verification_policy()` function; JS just uses the manifest
|
|
365
|
+
values. See `skills/buildsystem/wave-flat-dispatch.template.mjs` for the complete
|
|
366
|
+
template arguments and consumption logic.
|
|
367
|
+
|
|
368
|
+
Run the contract tests:
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
python -m unittest tests.test_agent_driver
|
|
372
|
+
python -m unittest tests.test_codex_driver_e2e
|
|
373
|
+
python -m unittest tests.test_openai_compatible_driver
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Design constraints
|
|
377
|
+
|
|
378
|
+
- **stdlib-only** at this layer (`abc`, `dataclasses`, `typing`, `subprocess`).
|
|
379
|
+
Provider SDKs (`openai`, `ollama`, …) belong to the concrete adapters, added
|
|
380
|
+
in Phases 2–3 — the interface stays importable everywhere.
|
|
381
|
+
- **ASCII-only**, **Windows + Linux safe**.
|
|
382
|
+
- **Honest probes.** `DriverCapabilities` defaults are conservative (no native
|
|
383
|
+
abilities, accuracy 0.0, tier 4). A backend must *opt in* to each capability.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"comment": "Aesop backend configuration examples. DO NOT include secrets in the actual aesop.config.json; use environment variables instead.",
|
|
3
|
+
"examples": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Claude Code (default)",
|
|
6
|
+
"backend": "claude",
|
|
7
|
+
"description": "Default backend: runs aesop through Claude Code Workflow harness. No API key needed (Claude Code manages auth). Tier 1 verification."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "OpenAI Codex / Chat Completions",
|
|
11
|
+
"backend": "codex",
|
|
12
|
+
"model": "gpt-3.5-turbo",
|
|
13
|
+
"description": "Uses OpenAI's Chat Completions API. Set OPENAI_API_KEY environment variable before running. Tier 2 verification (validate all JSON, spot-check, repair budget).",
|
|
14
|
+
"optional_fields": {
|
|
15
|
+
"model": "gpt-4-turbo for stronger verification",
|
|
16
|
+
"max_owned_bytes": 200000,
|
|
17
|
+
"max_retries": 2,
|
|
18
|
+
"timeout_s": 120.0
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "OpenAI-compatible (OpenRouter hosted)",
|
|
23
|
+
"backend": "openai-compatible",
|
|
24
|
+
"base_url": "https://openrouter.ai/api/v1",
|
|
25
|
+
"model": "openai/gpt-4-turbo",
|
|
26
|
+
"api_key_env": "OPENROUTER_API_KEY",
|
|
27
|
+
"description": "OpenAI-compatible endpoint on OpenRouter (a model aggregator). Set OPENROUTER_API_KEY environment variable. Tier 2 verification (hosted strong model).",
|
|
28
|
+
"optional_fields": {
|
|
29
|
+
"is_local": false,
|
|
30
|
+
"max_owned_bytes": 200000,
|
|
31
|
+
"max_retries": 2,
|
|
32
|
+
"timeout_s": 120.0
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "OpenAI-compatible (local Ollama)",
|
|
37
|
+
"backend": "openai-compatible",
|
|
38
|
+
"base_url": "http://localhost:11434/v1",
|
|
39
|
+
"model": "neural-chat",
|
|
40
|
+
"is_local": true,
|
|
41
|
+
"description": "Local/small open model via Ollama (no API key required, or dummy 'local-only' used). Tier 3 verification (validate all output, heavy spot-check, adversarial review).",
|
|
42
|
+
"optional_fields": {
|
|
43
|
+
"api_key_env": "OPENAI_API_KEY",
|
|
44
|
+
"max_owned_bytes": 200000,
|
|
45
|
+
"max_retries": 2,
|
|
46
|
+
"timeout_s": 120.0
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "OpenAI-compatible (Together.AI)",
|
|
51
|
+
"backend": "openai-compatible",
|
|
52
|
+
"base_url": "https://api.together.xyz/v1",
|
|
53
|
+
"model": "meta-llama/Llama-2-70b-chat",
|
|
54
|
+
"api_key_env": "TOGETHER_API_KEY",
|
|
55
|
+
"description": "OpenAI-compatible endpoint on Together AI. Set TOGETHER_API_KEY environment variable. Tier 2 verification (hosted model).",
|
|
56
|
+
"optional_fields": {
|
|
57
|
+
"is_local": false,
|
|
58
|
+
"max_owned_bytes": 200000,
|
|
59
|
+
"max_retries": 2,
|
|
60
|
+
"timeout_s": 120.0
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"production_config": {
|
|
65
|
+
"backend": "claude",
|
|
66
|
+
"comment": "Recommended production configuration: Claude Code with Haiku workers, Tier 1 verification. Drop this into aesop.config.json (removing comments) to use."
|
|
67
|
+
},
|
|
68
|
+
"experimental_codex": {
|
|
69
|
+
"backend": "codex",
|
|
70
|
+
"model": "gpt-3.5-turbo",
|
|
71
|
+
"comment": "Experimental Codex backend. Requires OPENAI_API_KEY set. Tier 2 verification."
|
|
72
|
+
},
|
|
73
|
+
"experimental_ollama": {
|
|
74
|
+
"backend": "openai-compatible",
|
|
75
|
+
"base_url": "http://localhost:11434/v1",
|
|
76
|
+
"model": "neural-chat",
|
|
77
|
+
"is_local": true,
|
|
78
|
+
"comment": "Experimental local Ollama backend. Requires 'ollama serve' running on localhost:11434. No API key needed (dummy 'local-only' used). Tier 3 verification."
|
|
79
|
+
}
|
|
80
|
+
}
|