@aragon-agent/cli 0.6.15 → 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 +108 -71
- package/dist/agent/controller.d.ts +10 -0
- package/dist/agent/controller.js +52 -47
- package/dist/agent/reducer.js +0 -4
- package/dist/cli.js +49 -15
- package/dist/commands/builtins.js +27 -43
- package/dist/compaction/child.d.ts +10 -8
- package/dist/compaction/child.js +23 -25
- package/dist/compaction/context-command.js +14 -3
- package/dist/compaction/limits.d.ts +0 -2
- package/dist/compaction/limits.js +0 -2
- package/dist/compaction/types.d.ts +6 -1
- package/dist/config/app-paths.d.ts +10 -0
- package/dist/config/app-paths.js +12 -0
- package/dist/config/cli-commands.d.ts +1 -1
- package/dist/config/cli-commands.js +16 -15
- package/dist/config/env.d.ts +2 -1
- package/dist/config/env.js +13 -1
- package/dist/config/load.d.ts +9 -17
- package/dist/config/load.js +14 -6
- package/dist/config/model-windows.d.ts +91 -0
- package/dist/config/model-windows.js +181 -0
- package/dist/config/schema.d.ts +34 -5
- package/dist/config/schema.js +15 -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/input/csiu-keys.d.ts +66 -0
- package/dist/input/csiu-keys.js +170 -0
- package/dist/input/keyboard-enhancement.d.ts +42 -0
- package/dist/input/keyboard-enhancement.js +65 -0
- package/dist/input/stdin-filter.d.ts +9 -0
- package/dist/input/stdin-filter.js +45 -9
- package/dist/input/win32-input-mode.d.ts +61 -0
- package/dist/input/win32-input-mode.js +251 -0
- 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/dist/team/subagent.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { Agent, createSkillFindTool, } from '@aragon-agent/core';
|
|
14
14
|
import { formatStreamError } from '../agent/reducer.js';
|
|
15
15
|
import { buildSystemPrompt } from '../agent/system-prompt.js';
|
|
16
|
+
import { buildFastBlock } from '../fast/prompt.js';
|
|
16
17
|
import { createBuiltinTools } from '../tools/index.js';
|
|
17
18
|
import { pickActivityArgs, sanitizeActivity } from './activity.js';
|
|
18
19
|
import { TEAM_LIMITS, TEAM_SUBAGENT_TOOL_NAMES } from './limits.js';
|
|
@@ -40,11 +41,17 @@ function assistantText(message) {
|
|
|
40
41
|
* the security boundary here, so it has to be directly checkable.
|
|
41
42
|
*/
|
|
42
43
|
export function buildSubagentTools(spec, deps, getAgent) {
|
|
44
|
+
// `team_wait`'s ceiling is the STRUCTURAL clamp when the child itself has no
|
|
45
|
+
// wall clock (`subagentTimeoutMs: 0`): a peer wait must stay bounded even when
|
|
46
|
+
// the child's run is not, or one forgotten wait would hold a slot forever.
|
|
47
|
+
const subagentTimeoutMs = deps.config.team.subagentTimeoutMs;
|
|
43
48
|
const commTools = [
|
|
44
49
|
makeTeamSend(deps.bus, spec.label),
|
|
45
50
|
makeTeamWait(deps.bus, spec.label, {
|
|
46
51
|
getAgent,
|
|
47
|
-
maxWaitMs:
|
|
52
|
+
maxWaitMs: subagentTimeoutMs > 0
|
|
53
|
+
? subagentTimeoutMs
|
|
54
|
+
: TEAM_LIMITS.waitMaxSeconds * 1000,
|
|
48
55
|
}),
|
|
49
56
|
];
|
|
50
57
|
const tools = createBuiltinTools({
|
|
@@ -141,9 +148,6 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
141
148
|
const run = {
|
|
142
149
|
label: spec.label,
|
|
143
150
|
description: spec.description,
|
|
144
|
-
// FROM THE SPEC, which the normalizer already downgraded when the tier was
|
|
145
|
-
// unavailable — so this is what RAN, not what was asked for (§3.4).
|
|
146
|
-
tier: spec.tier,
|
|
147
151
|
phase: 'queued',
|
|
148
152
|
turns: 0,
|
|
149
153
|
toolCalls: 0,
|
|
@@ -158,37 +162,38 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
158
162
|
let agentRef = null;
|
|
159
163
|
const getAgent = () => agentRef;
|
|
160
164
|
const tools = buildSubagentTools(spec, deps, getAgent);
|
|
161
|
-
// THE
|
|
162
|
-
//
|
|
163
|
-
//
|
|
165
|
+
// THE CHILD'S MODEL IS THE LEAD'S MODEL, READ FROM THE DISPATCH-TIME CONFIG
|
|
166
|
+
// (main-agent parity). Same provider, same model id, same base URL, same
|
|
167
|
+
// thinking level: a delegation is never a downgrade, and the only model a
|
|
168
|
+
// child may surprise its lead with is one a settings-screen edit made live
|
|
169
|
+
// between two dispatches.
|
|
164
170
|
//
|
|
165
|
-
// `
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
: {
|
|
178
|
-
ref: {
|
|
179
|
-
providerId: deps.config.provider,
|
|
180
|
-
modelId: deps.config.model,
|
|
181
|
-
...(deps.config.baseUrl ? { baseUrl: deps.config.baseUrl } : {}),
|
|
182
|
-
},
|
|
183
|
-
thinkingLevel: deps.config.thinkingLevel,
|
|
184
|
-
role: 'main',
|
|
185
|
-
};
|
|
171
|
+
// `maxTokens` inherits `deps.config.maxTokens` below - the same ambition the
|
|
172
|
+
// lead sends, clamped by the same adapter, so an inherited large value
|
|
173
|
+
// degrades to the right number rather than to an HTTP 400.
|
|
174
|
+
const resolved = {
|
|
175
|
+
ref: {
|
|
176
|
+
providerId: deps.config.provider,
|
|
177
|
+
modelId: deps.config.model,
|
|
178
|
+
...(deps.config.baseUrl ? { baseUrl: deps.config.baseUrl } : {}),
|
|
179
|
+
},
|
|
180
|
+
thinkingLevel: deps.config.thinkingLevel,
|
|
181
|
+
role: 'main',
|
|
182
|
+
};
|
|
186
183
|
const model = resolved.ref;
|
|
187
184
|
// HOISTED TO A LOCAL, AND THAT IS WHAT MAKES W3 POSSIBLE AT ALL. This was built
|
|
188
185
|
// INLINE inside the `agentFactory({...})` argument, so there was nothing for the
|
|
189
186
|
// child manager's `getSystemPrompt` accessor to close over - and the accessor
|
|
190
187
|
// cannot read it back off the agent, because `SubagentAgentLike` is narrowed to
|
|
191
188
|
// `state.messages` on purpose.
|
|
189
|
+
// THE SAME `<fast_tier>` BLOCK THE LEAD GETS, spliced only when this child
|
|
190
|
+
// will actually have a reviewer. The gating expression is written against
|
|
191
|
+
// `deps.review` here and the reviewer is built from the SAME predicate
|
|
192
|
+
// below, so the prompt can never advertise a capability the child lacks -
|
|
193
|
+
// and a child with a reviewer is never surprised by its first injection.
|
|
194
|
+
const fastBlock = deps.review !== undefined && deps.review.active()
|
|
195
|
+
? buildFastBlock({ model: deps.review.modelId(), review: true })
|
|
196
|
+
: '';
|
|
192
197
|
const systemPrompt = buildSystemPrompt({
|
|
193
198
|
cwd: deps.getCwd(),
|
|
194
199
|
tools,
|
|
@@ -203,6 +208,7 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
203
208
|
description: spec.description,
|
|
204
209
|
peers: deps.bus.peersOf(spec.label),
|
|
205
210
|
}),
|
|
211
|
+
...(fastBlock ? { fastBlock } : {}),
|
|
206
212
|
});
|
|
207
213
|
// LAZY ACCESSORS OVER `agentRef`, WHICH IS ASSIGNED AFTER THIS RETURNS. A
|
|
208
214
|
// non-lazy read here is `undefined` at construction and the child's estimate
|
|
@@ -244,6 +250,27 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
244
250
|
...(contextManager ? { contextManager } : {}),
|
|
245
251
|
});
|
|
246
252
|
agentRef = agent;
|
|
253
|
+
// PER-CHILD FAST REVIEW (main-agent parity). GATED ON THE PROVIDER'S OWN
|
|
254
|
+
// LIVE PREDICATE, read once here so the prompt and the reviewer CANNOT
|
|
255
|
+
// DISAGREE about whether the child has one: a child told about
|
|
256
|
+
// `<fast_review>` blocks must be a child that actually receives them, and a
|
|
257
|
+
// child with a reviewer must have been told. `abortRequested` is the flag
|
|
258
|
+
// `handle.abort()` sets (see `SubagentHandle`); the reviewer reads it as its
|
|
259
|
+
// never-steer-into-a-requested-abort fact.
|
|
260
|
+
let abortRequested = false;
|
|
261
|
+
const reviewLive = deps.review !== undefined && deps.review.active() === true;
|
|
262
|
+
const reviewer = reviewLive
|
|
263
|
+
? deps.review?.create({
|
|
264
|
+
label: spec.label,
|
|
265
|
+
goal: spec.description,
|
|
266
|
+
agent,
|
|
267
|
+
isRunning: () => run.phase === 'starting' ||
|
|
268
|
+
run.phase === 'thinking' ||
|
|
269
|
+
run.phase === 'tool' ||
|
|
270
|
+
run.phase === 'waiting',
|
|
271
|
+
isAbortRequested: () => abortRequested,
|
|
272
|
+
})
|
|
273
|
+
: undefined;
|
|
247
274
|
let lastEmit = 0;
|
|
248
275
|
let lastPhase = run.phase;
|
|
249
276
|
/**
|
|
@@ -325,8 +352,16 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
325
352
|
// an aborted run, which the report renders as partial rather than lost.
|
|
326
353
|
if (text.length > 0)
|
|
327
354
|
run.summary = text;
|
|
328
|
-
|
|
355
|
+
// `0` MEANS NO CAP (main-agent parity): the lead has no turn ceiling
|
|
356
|
+
// either, and a child that needs forty turns for a forty-turn job is
|
|
357
|
+
// not runaway - it is working.
|
|
358
|
+
const turnCap = deps.config.team.maxTurnsPerSubagent;
|
|
359
|
+
if (turnCap > 0 && run.turns >= turnCap) {
|
|
329
360
|
run.truncated = true;
|
|
361
|
+
// THE FLAG FIRST, exactly like `handle.abort()`: the child's
|
|
362
|
+
// reviewer reads `abortRequested` as its guard-1 fact, and a
|
|
363
|
+
// turn-cap stop must be visible to it in the same tick.
|
|
364
|
+
abortRequested = true;
|
|
330
365
|
agent.abort();
|
|
331
366
|
}
|
|
332
367
|
break;
|
|
@@ -404,5 +439,20 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
404
439
|
}
|
|
405
440
|
emit();
|
|
406
441
|
});
|
|
407
|
-
return {
|
|
442
|
+
return {
|
|
443
|
+
spec,
|
|
444
|
+
run,
|
|
445
|
+
agent,
|
|
446
|
+
tools,
|
|
447
|
+
// THE HANDLE-LEVEL ABORT (see `SubagentHandle`): the flag first, then the
|
|
448
|
+
// agent, so the reviewer's guard observes the request in the same tick.
|
|
449
|
+
abort: () => {
|
|
450
|
+
abortRequested = true;
|
|
451
|
+
agent.abort();
|
|
452
|
+
},
|
|
453
|
+
unsubscribe: () => {
|
|
454
|
+
reviewer?.dispose();
|
|
455
|
+
unsubscribe();
|
|
456
|
+
},
|
|
457
|
+
};
|
|
408
458
|
}
|
package/dist/team/task-tool.d.ts
CHANGED
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
* `normalizeSubagentSpecs`, which is deterministic and unit-tested. `maxItems`
|
|
20
20
|
* in the schema would behave differently depending on whether `ajv`, an OPTIONAL
|
|
21
21
|
* dependency of core, happened to install.
|
|
22
|
+
*
|
|
23
|
+
* EVERY CHILD RUNS THE LEAD'S OWN MODEL (main-agent parity): same provider,
|
|
24
|
+
* model, thinking level and token ambition, resolved from the LIVE config at
|
|
25
|
+
* dispatch. There is no per-child `model` property and no cheap tier to pick -
|
|
26
|
+
* a delegation is never a downgrade, and the fast tier reaches children the
|
|
27
|
+
* same way it reaches the lead (compaction summaries, per-child reviews).
|
|
22
28
|
*/
|
|
23
29
|
import { type AgentTool } from '@aragon-agent/core';
|
|
24
30
|
import type { ModelCost } from '@aragon-agent/core';
|
|
@@ -27,38 +33,12 @@ export interface TaskToolDeps {
|
|
|
27
33
|
runtime: TeamRuntime;
|
|
28
34
|
/** Read LIVE, never cached: `/team off` flips this, it does not unregister. */
|
|
29
35
|
isTeamEnabled: () => boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Whether the fast tier was resolvable AT CONSTRUCTION (fast-model-tier §3.3 /
|
|
32
|
-
* C-2).
|
|
33
|
-
*
|
|
34
|
-
* DECIDED ONCE, because the tool array is built once and must never be
|
|
35
|
-
* rebuilt: `Agent.setTools()` mutates the live `ToolRegistry`, and
|
|
36
|
-
* `submit_plan` flips the session mode from INSIDE a tool execution. So the
|
|
37
|
-
* `model` property either exists in this schema for the whole session or never
|
|
38
|
-
* does — and with it absent, `TASK_DESCRIPTION` and the schema are
|
|
39
|
-
* BYTE-IDENTICAL to the pre-feature build (AC-3).
|
|
40
|
-
*
|
|
41
|
-
* Optional so every existing construction site and test compiles unchanged.
|
|
42
|
-
*/
|
|
43
|
-
fastRegistered?: boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Whether `model:"fast"` is honoured RIGHT NOW. Read LIVE, at dispatch time
|
|
46
|
-
* (RV-3) — the tier can stop resolving mid-session, and a downgrade is the
|
|
47
|
-
* honest observable either way.
|
|
48
|
-
*/
|
|
49
|
-
fastAvailable?: () => boolean;
|
|
50
36
|
maxSubagents: () => number;
|
|
51
37
|
/** Whether a usable key exists for the active provider right now (P2-3). */
|
|
52
38
|
hasApiKey: () => boolean;
|
|
53
39
|
activeProvider: () => string;
|
|
54
40
|
/** The lead's cost table, so the report header states real spend (R-5). */
|
|
55
41
|
modelCost: () => ModelCost | undefined;
|
|
56
|
-
/** The FAST model's cost table (fast-model-tier §3.4). Absent when the tier is
|
|
57
|
-
* off, which is what leaves the report byte-identical. */
|
|
58
|
-
fastModelCost?: () => ModelCost | undefined;
|
|
59
|
-
/** Whether the static price table has never heard of the fast model (C-11 /
|
|
60
|
-
* RV-4). `unknown` is rendered as unknown, NEVER as `$0.00`. */
|
|
61
|
-
fastPricingUnknown?: () => boolean;
|
|
62
42
|
/**
|
|
63
43
|
* Run the dispatch with the LEAD's idle watchdog paused, `try/finally` inside.
|
|
64
44
|
*
|
package/dist/team/task-tool.js
CHANGED
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
* `normalizeSubagentSpecs`, which is deterministic and unit-tested. `maxItems`
|
|
20
20
|
* in the schema would behave differently depending on whether `ajv`, an OPTIONAL
|
|
21
21
|
* dependency of core, happened to install.
|
|
22
|
+
*
|
|
23
|
+
* EVERY CHILD RUNS THE LEAD'S OWN MODEL (main-agent parity): same provider,
|
|
24
|
+
* model, thinking level and token ambition, resolved from the LIVE config at
|
|
25
|
+
* dispatch. There is no per-child `model` property and no cheap tier to pick -
|
|
26
|
+
* a delegation is never a downgrade, and the fast tier reaches children the
|
|
27
|
+
* same way it reaches the lead (compaction summaries, per-child reviews).
|
|
22
28
|
*/
|
|
23
29
|
import { errorResult, textResult } from '@aragon-agent/core';
|
|
24
30
|
import { TEAM_LIMITS } from './limits.js';
|
|
@@ -33,7 +39,8 @@ const TEAM_OFF_REFUSAL = 'Team mode is off for this session. Do this work yourse
|
|
|
33
39
|
*/
|
|
34
40
|
const TASK_DESCRIPTION = 'Run several independent subagents in parallel and get one combined report. Each ' +
|
|
35
41
|
'subagent is a fresh agent with the same tools and working directory but NO memory of ' +
|
|
36
|
-
'this conversation - its prompt must be self-contained.
|
|
42
|
+
'this conversation - its prompt must be self-contained. Each runs on the same model ' +
|
|
43
|
+
'you are running on. Use this when a task splits ' +
|
|
37
44
|
'into 2 or more parts that do not depend on each other\'s output, especially reading or ' +
|
|
38
45
|
'searching several areas at once. Do NOT use it when one part needs another part\'s ' +
|
|
39
46
|
'result (do those yourself, in order), when two parts would edit the same file, or for ' +
|
|
@@ -41,37 +48,11 @@ const TASK_DESCRIPTION = 'Run several independent subagents in parallel and get
|
|
|
41
48
|
'cannot ask the user anything. Give each a description of at most ' +
|
|
42
49
|
`${TEAM_LIMITS.descriptionChars} characters and a complete prompt. Extra entries beyond the ` +
|
|
43
50
|
'configured maximum are dropped, so keep within it.';
|
|
44
|
-
/**
|
|
45
|
-
* The one sentence appended when the fast tier exists (fast-model-tier §4.1).
|
|
46
|
-
*
|
|
47
|
-
* WHEN to use a tier is POLICY and lives here and in `<fast_tier>`, where the
|
|
48
|
-
* model actually reads it; the `enum` below is SHAPE and lives in the schema.
|
|
49
|
-
* That split is what keeps behaviour the same whether or not `ajv` — an OPTIONAL
|
|
50
|
-
* dependency of core — happened to install (C-8).
|
|
51
|
-
*/
|
|
52
|
-
const TASK_FAST_SENTENCE = ' Set model:"fast" on a subagent whose job is bulk reading, searching or summarizing; ' +
|
|
53
|
-
'leave it out for work that needs judgement.';
|
|
54
|
-
/**
|
|
55
|
-
* NOT `as const`: `AgentTool.parameters` is a `JSONSchema7`, whose `enum` is a
|
|
56
|
-
* MUTABLE `unknown[]`, and a readonly tuple is not assignable to it.
|
|
57
|
-
*/
|
|
58
|
-
const SUBAGENT_MODEL_PROPERTY = {
|
|
59
|
-
type: 'string',
|
|
60
|
-
enum: ['main', 'fast'],
|
|
61
|
-
default: 'main',
|
|
62
|
-
description: 'Which tier runs this subagent. "fast" is a cheaper, quicker model - use it for ' +
|
|
63
|
-
'mechanical, high-volume work (reading or searching many files, summarizing long ' +
|
|
64
|
-
'output, mechanical edits). Keep "main" for design, tricky debugging, and anything ' +
|
|
65
|
-
'that must be right the first time.',
|
|
66
|
-
};
|
|
67
51
|
export function createTaskTool(deps) {
|
|
68
|
-
const fastRegistered = deps.fastRegistered === true;
|
|
69
52
|
return {
|
|
70
53
|
name: 'task',
|
|
71
54
|
label: 'Dispatch subagents',
|
|
72
|
-
|
|
73
|
-
// default session's description is the exact string it always was.
|
|
74
|
-
description: fastRegistered ? `${TASK_DESCRIPTION}${TASK_FAST_SENTENCE}` : TASK_DESCRIPTION,
|
|
55
|
+
description: TASK_DESCRIPTION,
|
|
75
56
|
parameters: {
|
|
76
57
|
type: 'object',
|
|
77
58
|
properties: {
|
|
@@ -99,11 +80,6 @@ export function createTaskTool(deps) {
|
|
|
99
80
|
default: false,
|
|
100
81
|
description: 'Refuse all writes and shell for this subagent.',
|
|
101
82
|
},
|
|
102
|
-
// Spread rather than a `?:` property, so with the tier off the
|
|
103
|
-
// object has exactly the four keys it always had — `undefined`
|
|
104
|
-
// survives `JSON.stringify` as an absent key but not as an
|
|
105
|
-
// identical object, and AC-3 is asserted on the schema itself.
|
|
106
|
-
...(fastRegistered ? { model: SUBAGENT_MODEL_PROPERTY } : {}),
|
|
107
83
|
},
|
|
108
84
|
required: ['description', 'prompt'],
|
|
109
85
|
},
|
|
@@ -131,31 +107,21 @@ export function createTaskTool(deps) {
|
|
|
131
107
|
'yourself, or ask the user to set a key.');
|
|
132
108
|
}
|
|
133
109
|
// 4. Repair, never reject. Zero survivors is the single hard failure.
|
|
134
|
-
|
|
135
|
-
// construction (RV-3): the tier can stop resolving mid-session, and the
|
|
136
|
-
// normalizer and the subagent factory must agree about that at the same
|
|
137
|
-
// instant or a child gets built against a provider with no key.
|
|
138
|
-
const { specs, requested, downgraded } = normalizeSubagentSpecs(params.subagents, deps.maxSubagents(), { fastAvailable: deps.fastAvailable?.() === true });
|
|
110
|
+
const { specs, requested } = normalizeSubagentSpecs(params.subagents, deps.maxSubagents());
|
|
139
111
|
if (specs.length === 0) {
|
|
140
112
|
return errorResult('No usable subagent specs: each needs a description and a prompt.');
|
|
141
113
|
}
|
|
142
114
|
// 5. Pause the lead's watchdog for the whole dispatch (I-3).
|
|
143
|
-
const outcome = await deps.withPausedWatchdog(() => deps.runtime.dispatch(specs, requested, ctx.signal
|
|
115
|
+
const outcome = await deps.withPausedWatchdog(() => deps.runtime.dispatch(specs, requested, ctx.signal));
|
|
144
116
|
// 6. ALWAYS A NON-ERROR RESULT, abort and all-children-failed included.
|
|
145
117
|
// A cancellation or a partial result rendered as a tool FAILURE invites
|
|
146
118
|
// the model to retry the whole fan-out, which is the most expensive
|
|
147
119
|
// possible reaction (the same reasoning as `ask_user`'s cancelled
|
|
148
|
-
// shape, and D-14 one level up).
|
|
149
|
-
//
|
|
150
|
-
// price is not a rounding error: for a Haiku child under a Sonnet lead
|
|
151
|
-
// it over-reports by roughly an order of magnitude, and the whole
|
|
152
|
-
// justification for the feature is a number in this report.
|
|
120
|
+
// shape, and D-14 one level up). Every child ran the lead's own model,
|
|
121
|
+
// so the lead's cost table is the one honest price for the total.
|
|
153
122
|
const cost = deps.modelCost();
|
|
154
|
-
const fastCost = deps.fastModelCost?.();
|
|
155
123
|
return textResult(buildDispatchReport(outcome, {
|
|
156
124
|
...(cost ? { cost } : {}),
|
|
157
|
-
...(fastCost ? { fastCost } : {}),
|
|
158
|
-
...(deps.fastPricingUnknown?.() ? { fastPricingUnknown: true } : {}),
|
|
159
125
|
}));
|
|
160
126
|
},
|
|
161
127
|
};
|
package/dist/team/types.d.ts
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
* changes ZERO files under `packages/core/` (AC-12).
|
|
12
12
|
*/
|
|
13
13
|
import type { TokenUsage } from '@aragon-agent/core';
|
|
14
|
-
import type { FastTierName } from '../fast/types.js';
|
|
15
14
|
import type { ActivityArgs } from './activity.js';
|
|
16
15
|
/** One normalized delegation request. Produced only by `normalizeSubagentSpecs`. */
|
|
17
16
|
export interface SubagentSpec {
|
|
@@ -27,34 +26,12 @@ export interface SubagentSpec {
|
|
|
27
26
|
* permission than the session it was spawned from.
|
|
28
27
|
*/
|
|
29
28
|
readOnly: boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Which model runs this child (fast-model-tier §3.4).
|
|
32
|
-
*
|
|
33
|
-
* THE WIRE NAME IS `model` AND THE INTERNAL NAME IS `tier`, on purpose: a
|
|
34
|
-
* model expects to see `model:"fast"`, while `SubagentSpec.model` would read
|
|
35
|
-
* as a model ID at every call site in this package.
|
|
36
|
-
*
|
|
37
|
-
* DELEGATION IS A MODEL CHOICE, NEVER A PERMISSION BOUNDARY (D-15 / I-4). A
|
|
38
|
-
* fast child gets the same tools, the same `--confirm` gate, the same
|
|
39
|
-
* plan-mode gate and the same skills ceiling as any other; only the model
|
|
40
|
-
* differs. Restricting a fast child's tools would look like security, would
|
|
41
|
-
* not be, and would make the report's `[fast]` rows mean two different things.
|
|
42
|
-
*/
|
|
43
|
-
tier: FastTierName;
|
|
44
29
|
}
|
|
45
30
|
export type SubagentPhase = 'queued' | 'starting' | 'thinking' | 'tool' | 'waiting' | 'done' | 'failed' | 'aborted';
|
|
46
31
|
/** Live, mutable record of one child. Projected into the UI and the report. */
|
|
47
32
|
export interface SubagentRun {
|
|
48
33
|
label: string;
|
|
49
34
|
description: string;
|
|
50
|
-
/**
|
|
51
|
-
* The tier this child actually ran on (fast-model-tier §3.4).
|
|
52
|
-
*
|
|
53
|
-
* WHAT RAN, NOT WHAT WAS ASKED FOR. A spec the normalizer downgraded arrives
|
|
54
|
-
* here as `'main'`, which is what makes the report's `[fast]` annotation and
|
|
55
|
-
* its second cost table agree with the bill.
|
|
56
|
-
*/
|
|
57
|
-
tier: FastTierName;
|
|
58
35
|
phase: SubagentPhase;
|
|
59
36
|
startedAt?: number;
|
|
60
37
|
endedAt?: number;
|
|
@@ -192,26 +169,11 @@ export interface DispatchOutcome {
|
|
|
192
169
|
/** Messages addressed to `lead`; surfaced in their own report section. */
|
|
193
170
|
leadMail: TeamMessage[];
|
|
194
171
|
/**
|
|
195
|
-
* Summed across
|
|
196
|
-
* (§3.9).
|
|
197
|
-
*
|
|
198
|
-
* THE MEANING NARROWED WHEN THE FAST TIER LANDED, and the split is not a
|
|
199
|
-
* rounding concern: a Haiku child under a Sonnet lead priced at the lead's
|
|
200
|
-
* table over-reports by roughly an order of magnitude, and the entire
|
|
201
|
-
* justification for delegating is a number in this report (R-7).
|
|
172
|
+
* Summed across all children. Real spend; it must reach the status bar
|
|
173
|
+
* (§3.9). Every child runs the LEAD's model (main-agent parity), so one
|
|
174
|
+
* total priced at the lead's table is the honest accounting.
|
|
202
175
|
*/
|
|
203
176
|
usage: TokenUsage;
|
|
204
|
-
/** Summed across FAST-TIER children. Absent when none ran, which is what
|
|
205
|
-
* keeps a pre-feature dispatch's report byte-identical. */
|
|
206
|
-
fastUsage?: TokenUsage;
|
|
207
|
-
/**
|
|
208
|
-
* Specs that asked for `model:"fast"` and ran on `main` anyway (§3.4 / R-6).
|
|
209
|
-
*
|
|
210
|
-
* REPORTED, NEVER SILENT. A silent downgrade means the model asked for a cheap
|
|
211
|
-
* child, got an expensive one, and has no way to learn that its cost model is
|
|
212
|
-
* wrong.
|
|
213
|
-
*/
|
|
214
|
-
downgraded?: number;
|
|
215
177
|
}
|
|
216
178
|
/**
|
|
217
179
|
* What the UI renders: a cheap immutable projection, rebuilt per event.
|
|
@@ -246,7 +208,6 @@ export type TeamEvent = {
|
|
|
246
208
|
dispatchId: string;
|
|
247
209
|
label: string;
|
|
248
210
|
usage: TokenUsage;
|
|
249
|
-
tier: FastTierName;
|
|
250
211
|
} | {
|
|
251
212
|
type: 'message';
|
|
252
213
|
dispatchId: string;
|
package/dist/ui/App.js
CHANGED
|
@@ -662,10 +662,9 @@ export function App({ controller, version, initialOverlay, initialPrompt, confir
|
|
|
662
662
|
// so it closes over the `cfg` object of the render it mounted in, and
|
|
663
663
|
// `setModel` builds a NEW one.
|
|
664
664
|
const live = controller.getConfig();
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
: { providerId: live.provider, modelId: live.model };
|
|
665
|
+
// Every child runs the lead's own model (main-agent parity), so the
|
|
666
|
+
// lead's live connection IS the tier that billed.
|
|
667
|
+
const ref = { providerId: live.provider, modelId: live.model };
|
|
669
668
|
// Unknown pricing contributes ZERO rather than a fabricated figure
|
|
670
669
|
// (C-11 / RV-4); `/fast status` and the dispatch report say `unknown`.
|
|
671
670
|
const costDelta = controller.isPricedModel(ref)
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { Box, Text } from 'ink';
|
|
5
5
|
export function BottomStatusRow({ plan, columns, theme }) {
|
|
6
|
-
const tones = { normal: theme.primary, muted: theme.muted, warning: theme.noticeWarn, error: theme.noticeError
|
|
6
|
+
const tones = { normal: theme.primary, muted: theme.muted, warning: theme.noticeWarn, error: theme.noticeError,
|
|
7
|
+
accent: theme.accent };
|
|
7
8
|
return _jsxs(Box, { height: 1, width: columns, flexShrink: 0, overflow: "hidden", children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { children: " " }) }), plan.fields.map((field, index) => _jsxs(React.Fragment, { children: [index > 0 && _jsx(Box, { width: plan.separatorCells, flexShrink: 0, children: _jsx(Text, { color: theme.muted, children: plan.separator }) }), _jsx(Box, { width: field.cells, flexShrink: 0, children: _jsx(Text, { wrap: "truncate", color: tones[field.tone], children: field.text }) })] }, field.id))] });
|
|
8
9
|
}
|
package/dist/ui/StatusBar.js
CHANGED
|
@@ -27,7 +27,8 @@ export function StatusBar(props) {
|
|
|
27
27
|
ecoRung: props.ecoRung, fastActive: props.fastActive, scrolledLines: props.scrolledLines,
|
|
28
28
|
});
|
|
29
29
|
const tones = { normal: props.theme.primary, muted: props.theme.muted,
|
|
30
|
-
warning: props.theme.noticeWarn, error: props.theme.noticeError
|
|
30
|
+
warning: props.theme.noticeWarn, error: props.theme.noticeError,
|
|
31
|
+
accent: props.theme.accent };
|
|
31
32
|
return _jsxs(Box, { width: cols, height: 1, flexShrink: 0, flexDirection: "row", overflow: "hidden", children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { children: redrawChar(props.redrawNonce ?? 0) }) }), plan.fields.map((item, index) => _jsxs(React.Fragment, { children: [index > 0 && _jsx(Box, { width: plan.separatorCells, flexShrink: 0, children: _jsx(Text, { color: props.theme.muted, children: plan.separator }) }), _jsx(Box, { width: item.cells, flexShrink: 0, children: _jsx(Text, { color: tones[item.tone], wrap: "truncate", children: item.id === 'phase' && active
|
|
32
33
|
? _jsxs(_Fragment, { children: [spinner ?? glyph, item.text.slice(glyph.length)] })
|
|
33
34
|
: item.text }) })] }, item.id))] });
|
package/dist/ui/TeamPanel.js
CHANGED
|
@@ -130,7 +130,7 @@ export function TeamPanel({ snapshot, rows, cols, reducedMotion, theme, caps, no
|
|
|
130
130
|
// `reducedMotion` and a non-Unicode terminal fall back to the same
|
|
131
131
|
// static marker, exactly as `AssistantEntry` and `ToolCard` already do.
|
|
132
132
|
const animate = isRunning(run) && !reducedMotion && caps.unicode;
|
|
133
|
-
return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: color, children: [' ', animate ? _jsx(Spinner, { type: "dots" }) : marker(run, glyphs), ' '] }), _jsx(Text, { color: theme.primary, children:
|
|
133
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: color, children: [' ', animate ? _jsx(Spinner, { type: "dots" }) : marker(run, glyphs), ' '] }), _jsx(Text, { color: theme.primary, children: run.label.padEnd(8).slice(0, 8) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { wrap: "truncate", color: theme.muted, children: run.description.replace(/\s+/g, ' ') }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: color, children: [' ', activityLine(run, cols)] }) }), _jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', run.startedAt ? formatDuration(Math.max(0, (run.endedAt ?? at) - run.startedAt)) : ''] })] }, run.label));
|
|
134
134
|
}), hiddenTotal > 0 && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', "+", hiddenTotal, " more", hiddenRunning > 0 ? ` (${hiddenRunning} running)` : ''] })), snapshot.lastMessage && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', glyphs.teamMail, " ", snapshot.lastMessage.from, " ", glyphs.arrowRight, " ", snapshot.lastMessage.to, ": ", snapshot.lastMessage.subject.replace(/\s+/g, ' ')] }))] }));
|
|
135
135
|
}
|
|
136
136
|
function marker(run, glyphs) {
|
|
@@ -48,12 +48,7 @@ function TeamCardImpl(props) {
|
|
|
48
48
|
: `${formatDuration(durationMs ?? 0)} (${ok} ok, ${failed} failed)`;
|
|
49
49
|
const count = `${runs.length} ${runs.length === 1 ? 'subagent' : 'subagents'}`;
|
|
50
50
|
const dropped = requested > runs.length ? ` (${runs.length} of ${requested} requested)` : '';
|
|
51
|
-
|
|
52
|
-
// (fast-model-tier §6). `n fast` rather than a ratio: the total is already one
|
|
53
|
-
// column to the left.
|
|
54
|
-
const fastCount = runs.filter((r) => r.tier === 'fast').length;
|
|
55
|
-
const fastNote = fastCount > 0 ? ` ${fastCount} fast` : '';
|
|
56
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: theme.accent, bold: true, children: "team" }), _jsxs(Text, { color: theme.muted, children: [' ', count, dropped, fastNote, ' '] }), active && !reducedMotion && caps.unicode ? (_jsxs(Text, { color: color, children: [_jsx(Spinner, { type: "dots" }), " ", headline] })) : (_jsxs(Text, { color: color, children: [active ? `${glyphs.spinnerStill} ` : '', headline] }))] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, paddingLeft: 1, ...railBorderProps(glyphs.railVertical, theme.border), children: [runs.map((run) => (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: isOk(run) ? theme.toolDone : theme.toolError, children: isOk(run) ? glyphs.toolDone : glyphs.toolError }), _jsxs(Text, { color: theme.primary, children: [' ', `${run.label}${run.tier === 'fast' ? '~' : ''}`.padEnd(8).slice(0, 8)] }), _jsxs(Text, { color: theme.muted, children: [' ', run.description, ' ', run.startedAt ? formatDuration(Math.max(0, (run.endedAt ?? 0) - run.startedAt)) : '', ` ${run.turns} turns`, run.filesTouched.length > 0 ? ` ${run.filesTouched.length} files` : '', run.error ? ` ${run.error}` : ''] }), run.retry && (_jsxs(Text, { color: theme.noticeWarn, bold: true, children: [' ', "retry ", run.retry.attempt, "/", run.retry.maxRetries] }))] }, run.label))), expanded &&
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: theme.accent, bold: true, children: "team" }), _jsxs(Text, { color: theme.muted, children: [' ', count, dropped, ' '] }), active && !reducedMotion && caps.unicode ? (_jsxs(Text, { color: color, children: [_jsx(Spinner, { type: "dots" }), " ", headline] })) : (_jsxs(Text, { color: color, children: [active ? `${glyphs.spinnerStill} ` : '', headline] }))] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, paddingLeft: 1, ...railBorderProps(glyphs.railVertical, theme.border), children: [runs.map((run) => (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: isOk(run) ? theme.toolDone : theme.toolError, children: isOk(run) ? glyphs.toolDone : glyphs.toolError }), _jsxs(Text, { color: theme.primary, children: [' ', run.label.padEnd(8).slice(0, 8)] }), _jsxs(Text, { color: theme.muted, children: [' ', run.description, ' ', run.startedAt ? formatDuration(Math.max(0, (run.endedAt ?? 0) - run.startedAt)) : '', ` ${run.turns} turns`, run.filesTouched.length > 0 ? ` ${run.filesTouched.length} files` : '', run.error ? ` ${run.error}` : ''] }), run.retry && (_jsxs(Text, { color: theme.noticeWarn, bold: true, children: [' ', "retry ", run.retry.attempt, "/", run.retry.maxRetries] }))] }, run.label))), expanded &&
|
|
57
52
|
runs.map((run) => (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: theme.accent, children: [run.label, " ", glyphs.midDot, " ", run.description] }), _jsx(Text, { color: theme.muted, children: run.summary ?? '(no summary)' })] }, `s-${run.label}`))), !expanded && !active && runs.length > 0 && (_jsxs(Text, { color: theme.muted, children: ["+", runs.length, " ", runs.length === 1 ? 'summary' : 'summaries', " (Ctrl+O)"] })), expanded && _jsx(Text, { color: theme.muted, children: "(Ctrl+O to collapse)" })] })] }));
|
|
58
53
|
}
|
|
59
54
|
/**
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { formatCost, formatTokens, promptTokensOf } from '../../agent/usage.js';
|
|
2
2
|
import { actionCandidates, clipStatusText, escapeClause } from '../interaction-hints.js';
|
|
3
|
+
import { MODE_LABEL } from '../../agent/agent-mode.js';
|
|
3
4
|
import { statusField, statusLinePlan, validContext } from './status-layout.js';
|
|
5
|
+
/**
|
|
6
|
+
* Uppercase mode word for the details row, mirroring the primary row's field:
|
|
7
|
+
* same vocabulary (`MODE_LABEL`), same `CUR>PENDING` deferred-switch shape.
|
|
8
|
+
*/
|
|
9
|
+
function detailModeText(mode, pendingMode) {
|
|
10
|
+
const word = (value) => MODE_LABEL[value] ?? value.toUpperCase();
|
|
11
|
+
if (pendingMode)
|
|
12
|
+
return `${word(mode || 'build')}>${word(pendingMode)}`;
|
|
13
|
+
return word(mode || 'build');
|
|
14
|
+
}
|
|
4
15
|
export function planStatusDetail(input) {
|
|
5
16
|
const { status, hints } = input;
|
|
6
17
|
const budget = Math.max(0, Math.floor(status.columns) - 1);
|
|
@@ -26,8 +37,7 @@ export function planStatusDetail(input) {
|
|
|
26
37
|
if (status.servicesActive?.live)
|
|
27
38
|
add(statusField('services', 'Svc' + status.servicesActive.live));
|
|
28
39
|
if (status.mode || status.pendingMode)
|
|
29
|
-
add(statusField('mode', status.pendingMode
|
|
30
|
-
? (status.mode ?? 'build') + '>' + status.pendingMode : status.mode));
|
|
40
|
+
add(statusField('mode', detailModeText(status.mode, status.pendingMode), 'accent'));
|
|
31
41
|
if (validContext(status.context)) {
|
|
32
42
|
const approximate = status.context.source === 'estimate' || status.context.deltaTokens > 0 ? '~' : '';
|
|
33
43
|
add(statusField('context', 'Context ' + approximate + formatTokens(status.context.occupied)
|
|
@@ -25,6 +25,7 @@ export interface StatusLayoutInput {
|
|
|
25
25
|
max: number;
|
|
26
26
|
secondsLeft: number;
|
|
27
27
|
};
|
|
28
|
+
/** Named on the primary row in EVERY mode - the §6.4 guarantee, restored. */
|
|
28
29
|
mode?: string;
|
|
29
30
|
pendingMode?: string | null;
|
|
30
31
|
servicesActive?: {
|
|
@@ -54,7 +55,8 @@ export interface StatusField {
|
|
|
54
55
|
id: string;
|
|
55
56
|
text: string;
|
|
56
57
|
cells: number;
|
|
57
|
-
|
|
58
|
+
/** 'accent' carries the mode word - the row's one always-on emphasis. */
|
|
59
|
+
tone: 'normal' | 'muted' | 'warning' | 'error' | 'accent';
|
|
58
60
|
}
|
|
59
61
|
export interface StatusLinePlan {
|
|
60
62
|
fields: readonly StatusField[];
|
|
@@ -68,5 +70,5 @@ export declare function statusLinePlan(fields: readonly StatusField[], separator
|
|
|
68
70
|
export declare function phaseLabels(input: Pick<StatusLayoutInput, 'phase' | 'activeTool' | 'runOutcome' | 'waitingForConfirmation' | 'stopping' | 'compacting' | 'retryActive'>): readonly [string, string];
|
|
69
71
|
export declare function validContext(context: ContextUsageSnapshot): boolean;
|
|
70
72
|
export declare function shortDuration(ms: number): string;
|
|
71
|
-
/**
|
|
73
|
+
/** Every field survives each width rung; only the redraw carrier is outside this plan. */
|
|
72
74
|
export declare function planPrimaryStatusFields(input: StatusPrimaryInput): StatusLinePlan;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import stringWidth from 'string-width';
|
|
2
2
|
import stripAnsi from 'strip-ansi';
|
|
3
3
|
import { formatDuration } from '../../agent/usage.js';
|
|
4
|
+
import { MODE_LABEL } from '../../agent/agent-mode.js';
|
|
4
5
|
import { interactionCopy as copy } from '../interaction-copy.js';
|
|
5
6
|
export function cleanStatusText(text) {
|
|
6
7
|
// eslint-disable-next-line no-control-regex
|
|
@@ -89,7 +90,27 @@ function feedbackLabel(input, form) {
|
|
|
89
90
|
return labels[feedback.kind][form === 'full' ? 0 : form === 'short' ? 1 : 2];
|
|
90
91
|
}
|
|
91
92
|
const thinkingCodes = { off: 'O', minimal: 'N', low: 'L', medium: 'M', high: 'H', xhigh: 'X' };
|
|
92
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* The mode word for the primary row: full rungs name the mode with
|
|
95
|
+
* `MODE_LABEL`, tight rungs keep only its first letter, and a deferred switch
|
|
96
|
+
* renders `CUR>PENDING` in both tiers. `null` when the caller names no mode at
|
|
97
|
+
* all, so callers and tests that predate the field keep a byte-identical plan.
|
|
98
|
+
* The word must survive every width rung: the border color cannot be the only
|
|
99
|
+
* mode signal the default view carries (plan-mode P1-6).
|
|
100
|
+
*/
|
|
101
|
+
function modeFieldText(mode, pendingMode, full) {
|
|
102
|
+
if (!mode && !pendingMode)
|
|
103
|
+
return null;
|
|
104
|
+
const word = (value) => {
|
|
105
|
+
const label = MODE_LABEL[value];
|
|
106
|
+
if (!label)
|
|
107
|
+
return full ? value.toUpperCase() : (value[0] ?? '?').toUpperCase();
|
|
108
|
+
return full ? label : label[0];
|
|
109
|
+
};
|
|
110
|
+
const current = word(mode || 'build');
|
|
111
|
+
return pendingMode ? `${current}>${word(pendingMode)}` : current;
|
|
112
|
+
}
|
|
113
|
+
/** Every field survives each width rung; only the redraw carrier is outside this plan. */
|
|
93
114
|
export function planPrimaryStatusFields(input) {
|
|
94
115
|
const budget = Math.max(0, (Number.isFinite(input.columns) ? Math.floor(input.columns) : 80) - 1);
|
|
95
116
|
const labels = phaseLabels(input);
|
|
@@ -104,8 +125,10 @@ export function planPrimaryStatusFields(input) {
|
|
|
104
125
|
const full = rung === 0;
|
|
105
126
|
const label = feedbackLabel(input, full ? 'full' : rung >= 4 ? 'tiny' : 'short')
|
|
106
127
|
?? (full ? labels[1] : rung >= 4 ? labels[0].slice(0, 4) : labels[0]);
|
|
128
|
+
const modeText = modeFieldText(input.mode, input.pendingMode, full);
|
|
107
129
|
return statusLinePlan([
|
|
108
130
|
statusField('phase', glyph + (rung >= 5 ? '' : ' ') + label, tone),
|
|
131
|
+
...(modeText ? [statusField('mode', modeText, 'accent')] : []),
|
|
109
132
|
statusField('context', (full ? 'Context ' : 'C') + pct),
|
|
110
133
|
statusField('thinking', full ? 'Think ' + (thinkingCodes[input.thinkingLevel] ? input.thinkingLevel : '?')
|
|
111
134
|
: (rung >= 2 ? '' : 'Th:') + code),
|
|
@@ -31,6 +31,7 @@ function keyRows(times) {
|
|
|
31
31
|
['Drag right edge', 'Scroll messages; input stays fixed; type to return to newest output'],
|
|
32
32
|
['Bottom rows', 'Fixed input, one status row; Ctrl+G adds one detail row'],
|
|
33
33
|
['C / Th / t/s', 'Context percent / thinking level / run-average output tokens per second'],
|
|
34
|
+
['B / P / P>B', 'Status-row mode word: BUILD / PLAN; CUR>PENDING = switch deferred to run end'],
|
|
34
35
|
['O/N/L/M/H/X', 'Thinking: off/minimal/low/medium/high/xhigh'],
|
|
35
36
|
['~ / ? / --', 'Estimated context / unknown context / unavailable output speed'],
|
|
36
37
|
['Output speed', 'Main Agent reported output tokens / total run time, including tools and waits'],
|
|
@@ -40,7 +41,6 @@ function keyRows(times) {
|
|
|
40
41
|
['Ctrl+C (with a selection)', 'Copy the pending selection - does not arm exit'],
|
|
41
42
|
['Native terminal selection', 'Copy-on-select is controlled by your terminal settings'],
|
|
42
43
|
['Queue / /queue', 'Pending receipt; /queue opens full text, PgUp/PgDn pages, Esc closes'],
|
|
43
|
-
['plan>build / build>plan', 'A mode switch pending until the current run ends'],
|
|
44
44
|
['/bg / /todo status', 'Show full service and TODO counts when status fields are hidden'],
|
|
45
45
|
['Queue paused', 'Unreceived messages persist after interruption until accepted or cancelled'],
|
|
46
46
|
['Up / Down', 'Prompt history (empty input)'],
|
|
@@ -113,7 +113,6 @@ const FAST_ROWS = [
|
|
|
113
113
|
['/fast model <id>', 'Set the fast model; accepts provider:model'],
|
|
114
114
|
['/fast same', 'Run the fast tier on the main model'],
|
|
115
115
|
['/fast review <n> | off', 'Turns between automatic reviews, or turn them off'],
|
|
116
|
-
['/fast delegate on | off', 'Allow model:"fast" on task subagents'],
|
|
117
116
|
['--fast / --no-fast', 'Start a session with the tier on or off (also ARAGON_FAST=1)'],
|
|
118
117
|
['<fast_review>', 'An automated second opinion from the fast model - advice, not the user'],
|
|
119
118
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
4
4
|
"description": "AragonAgent CLI — a Claude-Code / Codex-style interactive terminal UI (TUI) on top of the @aragon-agent/core engine. Installable and runnable via npm / npx.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AragonAgent contributors",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"prepublishOnly": "npm run build"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@aragon-agent/core": "^0.2.
|
|
59
|
+
"@aragon-agent/core": "^0.2.29",
|
|
60
60
|
"chalk": "^5.6.2",
|
|
61
61
|
"cli-highlight": "^2.0.0",
|
|
62
62
|
"commander": "^12.1.0",
|