@aragon-agent/cli 0.6.16 → 0.6.17
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/README.md +44 -47
- package/dist/agent/controller.js +39 -47
- package/dist/agent/reducer.js +0 -4
- package/dist/cli.js +0 -13
- package/dist/commands/builtins.js +3 -17
- package/dist/compaction/child.d.ts +10 -8
- package/dist/compaction/child.js +23 -25
- package/dist/compaction/limits.d.ts +0 -2
- package/dist/compaction/limits.js +0 -2
- package/dist/config/cli-commands.d.ts +1 -1
- package/dist/config/cli-commands.js +16 -15
- package/dist/config/load.d.ts +0 -17
- package/dist/config/load.js +0 -6
- package/dist/config/schema.d.ts +17 -5
- package/dist/config/schema.js +14 -11
- package/dist/exec/events.d.ts +12 -8
- package/dist/exec/events.js +2 -2
- package/dist/exec/runner.js +4 -1
- package/dist/fast/limits.d.ts +2 -2
- package/dist/fast/limits.js +2 -2
- package/dist/fast/prompt.d.ts +10 -11
- package/dist/fast/prompt.js +19 -20
- package/dist/fast/reviewer.d.ts +1 -1
- package/dist/fast/reviewer.js +1 -1
- package/dist/fast/types.d.ts +0 -2
- package/dist/fast/wiring.d.ts +18 -34
- package/dist/fast/wiring.js +20 -51
- package/dist/session/validate-session.js +3 -1
- package/dist/team/child-reviewer.d.ts +105 -0
- package/dist/team/child-reviewer.js +117 -0
- package/dist/team/normalize.d.ts +7 -26
- package/dist/team/normalize.js +9 -22
- package/dist/team/prompt.d.ts +0 -11
- package/dist/team/prompt.js +3 -12
- package/dist/team/report.d.ts +4 -19
- package/dist/team/report.js +1 -27
- package/dist/team/runtime.d.ts +5 -10
- package/dist/team/runtime.js +35 -39
- package/dist/team/subagent.d.ts +18 -18
- package/dist/team/subagent.js +80 -30
- package/dist/team/task-tool.d.ts +6 -26
- package/dist/team/task-tool.js +13 -47
- package/dist/team/types.d.ts +3 -42
- package/dist/ui/App.js +3 -4
- package/dist/ui/BottomStatusRow.js +2 -1
- package/dist/ui/StatusBar.js +2 -1
- package/dist/ui/TeamPanel.js +1 -1
- package/dist/ui/entries/TeamCard.js +1 -6
- package/dist/ui/layout/status-detail-layout.js +12 -2
- package/dist/ui/layout/status-layout.d.ts +4 -2
- package/dist/ui/layout/status-layout.js +24 -1
- package/dist/ui/overlays/HelpOverlay.js +1 -2
- package/package.json +2 -2
- package/dist/ui/ModeChip.d.ts +0 -18
- package/dist/ui/ModeChip.js +0 -24
package/README.md
CHANGED
|
@@ -409,7 +409,7 @@ signal ends the run (`130` SIGINT, `143` SIGTERM, `129` SIGHUP).
|
|
|
409
409
|
| `/team [on\|off\|max <n>]` | Team subagents: status and the live roster, the on/off switch, the fan-out width |
|
|
410
410
|
| `/todo [on\|off\|panel on\|off\|follow <mode>\|clear\|continue]` | Todo planning: status, the on/off switch, the rail, follow-through, and picking an unfinished plan back up |
|
|
411
411
|
| `/retry [show\|on\|off\|max <n>]` | API retry: the effective ladder, the on/off switch, the retry count. Takes effect **in the running session**, children included |
|
|
412
|
-
| `/fast [on\|off\|model <id>\|provider <id>\|same\|review <n\|off
|
|
412
|
+
| `/fast [on\|off\|model <id>\|provider <id>\|same\|review <n\|off>]` | Fast model tier: status and this session's totals, the on/off switch, which model, the review cadence |
|
|
413
413
|
| `/compact [status\|on\|off\|threshold <n>\|keep <n>\|history\|show <n>\|<instructions>]` | Context compaction: occupancy and this session's totals, the on/off switch, when it fires, how much it keeps. With free text, compacts now and tells the summarizer what to pay attention to |
|
|
414
414
|
| `/context` | What the context gauge is showing: occupancy split into measured and estimated, the window and **where it came from**, how stale the measurement is, compaction's actual state, and what the session-spend readout includes |
|
|
415
415
|
| `/bg [list\|logs <id> [n]\|stop <id\|all>\|status]` | Background services: what is running, its log tail, and how to stop it. `list` is the default |
|
|
@@ -810,9 +810,11 @@ still exits the session outright.
|
|
|
810
810
|
|
|
811
811
|
### Where the mode is shown
|
|
812
812
|
|
|
813
|
-
The status bar always names
|
|
814
|
-
|
|
815
|
-
|
|
813
|
+
The status bar's first row always names the current mode (`BUILD` or `PLAN`,
|
|
814
|
+
an accent word right after the run state; `PLAN>BUILD` while a switch is
|
|
815
|
+
pending; `B` / `P` / `P>B` when the terminal is narrow), including on short
|
|
816
|
+
terminals and with `--no-hints`. The Ctrl+G details row repeats it, and the
|
|
817
|
+
composer tints its border in plan mode.
|
|
816
818
|
|
|
817
819
|
### Switching mid-run
|
|
818
820
|
|
|
@@ -821,7 +823,7 @@ during a run takes effect immediately — you pressed it *because* the agent is
|
|
|
821
823
|
about to do something. Pressing it toward `BUILD` during a run is **deferred to
|
|
822
824
|
the end of the run**, so a session you launched under a read-only guarantee
|
|
823
825
|
cannot start writing files because of one stray keypress. The status bar shows
|
|
824
|
-
`PLAN
|
|
826
|
+
`PLAN>BUILD` while that is pending. Approving a plan is the one exception, and
|
|
825
827
|
it is an informed act rather than a stray keypress.
|
|
826
828
|
|
|
827
829
|
### If `Shift+Tab` does nothing
|
|
@@ -839,7 +841,7 @@ node -e "process.stdin.setRawMode(true);process.stdin.resume();process.stdin.on(
|
|
|
839
841
|
| It prints | What it means |
|
|
840
842
|
| --- | --- |
|
|
841
843
|
| `09` | The console is swallowing the modifier — the key is arriving as an ordinary `Tab`. Check `node -v`: below 22.17.0 (or on 24.0/24.1) this is expected, and aragon's own attempt to fix it was blocked. See [Requirements](#requirements) |
|
|
842
|
-
| `1b5b5a` | The key reaches the process fine, so something inside aragon is eating it — most often an overlay is open, or the run is still going and the switch is pending (the status bar shows `BUILD
|
|
844
|
+
| `1b5b5a` | The key reaches the process fine, so something inside aragon is eating it — most often an overlay is open, or the run is still going and the switch is pending (the status bar shows `PLAN>BUILD`) |
|
|
843
845
|
| nothing | Your terminal, multiplexer or remote-desktop stack never sent it; some never send `CSI Z` at all |
|
|
844
846
|
|
|
845
847
|
On the first row the wheel is dead for the same reason, and with the `/` palette
|
|
@@ -1184,25 +1186,24 @@ children's tokens are folded into the `[usage]` footer.
|
|
|
1184
1186
|
## Fast model tier
|
|
1185
1187
|
|
|
1186
1188
|
A second, cheaper model can be made a first-class citizen of a session. It is
|
|
1187
|
-
**off by default** — with `fast.enabled: false` the system prompt, the
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
**
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
*model* choice, never a permission boundary. This is where "not complicated, but
|
|
1196
|
-
very expensive in context" is actually paid for: a child that reads nine files
|
|
1197
|
-
and reports four sentences moves ~200 KB of file bodies out of the lead's window
|
|
1198
|
-
and onto a model that costs a fraction as much per token.
|
|
1189
|
+
**off by default** — with `fast.enabled: false` the system prompt, the
|
|
1190
|
+
transcript and the request payloads are exactly what they were before this
|
|
1191
|
+
feature existed — and it buys you two things once you turn it on.
|
|
1192
|
+
|
|
1193
|
+
**Every `task` child runs the lead's own model.** Per-child fast dispatch
|
|
1194
|
+
(`model: "fast"`) was removed for main-agent parity: a delegation is never a
|
|
1195
|
+
downgrade, and all the gates (tools, working directory, `--confirm`, plan mode,
|
|
1196
|
+
skills ceiling, compaction policy) are the lead's own.
|
|
1199
1197
|
|
|
1200
1198
|
**Periodic review (the harness decides).** Every *N* completed turns, a small
|
|
1201
1199
|
digest of what the lead has been doing goes to the fast model with one question
|
|
1202
1200
|
— is this still on track? — and if the answer is not "on track" it is injected
|
|
1203
1201
|
back into the running loop as a `<fast_review>` block. The lead sees a short
|
|
1204
1202
|
second opinion mid-run, when it can still act on it, for a few hundred tokens
|
|
1205
|
-
instead of a second full-size turn.
|
|
1203
|
+
instead of a second full-size turn. **Subagents get the same review**: when the
|
|
1204
|
+
tier is live and `fast.review` is on, each dispatched child runs with its own
|
|
1205
|
+
reviewer — same cadence, same budget per child, same fail-fast transport — so a
|
|
1206
|
+
team is as capable as the agent that dispatched it.
|
|
1206
1207
|
|
|
1207
1208
|
```
|
|
1208
1209
|
> refactor the config loader and keep the tests green
|
|
@@ -1224,7 +1225,7 @@ separately. If the fast model is not in the built-in price table the number is
|
|
|
1224
1225
|
shown as `unknown` rather than as `$0.00` — a feature that looks free while it
|
|
1225
1226
|
is spending money is worse than one that admits it does not know.
|
|
1226
1227
|
|
|
1227
|
-
**The review has a session budget
|
|
1228
|
+
**The review has a session budget.** A
|
|
1228
1229
|
session is not one run — it is one run per message you send — so a cadence alone
|
|
1229
1230
|
bounds nothing over a working afternoon. `fast.reviewMaxPerSession` (default
|
|
1230
1231
|
**40**) is the total number of reviews a session may *start*; reaching it prints
|
|
@@ -1233,9 +1234,7 @@ first review rather than a bare count you can only size afterwards. Raise it liv
|
|
|
1233
1234
|
with `/fast budget 80`. The budget is denominated in **reviews, not currency**,
|
|
1234
1235
|
because the fast tier is precisely where a model the price table has never seen
|
|
1235
1236
|
lives — a dollar ceiling would silently never fire for the configuration that
|
|
1236
|
-
most needs one.
|
|
1237
|
-
service of a message you sent, it is already bounded by `team.*`, and it exists
|
|
1238
|
-
to *reduce* total cost.
|
|
1237
|
+
most needs one.
|
|
1239
1238
|
|
|
1240
1239
|
### Turning it on
|
|
1241
1240
|
|
|
@@ -1255,9 +1254,8 @@ cannot grow a field mid-session.
|
|
|
1255
1254
|
| `fast.provider` | `''` | Empty inherits the main provider. |
|
|
1256
1255
|
| `fast.model` | `''` | The fast model id. Empty means *not configured* — it never falls back to the main model, so "same as main" stays distinguishable from a typo. |
|
|
1257
1256
|
| `fast.baseUrl` | `''` | Empty inherits the session's base URL **only** when the provider matches. |
|
|
1258
|
-
| `fast.thinkingLevel` | `'off'` | Applied to
|
|
1259
|
-
| `fast.
|
|
1260
|
-
| `fast.review` | `true` | Run the periodic review. |
|
|
1257
|
+
| `fast.thinkingLevel` | `'off'` | Applied to reviews (lead and subagents) and to fast-tier compaction summaries. |
|
|
1258
|
+
| `fast.review` | `true` | Run the periodic review — for the lead and for every `task` child. |
|
|
1261
1259
|
| `fast.reviewEveryTurns` | `5` | Turns between reviews (1–50). |
|
|
1262
1260
|
| `fast.reviewContextTurns` | `3` | Turns included in one digest (1–10). |
|
|
1263
1261
|
| `fast.reviewMaxChars` | `280` | Ceiling on an injected critique (80–600). |
|
|
@@ -1281,7 +1279,6 @@ reporting one:
|
|
|
1281
1279
|
/fast same run the fast tier on the main model
|
|
1282
1280
|
/fast review <n> | off
|
|
1283
1281
|
/fast budget [n] the session review budget; bare form reads it
|
|
1284
|
-
/fast delegate on | off
|
|
1285
1282
|
```
|
|
1286
1283
|
|
|
1287
1284
|
`/fast budget` with no argument is a **read**, so it is answerable while a `task`
|
|
@@ -1290,9 +1287,8 @@ like every other `/fast` setting.
|
|
|
1290
1287
|
|
|
1291
1288
|
**What you see.** A `fast` chip in the status bar's right cluster while the tier
|
|
1292
1289
|
is live (`fast*` while a review is in flight, dropped below 100 columns), a
|
|
1293
|
-
one-line card per review in the transcript
|
|
1294
|
-
|
|
1295
|
-
status bar cannot: reviews run, children delegated, tokens and cost. Under `-p`
|
|
1290
|
+
one-line card per review in the transcript. `/fast status` reports the session totals the
|
|
1291
|
+
status bar cannot: reviews run, tokens and cost. Under `-p`
|
|
1296
1292
|
nothing extra is written to stdout or stderr — the review spend is folded into
|
|
1297
1293
|
the `[usage]` footer and the reviews are in the log.
|
|
1298
1294
|
|
|
@@ -1558,19 +1554,20 @@ refusal is explained. Automatic tail clipping and failure truncation are disable
|
|
|
1558
1554
|
|
|
1559
1555
|
### Sub-agents get the same protection
|
|
1560
1556
|
|
|
1561
|
-
|
|
1562
|
-
`
|
|
1563
|
-
|
|
1564
|
-
dispatch reached you as one partial sentence.
|
|
1565
|
-
|
|
1566
|
-
Children now compact their own history, under tighter bounds: **two** retained
|
|
1567
|
-
turns instead of four, at most **two** compactions per child instead of five, the
|
|
1568
|
-
fast tier preferred whenever it resolves, and failures preserve history. Each
|
|
1557
|
+
Children compact their own history **under the lead's own policy**: the same
|
|
1558
|
+
`keepRecentTurns`, the same `onFailure`, the same archive setting, the same
|
|
1559
|
+
per-run compaction bound, the fast tier preferred whenever it resolves. Each
|
|
1569
1560
|
child owns its own context meter and counts compaction only after Core accepts
|
|
1570
1561
|
the candidate. There is no transcript card for a
|
|
1571
1562
|
child — the lead's transcript describes the lead's context. Turn it off with
|
|
1572
1563
|
`compaction.subagents: false`.
|
|
1573
1564
|
|
|
1565
|
+
Since main-agent parity, the turn cap, the per-child wall clock and the dispatch
|
|
1566
|
+
wall clock all default to **0 = no limit**: a child runs until it finishes, like
|
|
1567
|
+
the lead, with only its own idle watchdog and your Esc as ceilings. Set any of
|
|
1568
|
+
`team.subagentTimeoutMs` / `team.dispatchTimeoutMs` / `team.maxTurnsPerSubagent`
|
|
1569
|
+
to a positive value to bring a ceiling back.
|
|
1570
|
+
|
|
1574
1571
|
### A compaction is no longer irreversible
|
|
1575
1572
|
|
|
1576
1573
|
After a splice is adopted, the dropped messages are written verbatim to
|
|
@@ -1959,9 +1956,9 @@ env / `.env` → CLI flags**.
|
|
|
1959
1956
|
| `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered — `/team on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
|
|
1960
1957
|
| `team.maxSubagents` | `5` | Subagents per dispatch, clamped to `[1, 10]`. The 10 is the hard ceiling and is enforced twice — on the config value and again on what the model asks for — so hand-editing this file cannot raise it. |
|
|
1961
1958
|
| `team.maxConcurrent` | `3` | Subagents in flight at once, clamped to `[1, 10]` and capped at `maxSubagents`. A separate knob because provider rate limits are a different constraint from context economics. |
|
|
1962
|
-
| `team.subagentTimeoutMs` | `
|
|
1963
|
-
| `team.dispatchTimeoutMs` | `
|
|
1964
|
-
| `team.maxTurnsPerSubagent` | `
|
|
1959
|
+
| `team.subagentTimeoutMs` | `0` | One subagent's wall clock before it is aborted, clamped to `[0, 1800000]`. `0` (the default) = no ceiling — a wedged subagent still dies on its own idle watchdog, exactly like the lead. |
|
|
1960
|
+
| `team.dispatchTimeoutMs` | `0` | The whole dispatch's wall clock (and the `task` tool timeout), clamped to `[0, 3600000]`. `0` (the default) = no ceiling; only Esc ends a dispatch early. |
|
|
1961
|
+
| `team.maxTurnsPerSubagent` | `0` | Runaway-loop cap, clamped to `[0, 100]`. `0` (the default) = no cap, matching the lead. A subagent stopped at a positive cap is reported as `stopped: turn cap reached`, with whatever it had produced. |
|
|
1965
1962
|
| `todo.enabled` | `true` | Master switch for todo planning. `false` means the `todo_write` tool is never registered — `/todo on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
|
|
1966
1963
|
| `todo.panel` | `true` | Render the right-hand rail. Independent of `todo.enabled` on purpose: a screen-reader user wants the planning discipline without the column, and the system prompt varies one sentence accordingly. |
|
|
1967
1964
|
| `todo.followThrough` | `"notify"` | What happens when a run ends with steps left. `notify` says so and stops; `auto` continues the plan after a 3-second grace window, bounded by two structural limits (one fruitless attempt, 25 continuations per plan) that are deliberately **not** settings; `off` is silent. An unrecognized value falls back to `notify`. |
|
|
@@ -1972,7 +1969,7 @@ env / `.env` → CLI flags**.
|
|
|
1972
1969
|
| `retry.multiplier` | `2` | Growth factor, clamped to `[1, 5]`. The one **float** key in this section: `2.5` is a legitimate factor and is stored as typed. |
|
|
1973
1970
|
| `retry.jitter` | `true` | Equal jitter (`d/2 + rand·d/2`), which de-correlates concurrent subagents hitting the same 429 while keeping the announced countdown within a factor of two of the truth. Full jitter can fire 40 ms after announcing 30 s, which reads as a bug. |
|
|
1974
1971
|
| `retry.respectRetryAfter` | `true` | Honour `Retry-After` (and the provider rate-limit reset headers) as a **floor**, never a replacement — a `Retry-After: 1` on the ninth retry does not undo eight retries of backoff. A stated wait above 60 s is surfaced immediately instead of waited out. |
|
|
1975
|
-
| `retry.maxElapsedMs` | `240000` | Wall-clock budget from the first failure, clamped to `[10000, 1800000]`.
|
|
1972
|
+
| `retry.maxElapsedMs` | `240000` | Wall-clock budget from the first failure, clamped to `[10000, 1800000]`. When `team.subagentTimeoutMs` is positive, keep this below it: an equal budget means a subagent is killed at the same instant its ladder ends, and the user is then told "subagent timed out" for what was a provider outage. |
|
|
1976
1973
|
| `retry.onPartialStream` | `true` | Allow a restart after content has already streamed to the transcript. The view is rewound and the discarded tool cards removed; engine history is provably clean at that point, because it is only written on a completed turn. `false` refuses the whole path. |
|
|
1977
1974
|
| `skills.enabled` | `true` | Master switch for the skill system. |
|
|
1978
1975
|
| `skills.requireApproval` | `true` | Require a human to approve `skill_install` / `skill_create`. |
|
|
@@ -2364,19 +2361,19 @@ node packages/cli/dist/cli.js --version
|
|
|
2364
2361
|
- `echo "list files" | node dist/cli.js -p` prints an answer and exits `0`.
|
|
2365
2362
|
- A missing/invalid key produces a visible, actionable message (never a blank
|
|
2366
2363
|
screen), both in the TUI and headless.
|
|
2367
|
-
- `Shift+Tab` at 40, 80 and 120 columns - the
|
|
2368
|
-
|
|
2364
|
+
- `Shift+Tab` at 40, 80 and 120 columns - the status-bar mode word (`PLAN` / `P`)
|
|
2365
|
+
stays legible and nothing wraps onto a second row.
|
|
2369
2366
|
- The question wizard at 24 rows with 5 questions x 4 options - no clipping, and
|
|
2370
2367
|
the `n/N` counter matches what is on screen.
|
|
2371
2368
|
- Approve a plan and watch the SAME run start writing files, with no second
|
|
2372
2369
|
prompt.
|
|
2373
|
-
- `--no-color` on a legacy `cmd.exe` - the
|
|
2374
|
-
`*`/`o`, checkboxes render `[x]`/`[ ]`, no mojibake anywhere.
|
|
2370
|
+
- `--no-color` on a legacy `cmd.exe` - the mode word renders as plain `PLAN` text,
|
|
2371
|
+
radios render `*`/`o`, checkboxes render `[x]`/`[ ]`, no mojibake anywhere.
|
|
2375
2372
|
- A plan with a 600-character summary and a 400-character step detail - the text
|
|
2376
2373
|
wraps and scrolls, the footer count matches the real number of rows, and
|
|
2377
2374
|
nothing is truncated to a single line.
|
|
2378
2375
|
- `--no-hints` on a 20-row terminal in plan mode - the status bar still says
|
|
2379
|
-
`PLAN
|
|
2376
|
+
`PLAN`.
|
|
2380
2377
|
- Dismiss a plan card with `Esc`, let the agent resubmit, then close the card and press `Esc` twice within 1.5 seconds:
|
|
2381
2378
|
the run aborts and the session returns to an idle prompt. Do this one BY HAND
|
|
2382
2379
|
as well as in a test - the point of the check is whether the exit is findable,
|
package/dist/agent/controller.js
CHANGED
|
@@ -12,6 +12,7 @@ import { createBuiltinTools } from '../tools/index.js';
|
|
|
12
12
|
import { createFileChangeStore } from '../tools/file-change-store.js';
|
|
13
13
|
import { createToolOutputStore, } from '../tools/tool-output-store.js';
|
|
14
14
|
import { TeamRuntime } from '../team/runtime.js';
|
|
15
|
+
import { createChildReviewer } from '../team/child-reviewer.js';
|
|
15
16
|
import { TeamHumanQueue } from '../team/human-queue.js';
|
|
16
17
|
import { createTaskTool } from '../team/task-tool.js';
|
|
17
18
|
import { buildTeamBlock } from '../team/prompt.js';
|
|
@@ -161,14 +162,14 @@ export class AgentController {
|
|
|
161
162
|
// Fast model tier (fast-model-tier §3.1 / §3.3)
|
|
162
163
|
//
|
|
163
164
|
// ONE FIELD AND FOUR THIN FORWARDERS. The flag pair, the tier cache, the
|
|
164
|
-
// reviewer's lifetime and the
|
|
165
|
+
// reviewer's lifetime and the shared fail-fast review transport all live in
|
|
165
166
|
// `fast/wiring.ts`, which is a BUDGET decision rather than an aesthetic one
|
|
166
167
|
// (C-12 / RV-5): `CLAUDE.md` caps a source file at 1000 lines and this one had
|
|
167
168
|
// 40 to spare when the design was written.
|
|
168
169
|
//
|
|
169
170
|
// `null` when the tier could not be resolved at construction, which is the
|
|
170
|
-
// byte-identity branch: no reviewer is subscribed
|
|
171
|
-
//
|
|
171
|
+
// byte-identity branch: no reviewer is subscribed and `<fast_tier>` is
|
|
172
|
+
// never spliced (I-2).
|
|
172
173
|
// -----------------------------------------------------------------------
|
|
173
174
|
fast;
|
|
174
175
|
// -----------------------------------------------------------------------
|
|
@@ -311,8 +312,8 @@ export class AgentController {
|
|
|
311
312
|
this.todos = this.todoRegistered ? new TodoStore() : null;
|
|
312
313
|
// --- Fast model tier ---------------------------------------------------
|
|
313
314
|
//
|
|
314
|
-
// RESOLVED BEFORE THE
|
|
315
|
-
// `
|
|
315
|
+
// RESOLVED BEFORE THE AGENT, because `fastRegistered` decides whether the
|
|
316
|
+
// `FastWiring` (reviewer, tier cache) exists at all and the wiring is built
|
|
316
317
|
// ONCE (C-2). `FastWiring` re-runs the same pure function in its own
|
|
317
318
|
// constructor; the two agree by construction because they read the same
|
|
318
319
|
// config through the same resolver.
|
|
@@ -324,24 +325,35 @@ export class AgentController {
|
|
|
324
325
|
this.teamRuntime = this.teamRegistered
|
|
325
326
|
? new TeamRuntime({
|
|
326
327
|
getConfig: () => this.config,
|
|
327
|
-
// Read LIVE
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
// settings-screen edit reaches the next dispatch.
|
|
328
|
+
// Read LIVE: the closure is only ever called from inside a dispatch,
|
|
329
|
+
// and `childFactory()` re-reads `compaction.subagents` on every call
|
|
330
|
+
// so a settings-screen edit reaches the next dispatch.
|
|
331
331
|
contextManagerFor: (req) => this.compaction?.childFactory()?.(req),
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
332
|
+
// PER-CHILD FAST REVIEW (main-agent parity): one reviewer per
|
|
333
|
+
// child, sharing the lead wiring's tier, policy and fail-fast
|
|
334
|
+
// transport. `this.fast` is null until after the Agent exists; these
|
|
335
|
+
// closures run only from inside a dispatch, long after construction.
|
|
336
|
+
review: {
|
|
337
|
+
// EVERY `this.fast` READ LIVES INSIDE A CLOSURE: the wiring is
|
|
338
|
+
// assigned AFTER this constructor block (it needs the Agent), and
|
|
339
|
+
// a read in the constructor's own flow would be a use-before-assign.
|
|
340
|
+
// The closures run only from inside a dispatch, long after
|
|
341
|
+
// construction, when the field has its final value.
|
|
342
|
+
active: () => this.fast !== null && this.fast.available() && this.config.fast.review,
|
|
343
|
+
modelId: () => {
|
|
344
|
+
const tier = this.fast?.getTier();
|
|
345
|
+
return tier && tier.ok ? tier.ref.modelId : '';
|
|
344
346
|
},
|
|
347
|
+
create: (request) => this.fast
|
|
348
|
+
? createChildReviewer(request, {
|
|
349
|
+
getConfig: () => this.config,
|
|
350
|
+
hasKey: (id, role) => this.hasApiKey(id, role),
|
|
351
|
+
getApiKey: (id, role) => this.resolveKey(id, role),
|
|
352
|
+
complete: (providerId, llmRequest) => this.fast.completeViaFastRegistry(providerId, llmRequest),
|
|
353
|
+
available: () => this.fast?.available() === true,
|
|
354
|
+
})
|
|
355
|
+
: undefined,
|
|
356
|
+
},
|
|
345
357
|
providerRegistry: this.providerRegistry,
|
|
346
358
|
getCwd: () => this.cwd,
|
|
347
359
|
getMode: () => this.effectiveMode,
|
|
@@ -488,23 +500,12 @@ export class AgentController {
|
|
|
488
500
|
runtime: this.teamRuntime,
|
|
489
501
|
// Read LIVE: `/team off` flips the flag, it cannot unregister.
|
|
490
502
|
isTeamEnabled: () => this.teamEnabled,
|
|
491
|
-
// FROZEN AT CONSTRUCTION (C-2). `/fast on` in a session launched
|
|
492
|
-
// without the tier cannot add a schema property, and it says so
|
|
493
|
-
// rather than advertising one that is not there.
|
|
494
|
-
fastRegistered,
|
|
495
|
-
// Read LIVE at dispatch time (RV-3): the tier can stop resolving
|
|
496
|
-
// mid-session, and the normalizer and the subagent factory must
|
|
497
|
-
// agree about that at the same instant.
|
|
498
|
-
fastAvailable: () => this.fast?.delegationAvailable() === true,
|
|
499
503
|
maxSubagents: () => this.config.team.maxSubagents,
|
|
500
504
|
hasApiKey: () => this.hasApiKey(),
|
|
501
505
|
activeProvider: () => this.config.provider,
|
|
506
|
+
// Every child runs the lead's own model, so the lead's cost table
|
|
507
|
+
// is the one honest price for the dispatch total.
|
|
502
508
|
modelCost: () => this.getModelInfo().cost,
|
|
503
|
-
fastModelCost: () => {
|
|
504
|
-
const ref = this.fast?.fastRef();
|
|
505
|
-
return ref ? this.getModelInfoFor(ref).cost : undefined;
|
|
506
|
-
},
|
|
507
|
-
fastPricingUnknown: () => this.fast?.snapshot().pricingUnknown === true,
|
|
508
509
|
withPausedWatchdog: (fn) => this.withPausedWatchdog(fn),
|
|
509
510
|
}),
|
|
510
511
|
]
|
|
@@ -603,6 +604,10 @@ export class AgentController {
|
|
|
603
604
|
// number only bites BECAUSE `task` races `ctx.signal` — the
|
|
604
605
|
// executor's timeout is cooperative, so an override is inert for any
|
|
605
606
|
// tool that does not listen (I-2).
|
|
607
|
+
//
|
|
608
|
+
// `dispatchTimeoutMs: 0` (the default) reaches the executor as an
|
|
609
|
+
// override of `0` = NO TIMER AT ALL: the dispatch lasts as long as its
|
|
610
|
+
// slowest child, and only an Esc ends it early (main-agent parity).
|
|
606
611
|
...(this.teamRegistered ? { task: config.team.dispatchTimeoutMs } : {}),
|
|
607
612
|
},
|
|
608
613
|
},
|
|
@@ -672,13 +677,6 @@ export class AgentController {
|
|
|
672
677
|
});
|
|
673
678
|
if (this.fast) {
|
|
674
679
|
this.rebuildSystemPrompt();
|
|
675
|
-
// Fast-tier children are counted from the outcome rather than from the
|
|
676
|
-
// specs, so a downgraded child is not miscounted as a saving (§3.6).
|
|
677
|
-
this.teamRuntime?.subscribe((event) => {
|
|
678
|
-
if (event.type !== 'dispatch_end')
|
|
679
|
-
return;
|
|
680
|
-
this.fast?.noteDelegated(event.outcome.runs.filter((r) => r.tier === 'fast').length);
|
|
681
|
-
});
|
|
682
680
|
}
|
|
683
681
|
// ONE LINE FOR THE TWO CONFIGURATION MISTAKES THAT ARE OTHERWISE INVISIBLE
|
|
684
682
|
// (§3.3): the tier is on but unnamed, or named against a provider with no
|
|
@@ -738,11 +736,6 @@ export class AgentController {
|
|
|
738
736
|
? buildTeamBlock({
|
|
739
737
|
maxSubagents: config.team.maxSubagents,
|
|
740
738
|
maxConcurrent: config.team.maxConcurrent,
|
|
741
|
-
// One cross-reference sentence, present only when the capability
|
|
742
|
-
// is (§3.8). `this.fast` is null during the FIRST compose (the
|
|
743
|
-
// wiring needs the Agent), which is why the constructor composes
|
|
744
|
-
// again once it exists.
|
|
745
|
-
fastDelegation: !!fastAvailable && config.fast.delegate,
|
|
746
739
|
})
|
|
747
740
|
: '',
|
|
748
741
|
// BOTH FLAGS, exactly as team mode uses both, and for the identical
|
|
@@ -762,7 +755,6 @@ export class AgentController {
|
|
|
762
755
|
fastBlock: fastAvailable
|
|
763
756
|
? buildFastBlock({
|
|
764
757
|
model: tier.ok ? tier.ref.modelId : '',
|
|
765
|
-
delegate: config.fast.delegate,
|
|
766
758
|
review: config.fast.review,
|
|
767
759
|
})
|
|
768
760
|
: '',
|
package/dist/agent/reducer.js
CHANGED
|
@@ -860,10 +860,6 @@ export function viewReducer(state, action) {
|
|
|
860
860
|
const runs = action.specs.map((spec) => ({
|
|
861
861
|
label: spec.label,
|
|
862
862
|
description: spec.description,
|
|
863
|
-
// Already downgraded by the normalizer when the tier was unavailable, so
|
|
864
|
-
// the card and the report agree from the first frame (fast-model-tier
|
|
865
|
-
// §3.4).
|
|
866
|
-
tier: spec.tier,
|
|
867
863
|
phase: 'queued',
|
|
868
864
|
turns: 0,
|
|
869
865
|
toolCalls: 0,
|
package/dist/cli.js
CHANGED
|
@@ -160,11 +160,6 @@ function toFlags(opts) {
|
|
|
160
160
|
fastModel: opts.fastModel,
|
|
161
161
|
fastProvider: opts.fastProvider,
|
|
162
162
|
fastReview: opts.fastReview,
|
|
163
|
-
// …and again for `--fast-delegate` / `--no-fast-delegate`, one feature
|
|
164
|
-
// later — NINE features, one trap. It is `fast.delegate`'s only channel:
|
|
165
|
-
// there is no `ARAGON_FAST_DELEGATE`, so missing this line leaves a wrapper
|
|
166
|
-
// with no way at all to say "do not delegate on this run".
|
|
167
|
-
fastDelegate: opts.fastDelegate,
|
|
168
163
|
// `--verbose` is just a shorthand for `--log-level debug`; an explicit
|
|
169
164
|
// `--log-level` still wins, so the two can be combined without surprise.
|
|
170
165
|
logLevel: opts.logLevel ?? (opts.verbose ? 'debug' : undefined),
|
|
@@ -1537,14 +1532,6 @@ function buildProgram() {
|
|
|
1537
1532
|
.option('--fast-model <id>', 'The fast model id (implies nothing about --fast)')
|
|
1538
1533
|
.option('--fast-provider <id>', 'Provider for the fast model (default: the main provider)')
|
|
1539
1534
|
.option('--fast-review <n|off>', 'Turns between automatic fast reviews, or "off"')
|
|
1540
|
-
// BOTH FORMS, POSITIVE FIRST, and here it matters more than anywhere above:
|
|
1541
|
-
// `fast.delegate` is PERSISTED and defaults to TRUE, so declaring only
|
|
1542
|
-
// `--no-fast-delegate` would make commander default `opts.fastDelegate` to
|
|
1543
|
-
// `true` and force `delegate: true` on EVERY run that passed no flag at all
|
|
1544
|
-
// — silently overwriting a user's stored `false`. Same polarity, same trap
|
|
1545
|
-
// and same fix as `--update` / `--compaction`.
|
|
1546
|
-
.option('--fast-delegate', 'Let the fast tier take mechanical sub-steps (the default)')
|
|
1547
|
-
.option('--no-fast-delegate', 'Run every sub-step on the main model')
|
|
1548
1535
|
// BOTH FORMS, positive first, for the reason recorded seven times above —
|
|
1549
1536
|
// and this is the pair whose omission would be worst. `update.mode` is
|
|
1550
1537
|
// PERSISTED and defaults to `'auto'`, so a lone `--no-update` would make
|
|
@@ -106,8 +106,7 @@ function formatFastStatus(controller) {
|
|
|
106
106
|
else {
|
|
107
107
|
lines.push(`Fast tier: ${state}. Model: ${cfg.model || '(not set)'}.`);
|
|
108
108
|
}
|
|
109
|
-
lines.push(`Review: ${cfg.review ? `every ${cfg.reviewEveryTurns} turns` : 'off'}
|
|
110
|
-
`Delegation: ${cfg.delegate ? 'on' : 'off'}.`);
|
|
109
|
+
lines.push(`Review: ${cfg.review ? `every ${cfg.reviewEveryTurns} turns` : 'off'}.`);
|
|
111
110
|
const snapshot = status.snapshot;
|
|
112
111
|
const cost = snapshot.pricingUnknown
|
|
113
112
|
? `unknown (no price table for ${snapshot.model})`
|
|
@@ -124,7 +123,6 @@ function formatFastStatus(controller) {
|
|
|
124
123
|
// numbers are `0` placeholders and `reviews >= reviewBudget` would be true.
|
|
125
124
|
const budget = snapshot.budgetReached ? ' (budget reached - raise with /fast budget <n>)' : '';
|
|
126
125
|
lines.push(`This session: ${snapshot.reviews}/${snapshot.reviewBudget} reviews${budget}, ` +
|
|
127
|
-
`${snapshot.delegated} delegated subagents, ` +
|
|
128
126
|
`in ${formatTokens(snapshot.usage.inputTokens)} / out ` +
|
|
129
127
|
`${formatTokens(snapshot.usage.outputTokens)}, cost ${cost}.`);
|
|
130
128
|
return lines.join('\n');
|
|
@@ -339,7 +337,7 @@ const COMMANDS = [
|
|
|
339
337
|
{
|
|
340
338
|
name: 'fast',
|
|
341
339
|
description: 'Fast model tier: status | on | off | model <id> | provider <id> | same | ' +
|
|
342
|
-
'review <n|off> | budget <n>
|
|
340
|
+
'review <n|off> | budget <n>',
|
|
343
341
|
/**
|
|
344
342
|
* `/fast on` CANNOT turn the tier on in a session that started without it,
|
|
345
343
|
* for the reason `/team on` above records at length: the tool array is built
|
|
@@ -516,20 +514,8 @@ const COMMANDS = [
|
|
|
516
514
|
`${snapshot.reviews} used.`);
|
|
517
515
|
return;
|
|
518
516
|
}
|
|
519
|
-
if (verb === 'delegate') {
|
|
520
|
-
const raw = (value ?? '').trim().toLowerCase();
|
|
521
|
-
if (raw !== 'on' && raw !== 'off') {
|
|
522
|
-
ctx.notify('warn', 'Usage: /fast delegate <on|off>');
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
if (!persist({ delegate: raw === 'on' }))
|
|
526
|
-
return;
|
|
527
|
-
ctx.toast('success', `Fast delegation ${raw}.`);
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
517
|
ctx.notify('warn', `Unknown argument "${verb}" - use /fast ` +
|
|
531
|
-
'[status|on|off|model <id>|provider <id>|same|review <n|off>|budget <n
|
|
532
|
-
'delegate on|off].');
|
|
518
|
+
'[status|on|off|model <id>|provider <id>|same|review <n|off>|budget <n>].');
|
|
533
519
|
},
|
|
534
520
|
},
|
|
535
521
|
{
|
|
@@ -13,15 +13,17 @@
|
|
|
13
13
|
* turn the child already ran, and receives one partial sentence for all of it.
|
|
14
14
|
* Two fast-model summarizations is the cheap side of that trade.
|
|
15
15
|
*
|
|
16
|
-
* A CHILD MANAGER
|
|
17
|
-
* overlay
|
|
16
|
+
* SINCE MAIN-AGENT PARITY, A CHILD MANAGER RUNS THE LEAD'S OWN POLICY. The only
|
|
17
|
+
* overlay left is the CONNECTION (provider / model / base URL / manual window),
|
|
18
|
+
* which must follow the model the child actually runs on. `keepRecentTurns`,
|
|
19
|
+
* `onFailure`, `useFastTier`, `archive` and the per-run compaction bound are all
|
|
20
|
+
* read from the SAME live config the lead reads, so a user who tunes compaction
|
|
21
|
+
* tunes every child identically - the requirement "same mode and configuration
|
|
22
|
+
* as the main agent", taken literally.
|
|
18
23
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* path by design (`limits.ts` header). Without it the child silently
|
|
23
|
-
* inherits the lead's 5 - two and a half times the bound the reversal above
|
|
24
|
-
* rests on.
|
|
24
|
+
* THE INSTANCE BOUND stays (mechanism B of RV-2) because `maxPerRun` is
|
|
25
|
+
* STRUCTURAL with no config path by design (`limits.ts` header); it is now the
|
|
26
|
+
* SAME `COMPACTION_LIMITS.maxPerRun` the lead's own manager runs under.
|
|
25
27
|
*
|
|
26
28
|
* NO UI. A child's compaction produces no transcript card (DH-7): the lead's
|
|
27
29
|
* transcript describes the LEAD's context, and a card there would claim the
|
package/dist/compaction/child.js
CHANGED
|
@@ -13,15 +13,17 @@
|
|
|
13
13
|
* turn the child already ran, and receives one partial sentence for all of it.
|
|
14
14
|
* Two fast-model summarizations is the cheap side of that trade.
|
|
15
15
|
*
|
|
16
|
-
* A CHILD MANAGER
|
|
17
|
-
* overlay
|
|
16
|
+
* SINCE MAIN-AGENT PARITY, A CHILD MANAGER RUNS THE LEAD'S OWN POLICY. The only
|
|
17
|
+
* overlay left is the CONNECTION (provider / model / base URL / manual window),
|
|
18
|
+
* which must follow the model the child actually runs on. `keepRecentTurns`,
|
|
19
|
+
* `onFailure`, `useFastTier`, `archive` and the per-run compaction bound are all
|
|
20
|
+
* read from the SAME live config the lead reads, so a user who tunes compaction
|
|
21
|
+
* tunes every child identically - the requirement "same mode and configuration
|
|
22
|
+
* as the main agent", taken literally.
|
|
18
23
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* path by design (`limits.ts` header). Without it the child silently
|
|
23
|
-
* inherits the lead's 5 - two and a half times the bound the reversal above
|
|
24
|
-
* rests on.
|
|
24
|
+
* THE INSTANCE BOUND stays (mechanism B of RV-2) because `maxPerRun` is
|
|
25
|
+
* STRUCTURAL with no config path by design (`limits.ts` header); it is now the
|
|
26
|
+
* SAME `COMPACTION_LIMITS.maxPerRun` the lead's own manager runs under.
|
|
25
27
|
*
|
|
26
28
|
* NO UI. A child's compaction produces no transcript card (DH-7): the lead's
|
|
27
29
|
* transcript describes the LEAD's context, and a card there would claim the
|
|
@@ -45,11 +47,11 @@ export function createChildContextManager(req, deps) {
|
|
|
45
47
|
* which is the same reason `subagent.ts` reuses the lead's `getApiKey` closure
|
|
46
48
|
* rather than the resolved key.
|
|
47
49
|
*
|
|
48
|
-
* `useFastTier
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
50
|
+
* `useFastTier` is read LIVE from the base config (main-agent
|
|
51
|
+
* parity - no overlay): it expresses a PREFERENCE, not an outcome.
|
|
52
|
+
* `resolveFastTier` still decides, and when nothing resolves the child
|
|
53
|
+
* falls back exactly as the lead does - to its OWN model, because
|
|
54
|
+
* `provider` / `model` are overlaid here too.
|
|
53
55
|
* Failed summaries preserve the child's task just as they preserve the lead's.
|
|
54
56
|
*/
|
|
55
57
|
const childConfig = () => {
|
|
@@ -63,16 +65,11 @@ export function createChildContextManager(req, deps) {
|
|
|
63
65
|
baseUrl: req.model.baseUrl,
|
|
64
66
|
// The lead's manual limit describes its connection, not every worker.
|
|
65
67
|
contextWindow: sameConnection ? base.contextWindow : null,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// ONE ARCHIVE PER LEAD COMPACTION IS AUDITABLE; TWENTY PER DISPATCH IS
|
|
72
|
-
// NOISE. The child's dropped slice is therefore never retained either -
|
|
73
|
-
// `runCompaction` reads this key before it stashes anything.
|
|
74
|
-
archive: false,
|
|
75
|
-
},
|
|
68
|
+
// NO POLICY OVERLAY (main-agent parity): `keepRecentTurns`, `onFailure`,
|
|
69
|
+
// `useFastTier` and `archive` are read LIVE from the base config, so the
|
|
70
|
+
// child compacts under exactly the policy the lead compacts under. A
|
|
71
|
+
// settings-screen edit mid-dispatch reaches a running child because this
|
|
72
|
+
// view is re-read on every call.
|
|
76
73
|
};
|
|
77
74
|
};
|
|
78
75
|
const meter = new ContextMeter({
|
|
@@ -121,8 +118,9 @@ export function createChildContextManager(req, deps) {
|
|
|
121
118
|
// user's transcript with no card to explain which agent it is about.
|
|
122
119
|
notify: () => { },
|
|
123
120
|
},
|
|
124
|
-
// MECHANISM B - the instance bound (RV-2 / DH-16).
|
|
125
|
-
|
|
121
|
+
// MECHANISM B - the instance bound (RV-2 / DH-16). The SAME bound the
|
|
122
|
+
// lead's own manager runs under (main-agent parity).
|
|
123
|
+
{ maxPerRun: COMPACTION_LIMITS.maxPerRun });
|
|
126
124
|
return {
|
|
127
125
|
// THERE IS NO `/compact` FOR A CHILD, so nothing is ever queued and the
|
|
128
126
|
// manual branch of `shouldCompact` is unreachable by construction.
|
|
@@ -28,8 +28,6 @@ export declare const COMPACTION_LIMITS: {
|
|
|
28
28
|
readonly archiveMaxFiles: 20;
|
|
29
29
|
readonly archiveMaxAgeMs: 604800000;
|
|
30
30
|
readonly archiveMaxBytes: 8000000;
|
|
31
|
-
readonly childKeepRecentTurns: 2;
|
|
32
|
-
readonly childMaxPerRun: 2;
|
|
33
31
|
readonly cardTextRows: 6;
|
|
34
32
|
readonly statusCompactCols: 100;
|
|
35
33
|
};
|
|
@@ -42,7 +42,7 @@ export declare const RETRY_CONFIG_SET_KEYS: readonly ["retry.enabled", "retry.ma
|
|
|
42
42
|
* would silently never take effect, and `config set` would still print
|
|
43
43
|
* `Set fast.model = haiku`.
|
|
44
44
|
*/
|
|
45
|
-
export declare const FAST_CONFIG_SET_KEYS: readonly ["fast.enabled", "fast.provider", "fast.model", "fast.baseUrl", "fast.thinkingLevel", "fast.
|
|
45
|
+
export declare const FAST_CONFIG_SET_KEYS: readonly ["fast.enabled", "fast.provider", "fast.model", "fast.baseUrl", "fast.thinkingLevel", "fast.review", "fast.reviewEveryTurns", "fast.reviewContextTurns", "fast.reviewMaxChars", "fast.reviewMaxPerSession"];
|
|
46
46
|
/**
|
|
47
47
|
* Config keys under `update.` that `aragon config set` accepts (cli-auto-update
|
|
48
48
|
* §4.1).
|