@aragon-agent/cli 0.6.39 → 0.6.42
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 +109 -0
- package/README.md +126 -20
- package/dist/agent/controller.d.ts +139 -14
- package/dist/agent/controller.js +299 -40
- package/dist/agent/model-profile-settings.js +12 -1
- package/dist/agent/plan-prompt.d.ts +1 -3
- package/dist/agent/plan-prompt.js +13 -7
- package/dist/agent/reducer.d.ts +29 -1
- package/dist/agent/reducer.js +34 -6
- package/dist/agent/skill-triage-prompt.d.ts +42 -0
- package/dist/agent/skill-triage-prompt.js +74 -0
- package/dist/agent/system-prompt.d.ts +33 -2
- package/dist/agent/system-prompt.js +12 -4
- package/dist/cli.js +21 -5
- package/dist/commands/builtins.js +28 -185
- package/dist/commands/skills.js +86 -1
- package/dist/commands/subagent-command.d.ts +30 -0
- package/dist/commands/subagent-command.js +39 -0
- package/dist/commands/team-command.d.ts +49 -0
- package/dist/commands/team-command.js +259 -0
- package/dist/compaction/command.js +16 -3
- package/dist/compaction/compactor.d.ts +25 -0
- package/dist/compaction/compactor.js +111 -10
- package/dist/compaction/digest.d.ts +24 -1
- package/dist/compaction/digest.js +139 -17
- package/dist/compaction/limits.d.ts +21 -0
- package/dist/compaction/limits.js +21 -0
- package/dist/compaction/reason-text.d.ts +36 -0
- package/dist/compaction/reason-text.js +78 -0
- package/dist/compaction/types.d.ts +82 -14
- package/dist/compaction/wiring.d.ts +13 -8
- package/dist/compaction/wiring.js +1 -0
- package/dist/config/load.js +50 -3
- package/dist/config/model-kits.d.ts +2 -1
- package/dist/config/schema.d.ts +82 -6
- package/dist/config/schema.js +107 -9
- package/dist/config/store.js +10 -4
- package/dist/proc/log-mirror.d.ts +21 -4
- package/dist/proc/log-mirror.js +29 -7
- package/dist/skills/service.d.ts +41 -0
- package/dist/skills/service.js +62 -0
- package/dist/skills/triage.d.ts +194 -0
- package/dist/skills/triage.js +393 -0
- package/dist/team/dispatch-gate.d.ts +86 -0
- package/dist/team/dispatch-gate.js +75 -0
- package/dist/team/forced-dispatch.d.ts +95 -0
- package/dist/team/forced-dispatch.js +208 -0
- package/dist/team/forced-mode.d.ts +116 -0
- package/dist/team/forced-mode.js +156 -0
- package/dist/team/forced-prompt.d.ts +48 -0
- package/dist/team/forced-prompt.js +84 -0
- package/dist/team/limits.d.ts +61 -1
- package/dist/team/limits.js +69 -1
- package/dist/team/model.d.ts +5 -5
- package/dist/team/model.js +5 -5
- package/dist/team/normalize.d.ts +15 -0
- package/dist/team/normalize.js +21 -4
- package/dist/team/prompt.d.ts +6 -3
- package/dist/team/prompt.js +9 -5
- package/dist/team/task-tool.js +11 -7
- package/dist/tools/human-input.d.ts +35 -2
- package/dist/tools/human-input.js +38 -0
- package/dist/tools/plan-tools.d.ts +20 -12
- package/dist/tools/plan-tools.js +24 -17
- package/dist/ui/App.js +130 -11
- package/dist/ui/StatusBar.d.ts +15 -0
- package/dist/ui/StatusBar.js +2 -0
- package/dist/ui/Transcript.js +1 -1
- package/dist/ui/entries/CompactionCard.d.ts +11 -1
- package/dist/ui/entries/CompactionCard.js +65 -4
- package/dist/ui/layout/status-layout.d.ts +27 -0
- package/dist/ui/layout/status-layout.js +27 -1
- package/dist/ui/overlays/HelpOverlay.js +8 -4
- package/dist/ui/overlays/SettingsScreen.d.ts +14 -0
- package/dist/ui/overlays/SettingsScreen.js +39 -5
- package/dist/ui/overlays/TeamFanoutPage.d.ts +51 -0
- package/dist/ui/overlays/TeamFanoutPage.js +90 -0
- package/dist/ui/overlays/kit-settings-state.js +3 -2
- package/dist/ui/overlays/model-profile-state.d.ts +20 -2
- package/dist/ui/overlays/model-profile-state.js +12 -0
- package/dist/ui/overlays/team-fanout-state.d.ts +106 -0
- package/dist/ui/overlays/team-fanout-state.js +155 -0
- package/package.json +81 -81
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,74 @@ were written.
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
|
+
- **Automatic skill triage, and no round limit on questions.** Two changes that
|
|
12
|
+
share one idea: replace a hard limit with guidance the agent can act on.
|
|
13
|
+
`ask_user` is no longer capped at four rounds per turn — the cap, its prompt
|
|
14
|
+
wording (`you may ask up to 4 rounds`), its tool-result counters
|
|
15
|
+
(`roundsUsed` / `roundsRemaining`) and its `/plan status` readout are all gone,
|
|
16
|
+
because an agent that is told it is running out of questions behaves like it.
|
|
17
|
+
What replaced it is a de-duplication guard: a question batch you have already
|
|
18
|
+
**answered** in this turn returns a note instead of reopening the overlay, while
|
|
19
|
+
a **cancelled** one records nothing, so an accidental `Esc` never retires a
|
|
20
|
+
question. Steering does not reset the guard, because a steer resumes the same
|
|
21
|
+
turn. `planModeMaxAskRounds` is retired rather than defaulted to a large number:
|
|
22
|
+
`config set` names the reason and exits `2`, and the key disappears from
|
|
23
|
+
`config.json` at the next write. The single-wait ceiling
|
|
24
|
+
(`planModeHumanTimeoutMs`) is untouched — it protects an unattended terminal, not
|
|
25
|
+
the agent's vocabulary.
|
|
26
|
+
Skill use now begins with a step instead of a hope. Every task gets a
|
|
27
|
+
`<skill_triage>` protocol fixing *when* to decide (after the project guidance and
|
|
28
|
+
the directory listing, before any plan or edit) plus up to three ranked
|
|
29
|
+
`<skill_candidates>` computed locally from your message against the installed
|
|
30
|
+
records — no model call, no file read, no `SKILL.md` body, so the disclosure
|
|
31
|
+
ladder keeps its lower levels untouched. When a strongly-matching skill was
|
|
32
|
+
available and the turn did real work without loading it, the run ends with one
|
|
33
|
+
`info` line and a pointer to `/skills route`; that fires at most once per skill
|
|
34
|
+
per session, because a line printed every turn is a line you learn to skip.
|
|
35
|
+
`/skills route <text>` explains any decision (including the runner-up and the
|
|
36
|
+
threshold on a miss), `/skills triage on|off` flips the feature live, and
|
|
37
|
+
`skills.triage` (default `true`) makes it permanent — off restores the previous
|
|
38
|
+
prompt byte for byte. Subagents are deliberately not triaged: a child has no
|
|
39
|
+
`skill` tool, so candidates would advertise a capability it does not have.
|
|
40
|
+
- **`/team <brief>` forces team mode and starts the work in one line.** Typing
|
|
41
|
+
`/team write today's AI briefing` no longer answers `Unknown argument` — it arms a
|
|
42
|
+
SESSION-level forced mode and submits that brief as an ordinary turn. The lead
|
|
43
|
+
analyses and plans it, then has to call `task`: three layers say so, and only the
|
|
44
|
+
third is mechanical. The submitted directive (unchanged bytes) covers the first
|
|
45
|
+
turn, a new `<forced_team_mode>` prompt block covers every later turn, and an
|
|
46
|
+
end-of-turn gate covers a model that did neither — when a turn used tools and
|
|
47
|
+
dispatched nothing, the app asks once in the transcript
|
|
48
|
+
(`Forced team mode: no dispatch last turn - asking the agent to dispatch now.`)
|
|
49
|
+
and re-prompts with the armed count. The gate is bounded on three sides, because
|
|
50
|
+
a helpful nudge that fires for ever is a bill: at most one nudge per user
|
|
51
|
+
request (a human submit refills the budget, a turn never does), never for a pure
|
|
52
|
+
question that used no tools, and never after Esc or an error. A turn that
|
|
53
|
+
already tried `task` — even one the tool refused — counts as an attempt, so a
|
|
54
|
+
closed capability cannot be mistaken for a disobedient model. While the session
|
|
55
|
+
is armed the status bar carries `Team 4` (`T4` when narrow), the only
|
|
56
|
+
persistent signal that `/team` happened. Forced mode is never persisted: no
|
|
57
|
+
new `config.json` key, no session-file field, and `aragon exec` is unchanged.
|
|
58
|
+
`/team on` arms without starting, `/team off` leaves, `/team` reports, and a
|
|
59
|
+
quoted `"/team \"off\""` is a brief named `off` rather than the keyword.
|
|
60
|
+
|
|
61
|
+
- **`/subagent`: force a parallel fan-out with one command.** The escape hatch for
|
|
62
|
+
"I want a team on this, not the model's judgement": `/subagent -n 6 review the error
|
|
63
|
+
handling in packages/cli/src/team`, `/subagent --parts api,ui,docs audit the request
|
|
64
|
+
path`, `/subagent --read-only profile the parser`. With no argument it reports live
|
|
65
|
+
capacity, the subagent model, the supervisor and the team switch, and it answers even in
|
|
66
|
+
a `--no-team` session rather than pretending. The command compiles your intent into ONE
|
|
67
|
+
user turn that tells the lead to call `task` once, so it shares the single dispatch path
|
|
68
|
+
(same Esc, same report, same spend accounting) - the forcing is instruction-level, and
|
|
69
|
+
the notice says what the next turn will do instead of claiming children have started.
|
|
70
|
+
A count above `team.maxSubagents` is narrowed AND disclosed (`asked for 12;
|
|
71
|
+
team.maxSubagents is 8`), a parts list is narrowed by both the structural 8 and the
|
|
72
|
+
configured width, and `-n 0` is an error rather than a silent 1.
|
|
73
|
+
- **`/settings` → `Subagent fan-out`.** A fourth root row holding `Max subagents`,
|
|
74
|
+
`Run at once` and `Supervisor`, adjusted with `Left` / `Right` and saved by the same
|
|
75
|
+
single transaction as every other settings row (`Ctrl+S` on the main page; the fan-out
|
|
76
|
+
page's footer says so instead of promising a key it does not listen for). Narrowing the
|
|
77
|
+
population narrows the pool with it, and the follow-down is committed, so widening again
|
|
78
|
+
does not silently restore a pool you did not choose.
|
|
11
79
|
- **`--threads`: one process, N isolated conversations.** A headless `aragon exec`
|
|
12
80
|
process used to be one conversation: the seventh tenant's messages appeared in the
|
|
13
81
|
third tenant's history, one `todo` list served everybody, and `interrupt` ended the
|
|
@@ -55,6 +123,38 @@ were written.
|
|
|
55
123
|
spawning anything.
|
|
56
124
|
|
|
57
125
|
### Changed
|
|
126
|
+
- **`/team` is now an action, and its configuration verbs are gone.** `status` and
|
|
127
|
+
`on` / `off` survive as SESSION control words (enter, leave, report), and `off`
|
|
128
|
+
no longer saves anything: **`/team on|off` used to write `config.json` and no
|
|
129
|
+
longer does**, so a mode you switch for this conversation is not silently a mode
|
|
130
|
+
for every later one. The four settings that used to live on the command moved to
|
|
131
|
+
`Settings > Team`, which is now the only persistent writer: `Team mode` (new —
|
|
132
|
+
the capability switch, previously only reachable as `/team on|off`), `Max
|
|
133
|
+
subagents`, `Run at once` and `Supervisor`. `max <n>`, `overseer on|off` and
|
|
134
|
+
`model <name>` are not verbs any more — `/team max 6` is a brief that starts work
|
|
135
|
+
on the text "max 6", because a command that both changes configuration and
|
|
136
|
+
executes work leaves you unable to predict what it did. `/subagent` remains as a
|
|
137
|
+
DEPRECATED ALIAS of `/team` (same arguments, one extra toast); nothing about its
|
|
138
|
+
behaviour changed except that a team-off session is now turned on for the session
|
|
139
|
+
in place instead of being refused. The settings page is retitled `Team` (it was
|
|
140
|
+
`Subagent fan-out`) and its root row prints `off - no subagents` while the
|
|
141
|
+
capability is off, rather than two numbers that describe nothing you can spend.
|
|
142
|
+
A session started with `--no-team` shows `on (next launch)` on the `Team mode`
|
|
143
|
+
row instead of claiming that saving will change the running session — the tool
|
|
144
|
+
array is immutable, and the row says so. One internal truth was deleted rather
|
|
145
|
+
than patched: `AgentController` no longer keeps a private `teamEnabled` copy of
|
|
146
|
+
`config.team.enabled`, so a settings save takes effect on the next turn instead of
|
|
147
|
+
at the next launch.
|
|
148
|
+
- **The subagent fan-out default is now 8 per dispatch and 8 in flight at once** (it was
|
|
149
|
+
5 and 3). The perceived "only 3 subagents" was the concurrency ceiling, not the
|
|
150
|
+
population - changing only the population would have shown nothing, because children
|
|
151
|
+
4..8 would simply queue. `maxConcurrent` stays a separate knob precisely so a single API
|
|
152
|
+
key collecting 429s can be fixed by lowering `Run at once`; the settings row and the
|
|
153
|
+
README both say which number to lower. The hard ceiling is unchanged at 10: 8 is a
|
|
154
|
+
default you can move, 10 is the limit you cannot. **A persisted `5`/`3` pair from an
|
|
155
|
+
older install is migrated to `8`/`8` once**, with a `team.fanoutMigrated` marker so a
|
|
156
|
+
deliberate return to 5/3 sticks instead of being widened again on every launch. A
|
|
157
|
+
configuration whose values are anything else is never touched.
|
|
58
158
|
- `makeExecController` now separates PROCESS-LEVEL log mounts from PER-CONTROLLER ones:
|
|
59
159
|
`run_exec`, the `onFailure` handler and the untrusted-skill notices happen once per
|
|
60
160
|
process (selected by the new `ExecControllerDeps.processLevelMounts`, which only the
|
|
@@ -68,6 +168,15 @@ were written.
|
|
|
68
168
|
the same bytes it wrote before.
|
|
69
169
|
|
|
70
170
|
### Fixed
|
|
171
|
+
- Changing only the fan-out width no longer drops the subagent model a session kit
|
|
172
|
+
installed. The settings save read "the `team` section was written" as "the user
|
|
173
|
+
re-decided the subagent slot", so adjusting `Max subagents` silently released a slot the
|
|
174
|
+
kit held - with every value on screen still correct. Only an explicit `model` /
|
|
175
|
+
`modelProfileId` decision releases the slot now, and the fan-out page can express
|
|
176
|
+
nothing else.
|
|
177
|
+
- The `task` tool's description no longer states a fixed width (`2-5 independent
|
|
178
|
+
subagents`, `hard maximum 10`), which contradicted the configured maximum in the very
|
|
179
|
+
same request. It points at `<team_mode>`, which is generated from the live config.
|
|
71
180
|
- A process-level signal now has exactly ONE owner in thread mode (it used to be
|
|
72
181
|
installed by every runner into a single process-wide slot, so the last one won): the
|
|
73
182
|
terminator fans out to all threads, `result` is written before the process exits, and a
|
package/README.md
CHANGED
|
@@ -942,6 +942,7 @@ ignores them rather than rejecting the library):
|
|
|
942
942
|
| `/thinking <level>` | Set the thinking level |
|
|
943
943
|
| `/max-tokens [<n>\|auto\|default]` | Output token cap; with no argument, reports the setting **and** the effective cap for the live model |
|
|
944
944
|
| `/agents` | Open the **subagent board**: every child of the current (or most recent) dispatch, its full facts, its result and its 24-event timeline. The same board as `Ctrl+B`. Read-only - it can never nudge, kill or re-dispatch a child |
|
|
945
|
+
| `/subagent [<brief>]` | **Force the next turn to fan out.** With no argument it reports the live capacity, the subagent model, the supervisor and the team switch. With a brief it submits one directive telling the lead to call `task` once with that wide a team: `-n 4` fixes the count, `--parts api,ui,docs` names the split, `--read-only` denies every child writes and shell. A count above `team.maxSubagents` is narrowed **and disclosed**, and `-n 0` is an error rather than a silent 1. The forcing is instruction-level, not mechanical: the proof is the `task` card in the next turn |
|
|
945
946
|
| `/tools` | List active tools |
|
|
946
947
|
| `/clear` | Start a new conversation: interrupt the run, archive the old session, clear the context, transcript, queues and todo panel. `/clear screen` only clears the screen |
|
|
947
948
|
| `/reset` | Alias of `/clear` - one implementation, so the two cannot drift apart |
|
|
@@ -950,7 +951,7 @@ ignores them rather than rejecting the library):
|
|
|
950
951
|
| `/resume [file]` | Load a saved session. This session moves to a NEW id, and the spend counter restarts |
|
|
951
952
|
| `/session [copy\|pin]` | Report this session's id, file and branch parent; `copy` puts `aragon --resume <id>` on the clipboard; `pin` makes `sessions prune` skip the file forever |
|
|
952
953
|
| `/plan [on\|off\|status]` | Toggle plan mode - the keyboard-free equivalent of `Shift+Tab` |
|
|
953
|
-
| `/team [on\|off\|
|
|
954
|
+
| `/team [on\|off\|status]` / `/team [-n <n>] [--parts a,b,c] [--read-only] <brief>` | **Force team mode and start now.** `/team <brief>` arms forced team mode and submits that work as a normal turn: the lead analyses and plans it, then calls `task` — the directive, the `<forced_team_mode>` prompt block and a mechanical end-of-turn gate all say so. `/team on` arms without submitting, `/team off` leaves, `/team` reports. The configuration it used to carry (team switch, width, concurrency, supervisor, subagent model) lives in `Settings > Team` |
|
|
954
955
|
| `/todo [on\|off\|panel on\|off\|follow <mode>\|acceptance on\|off\|reset\|clear\|continue]` | Todo planning: status, the on/off switch, the rail, follow-through, acceptance criteria, and picking an unfinished plan back up |
|
|
955
956
|
| `/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 |
|
|
956
957
|
| `/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 |
|
|
@@ -1591,6 +1592,16 @@ questions.
|
|
|
1591
1592
|
Cancelling either one is not an error. The agent is told to proceed on stated
|
|
1592
1593
|
assumptions rather than to retry.
|
|
1593
1594
|
|
|
1595
|
+
**There is no limit on how many rounds of questions the agent may ask.** Call it
|
|
1596
|
+
for the fifth, tenth or twentieth time and it still works; the only bound is a
|
|
1597
|
+
30-minute ceiling on a *single* wait (`planModeHumanTimeoutMs`), which exists so an
|
|
1598
|
+
unattended terminal cannot wedge a CI job — it says nothing about how often the
|
|
1599
|
+
agent may ask. The one thing the agent cannot do is re-ask a batch of questions you
|
|
1600
|
+
have already **answered** in the same turn: that call returns a note saying so, as
|
|
1601
|
+
a non-error result, and the overlay does not open. A *cancelled* round records
|
|
1602
|
+
nothing, so an `Esc` you did not mean leaves the question askable — a mis-touch
|
|
1603
|
+
must never cost you the chance to answer. `/plan status` reports only the mode.
|
|
1604
|
+
|
|
1594
1605
|
**Dismissing a plan is not how you stop.** `Esc` on a plan card asks for a
|
|
1595
1606
|
*better* plan — the agent is told to refine it and submit again — so a model that
|
|
1596
1607
|
keeps submitting keeps getting cards. To stop the run itself, close the card with `Esc`, then **press `Esc`
|
|
@@ -2071,14 +2082,61 @@ that existed before this feature.
|
|
|
2071
2082
|
**Which model a subagent runs on is your setting, not the model's.** The
|
|
2072
2083
|
default (`team.model: 'main'`) keeps main-agent parity: every child runs the
|
|
2073
2084
|
lead's own connection. Switch it to the **fast tier** or a **saved profile**
|
|
2074
|
-
from the settings screen's *Subagent model* row
|
|
2075
|
-
|
|
2076
|
-
scouts does not need the main model. The choice is re-resolved on every
|
|
2085
|
+
from the settings screen's *Subagent model* row — useful when a fan-out of
|
|
2086
|
+
read-only scouts does not need the main model. The choice is re-resolved on every
|
|
2077
2087
|
dispatch, and an unusable one (tier off, profile deleted, key missing) falls
|
|
2078
2088
|
back to the main model with a disclosed line in the dispatch report instead of
|
|
2079
2089
|
failing the dispatch. The model itself still cannot downgrade its own
|
|
2080
2090
|
delegation: a stale `model` key in a `task` call is ignored, exactly as before.
|
|
2081
2091
|
|
|
2092
|
+
**How wide a fan-out is also your setting.** `/settings` → `Team` (row four,
|
|
2093
|
+
directly under *Subagent model*) holds four values: `Team mode`, `Max subagents`,
|
|
2094
|
+
`Run at once` and `Supervisor`, adjusted with `Left` / `Right` (`Enter` toggles
|
|
2095
|
+
the two on/off rows). Nothing is written until you press `Ctrl+S` **on the main
|
|
2096
|
+
settings page** — the arrows edit a draft, and `Esc` on the `Team` page returns
|
|
2097
|
+
to the main page rather than saving. `Team mode` is the capability switch that
|
|
2098
|
+
used to be `/team on|off`, and it is the only place that saves it; a session
|
|
2099
|
+
started with `--no-team` shows `on (next launch)` rather than pretending the
|
|
2100
|
+
tool can still be added. The numbers are also settable without the screen:
|
|
2101
|
+
`aragon config set team.maxSubagents <n>`.
|
|
2102
|
+
|
|
2103
|
+
Narrowing `Max subagents` also narrows `Run at once`, because a pool wider than
|
|
2104
|
+
its own population is meaningless; the follow-down is committed, so widening the
|
|
2105
|
+
population again does not silently restore a pool you did not ask for. And the
|
|
2106
|
+
width change never touches the model a session kit installed: only an explicit
|
|
2107
|
+
model choice releases that slot.
|
|
2108
|
+
|
|
2109
|
+
**Or bypass the model's judgement entirely: `/team <brief>`.** The command plus
|
|
2110
|
+
the work in one line compiles your intent into a single user turn that tells the
|
|
2111
|
+
lead to call `task` once with that many children, so it shares the one dispatch
|
|
2112
|
+
path — same Esc, same report, same spend accounting — and then stays on:
|
|
2113
|
+
|
|
2114
|
+
```
|
|
2115
|
+
/team -n 6 review the error handling in packages/cli/src/team
|
|
2116
|
+
/team --parts api,ui,docs audit the request path
|
|
2117
|
+
/team --read-only --parts perf,memory profile the parser
|
|
2118
|
+
```
|
|
2119
|
+
|
|
2120
|
+
Forced mode is SESSION state, not a saved setting: the next message of any kind
|
|
2121
|
+
dispatches too, until `/team off`. It is enforced three ways, and the third one
|
|
2122
|
+
does not depend on the model's cooperation — the submitted directive, a
|
|
2123
|
+
`<forced_team_mode>` block in every later system prompt, and an end-of-turn gate
|
|
2124
|
+
that asks once (`Forced team mode: no dispatch last turn - asking the agent to
|
|
2125
|
+
dispatch now.`) when a turn used tools and dispatched nothing. The gate never
|
|
2126
|
+
fires twice for one request: a human submit refills the budget, a turn does not.
|
|
2127
|
+
While it is armed the status bar carries `Team 4` (`T4` on a narrow terminal).
|
|
2128
|
+
|
|
2129
|
+
`/team` with no argument reports the forced state, capacity, the subagent model
|
|
2130
|
+
and where the switches live — and answers even in a `--no-team` session, where
|
|
2131
|
+
the honest answer is that this session has no team capability. Narrowing is
|
|
2132
|
+
always disclosed (`asked for 12; team.maxSubagents is 8`), `-n 0` is refused
|
|
2133
|
+
rather than silently becoming 1, and the notice says what the **next turn** will
|
|
2134
|
+
do rather than claiming children have started. `"off"` in quotes is a brief
|
|
2135
|
+
named `off`, not the keyword.
|
|
2136
|
+
|
|
2137
|
+
`/subagent` is a **deprecated alias** of `/team`: same arguments, same
|
|
2138
|
+
behaviour, plus one toast saying so.
|
|
2139
|
+
|
|
2082
2140
|
```
|
|
2083
2141
|
> read the auth middleware, map the route table, and check the migration
|
|
2084
2142
|
|
|
@@ -2093,12 +2151,18 @@ tools and the same working directory — but no memory of your conversation, so
|
|
|
2093
2151
|
its brief has to be self-contained. It cannot delegate further (depth is capped
|
|
2094
2152
|
at one by construction) and it cannot ask you anything.
|
|
2095
2153
|
|
|
2096
|
-
**Delegate wide, not deep.** Two to four subagents is
|
|
2097
|
-
default
|
|
2098
|
-
and no config file can raise it
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2154
|
+
**Delegate wide, not deep.** Two to four subagents is usually enough. The
|
|
2155
|
+
default is **8 per dispatch and 8 in flight at once** (it was 5 and 3 before
|
|
2156
|
+
subagent-fanout); the hard maximum is 10 and no config file can raise it, so 8
|
|
2157
|
+
is a default you can move in either direction and 10 is the ceiling you cannot.
|
|
2158
|
+
Both numbers live in `/settings` (`Subagent fan-out`) and in
|
|
2159
|
+
`team.maxSubagents` / `team.maxConcurrent`.
|
|
2160
|
+
|
|
2161
|
+
`maxConcurrent` is separate from `maxSubagents` on purpose: eight simultaneous
|
|
2162
|
+
streams against one API key is a reliable way to collect rate-limit errors, and
|
|
2163
|
+
each one would land in the report as a failed subagent. **If you see rate-limit
|
|
2164
|
+
errors, lower `Run at once`** — that is the one number to change, and it is the
|
|
2165
|
+
only reason the two knobs are separate.
|
|
2102
2166
|
|
|
2103
2167
|
**The report.** One text result: a header with the ok/failed counts, aggregate
|
|
2104
2168
|
tokens and cost, then one section per subagent with its status, timing, the
|
|
@@ -2134,9 +2198,9 @@ nothing is killed. A subagent still ends on the user's Esc, the explicit
|
|
|
2134
2198
|
watchdog (lengthened 4× while supervised), or the supervisor's own
|
|
2135
2199
|
replace/abandon verdict. One boundary to know: a session with NO fast wiring
|
|
2136
2200
|
at all and `team.overseer: true` runs children with no wall clock whatsoever
|
|
2137
|
-
— they finish, or die on their own un-lengthened watchdog.
|
|
2138
|
-
|
|
2139
|
-
`team.subagentTimeoutMs` is a hard abort again.
|
|
2201
|
+
— they finish, or die on their own un-lengthened watchdog. `Settings > Team` →
|
|
2202
|
+
`Supervisor` (or `aragon config set team.overseer false`) is the escape hatch
|
|
2203
|
+
back to the legacy regime where `team.subagentTimeoutMs` is a hard abort again.
|
|
2140
2204
|
|
|
2141
2205
|
**Talking to each other.** Subagents get two extra tools, `team_send` and
|
|
2142
2206
|
`team_wait`. Messages are delivered by attaching them to the recipient's next
|
|
@@ -2752,6 +2816,7 @@ This is the part that makes skills cheap enough to install a lot of:
|
|
|
2752
2816
|
| Level | What the model gets | When |
|
|
2753
2817
|
| --- | --- | --- |
|
|
2754
2818
|
| 1 | Name, scope, and a one-line "what + when" | Always, in the system prompt. Whole catalog capped at 6 000 bytes. |
|
|
2819
|
+
| 1.5 | `<skill_triage>` protocol + up to 3 ranked `<skill_candidates>` | Always (protocol), rebuilt per task (candidates). ≤ 1 500 + ≤ 900 bytes. |
|
|
2755
2820
|
| 2 | The full `SKILL.md` body + a list of bundled files | Only when the model calls `skill(name=…)` |
|
|
2756
2821
|
| 3 | The bundled files themselves | Only when it reads them with `read_file` / `bash` |
|
|
2757
2822
|
|
|
@@ -2759,6 +2824,34 @@ A skill costs a line in the prompt rather than its whole body, so installing
|
|
|
2759
2824
|
many of them stays cheap. The model decides on its own whether a task matches a
|
|
2760
2825
|
skill — you do not have to name one.
|
|
2761
2826
|
|
|
2827
|
+
**Level 1.5 is what turns that from a claim into a step.** Reading a catalog is
|
|
2828
|
+
not the same as being told to read it: the catalog's own preamble is a statement
|
|
2829
|
+
("if a task matches one, load it"), and a statement the model has seen forty times
|
|
2830
|
+
is the one it skims. So the prompt now carries a `<skill_triage>` protocol that
|
|
2831
|
+
fixes *when* the decision happens — after the project guidance and the directory
|
|
2832
|
+
listing, before any plan or edit — plus a short candidate list computed from your
|
|
2833
|
+
message against the in-memory skill records (name, description, keywords). Both are
|
|
2834
|
+
local string work: no model call, no file read, no body loaded, so "which skills
|
|
2835
|
+
could apply?" costs zero context bytes beyond the block itself.
|
|
2836
|
+
|
|
2837
|
+
Two consequences worth knowing:
|
|
2838
|
+
|
|
2839
|
+
- **It is a guess, not a verdict.** The block says so in as many words, and the
|
|
2840
|
+
model is told to load nothing when nothing fits. It never loads a skill for you.
|
|
2841
|
+
- **Silence on success, one line on failure.** When a strongly-matching skill was
|
|
2842
|
+
available and the turn did real work without loading it, the run ends with one
|
|
2843
|
+
`info` line naming the skill and pointing at `/skills route`. That happens at
|
|
2844
|
+
most once per skill per session — a message printed every turn is a message you
|
|
2845
|
+
learn to skip.
|
|
2846
|
+
|
|
2847
|
+
`/skills route <text>` shows the scoring for any phrasing you type (or with no
|
|
2848
|
+
argument, for the last real task), including the runner-up and the threshold when
|
|
2849
|
+
nothing qualified. `/skills triage off` turns the whole level off for the session
|
|
2850
|
+
and `skills.triage=false` makes it permanent; either way the prompt returns to its
|
|
2851
|
+
pre-feature bytes. **Subagents are not triaged** — a child has no `skill` tool, so
|
|
2852
|
+
proposing skills to it would describe a capability it does not have; name the skill
|
|
2853
|
+
in the `task` description instead.
|
|
2854
|
+
|
|
2762
2855
|
At Level 2 the file list is split into what to read and what to run, and carries
|
|
2763
2856
|
the skill's absolute root so the model can build real paths. The accompanying
|
|
2764
2857
|
guidance is **platform-specific**: on Windows the `bash` tool runs `cmd.exe`, so
|
|
@@ -2834,7 +2927,8 @@ keeping `installedAt` and recording `updatedAt` + `previousVersion`.
|
|
|
2834
2927
|
|
|
2835
2928
|
Interactively the same lives under `/skills …` (`/skills update <name> [--force]`,
|
|
2836
2929
|
`/skills update --all`, `/skills list --sort=recent`, `/skills policy [mode]`,
|
|
2837
|
-
`/skills unload`, `/skills usage [--reset]
|
|
2930
|
+
`/skills unload`, `/skills usage [--reset]`, `/skills triage [on|off]`,
|
|
2931
|
+
`/skills route [text]`). Every usable skill also becomes a
|
|
2838
2932
|
slash command:
|
|
2839
2933
|
|
|
2840
2934
|
```
|
|
@@ -3071,19 +3165,20 @@ env / `.env` → CLI flags**.
|
|
|
3071
3165
|
| `renderGovernor` | `true` | Widen the streaming frame interval when a frame is genuinely expensive. See [Render performance](#render-performance). |
|
|
3072
3166
|
| `maxRenderIntervalMs` | `320` | Ceiling of the governor ladder, clamped to `[33, 1000]`. `33` flattens it to the pre-0.6 cadence without disabling the mechanism. |
|
|
3073
3167
|
| `planModeDefault` | `false` | Start every session in plan mode. `--no-plan` still overrides it for a single run. |
|
|
3074
|
-
|
|
|
3168
|
+
| ~~`planModeMaxAskRounds`~~ | — | **Removed.** `ask_user` has no round limit any more, so there is nothing to configure. `aragon config set planModeMaxAskRounds 5` now prints an explanation and exits `2`; an existing key is removed from `config.json` at the next write. |
|
|
3075
3169
|
| `planModeHumanTimeoutMs` | `1800000` | Ceiling on a single question / plan wait, clamped to `[60000, 7200000]`. Thirty minutes is far outside "went to get coffee", but a ceiling has to exist so an unattended terminal cannot wedge a CI job forever. |
|
|
3076
3170
|
| `paste` | `true` | Recognise pasted text before Ink's key parser sees it: line breaks become buffer newlines instead of fifteen separate messages, escape SEQUENCES are removed whole (deleting only the introducer byte is what put `[38;2;18;52;86m` on screen and in the model's input) as are stray control bytes, and a paste above 6 lines or 400 characters collapses to a one-line placeholder that expands when you send. `false` treats pasted bytes as keystrokes, which is what 0.6.2 did. |
|
|
3077
3171
|
| `historyEnabled` | `true` | Record submitted prompts to `prompt-history.jsonl` for `↑` recall. Setting it to `false` stops new writes; it does not delete what is already stored (that is `aragon history clear --yes`) and does not stop reading. See [Prompt history](#prompt-history). |
|
|
3078
|
-
| `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered — `/team
|
|
3079
|
-
| `team.maxSubagents` | `
|
|
3080
|
-
| `team.maxConcurrent` | `
|
|
3172
|
+
| `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered. Written by the `Team mode` row in `Settings > Team` and nowhere else — `/team` never saves configuration. In a session already started with `--no-team` the row reads `on (next launch)`, rather than advertising a tool that is not there. |
|
|
3173
|
+
| `team.maxSubagents` | `8` | Subagents per dispatch, clamped to `[1, 10]`. 8 is the default; 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. A persisted `5`/`3` pair from an older install is migrated to `8`/`8` once (`fanoutMigrated` records that it happened, so moving back to 5/3 sticks). |
|
|
3174
|
+
| `team.maxConcurrent` | `8` | 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: lower this one if you collect 429s. |
|
|
3175
|
+
| `team.fanoutMigrated` | absent | Written only by the one-shot fan-out migration. Never set it by hand; a `true` here tells the next launch "5/3 was my choice, leave it alone". |
|
|
3081
3176
|
| `team.subagentTimeoutMs` | `0` | One subagent's wall clock, clamped to `[0, 1800000]`. With `team.overseer: false` it is a hard abort (the legacy regime). With the supervisor on (the default) it **never aborts anything** — a positive value is only a compatibility source for the supervisor's first cadence check. `0` (the default) = use `team.overseerIntervalMs` / the structural 5 min instead. |
|
|
3082
3177
|
| `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. |
|
|
3083
3178
|
| `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. |
|
|
3084
|
-
| `team.overseer` | `true` | The dispatch supervisor: one per dispatch on the fast model, ticking on a geometric cadence over every live subagent and deciding wait / nudge / replace / abandon. With the fast tier missing a tick degrades to an announced unassisted wait — never a kill; with this `false`, children run under the legacy hard ceilings exactly.
|
|
3179
|
+
| `team.overseer` | `true` | The dispatch supervisor: one per dispatch on the fast model, ticking on a geometric cadence over every live subagent and deciding wait / nudge / replace / abandon. With the fast tier missing a tick degrades to an announced unassisted wait — never a kill; with this `false`, children run under the legacy hard ceilings exactly. The `Supervisor` row in `Settings > Team` flips it live (a settings save rebuilds the prompt), and it is read per dispatch. |
|
|
3085
3180
|
| `team.overseerIntervalMs` | `0` | Supervisor cadence base, clamped to `[0, 3600000]`. `0` (the default) = the structural 300 s; a positive `team.subagentTimeoutMs` is honoured first when this is `0` (compat). Later checks grow ×1.6, clamped to `[60 s, 900 s]`; any nudge/replace/abandon resets that child's cadence to the base. Only meaningful while `team.overseer` is true. |
|
|
3086
|
-
| `team.model` | `"main"` | Which model every subagent runs on: `'main'` (the default - the lead's own connection), `'fast'` (the fast tier, re-resolved per dispatch), or `'profile'` (the entry named by `team.modelProfileId`). A **user-owned setting** — the model itself still cannot downgrade its own delegation, and an unusable choice falls back to the main model with a disclosed line in the dispatch report.
|
|
3181
|
+
| `team.model` | `"main"` | Which model every subagent runs on: `'main'` (the default - the lead's own connection), `'fast'` (the fast tier, re-resolved per dispatch), or `'profile'` (the entry named by `team.modelProfileId`). A **user-owned setting** — the model itself still cannot downgrade its own delegation, and an unusable choice falls back to the main model with a disclosed line in the dispatch report. Settable only through the settings screen's **Subagent model** row: `/team` no longer writes configuration. |
|
|
3087
3182
|
| `team.modelProfileId` | `null` | The profile entry `team.model: 'profile'` binds to. Reference existence is not validated here — a dangling id degrades to the main model at resolution time, so deleting a profile never breaks a dispatch. |
|
|
3088
3183
|
| `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. |
|
|
3089
3184
|
| `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. |
|
|
@@ -3108,6 +3203,7 @@ env / `.env` → CLI flags**.
|
|
|
3108
3203
|
| `skills.integrity` | `warn` | What to do when `SKILL.md` no longer matches the copy you approved. `off` skips the check; `warn` flags it in `/skills list` and once per session; `strict` removes it from the catalog and makes `skill()` refuse it. Defaults to `warn` because editing an installed skill is a legitimate thing to do — `strict` suits CI and managed environments. |
|
|
3109
3204
|
| `skills.usageTracking` | `true` | Keep local per-skill use counters to rank the catalog. Name, count and timestamp only; never transmitted. Inspect with `aragon skills usage`, erase with `--reset --yes`. |
|
|
3110
3205
|
| `skills.toolPolicy` | `enforce` | How hard a skill's `allowed-tools` bites, for the turn it is loaded in. `off` disables it and says nothing about it to the model; `warn` runs the tool and reports it; `enforce` refuses. Unlike `skills.integrity`, a false positive here means a skill AUTHOR under-declared their own skill — which `aragon skills doctor` reports before it can bite. |
|
|
3206
|
+
| `skills.triage` | `true` | Put a short `<skill_candidates>` list in the system prompt for each new task, so "is an installed skill relevant?" is a step the agent is required to take instead of one it has to remember. Default on; turning it off restores the pre-feature prompt byte for byte. Matching is local over in-memory skill records — no model call, no file read. Explain any decision with `/skills route`, flip it live with `/skills triage off`. |
|
|
3111
3207
|
| `log.level` | `info` | `silent` · `error` · `warn` · `info` · `debug` · `trace`. See [Files & logs](#files--logs) for what each level records. |
|
|
3112
3208
|
| `log.toFile` | `true` | Write records to a file at all. `false` here is respected; `--log-file` overrides it for one run. |
|
|
3113
3209
|
| `log.dir` | `""` | Log directory. Empty means `<home>/logs`. Only **absolute** paths are accepted — a relative one would mean a different directory for every working directory you launch from. |
|
|
@@ -3595,6 +3691,16 @@ VS Code 用户设置添加 `"terminal.integrated.copyOnSelection": false`,快
|
|
|
3595
3691
|
|
|
3596
3692
|
编辑方案时可以当场验证:**Test connection**(Ctrl+R)用草稿里的服务商、模型、地址和解析后的密钥做一次真实往返,成功显示 `OK 812 ms` 与用量,失败给出分类结论和第二行“怎么办”;**Discover models**(Ctrl+F)列出该密钥实际可访问的模型供选择,只写回模型字段,不动上下文窗口与凭据。两者都作用于未保存的草稿,`Discover` 零 token;探测期间 Esc 只取消探测而不丢弃表单,修改服务商、模型或密钥后旧结论立刻回到未测试。
|
|
3597
3693
|
|
|
3694
|
+
## 子代理扇出宽度与 `/subagent`
|
|
3695
|
+
|
|
3696
|
+
子代理扇出的默认值现在是**每次派单 8 个、同时最多 8 个在跑**(原为 5 和 3)。用户感知的“最多只有 3 个”来自并发上限而不是派单上限——只把派单数改大而并发不动,观感不会有任何变化,所以两个数一起改。硬上限仍是 10:8 是默认值,10 是天花板,中间由用户自己决定。
|
|
3697
|
+
|
|
3698
|
+
在 `/settings` 的第 4 行 **Subagent fan-out** 里可以改这三个值:**Max subagents**、**Run at once**、**Supervisor**,用左右方向键调整。页内只改草稿,回到根设置页按 Ctrl+S 才真正落盘(本页页脚如实写着这一点,因为子页上根本没有 Ctrl+S 监听者)。把扇出调窄时并发会跟着下调,并且这个跟随**会写进补丁**:再把扇出调宽时并发停在你选的位置,不会被悄悄拉回。只改宽度**不会**释放会话 kit 给的子代理模型,只有显式改子代理模型才会。
|
|
3699
|
+
|
|
3700
|
+
磁盘上仍带着旧默认值 5/3 的配置会在首次启动时被一次性迁移到 8/8,并写下 `team.fanoutMigrated` 标记;之后你手工改回 5/3 会一直保持,不会被再次迁移。其他任何组合(2/2、5/5、10/10)都不迁移。
|
|
3701
|
+
|
|
3702
|
+
想绕开“模型自己决定要不要派单”时用 **`/subagent`**:它把你的意图编译成一条用户回合,要求 lead 在同一条 `task` 路径上一次性派出指定数量的子代理,因此 Esc、报告、费用记账、并发锁全部沿用既有实现。`-n 6` 指定数量,`--parts api,ui,docs` 指定拆分维度,`--read-only` 让每个子代理都不能写文件也不能跑 shell。不带参数时打印容量、子代理模型、监察开关与 team 开关,`--no-team` 会话里也照实回答。参数被收窄一定伴随披露(`asked for 12; team.maxSubagents is 8`),`-n 0` 直接报错而不是静默变成 1;提示语说的是“下一轮会派单”,不会假装子代理已经开始。并发报 429 时把 **Run at once** 调低即可。
|
|
3703
|
+
|
|
3598
3704
|
**Current custom** 保留旧式连接,可继续编辑原连接字段。创建方案时从磁盘上的旧式配置预填,不复制环境变量或 `--api-key` 的运行时密钥。专属密钥可保持、替换或切换为共享/环境凭据;修改服务商或地址后,必须明确选择保留原密钥,或重新输入。空地址在方案中表示服务商默认地址,快速方案不会继承主网关。
|
|
3599
3705
|
|
|
3600
3706
|
启动优先级为 CLI 参数、环境变量、所选方案、旧式字段、默认值。界面显示启动覆盖;明确重新选择方案可对本次会话立即生效,重启仍遵循启动参数。专属密钥仅对对应角色和目标地址生效;主模型启动密钥不会跟随切换发往另一个网关。
|
|
@@ -25,6 +25,7 @@ import type { ToolPermission } from '../exec/permission.js';
|
|
|
25
25
|
import { type ToolOutputListener } from '../tools/tool-output-store.js';
|
|
26
26
|
import type { FilePatch } from '../tools/patch.js';
|
|
27
27
|
import type { SubagentModelResolution } from '../team/model.js';
|
|
28
|
+
import type { ForcedTeamState } from '../team/forced-mode.js';
|
|
28
29
|
import type { TeamEvent, TeamSnapshot } from '../team/types.js';
|
|
29
30
|
import { ProcSupervisor } from '../proc/supervisor.js';
|
|
30
31
|
import type { ProcEventListener, ServiceSnapshot } from '../proc/types.js';
|
|
@@ -36,6 +37,7 @@ import type { CompactionEventListener, CompactionSnapshot, ContextUsageSnapshot
|
|
|
36
37
|
import type { AcceptanceItem, TodoEventListener, TodoSnapshot } from '../todo/types.js';
|
|
37
38
|
import { type HumanInputGate } from '../tools/human-input.js';
|
|
38
39
|
import { SkillService, type ApprovalGate } from '../skills/service.js';
|
|
40
|
+
import type { SkillRoutingReport } from '../skills/triage.js';
|
|
39
41
|
import { type ConversationResetOptions, type ConversationResetResult } from './conversation-reset.js';
|
|
40
42
|
import type { AgentMode } from './agent-mode.js';
|
|
41
43
|
import type { NoticeLevel } from './reducer.js';
|
|
@@ -183,16 +185,19 @@ export interface ControllerDeps {
|
|
|
183
185
|
*/
|
|
184
186
|
modelWindows?: ModelWindows;
|
|
185
187
|
}
|
|
186
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* What `setAgentMode` actually adopted — see `AgentController.setAgentMode`.
|
|
190
|
+
*
|
|
191
|
+
* THIS IS ALSO WHAT `/plan status` REPORTS. A `PlanStatus extends AgentModeState`
|
|
192
|
+
* with `askRoundsUsed` / `maxAskRounds` existed until the round cap was deleted;
|
|
193
|
+
* keeping an empty sub-interface around would only leave a comment that every
|
|
194
|
+
* later reader has to work through to learn that nothing is missing.
|
|
195
|
+
*/
|
|
187
196
|
export interface AgentModeState {
|
|
188
197
|
effective: AgentMode;
|
|
189
198
|
/** Non-null only while a `plan -> build` switch is waiting for `agent_end`. */
|
|
190
199
|
pending: AgentMode | null;
|
|
191
200
|
}
|
|
192
|
-
export interface PlanStatus extends AgentModeState {
|
|
193
|
-
askRoundsUsed: number;
|
|
194
|
-
maxAskRounds: number;
|
|
195
|
-
}
|
|
196
201
|
export interface PreflightResult {
|
|
197
202
|
ok: boolean;
|
|
198
203
|
message?: string;
|
|
@@ -235,6 +240,21 @@ export declare class AgentController {
|
|
|
235
240
|
private readonly skills;
|
|
236
241
|
private readonly skillsEnabled;
|
|
237
242
|
private onSkillsChanged?;
|
|
243
|
+
/**
|
|
244
|
+
* This turn's routing result, or `null` when triage is off or nothing scored.
|
|
245
|
+
*
|
|
246
|
+
* It also carries the task it was computed for (`SkillRoutingReport.task`), so
|
|
247
|
+
* there is no separate copy of the turn's text to keep in step with it.
|
|
248
|
+
*/
|
|
249
|
+
private turnRouting;
|
|
250
|
+
/** The previous turn's routing, for `/skills route` with no argument. */
|
|
251
|
+
private lastSkillRouting;
|
|
252
|
+
/** Did this turn call `skill(name)` successfully? The only proof of adoption. */
|
|
253
|
+
private skillLoadedThisTurn;
|
|
254
|
+
/** Tool calls this turn, EXCLUDING `skill` / `skill_find` (see §4.2.7). */
|
|
255
|
+
private toolCallsThisTurn;
|
|
256
|
+
/** Skills already reported as "not loaded" — a session says it once (I-T5). */
|
|
257
|
+
private readonly skillTriageNoticed;
|
|
238
258
|
/** Mutable session cwd — tools resolve relative paths against this. */
|
|
239
259
|
private cwd;
|
|
240
260
|
/**
|
|
@@ -259,12 +279,25 @@ export declare class AgentController {
|
|
|
259
279
|
private readonly structuredResultBlock;
|
|
260
280
|
private effectiveMode;
|
|
261
281
|
private pendingMode;
|
|
262
|
-
|
|
282
|
+
/**
|
|
283
|
+
* Fingerprints of the question SETS the user ANSWERED in this turn. Bounded,
|
|
284
|
+
* and the bound is storage hygiene rather than a refusal rule — see
|
|
285
|
+
* `ASK_GUARD_LIMITS`.
|
|
286
|
+
*
|
|
287
|
+
* Replaces a numeric round counter that capped `ask_user` at four calls. There
|
|
288
|
+
* is no cap now; the only thing this prevents is the same batch of questions
|
|
289
|
+
* being put to the user twice, which is noise rather than information.
|
|
290
|
+
*
|
|
291
|
+
* Cleared in `prepareUserTurn` for a NEW turn only. A steer continuation is the
|
|
292
|
+
* same turn — clearing there would disable the guard exactly when a long turn
|
|
293
|
+
* most needs it (§4.1.6).
|
|
294
|
+
*/
|
|
295
|
+
private readonly askedFingerprints;
|
|
263
296
|
/** Static: whether this session could ever render a question overlay. */
|
|
264
297
|
private readonly planInteractive;
|
|
265
298
|
private readonly teamRegistered;
|
|
266
|
-
private teamEnabled;
|
|
267
299
|
private readonly teamRuntime;
|
|
300
|
+
private forcedTeam;
|
|
268
301
|
private readonly todoRegistered;
|
|
269
302
|
private todoEnabled;
|
|
270
303
|
private readonly todos;
|
|
@@ -445,6 +478,24 @@ export declare class AgentController {
|
|
|
445
478
|
* semantics depend on whether a notice happened to be pending.
|
|
446
479
|
*/
|
|
447
480
|
private flushPendingNotices;
|
|
481
|
+
/**
|
|
482
|
+
* THE BOUNDARY OF ONE TURN — and there are TWO call sites, which is the reason
|
|
483
|
+
* this takes an explicit flag instead of resetting everything unconditionally.
|
|
484
|
+
*
|
|
485
|
+
* `startPrompt` passes `{ steering: false }`: the user typed something new, so
|
|
486
|
+
* this really is a new turn. `continue()` passes `{ steering: true }` with the
|
|
487
|
+
* CONCATENATED queued steering text, which resumes the SAME turn.
|
|
488
|
+
*
|
|
489
|
+
* A steer continuation must not re-triage (the candidates would change mid-turn,
|
|
490
|
+
* and rebuilding the prompt aborts an idle compaction for no gain) and must not
|
|
491
|
+
* clear the answered-question guard (a long turn interrupted by one steer is
|
|
492
|
+
* exactly when a repeat question is most likely). Hence per-turn state is
|
|
493
|
+
* initialised in ONE branch.
|
|
494
|
+
*
|
|
495
|
+
* `steering` is REQUIRED and positional-second so each call site states which
|
|
496
|
+
* kind of turn it is starting, rather than letting a default make "new turn" the
|
|
497
|
+
* thoughtless option.
|
|
498
|
+
*/
|
|
448
499
|
private prepareUserTurn;
|
|
449
500
|
/** Cancel pending startup as well as any engine run already in progress. */
|
|
450
501
|
abort(): void;
|
|
@@ -583,9 +634,53 @@ export declare class AgentController {
|
|
|
583
634
|
*/
|
|
584
635
|
applyPendingMode(): AgentModeState | null;
|
|
585
636
|
/** Named read surface for `/plan status`, so no command reaches into internals. */
|
|
586
|
-
getPlanStatus():
|
|
587
|
-
/**
|
|
588
|
-
|
|
637
|
+
getPlanStatus(): AgentModeState;
|
|
638
|
+
/**
|
|
639
|
+
* READ-ONLY guard probe, called by `ask_user` BEFORE it opens the overlay.
|
|
640
|
+
*
|
|
641
|
+
* No side effect of any kind: a check that also writes cannot be placed before
|
|
642
|
+
* the question without recording an answer that has not happened yet, and the
|
|
643
|
+
* "a cancelled round stays askable" rule would then be unimplementable.
|
|
644
|
+
*/
|
|
645
|
+
private hasAnswered;
|
|
646
|
+
/**
|
|
647
|
+
* Record an ANSWERED question set, called by `ask_user` after a real answer.
|
|
648
|
+
*
|
|
649
|
+
* Evicts the oldest entry past `ASK_GUARD_LIMITS.maxRemembered`. That eviction
|
|
650
|
+
* is memory hygiene and NOT a refusal rule — a bounded rejection would be the
|
|
651
|
+
* deleted round cap wearing a bigger number.
|
|
652
|
+
*/
|
|
653
|
+
private noteAnswered;
|
|
654
|
+
/** `/skills route` with no argument: the LAST turn's real routing result. */
|
|
655
|
+
getSkillRouting(): SkillRoutingReport | null;
|
|
656
|
+
/**
|
|
657
|
+
* One line when a confidently-matched skill was NOT loaded — and silence every
|
|
658
|
+
* other time (D-8).
|
|
659
|
+
*
|
|
660
|
+
* THE DISCIPLINE IS "SILENT ON SUCCESS, VISIBLE ON FAILURE". Announcing the
|
|
661
|
+
* candidates every turn would be ignored by the third day; announcing nothing
|
|
662
|
+
* ever would make the whole feature unfalsifiable. "A skill covered this task,
|
|
663
|
+
* you did the work anyway, and you never opened it" is precisely the failure this
|
|
664
|
+
* feature exists to fix, so it is the one case that speaks — and it names the
|
|
665
|
+
* command that explains it.
|
|
666
|
+
*
|
|
667
|
+
* SEVEN CONDITIONS, and the first one is the one that is easy to get wrong.
|
|
668
|
+
*
|
|
669
|
+
* 0. This turn was NOT aborted and NOT ended by an error.
|
|
670
|
+
* `agent_end` is emitted unconditionally from a `finally` block in
|
|
671
|
+
* `core/src/engine/agent.ts` and its payload carries no reason, no `aborted`
|
|
672
|
+
* and no `error` field — so "did this turn finish normally?" has to be read
|
|
673
|
+
* from this class's own state. `stopEngine()` sets `abortRequested` before it
|
|
674
|
+
* calls `agent.abort()` and `agent_start` clears it, which makes it an exact
|
|
675
|
+
* answer. Without this condition an Esc mis-touch would produce a line
|
|
676
|
+
* criticising the model for not loading a skill: commentary in response to an
|
|
677
|
+
* interruption.
|
|
678
|
+
*
|
|
679
|
+
* Conditions 5 and 0 are not redundant: 0 decides what counts as the end of a
|
|
680
|
+
* turn, 5 decides whether the turn did any work. With only 5, a tool call made
|
|
681
|
+
* before an abort would still trigger the notice.
|
|
682
|
+
*/
|
|
683
|
+
private maybeReportSkillTriage;
|
|
589
684
|
/**
|
|
590
685
|
* Run `fn` with the idle watchdog paused.
|
|
591
686
|
*
|
|
@@ -610,17 +705,47 @@ export declare class AgentController {
|
|
|
610
705
|
withHumanWait<T>(fn: () => Promise<T>): Promise<T>;
|
|
611
706
|
/** Whether `task` is in `this.tools`. Fixed at construction; see the fields. */
|
|
612
707
|
isTeamRegistered(): boolean;
|
|
613
|
-
/**
|
|
708
|
+
/**
|
|
709
|
+
* Whether `task` will actually dispatch - a DERIVED value.
|
|
710
|
+
*
|
|
711
|
+
* One truth (`config.team.enabled`) plus one immutable snapshot
|
|
712
|
+
* (`teamRegistered`). The previous version read a private copy that `/team
|
|
713
|
+
* on|off` hand-synchronised, which worked only while that command was the sole
|
|
714
|
+
* writer; the settings screen writes the config directly, so the copy would
|
|
715
|
+
* have kept saying `on` (P1-4 / AC-25).
|
|
716
|
+
*/
|
|
614
717
|
isTeamEnabled(): boolean;
|
|
615
718
|
/**
|
|
616
719
|
* Flip the live switch and re-render the prompt.
|
|
617
720
|
*
|
|
721
|
+
* THE NAME IS KEPT (three call sites plus the settings path) but the body is
|
|
722
|
+
* one write: `setTeamConfig()` already clamps, bumps the revision and rebuilds,
|
|
723
|
+
* so there is no second place where a half-applied state can exist.
|
|
724
|
+
*
|
|
618
725
|
* Turning it ON in a session that started with `--no-team` deliberately does
|
|
619
726
|
* NOT register the tool (D-17): the array is immutable, and advertising an
|
|
620
727
|
* unregistered tool is the dead end P0-2 is about. `/team` reports that
|
|
621
728
|
* honestly by checking `isTeamRegistered()` first.
|
|
622
729
|
*/
|
|
623
730
|
setTeamEnabled(enabled: boolean): void;
|
|
731
|
+
/**
|
|
732
|
+
* Arm forced team mode for this session (team-command-forced-dispatch §3.5).
|
|
733
|
+
*
|
|
734
|
+
* Returns the count actually adopted. The clamp is `[1, team.maxSubagents]`:
|
|
735
|
+
* `0`, a negative and a fraction are refused by the parser upstream (`-n 0` is
|
|
736
|
+
* a syntax error, not a clamp), so this is the boundary check of a value that
|
|
737
|
+
* crossed a module line - which is the one place `CLAUDE.md` asks for it, not a
|
|
738
|
+
* second validation of the same input.
|
|
739
|
+
*
|
|
740
|
+
* THE COUNT IS FROZEN for the rest of the session: `/team -n 2 <brief>` then a
|
|
741
|
+
* plain message keeps two children per turn, so the user's one expressed intent
|
|
742
|
+
* does not silently widen back to four.
|
|
743
|
+
*/
|
|
744
|
+
armForcedTeam(count: number): number;
|
|
745
|
+
/** Disarm. IDEMPOTENT: disarming an unarmed session rewrites nothing. */
|
|
746
|
+
disarmForcedTeam(): void;
|
|
747
|
+
/** The armed state, read at render time by the chip and by `/team`'s status. */
|
|
748
|
+
getForcedTeam(): ForcedTeamState | null;
|
|
624
749
|
getTeamConfig(): TeamConfig;
|
|
625
750
|
/**
|
|
626
751
|
* Adopt a new team config for this session and re-render the prompt (the block
|
|
@@ -634,8 +759,8 @@ export declare class AgentController {
|
|
|
634
759
|
* One authority for the `task` report's disclosure line and its price
|
|
635
760
|
* table: both read through here, so the header can never name one model
|
|
636
761
|
* while pricing another. Re-resolved on every call for the reason
|
|
637
|
-
* `resolveFastTier` records - `/fast off`, a settings save and
|
|
638
|
-
* all rewrite the inputs mid-session.
|
|
762
|
+
* `resolveFastTier` records - `/fast off`, a settings save and the `Subagent
|
|
763
|
+
* model` row all rewrite the inputs mid-session.
|
|
639
764
|
*/
|
|
640
765
|
subagentModelResolution(): SubagentModelResolution;
|
|
641
766
|
/** Refused mid-dispatch by `/team`; half a dispatch under two ceilings is not
|
|
@@ -677,7 +802,7 @@ export declare class AgentController {
|
|
|
677
802
|
* THIS EXISTS BECAUSE `persistConfig` DOES NOT TOUCH THE RUNTIME (P1-2 /
|
|
678
803
|
* AC-38). `App` reads `controller.getConfig()` on every render, and that
|
|
679
804
|
* returns THIS object; the App's `persistConfig` only writes the file. So
|
|
680
|
-
* `/todo panel off` must call both, exactly as
|
|
805
|
+
* `/todo panel off` must call both, exactly as settings' `Team` page does — with
|
|
681
806
|
* the persist call the command reports success and changes nothing until the
|
|
682
807
|
* next launch.
|
|
683
808
|
*
|