@aragon-agent/cli 0.6.21 → 0.6.23
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 +32 -12
- package/dist/agent/controller.js +22 -1
- package/dist/agent/reducer.js +8 -6
- package/dist/commands/builtins.js +2 -1
- package/dist/config/cli-commands.d.ts +1 -1
- package/dist/config/cli-commands.js +3 -0
- package/dist/config/load.js +42 -3
- package/dist/config/schema.d.ts +53 -12
- package/dist/config/schema.js +42 -0
- package/dist/team/limits.d.ts +73 -13
- package/dist/team/limits.js +82 -15
- package/dist/team/normalize.js +7 -2
- package/dist/team/overseer.d.ts +158 -18
- package/dist/team/overseer.js +356 -49
- package/dist/team/report.d.ts +9 -0
- package/dist/team/report.js +32 -4
- package/dist/team/runtime.d.ts +51 -9
- package/dist/team/runtime.js +498 -74
- package/dist/team/subagent.d.ts +10 -0
- package/dist/team/subagent.js +20 -6
- package/dist/team/task-tool.d.ts +7 -0
- package/dist/team/task-tool.js +2 -0
- package/dist/team/types.d.ts +44 -2
- package/dist/ui/App.js +14 -0
- package/dist/ui/TeamPanel.d.ts +22 -0
- package/dist/ui/TeamPanel.js +71 -2
- package/dist/ui/layout/team-panel.js +4 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1148,15 +1148,34 @@ than a fact: the file list is derived from `write_file` / `edit_file`, so a
|
|
|
1148
1148
|
write made through `bash` is invisible to it.
|
|
1149
1149
|
|
|
1150
1150
|
**The dispatch supervisor.** A time ceiling on a subagent is an inspection
|
|
1151
|
-
trigger, not a death sentence
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1151
|
+
trigger, not a death sentence. Every dispatch gets its own supervisor on the
|
|
1152
|
+
fast model: a per-child silence window for suspected stalls, plus a periodic
|
|
1153
|
+
cadence check over the WHOLE roster — one bounded call that carries every live
|
|
1154
|
+
subagent and returns one decision per child: keep waiting, steer a nudge in,
|
|
1155
|
+
rebuild the child with an amended brief, or abandon it with a recorded reason.
|
|
1156
|
+
The cadence grows geometrically (5 min base, ×1.6, capped at 15 min), so a
|
|
1157
|
+
healthy slow subagent is checked logarithmically in its run time rather than
|
|
1158
|
+
every five minutes forever. The budgets are structural, not settings — 12
|
|
1159
|
+
looks, 3 nudges, 1 replacement and 1 abandon per child per dispatch. When the
|
|
1160
|
+
look budget is spent the supervisor says so once (`quiet` in the report) and
|
|
1161
|
+
stops waking that child; failed inspection calls cost a look but never an
|
|
1162
|
+
action. Every applied decision is recorded in the report's Supervisor section
|
|
1163
|
+
with the supervisor's own fast-tier spend, and replace/abandon also surface as
|
|
1164
|
+
a transcript notice while the dispatch runs.
|
|
1165
|
+
|
|
1166
|
+
**No kill by default.** While `team.overseer` is on (the default),
|
|
1167
|
+
`team.subagentTimeoutMs` never aborts anything — a positive value is only the
|
|
1168
|
+
supervisor's first cadence check. If the fast tier is missing (no key,
|
|
1169
|
+
`/fast off`), a due check degrades to an announced *unassisted wait*: the
|
|
1170
|
+
children keep running, the report notes how many checks ran degraded, and
|
|
1171
|
+
nothing is killed. A subagent still ends on the user's Esc, the explicit
|
|
1172
|
+
`team.dispatchTimeoutMs` / `team.maxTurnsPerSubagent` ceilings, its own idle
|
|
1173
|
+
watchdog (lengthened 4× while supervised), or the supervisor's own
|
|
1174
|
+
replace/abandon verdict. One boundary to know: a session with NO fast wiring
|
|
1175
|
+
at all and `team.overseer: true` runs children with no wall clock whatsoever
|
|
1176
|
+
— they finish, or die on their own un-lengthened watchdog. `/team overseer
|
|
1177
|
+
off` is the escape hatch back to the legacy regime where
|
|
1178
|
+
`team.subagentTimeoutMs` is a hard abort again.
|
|
1160
1179
|
|
|
1161
1180
|
**Talking to each other.** Subagents get two extra tools, `team_send` and
|
|
1162
1181
|
`team_wait`. Messages are delivered by attaching them to the recipient's next
|
|
@@ -2001,10 +2020,11 @@ env / `.env` → CLI flags**.
|
|
|
2001
2020
|
| `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. |
|
|
2002
2021
|
| `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. |
|
|
2003
2022
|
| `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. |
|
|
2004
|
-
| `team.subagentTimeoutMs` | `0` | One subagent's wall clock, clamped to `[0, 1800000]`. With
|
|
2023
|
+
| `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. |
|
|
2005
2024
|
| `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. |
|
|
2006
2025
|
| `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. |
|
|
2007
|
-
| `team.overseer` | `true` | The dispatch supervisor:
|
|
2026
|
+
| `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. `/team overseer on\|off` flips it live, and it is read per dispatch. |
|
|
2027
|
+
| `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. |
|
|
2008
2028
|
| `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. |
|
|
2009
2029
|
| `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. |
|
|
2010
2030
|
| `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`. |
|
|
@@ -2015,7 +2035,7 @@ env / `.env` → CLI flags**.
|
|
|
2015
2035
|
| `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. |
|
|
2016
2036
|
| `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. |
|
|
2017
2037
|
| `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. |
|
|
2018
|
-
| `retry.maxElapsedMs` | `240000` | Wall-clock budget from the first failure, clamped to `[10000, 1800000]`.
|
|
2038
|
+
| `retry.maxElapsedMs` | `240000` | Wall-clock budget from the first failure, clamped to `[10000, 1800000]`. Under the legacy regime (`team.overseer: false`) with `team.subagentTimeoutMs` 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. |
|
|
2019
2039
|
| `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. |
|
|
2020
2040
|
| `skills.enabled` | `true` | Master switch for the skill system. |
|
|
2021
2041
|
| `skills.requireApproval` | `true` | Require a human to approve `skill_install` / `skill_create`. |
|
package/dist/agent/controller.js
CHANGED
|
@@ -519,6 +519,19 @@ export class AgentController {
|
|
|
519
519
|
// Every child runs the lead's own model, so the lead's cost table
|
|
520
520
|
// is the one honest price for the dispatch total.
|
|
521
521
|
modelCost: () => this.getModelInfo().cost,
|
|
522
|
+
// The FAST table for the supervisor's own spend line
|
|
523
|
+
// (subagent-overseer-v2 D-7 / R-P1-2). Reuses the tier
|
|
524
|
+
// resolution and the unknown-pricing predicate the fast
|
|
525
|
+
// reviewer already uses: undefined prices as `pricing
|
|
526
|
+
// unknown`, never as $0.00 (C-11 / RV-4).
|
|
527
|
+
fastModelCost: () => {
|
|
528
|
+
const tier = this.fast?.getTier();
|
|
529
|
+
if (!tier || !tier.ok)
|
|
530
|
+
return undefined;
|
|
531
|
+
return this.isPricedModel(tier.ref)
|
|
532
|
+
? this.getModelInfoFor(tier.ref).cost
|
|
533
|
+
: undefined;
|
|
534
|
+
},
|
|
522
535
|
withPausedWatchdog: (fn) => this.withPausedWatchdog(fn),
|
|
523
536
|
}),
|
|
524
537
|
]
|
|
@@ -621,7 +634,15 @@ export class AgentController {
|
|
|
621
634
|
// `dispatchTimeoutMs: 0` (the default) reaches the executor as an
|
|
622
635
|
// override of `0` = NO TIMER AT ALL: the dispatch lasts as long as its
|
|
623
636
|
// slowest child, and only an Esc ends it early (main-agent parity).
|
|
624
|
-
|
|
637
|
+
// D-4, THE SECOND ARMING SITE: the runtime arms its own dispatch
|
|
638
|
+
// timer under the same gate, because the executor timeout being
|
|
639
|
+
// cooperative means this override must never be the ONLY ceiling.
|
|
640
|
+
// With the supervisor gate open the ceiling disarms HERE too, so
|
|
641
|
+
// team.overseer can never leave two kill paths alive behind one
|
|
642
|
+
// config. Read once at construction, exactly as before.
|
|
643
|
+
...(this.teamRegistered
|
|
644
|
+
? { task: config.team.overseer ? 0 : config.team.dispatchTimeoutMs }
|
|
645
|
+
: {}),
|
|
625
646
|
},
|
|
626
647
|
},
|
|
627
648
|
});
|
package/dist/agent/reducer.js
CHANGED
|
@@ -183,18 +183,20 @@ export function reduceEvent(event, cost, patches) {
|
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
185
|
* Tools that render their own transcript entry, so the generic tool card would
|
|
186
|
-
* be a duplicate.
|
|
187
|
-
*
|
|
186
|
+
* be a duplicate. `task` is the second member (F-8 A'3): every dispatch opens
|
|
187
|
+
* a TeamCard immediately after, so the pair read as TWO dispatches - the first
|
|
188
|
+
* failed, the second succeeded - when there was only ever one. `todo_write`'s
|
|
189
|
+
* reasons (todo-plan-execution §3.8 / D-10) carry over unchanged.
|
|
188
190
|
*
|
|
189
191
|
* SUPPRESSING ONLY `tool_call_start` IS SUFFICIENT, AND THAT IS THE WHOLE REASON
|
|
190
192
|
* THIS IS SAFE (D-10). Every later handler — `toolCallDelta` / `toolCallEnd` /
|
|
191
193
|
* `toolExecStart` / `toolExecEnd` — resolves its target through
|
|
192
194
|
* `findToolEntryId`, which returns `undefined` when no entry was created, and
|
|
193
|
-
* every one of them already early-returns on that. There is no fifth handler.
|
|
194
|
-
*
|
|
195
|
-
*
|
|
195
|
+
* every one of them already early-returns on that. There is no fifth handler.
|
|
196
|
+
* Blast radius verified: headless and `exec` writers key on EVENTS, not tool
|
|
197
|
+
* names, and `transcript-text` renders `kind:'team'` on its own.
|
|
196
198
|
*/
|
|
197
|
-
const SELF_RENDERING_TOOLS = new Set(['todo_write']);
|
|
199
|
+
const SELF_RENDERING_TOOLS = new Set(['todo_write', 'task']);
|
|
198
200
|
function reduceStreamEvent(se) {
|
|
199
201
|
switch (se.type) {
|
|
200
202
|
case 'thinking_start':
|
|
@@ -294,7 +294,8 @@ const COMMANDS = [
|
|
|
294
294
|
? `\nRunning: ${snapshot.runs.map((r) => `${r.label} (${r.phase})`).join(', ')}`
|
|
295
295
|
: '';
|
|
296
296
|
ctx.notify('info', `Team mode: ${state}. Max subagents: ${cfg.maxSubagents}, ` +
|
|
297
|
-
`concurrent: ${cfg.maxConcurrent}, supervisor: ${cfg.overseer ? 'on' : 'off'}
|
|
297
|
+
`concurrent: ${cfg.maxConcurrent}, supervisor: ${cfg.overseer ? 'on' : 'off'}` +
|
|
298
|
+
`${cfg.overseer ? ' (never kills; checks the fast tier each tick)' : ' (legacy hard timeouts)'}.${roster}`);
|
|
298
299
|
return;
|
|
299
300
|
}
|
|
300
301
|
if (verb === 'on' || verb === 'off') {
|
|
@@ -20,7 +20,7 @@ export declare const LOG_CONFIG_SET_KEYS: readonly ["log.level", "log.toFile", "
|
|
|
20
20
|
* switch falls through every case, writes nothing, and still prints
|
|
21
21
|
* `Set team.enabled = false`.
|
|
22
22
|
*/
|
|
23
|
-
export declare const TEAM_CONFIG_SET_KEYS: readonly ["team.enabled", "team.maxSubagents", "team.maxConcurrent", "team.subagentTimeoutMs", "team.dispatchTimeoutMs", "team.maxTurnsPerSubagent", "team.overseer"];
|
|
23
|
+
export declare const TEAM_CONFIG_SET_KEYS: readonly ["team.enabled", "team.maxSubagents", "team.maxConcurrent", "team.subagentTimeoutMs", "team.dispatchTimeoutMs", "team.maxTurnsPerSubagent", "team.overseer", "team.overseerIntervalMs"];
|
|
24
24
|
/**
|
|
25
25
|
* Config keys under `retry.` that `aragon config set` accepts
|
|
26
26
|
* (llm-api-retry-backoff §8.2).
|
|
@@ -44,6 +44,7 @@ export const TEAM_CONFIG_SET_KEYS = [
|
|
|
44
44
|
'team.dispatchTimeoutMs',
|
|
45
45
|
'team.maxTurnsPerSubagent',
|
|
46
46
|
'team.overseer',
|
|
47
|
+
'team.overseerIntervalMs',
|
|
47
48
|
];
|
|
48
49
|
/**
|
|
49
50
|
* Config keys under `retry.` that `aragon config set` accepts
|
|
@@ -202,6 +203,8 @@ export function applyTeamConfigSet(key, value) {
|
|
|
202
203
|
return patch(clampOne('maxTurnsPerSubagent'));
|
|
203
204
|
case 'team.overseer':
|
|
204
205
|
return patch({ overseer: isTrue(value) });
|
|
206
|
+
case 'team.overseerIntervalMs':
|
|
207
|
+
return patch(clampOne('overseerIntervalMs'));
|
|
205
208
|
default:
|
|
206
209
|
return null;
|
|
207
210
|
}
|
package/dist/config/load.js
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* legitimately long single tool run can never be watchdog-killed.
|
|
7
7
|
*/
|
|
8
8
|
import process from 'node:process';
|
|
9
|
-
import { DEFAULT_CONFIG, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampCompactionConfig, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampBashConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampContextWindow, clampMaxTokens, clampMaxRenderInterval, clampScrollResumeMs, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, parseThresholdInput, } from './schema.js';
|
|
9
|
+
import { DEFAULT_CONFIG, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampCompactionConfig, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampBashConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampContextWindow, clampMaxTokens, clampMaxRenderInterval, clampScrollResumeMs, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, legacyTeamCeilingPatch, parseThresholdInput, } from './schema.js';
|
|
10
10
|
import { loadDotenv, readEnvConfig, readEnvDisabledSkills } from './env.js';
|
|
11
|
-
import { readConfigFile } from './store.js';
|
|
12
|
-
import { projectModelProfiles, resolveModelProfileState, resolveModelRoleKey } from './model-profile-resolution.js';
|
|
11
|
+
import { readConfigFile, updatePersistedConfig } from './store.js';
|
|
12
|
+
import { projectModelProfiles, resolveModelProfileState, resolveModelRoleKey, } from './model-profile-resolution.js';
|
|
13
13
|
import { getConfigPath } from './app-paths.js';
|
|
14
14
|
import { setHistoryEnabled } from './prompt-history.js';
|
|
15
15
|
import { setEntryRetain } from '../agent/entry-limits.js';
|
|
@@ -439,6 +439,44 @@ function resolveContextWindow(env, file) {
|
|
|
439
439
|
}
|
|
440
440
|
return DEFAULT_CONFIG.contextWindow;
|
|
441
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* Rewrite the cli<=0.6.16 persisted team ceiling defaults to 0 and persist the
|
|
444
|
+
* change (F-8 A'4). ONE-SHOT and IDEMPOTENT: after the first rewrite the file
|
|
445
|
+
* carries 0, which matches nothing, so nothing is written again.
|
|
446
|
+
*
|
|
447
|
+
* THE FILE LAYER ONLY, deliberately: env and flags are this-launch intent and
|
|
448
|
+
* survive untouched, and with the D-4 semantics a positive surviving value is
|
|
449
|
+
* a supervisor cadence hint, never a kill. The raw file object is patched IN
|
|
450
|
+
* PLACE (the same precedent `readConfigFile` sets with `fullscreen`) so the
|
|
451
|
+
* `file` layer this function's caller resolves from already reads 0; the
|
|
452
|
+
* write goes through `updatePersistedConfig`, the one atomic write path every
|
|
453
|
+
* other settings change uses.
|
|
454
|
+
*
|
|
455
|
+
* A FAILED WRITE MUST NOT BLOCK STARTUP: the values are already neutralized
|
|
456
|
+
* in memory, and the next launch retries — which is why the catch is empty
|
|
457
|
+
* and the migration is logged instead of surfaced.
|
|
458
|
+
*/
|
|
459
|
+
function migrateLegacyTeamCeilings(raw) {
|
|
460
|
+
const patch = legacyTeamCeilingPatch(raw?.team);
|
|
461
|
+
if (patch === null)
|
|
462
|
+
return;
|
|
463
|
+
// THE FULL SECTION, not the bare patch: the write port types `team` as a
|
|
464
|
+
// whole `TeamConfig` (its merge then deep-merges over what is on disk), and
|
|
465
|
+
// the section the file already carries plus the zeroed keys IS the section
|
|
466
|
+
// we want on disk.
|
|
467
|
+
const migratedTeam = { ...raw.team, ...patch };
|
|
468
|
+
Object.assign(raw.team, patch);
|
|
469
|
+
try {
|
|
470
|
+
updatePersistedConfig({ team: migratedTeam });
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
// Unwritable config dir: in-memory values are already migrated; retry
|
|
474
|
+
// next launch (idempotent).
|
|
475
|
+
}
|
|
476
|
+
getLogger().warn('config', 'team_legacy_ceilings_migrated', {
|
|
477
|
+
keys: Object.keys(patch).join(','),
|
|
478
|
+
});
|
|
479
|
+
}
|
|
442
480
|
/**
|
|
443
481
|
* Resolve the effective config by merging all layers, then derive the runtime
|
|
444
482
|
* (non-persisted) fields and enforce the timeout invariant.
|
|
@@ -448,6 +486,7 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
448
486
|
// `.env` must be loaded before reading env overrides.
|
|
449
487
|
loadDotenv(cwd);
|
|
450
488
|
const read = readConfigFile();
|
|
489
|
+
migrateLegacyTeamCeilings(read.config);
|
|
451
490
|
const projection = projectModelProfiles(read.config ?? {});
|
|
452
491
|
const file = projection.file;
|
|
453
492
|
const env = readEnvConfig();
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -309,10 +309,11 @@ export interface TeamConfig {
|
|
|
309
309
|
* the lead, whose only in-run ceiling is the event-silence idle watchdog
|
|
310
310
|
* a child already keeps. A wedged child still dies on its OWN watchdog.
|
|
311
311
|
*
|
|
312
|
-
* WITH `team.overseer` ON (the default) this
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
312
|
+
* WITH `team.overseer` ON (the default) this NEVER aborts anything
|
|
313
|
+
* (subagent-overseer-v2 D-4): a positive value is only a COMPATIBILITY
|
|
314
|
+
* SOURCE for the supervisor's first cadence check, honouring users who
|
|
315
|
+
* already treated it as a trigger point. The only hard abort left is
|
|
316
|
+
* the legacy regime (`team.overseer: false`).
|
|
316
317
|
*/
|
|
317
318
|
subagentTimeoutMs: number;
|
|
318
319
|
/**
|
|
@@ -329,17 +330,32 @@ export interface TeamConfig {
|
|
|
329
330
|
*/
|
|
330
331
|
maxTurnsPerSubagent: number;
|
|
331
332
|
/**
|
|
332
|
-
* The dispatch supervisor (team-overseer): time
|
|
333
|
-
* become inspection triggers for a fast-tier
|
|
334
|
-
* wait / nudge / replace / abandon, instead of
|
|
333
|
+
* The dispatch supervisor (team-overseer / subagent-overseer-v2): time
|
|
334
|
+
* ceilings on children become inspection triggers for a fast-tier
|
|
335
|
+
* supervisor that decides wait / nudge / replace / abandon, instead of
|
|
336
|
+
* aborts. Default TRUE.
|
|
335
337
|
*
|
|
336
|
-
* READ PER DISPATCH.
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* a
|
|
338
|
+
* READ PER DISPATCH. The supervisor ticks on a cadence ladder over every
|
|
339
|
+
* live child, and NO timeout is a death sentence while this is on: with
|
|
340
|
+
* the fast tier missing a tick degrades to an announced unassisted wait,
|
|
341
|
+
* never a kill. With this FALSE, children run exactly the pre-feature
|
|
342
|
+
* legacy regime: `subagentTimeoutMs` is a hard abort and silence is the
|
|
343
|
+
* child's own watchdog.
|
|
341
344
|
*/
|
|
342
345
|
overseer: boolean;
|
|
346
|
+
/**
|
|
347
|
+
* Supervisor cadence BASE, in milliseconds (subagent-overseer-v2 D-8).
|
|
348
|
+
* `0` (the default) = the structural default
|
|
349
|
+
* (`TEAM_LIMITS.overseerDefaultCheckMs`, 300 s).
|
|
350
|
+
*
|
|
351
|
+
* EFFECTIVE FIRST CHECK, derived read-only and never written back:
|
|
352
|
+
* `overseerIntervalMs > 0` wins; otherwise a positive
|
|
353
|
+
* `subagentTimeoutMs` is honoured (users who already treated it as a
|
|
354
|
+
* trigger point); otherwise the structural default. Later checks grow
|
|
355
|
+
* by `overseerCadenceRatio` (1.6), clamped to [60 s, 900 s]. Only
|
|
356
|
+
* meaningful while `team.overseer` is true.
|
|
357
|
+
*/
|
|
358
|
+
overseerIntervalMs: number;
|
|
343
359
|
}
|
|
344
360
|
/**
|
|
345
361
|
* The requirement's ceiling on the fan-out (R-g).
|
|
@@ -364,6 +380,31 @@ export declare const DEFAULT_TEAM_CONFIG: TeamConfig;
|
|
|
364
380
|
* the two disagree would make the panel's `n/m` readout confusing for no gain.
|
|
365
381
|
*/
|
|
366
382
|
export declare function clampTeamConfig(raw: unknown): TeamConfig;
|
|
383
|
+
/**
|
|
384
|
+
* The team ceilings cli <= 0.6.16 (7a6bf5630) persisted as its OWN defaults:
|
|
385
|
+
* every user who touched team mode back then still carries this exact triple
|
|
386
|
+
* in config.json, because `resolveTeamConfig` merges file values verbatim and
|
|
387
|
+
* no migration ever rewrote them. They are the kill ceilings behind F-8's
|
|
388
|
+
* "first block all failed" dispatches, so loading rewrites them to 0 (= no
|
|
389
|
+
* ceiling, the shipped default since 2ff15a9c3).
|
|
390
|
+
*
|
|
391
|
+
* EXACT-EQUALITY ONLY: a value that differs was a deliberate user choice and
|
|
392
|
+
* survives untouched. The price of that test is that a user who hand-types
|
|
393
|
+
* 300000 today is migrated to 0 too - the accepted trade, and the safe
|
|
394
|
+
* direction (no ceiling, not a cliff).
|
|
395
|
+
*/
|
|
396
|
+
export declare const LEGACY_TEAM_CEILING_DEFAULTS: Readonly<{
|
|
397
|
+
subagentTimeoutMs: number;
|
|
398
|
+
dispatchTimeoutMs: number;
|
|
399
|
+
maxTurnsPerSubagent: number;
|
|
400
|
+
}>;
|
|
401
|
+
/**
|
|
402
|
+
* The `{ key: 0 }` patch for legacy-default-equal ceilings, or `null` when
|
|
403
|
+
* nothing matches. Pure on purpose: `loadConfig` decides WHERE the patch is
|
|
404
|
+
* applied and persisted; this function only answers WHICH keys match, so the
|
|
405
|
+
* equality test lives beside the constants it reads.
|
|
406
|
+
*/
|
|
407
|
+
export declare function legacyTeamCeilingPatch(raw: unknown): Partial<TeamConfig> | null;
|
|
367
408
|
export interface TodoConfig {
|
|
368
409
|
/** Register `todo_write` at all. Default TRUE. */
|
|
369
410
|
enabled: boolean;
|
package/dist/config/schema.js
CHANGED
|
@@ -455,6 +455,8 @@ export const DEFAULT_TEAM_CONFIG = {
|
|
|
455
455
|
// The dispatch supervisor, default ON (team-overseer): ceilings become
|
|
456
456
|
// inspections; the fast-tier supervisor decides what to do.
|
|
457
457
|
overseer: true,
|
|
458
|
+
// 0 = the structural cadence default (300 s). See the field docstring.
|
|
459
|
+
overseerIntervalMs: 0,
|
|
458
460
|
};
|
|
459
461
|
const SUBAGENTS_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
|
|
460
462
|
const CONCURRENT_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
|
|
@@ -463,6 +465,7 @@ const CONCURRENT_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
|
|
|
463
465
|
// ("my setting won't stick"), the exact trap `scrollResumeMs` records above.
|
|
464
466
|
const SUBAGENT_TIMEOUT_RANGE = { min: 0, max: 1_800_000 };
|
|
465
467
|
const DISPATCH_TIMEOUT_RANGE = { min: 0, max: 3_600_000 };
|
|
468
|
+
const OVERSEER_INTERVAL_RANGE = { min: 0, max: 3_600_000 };
|
|
466
469
|
const TURNS_RANGE = { min: 0, max: 100 };
|
|
467
470
|
/**
|
|
468
471
|
* THE single gate for every team-config read AND write, mirroring
|
|
@@ -486,8 +489,47 @@ export function clampTeamConfig(raw) {
|
|
|
486
489
|
dispatchTimeoutMs: clampIntAllowingZero(src.dispatchTimeoutMs, DEFAULT_TEAM_CONFIG.dispatchTimeoutMs, DISPATCH_TIMEOUT_RANGE),
|
|
487
490
|
maxTurnsPerSubagent: clampIntAllowingZero(src.maxTurnsPerSubagent, DEFAULT_TEAM_CONFIG.maxTurnsPerSubagent, TURNS_RANGE),
|
|
488
491
|
overseer: bool(src.overseer, DEFAULT_TEAM_CONFIG.overseer),
|
|
492
|
+
overseerIntervalMs: clampIntAllowingZero(src.overseerIntervalMs, DEFAULT_TEAM_CONFIG.overseerIntervalMs, OVERSEER_INTERVAL_RANGE),
|
|
489
493
|
};
|
|
490
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* The team ceilings cli <= 0.6.16 (7a6bf5630) persisted as its OWN defaults:
|
|
497
|
+
* every user who touched team mode back then still carries this exact triple
|
|
498
|
+
* in config.json, because `resolveTeamConfig` merges file values verbatim and
|
|
499
|
+
* no migration ever rewrote them. They are the kill ceilings behind F-8's
|
|
500
|
+
* "first block all failed" dispatches, so loading rewrites them to 0 (= no
|
|
501
|
+
* ceiling, the shipped default since 2ff15a9c3).
|
|
502
|
+
*
|
|
503
|
+
* EXACT-EQUALITY ONLY: a value that differs was a deliberate user choice and
|
|
504
|
+
* survives untouched. The price of that test is that a user who hand-types
|
|
505
|
+
* 300000 today is migrated to 0 too - the accepted trade, and the safe
|
|
506
|
+
* direction (no ceiling, not a cliff).
|
|
507
|
+
*/
|
|
508
|
+
export const LEGACY_TEAM_CEILING_DEFAULTS = {
|
|
509
|
+
subagentTimeoutMs: 300_000,
|
|
510
|
+
dispatchTimeoutMs: 900_000,
|
|
511
|
+
maxTurnsPerSubagent: 24,
|
|
512
|
+
};
|
|
513
|
+
/**
|
|
514
|
+
* The `{ key: 0 }` patch for legacy-default-equal ceilings, or `null` when
|
|
515
|
+
* nothing matches. Pure on purpose: `loadConfig` decides WHERE the patch is
|
|
516
|
+
* applied and persisted; this function only answers WHICH keys match, so the
|
|
517
|
+
* equality test lives beside the constants it reads.
|
|
518
|
+
*/
|
|
519
|
+
export function legacyTeamCeilingPatch(raw) {
|
|
520
|
+
if (!raw || typeof raw !== 'object')
|
|
521
|
+
return null;
|
|
522
|
+
const src = raw;
|
|
523
|
+
const patch = {};
|
|
524
|
+
let matched = false;
|
|
525
|
+
for (const key of Object.keys(LEGACY_TEAM_CEILING_DEFAULTS)) {
|
|
526
|
+
if (src[key] === LEGACY_TEAM_CEILING_DEFAULTS[key]) {
|
|
527
|
+
patch[key] = 0;
|
|
528
|
+
matched = true;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return matched ? patch : null;
|
|
532
|
+
}
|
|
491
533
|
export const DEFAULT_TODO_CONFIG = {
|
|
492
534
|
enabled: true,
|
|
493
535
|
panel: true,
|
package/dist/team/limits.d.ts
CHANGED
|
@@ -102,11 +102,12 @@ export declare const TEAM_LIMITS: {
|
|
|
102
102
|
readonly maxColdStartRetries: 1;
|
|
103
103
|
readonly retryBackoffMs: 2000;
|
|
104
104
|
/**
|
|
105
|
-
* Wall-clock budget of everything one inspection may carry
|
|
106
|
-
* run facts, the supervisor's own
|
|
107
|
-
* history; unbounded, one look at a
|
|
108
|
-
*
|
|
109
|
-
* FAST_LIMITS.digestMaxChars makes,
|
|
105
|
+
* Wall-clock budget of everything one SINGLE inspection may carry (the
|
|
106
|
+
* silence-triggered path). The digest holds run facts, the supervisor's own
|
|
107
|
+
* memory and the tail of the child's live history; unbounded, one look at a
|
|
108
|
+
* child that read five big files would make the "cheap" supervision call
|
|
109
|
+
* cost more than the child (the argument FAST_LIMITS.digestMaxChars makes,
|
|
110
|
+
* one level up).
|
|
110
111
|
*/
|
|
111
112
|
readonly overseerDigestBytes: 8000;
|
|
112
113
|
/** Clamp on a `nudge` guidance text. Advice, not a second brief. */
|
|
@@ -114,11 +115,48 @@ export declare const TEAM_LIMITS: {
|
|
|
114
115
|
/** Clamp on the decision `reason` recorded in the report. */
|
|
115
116
|
readonly overseerReasonChars: 200;
|
|
116
117
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
118
|
+
* Per-child slice of a BATCH digest (D-3 / R-P2-5). 6.7x tighter than the
|
|
119
|
+
* single-inspection budget above: a batch carries up to ten children in one
|
|
120
|
+
* call, and memory plus the history tail are the first to give way (the
|
|
121
|
+
* facts-first assembly order already puts them last).
|
|
120
122
|
*/
|
|
121
|
-
readonly
|
|
123
|
+
readonly overseerPerChildDigestBytes: 1200;
|
|
124
|
+
/** Whole-batch digest ceiling (D-3): 10 children x 1 200 B fits exactly. */
|
|
125
|
+
readonly overseerBatchDigestBytes: 12000;
|
|
126
|
+
/**
|
|
127
|
+
* Output budget of ONE batch inspection (R-P0-1). The single-inspection path
|
|
128
|
+
* keeps `FAST_LIMITS.reviewOutputTokens` (512); a batch must return up to
|
|
129
|
+
* ten decision objects, and 512 tokens cannot physically hold ten x
|
|
130
|
+
* (reason <= 200 + guidance <= 1200). A truncated batch reply fails
|
|
131
|
+
* "first `[` to last `]`" parsing and degrades to all-wait - exactly the
|
|
132
|
+
* failure this separate, larger budget exists to prevent.
|
|
133
|
+
*/
|
|
134
|
+
readonly overseerBatchOutputTokens: 2048;
|
|
135
|
+
/** Tighter `reason` clamp inside the batch protocol (R-P0-1). */
|
|
136
|
+
readonly overseerBatchReasonChars: 80;
|
|
137
|
+
/** Tighter `guidance` clamp inside the batch protocol (R-P0-1). */
|
|
138
|
+
readonly overseerBatchGuidanceChars: 400;
|
|
139
|
+
/**
|
|
140
|
+
* LOOKS per child per dispatch (D-5). A look is cost, not mutation: every
|
|
141
|
+
* inspection of a child - silence-triggered, cadence tick or post-mortem -
|
|
142
|
+
* spends one, including a call that failed softly. Twelve with the cadence
|
|
143
|
+
* ladder covers hours of healthy slow work; past the budget the supervisor
|
|
144
|
+
* says so once (`trigger: 'quiet'`) and stops waking that child up.
|
|
145
|
+
*/
|
|
146
|
+
readonly overseerMaxLooksPerChild: 12;
|
|
147
|
+
/**
|
|
148
|
+
* LOOKS per dispatch, the fool-proof total (R-P1-6):
|
|
149
|
+
* hardMaxSubagents x overseerMaxLooksPerChild = 120. A mathematical upper
|
|
150
|
+
* bound, not a tuning knob - the per-child budget always binds first; this
|
|
151
|
+
* one exists so a bug cannot loop calls forever. When it trips, the whole
|
|
152
|
+
* MonitorLoop stops with one aggregate notice.
|
|
153
|
+
*/
|
|
154
|
+
readonly overseerMaxLooksPerDispatch: number;
|
|
155
|
+
/**
|
|
156
|
+
* NUDGES per child per dispatch (D-5). Advice is cheap but not free: a
|
|
157
|
+
* supervisor that steers the same child forever is one that never decided.
|
|
158
|
+
*/
|
|
159
|
+
readonly overseerMaxNudgesPerChild: 3;
|
|
122
160
|
/**
|
|
123
161
|
* Rebuilds PER CHILD per dispatch. One: a replacement that also stalls dies
|
|
124
162
|
* on its own watchdog rather than ping-ponging fresh children at a task the
|
|
@@ -126,13 +164,25 @@ export declare const TEAM_LIMITS: {
|
|
|
126
164
|
*/
|
|
127
165
|
readonly overseerMaxReplacementsPerChild: 1;
|
|
128
166
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
167
|
+
* Abandons PER CHILD per dispatch (D-5). One, so a supervisor that has
|
|
168
|
+
* already given up on a brief cannot keep re-killing bodies of it.
|
|
169
|
+
*/
|
|
170
|
+
readonly overseerMaxAbandonsPerChild: 1;
|
|
171
|
+
/**
|
|
172
|
+
* Cadence ladder growth factor (D-2). Each no-action inspection schedules
|
|
173
|
+
* the next `previous * ratio` out, so a healthy slow child is looked at
|
|
174
|
+
* logarithmically in its run time rather than every five minutes.
|
|
175
|
+
*/
|
|
176
|
+
readonly overseerCadenceRatio: 1.6;
|
|
177
|
+
/**
|
|
178
|
+
* First cadence check when neither `team.overseerIntervalMs` nor
|
|
179
|
+
* `team.subagentTimeoutMs` names one (the shipped defaults): the supervisor
|
|
180
|
+
* still looks even when no ceiling was configured.
|
|
131
181
|
*/
|
|
132
182
|
readonly overseerDefaultCheckMs: 300000;
|
|
133
|
-
/** Clamp on
|
|
183
|
+
/** Clamp on a ladder step / model-chosen `nextCheckMs`, lower bound. */
|
|
134
184
|
readonly overseerNextCheckMinMs: 60000;
|
|
135
|
-
/** Clamp on
|
|
185
|
+
/** Clamp on a ladder step / model-chosen `nextCheckMs`, upper bound. */
|
|
136
186
|
readonly overseerNextCheckMaxMs: 900000;
|
|
137
187
|
/**
|
|
138
188
|
* A child's OWN idle watchdog, multiplied by this while the supervisor is
|
|
@@ -142,6 +192,16 @@ export declare const TEAM_LIMITS: {
|
|
|
142
192
|
*/
|
|
143
193
|
readonly overseerWatchdogFactor: 4;
|
|
144
194
|
};
|
|
195
|
+
/**
|
|
196
|
+
* The pseudo-label the runtime's AGGREGATE supervisor notices travel under
|
|
197
|
+
* (subagent-overseer-v2 D-5 / R-P1-6): the dispatch-total look-budget notice
|
|
198
|
+
* is one fact about the whole roster, not a row any child owns. RESERVED at
|
|
199
|
+
* normalization (`normalizeSubagentSpecs` seeds `dedupeLabel` with it), so a
|
|
200
|
+
* spec asking for the bare label `team` is handed `team-2` instead - the
|
|
201
|
+
* report ledger and the exec stream can then never attribute an aggregate
|
|
202
|
+
* notice to a real child, or swallow that child's own quiet note.
|
|
203
|
+
*/
|
|
204
|
+
export declare const TEAM_AGGREGATE_LABEL = "team";
|
|
145
205
|
/**
|
|
146
206
|
* The two comm tools, which are POLICY-EXEMPT inside a child (§3.11).
|
|
147
207
|
*
|