@ian-pascoe/pi-minimal-subagents 0.15.0 → 0.17.0
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 +9 -7
- package/package.json +6 -6
- package/src/minimal-subagents-config.ts +65 -53
- package/src/minimal-subagents-context.ts +1 -1
- package/src/minimal-subagents-coordinator.ts +1 -1
- package/src/minimal-subagents-extension.ts +58 -19
- package/src/minimal-subagents-render-contract.ts +4 -1
- package/src/minimal-subagents-rendering.ts +214 -193
- package/src/minimal-subagents-settings-writer.ts +22 -36
- package/src/minimal-subagents-status-panel.ts +93 -69
- package/src/minimal-subagents-tools.ts +46 -15
- package/src/minimal-subagents-transcript.ts +16 -11
- package/src/minimal-subagents-ui.ts +51 -154
- package/src/minimal-subagents-usage.ts +30 -0
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ filter in `~/.pi/agent/settings.json` using the repository-relative path:
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
From this package checkout, load the source directly with
|
|
32
|
-
`pi -e ./src/index.ts`. Requires Node `>=22.19.0` and Pi `>=
|
|
32
|
+
`pi -e ./src/index.ts`. Requires Node `>=22.19.0` and Pi `>=1.1.0`.
|
|
33
33
|
|
|
34
34
|
## Typical workflow
|
|
35
35
|
|
|
@@ -276,10 +276,10 @@ creation; reloading does not silently broaden them. The default maximum depth
|
|
|
276
276
|
is two levels beneath the interactive Root Agent.
|
|
277
277
|
|
|
278
278
|
The extension registers six coordinator tools for the Root Agent and fanout
|
|
279
|
-
children: `subagent`, `agent_message`, `subagent_wait`, `subagent_status`,
|
|
280
|
-
`subagent_cancel`, and `subagent_delete`.
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
children below the depth cap: `subagent`, `agent_message`, `subagent_wait`, `subagent_status`,
|
|
280
|
+
`subagent_cancel`, and `subagent_delete`. Children that cannot spawn (delegation
|
|
281
|
+
`none`, or fanout at the depth cap) have no children to wait on or inspect, so they
|
|
282
|
+
receive only `agent_message`.
|
|
283
283
|
|
|
284
284
|
A running child's `latest_activity_at` advances with the timestamps of its latest
|
|
285
285
|
messages and tool results. Targeted `subagent_status` includes `recent_activity`, a bounded tail of message
|
|
@@ -288,7 +288,9 @@ assistant message but omits image data. Timeout Wait Events carry only a compact
|
|
|
288
288
|
progress snapshot. Children target only direct children; the Root Agent
|
|
289
289
|
may inspect any descendant. Model-facing status reports a `child_count` but no
|
|
290
290
|
nested `children` summaries. Reported `usage` always includes `cacheWrite1h`
|
|
291
|
-
and `reasoning`, as `0` when the provider reports none.
|
|
291
|
+
and `reasoning`, as `0` when the provider reports none. Tool-result text and
|
|
292
|
+
`structuredContent` round every `usage.cost` field to six decimal places of USD;
|
|
293
|
+
exact values stay in session data. `subagent_cancel`
|
|
292
294
|
lists in `affected_agent_ids` only agents whose active turns it cancelled.
|
|
293
295
|
|
|
294
296
|
`session_context` defaults to `omit`: the child starts with only its system
|
|
@@ -435,7 +437,7 @@ with Pi's tool-expansion hint (normally Ctrl+O), which reveals the rest and the
|
|
|
435
437
|
full detail. Automatic agent results and messages preview the same way.
|
|
436
438
|
|
|
437
439
|
In TUI mode, `/subagents` or `/subagents status` opens a large, centered,
|
|
438
|
-
|
|
440
|
+
overlay in Pi's selector frame. Up/Down selects a Child Agent; Enter opens its Child Session
|
|
439
441
|
Transcript. Escape returns to the tree, then Escape closes the overlay. The
|
|
440
442
|
viewer is read-only: Root Agent input and ongoing agent work remain intact.
|
|
441
443
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ian-pascoe/pi-minimal-subagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Persistent nested subagents with bounded delegation for Pi",
|
|
6
6
|
"keywords": [
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"provenance": true
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ian-pascoe/pi-utils": "^0.
|
|
34
|
+
"@ian-pascoe/pi-utils": "^0.5.0",
|
|
35
35
|
"minimatch": "^10.2.6"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@earendil-works/pi-agent-core": ">=
|
|
39
|
-
"@earendil-works/pi-ai": ">=
|
|
40
|
-
"@earendil-works/pi-coding-agent": ">=
|
|
41
|
-
"@earendil-works/pi-tui": ">=
|
|
38
|
+
"@earendil-works/pi-agent-core": ">=1.1.0",
|
|
39
|
+
"@earendil-works/pi-ai": ">=1.1.0",
|
|
40
|
+
"@earendil-works/pi-coding-agent": ">=1.1.0",
|
|
41
|
+
"@earendil-works/pi-tui": ">=1.1.0",
|
|
42
42
|
"typebox": "*"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import {
|
|
3
|
+
type LayeredSettingScope,
|
|
4
|
+
resolveLayeredOptions,
|
|
5
|
+
} from "@ian-pascoe/pi-utils/layered-settings";
|
|
2
6
|
import { Minimatch } from "minimatch";
|
|
3
7
|
import { type Static, Type } from "typebox";
|
|
4
8
|
import { Value } from "typebox/value";
|
|
@@ -224,29 +228,28 @@ function readMinimalSubagentsSettings(
|
|
|
224
228
|
return {};
|
|
225
229
|
}
|
|
226
230
|
|
|
231
|
+
/** Merge one scope's model roles into those of lower scopes, entry by entry. */
|
|
227
232
|
function mergeModelRoleEntries(
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
current: ReadonlyMap<string, ScopedSettingValue>,
|
|
234
|
+
value: ModelRolesWireValue,
|
|
235
|
+
source: LayeredSettingScope,
|
|
230
236
|
warnings: string[],
|
|
231
237
|
): Map<string, ScopedSettingValue> {
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
} else if (globalValue?.kind === "invalid") {
|
|
238
|
-
warnings.push("global minimalSubagents.modelRoles: expected an object or null");
|
|
238
|
+
if (value.kind === "reset") return new Map();
|
|
239
|
+
if (value.kind === "invalid") {
|
|
240
|
+
warnings.push(`${source} minimalSubagents.modelRoles: expected an object or null`);
|
|
241
|
+
return new Map(current);
|
|
239
242
|
}
|
|
240
|
-
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
|
|
243
|
+
const entries = new Map(current);
|
|
244
|
+
if (source === "global") {
|
|
245
|
+
for (const [name, roleValue] of value.entries) {
|
|
246
|
+
entries.set(name, { scope: "global", value: roleValue });
|
|
247
|
+
}
|
|
244
248
|
return entries;
|
|
245
249
|
}
|
|
246
|
-
if (projectValue.kind !== "entries") return entries;
|
|
247
250
|
|
|
248
|
-
for (const [name,
|
|
249
|
-
if (
|
|
251
|
+
for (const [name, roleValue] of value.entries) {
|
|
252
|
+
if (roleValue.kind === "delete") {
|
|
250
253
|
entries.delete(name);
|
|
251
254
|
continue;
|
|
252
255
|
}
|
|
@@ -254,9 +257,9 @@ function mergeModelRoleEntries(
|
|
|
254
257
|
const mergedValue =
|
|
255
258
|
inherited !== undefined &&
|
|
256
259
|
isExpandedModelRoleWireValue(inherited) &&
|
|
257
|
-
isExpandedModelRoleWireValue(
|
|
258
|
-
? parseModelRoleWireValue({ ...inherited.fields, ...
|
|
259
|
-
:
|
|
260
|
+
isExpandedModelRoleWireValue(roleValue)
|
|
261
|
+
? parseModelRoleWireValue({ ...inherited.fields, ...roleValue.fields })
|
|
262
|
+
: roleValue;
|
|
260
263
|
entries.set(name, { scope: "project", value: mergedValue });
|
|
261
264
|
}
|
|
262
265
|
return entries;
|
|
@@ -380,26 +383,24 @@ function resolveSubagentAccessSettings(
|
|
|
380
383
|
};
|
|
381
384
|
}
|
|
382
385
|
|
|
383
|
-
function
|
|
384
|
-
|
|
385
|
-
|
|
386
|
+
function mergeMaxSubagentDepth(
|
|
387
|
+
current: number,
|
|
388
|
+
value: MaxSubagentDepthWireValue,
|
|
389
|
+
source: LayeredSettingScope,
|
|
386
390
|
warnings: string[],
|
|
387
391
|
): number {
|
|
388
|
-
|
|
389
|
-
if (
|
|
390
|
-
resolvedDepth = globalValue.value;
|
|
391
|
-
} else if (globalValue?.kind === "invalid") {
|
|
392
|
-
warnings.push(
|
|
393
|
-
"global minimalSubagents.maxSubagentDepth: expected a positive safe integer or null",
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
if (projectValue === undefined) return resolvedDepth;
|
|
397
|
-
if (projectValue.kind === "reset") return DEFAULT_MAX_SUBAGENT_DEPTH;
|
|
398
|
-
if (projectValue.kind === "depth") return projectValue.value;
|
|
392
|
+
if (value.kind === "reset") return DEFAULT_MAX_SUBAGENT_DEPTH;
|
|
393
|
+
if (value.kind === "depth") return value.value;
|
|
399
394
|
warnings.push(
|
|
400
|
-
|
|
395
|
+
`${source} minimalSubagents.maxSubagentDepth: expected a positive safe integer or null`,
|
|
401
396
|
);
|
|
402
|
-
return
|
|
397
|
+
return current;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Settings resolved across scopes, before model role references are checked. */
|
|
401
|
+
interface MergedMinimalSubagentsSettings extends MinimalSubagentsToolsets {
|
|
402
|
+
maxSubagentDepth: number;
|
|
403
|
+
modelRoles: Map<string, ScopedSettingValue>;
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
/** Resolve trusted global and project settings into validated subagent guidance and limits. */
|
|
@@ -412,28 +413,39 @@ export function resolveMinimalSubagentsConfig(
|
|
|
412
413
|
input.projectTrusted === false
|
|
413
414
|
? {}
|
|
414
415
|
: readMinimalSubagentsSettings(input.projectSettings, "project", warnings);
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
416
|
+
const { settings } = resolveLayeredOptions<
|
|
417
|
+
ParsedMinimalSubagentsSettings,
|
|
418
|
+
MergedMinimalSubagentsSettings
|
|
419
|
+
>({
|
|
420
|
+
defaults: {
|
|
421
|
+
maxSubagentDepth: DEFAULT_MAX_SUBAGENT_DEPTH,
|
|
422
|
+
modelRoles: new Map(),
|
|
423
|
+
baseToolset: [...DEFAULT_TOOLSETS.baseToolset],
|
|
424
|
+
readToolset: [...DEFAULT_TOOLSETS.readToolset],
|
|
425
|
+
modifyToolset: [...DEFAULT_TOOLSETS.modifyToolset],
|
|
426
|
+
},
|
|
427
|
+
// Depth warnings precede model role warnings, as each key merges across scopes in turn.
|
|
428
|
+
optionKeys: ["maxSubagentDepth", "modelRoles", "baseToolset", "readToolset", "modifyToolset"],
|
|
429
|
+
layers: [
|
|
430
|
+
["global", globalConfig],
|
|
431
|
+
["project", projectConfig],
|
|
432
|
+
],
|
|
433
|
+
merge: {
|
|
434
|
+
maxSubagentDepth: (current, value, source) =>
|
|
435
|
+
mergeMaxSubagentDepth(current, value, source, warnings),
|
|
436
|
+
modelRoles: (current, value, source) =>
|
|
437
|
+
mergeModelRoleEntries(current, value, source, warnings),
|
|
438
|
+
},
|
|
439
|
+
});
|
|
425
440
|
|
|
426
441
|
return {
|
|
427
|
-
maxSubagentDepth,
|
|
442
|
+
maxSubagentDepth: settings.maxSubagentDepth,
|
|
428
443
|
subagentAccess: resolveSubagentAccessSettings(globalConfig.enabled, projectConfig.enabled),
|
|
429
|
-
modelRoles: parseModelRoles(
|
|
444
|
+
modelRoles: parseModelRoles(settings.modelRoles, input.eligibleModelIds, warnings),
|
|
430
445
|
toolsets: {
|
|
431
|
-
baseToolset:
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
globalConfig.readToolset ?? [...DEFAULT_TOOLSETS.readToolset],
|
|
435
|
-
modifyToolset: projectConfig.modifyToolset ??
|
|
436
|
-
globalConfig.modifyToolset ?? [...DEFAULT_TOOLSETS.modifyToolset],
|
|
446
|
+
baseToolset: settings.baseToolset,
|
|
447
|
+
readToolset: settings.readToolset,
|
|
448
|
+
modifyToolset: settings.modifyToolset,
|
|
437
449
|
},
|
|
438
450
|
warnings,
|
|
439
451
|
};
|
|
@@ -353,7 +353,7 @@ export function buildSubagentSystemPrompt(
|
|
|
353
353
|
): string {
|
|
354
354
|
const coordinatorBoundary = options.canSpawn
|
|
355
355
|
? "Coordinator tools support subagent, agent_message, subagent_wait, subagent_status, subagent_cancel, and subagent_delete. Wait, status, cancel, and delete target direct children only; recursive cancel and delete may affect a child's subtree."
|
|
356
|
-
: "Coordinator tools support agent_message
|
|
356
|
+
: "Coordinator tools support only agent_message; you have no children to wait on or inspect.";
|
|
357
357
|
const delegationBoundary = options.canSpawn
|
|
358
358
|
? [
|
|
359
359
|
"You have explicit fanout responsibility for this assigned task.",
|
|
@@ -370,7 +370,7 @@ export class MinimalSubagentsCoordinator {
|
|
|
370
370
|
this.dependencies.notify?.({
|
|
371
371
|
type: "tool-warning",
|
|
372
372
|
agentId,
|
|
373
|
-
message: `
|
|
373
|
+
message: `Tool warnings for ${agentId}:\n- ${warnings.join("\n- ")}`,
|
|
374
374
|
});
|
|
375
375
|
}
|
|
376
376
|
this.dependencies.notify?.({
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type TurnEndEvent,
|
|
21
21
|
} from "@earendil-works/pi-coding-agent";
|
|
22
22
|
import { isKeyRelease, isKeyRepeat, matchesKey } from "@earendil-works/pi-tui";
|
|
23
|
+
import { expandMessageOnClick, noticeText } from "@ian-pascoe/pi-utils/ui";
|
|
23
24
|
import {
|
|
24
25
|
createSubagentAccessBranchRecord,
|
|
25
26
|
reconcileCoordinatorToolAccess,
|
|
@@ -247,7 +248,10 @@ function reportInvalidRegistryRecords(
|
|
|
247
248
|
.map(({ entry_index: entryIndex, code }) => `entry ${entryIndex}: ${code}`)
|
|
248
249
|
.join(", ");
|
|
249
250
|
context.ui.notify(
|
|
250
|
-
|
|
251
|
+
noticeText(
|
|
252
|
+
"Subagents",
|
|
253
|
+
`Registry ignored ${diagnostics.length} invalid active-branch record${diagnostics.length === 1 ? "" : "s"} (${summaries}${diagnostics.length > 3 ? ", ..." : ""}).`,
|
|
254
|
+
),
|
|
251
255
|
"warning",
|
|
252
256
|
);
|
|
253
257
|
};
|
|
@@ -342,7 +346,10 @@ async function rebindForkAgents(
|
|
|
342
346
|
const message = error instanceof Error ? error.message : String(error);
|
|
343
347
|
failedSubtrees.add(agent.agent_id);
|
|
344
348
|
agents.push(unavailableForkAgent(agent, message));
|
|
345
|
-
context.ui.notify(
|
|
349
|
+
context.ui.notify(
|
|
350
|
+
noticeText("Subagents", `${options.notifyLabel} for ${agent.agent_id}: ${message}`),
|
|
351
|
+
"error",
|
|
352
|
+
);
|
|
346
353
|
}
|
|
347
354
|
}
|
|
348
355
|
return agents;
|
|
@@ -410,7 +417,10 @@ function reportInvalidSubagentAccessRecords(
|
|
|
410
417
|
): (diagnostics: SubagentAccessReplayDiagnostic[]) => void {
|
|
411
418
|
return (diagnostics) => {
|
|
412
419
|
context.ui.notify(
|
|
413
|
-
|
|
420
|
+
noticeText(
|
|
421
|
+
"Subagents",
|
|
422
|
+
`Ignored ${diagnostics.length} invalid Subagent Access branch record${diagnostics.length === 1 ? "" : "s"}.`,
|
|
423
|
+
),
|
|
414
424
|
"warning",
|
|
415
425
|
);
|
|
416
426
|
};
|
|
@@ -545,11 +555,18 @@ export class MinimalSubagentsLifecycleController {
|
|
|
545
555
|
schemas: createCoordinatorToolSchemas([]),
|
|
546
556
|
captureCaller: (context) => rootCallerSnapshot(this.pi, context),
|
|
547
557
|
onActivity: () => this.uiController?.refresh(),
|
|
548
|
-
onAttention: (message) =>
|
|
558
|
+
onAttention: (message) =>
|
|
559
|
+
this.accessSession?.context.ui.notify(noticeText("Subagents", message), "error"),
|
|
549
560
|
});
|
|
550
561
|
for (const tool of rootTools) this.pi.registerTool(tool);
|
|
551
|
-
this.pi.registerMessageRenderer(
|
|
552
|
-
|
|
562
|
+
this.pi.registerMessageRenderer(
|
|
563
|
+
"minimal-subagents.message",
|
|
564
|
+
expandMessageOnClick(renderMinimalSubagentsMessage),
|
|
565
|
+
);
|
|
566
|
+
this.pi.registerMessageRenderer(
|
|
567
|
+
"minimal-subagents.result",
|
|
568
|
+
expandMessageOnClick(renderMinimalSubagentsResult),
|
|
569
|
+
);
|
|
553
570
|
this.pi.registerCommand("subagents", {
|
|
554
571
|
description: "Control Subagent Access and inspect Child Agents",
|
|
555
572
|
getArgumentCompletions: completeSubagentsCommandArguments,
|
|
@@ -587,7 +604,10 @@ export class MinimalSubagentsLifecycleController {
|
|
|
587
604
|
).override;
|
|
588
605
|
if (minimalSubagentsConfig.warnings.length > 0) {
|
|
589
606
|
context.ui.notify(
|
|
590
|
-
|
|
607
|
+
noticeText(
|
|
608
|
+
"Subagents",
|
|
609
|
+
`Configuration warnings:\n- ${minimalSubagentsConfig.warnings.join("\n- ")}`,
|
|
610
|
+
),
|
|
591
611
|
"warning",
|
|
592
612
|
);
|
|
593
613
|
}
|
|
@@ -648,7 +668,7 @@ export class MinimalSubagentsLifecycleController {
|
|
|
648
668
|
callerId,
|
|
649
669
|
childContext.sessionManager.getLeafId() ?? callerId,
|
|
650
670
|
),
|
|
651
|
-
onAttention: (message) => context.ui.notify(message, "error"),
|
|
671
|
+
onAttention: (message) => context.ui.notify(noticeText("Subagents", message), "error"),
|
|
652
672
|
});
|
|
653
673
|
},
|
|
654
674
|
});
|
|
@@ -665,7 +685,11 @@ export class MinimalSubagentsLifecycleController {
|
|
|
665
685
|
notify: (notification) => {
|
|
666
686
|
this.uiController?.refresh();
|
|
667
687
|
if (shouldSurfaceNotification(notification)) {
|
|
668
|
-
|
|
688
|
+
const level = notificationLevel(notification);
|
|
689
|
+
context.ui.notify(
|
|
690
|
+
level === "info" ? notification.message : noticeText("Subagents", notification.message),
|
|
691
|
+
level,
|
|
692
|
+
);
|
|
669
693
|
}
|
|
670
694
|
},
|
|
671
695
|
});
|
|
@@ -679,7 +703,10 @@ export class MinimalSubagentsLifecycleController {
|
|
|
679
703
|
if (forkSnapshot?.source_root_session_id !== sourceRootSessionId) {
|
|
680
704
|
if (forkSnapshot) {
|
|
681
705
|
context.ui.notify(
|
|
682
|
-
|
|
706
|
+
noticeText(
|
|
707
|
+
"Subagents",
|
|
708
|
+
"Fork handoff rejected because its source root identity did not match.",
|
|
709
|
+
),
|
|
683
710
|
"error",
|
|
684
711
|
);
|
|
685
712
|
}
|
|
@@ -705,7 +732,10 @@ export class MinimalSubagentsLifecycleController {
|
|
|
705
732
|
);
|
|
706
733
|
} else {
|
|
707
734
|
context.ui.notify(
|
|
708
|
-
|
|
735
|
+
noticeText(
|
|
736
|
+
"Subagents",
|
|
737
|
+
"Fork recovery skipped because the destination selected branch could not be proven from parentSession provenance.",
|
|
738
|
+
),
|
|
709
739
|
"warning",
|
|
710
740
|
);
|
|
711
741
|
}
|
|
@@ -733,7 +763,7 @@ export class MinimalSubagentsLifecycleController {
|
|
|
733
763
|
schemas,
|
|
734
764
|
captureCaller: (toolContext) => rootCallerSnapshot(this.pi, toolContext),
|
|
735
765
|
onActivity: () => this.uiController?.refresh(),
|
|
736
|
-
onAttention: (message) => context.ui.notify(message, "error"),
|
|
766
|
+
onAttention: (message) => context.ui.notify(noticeText("Subagents", message), "error"),
|
|
737
767
|
});
|
|
738
768
|
for (const tool of rootTools) this.pi.registerTool(tool);
|
|
739
769
|
this.accessSession = {
|
|
@@ -760,7 +790,10 @@ export class MinimalSubagentsLifecycleController {
|
|
|
760
790
|
|
|
761
791
|
if (hasHistoricalChildIdentity(context.sessionManager.getBranch())) {
|
|
762
792
|
context.ui.notify(
|
|
763
|
-
|
|
793
|
+
noticeText(
|
|
794
|
+
"Subagents",
|
|
795
|
+
"Opened a former subagent session directly. It is now an independent root; former descendants and parent messaging were not restored. Concurrent ownership by its original root is unsupported.",
|
|
796
|
+
),
|
|
764
797
|
"warning",
|
|
765
798
|
);
|
|
766
799
|
}
|
|
@@ -828,11 +861,11 @@ export class MinimalSubagentsLifecycleController {
|
|
|
828
861
|
private async runSubagentsCommand(args: string, context: ExtensionCommandContext): Promise<void> {
|
|
829
862
|
const parsed = parseSubagentsCommandArguments(args);
|
|
830
863
|
if (!parsed.ok) {
|
|
831
|
-
context.ui.notify(parsed.message, "error");
|
|
864
|
+
context.ui.notify(noticeText("Subagents", parsed.message), "error");
|
|
832
865
|
return;
|
|
833
866
|
}
|
|
834
867
|
if (!this.accessSession || !this.coordinator) {
|
|
835
|
-
context.ui.notify("
|
|
868
|
+
context.ui.notify(noticeText("Subagents", "Not active for this session."), "error");
|
|
836
869
|
return;
|
|
837
870
|
}
|
|
838
871
|
if (parsed.command.action === "status") {
|
|
@@ -861,7 +894,10 @@ export class MinimalSubagentsLifecycleController {
|
|
|
861
894
|
command.action === "reset" ? undefined : command.action === "enable",
|
|
862
895
|
);
|
|
863
896
|
} catch (error) {
|
|
864
|
-
context.ui.notify(
|
|
897
|
+
context.ui.notify(
|
|
898
|
+
noticeText("Subagents", error instanceof Error ? error.message : String(error)),
|
|
899
|
+
"error",
|
|
900
|
+
);
|
|
865
901
|
return;
|
|
866
902
|
}
|
|
867
903
|
persistedScope = command.scope;
|
|
@@ -885,9 +921,12 @@ export class MinimalSubagentsLifecycleController {
|
|
|
885
921
|
} catch (error) {
|
|
886
922
|
const detail = error instanceof Error ? error.message : String(error);
|
|
887
923
|
context.ui.notify(
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
924
|
+
noticeText(
|
|
925
|
+
"Subagents",
|
|
926
|
+
persistedScope
|
|
927
|
+
? `${persistedScope} default changed, but the current session did not: ${detail}`
|
|
928
|
+
: `Could not change the current session: ${detail}`,
|
|
929
|
+
),
|
|
891
930
|
"error",
|
|
892
931
|
);
|
|
893
932
|
return;
|
|
@@ -272,7 +272,10 @@ const CoordinatorWaitSourceOutputSchema = {
|
|
|
272
272
|
source_turn_id: Type.String(),
|
|
273
273
|
};
|
|
274
274
|
|
|
275
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* Final details schemas exposed to CodeMode for the six coordinator tools. `structuredContent`
|
|
277
|
+
* matches them with every `usage.cost` field rounded for presentation.
|
|
278
|
+
*/
|
|
276
279
|
export const CoordinatorToolOutputSchemas = {
|
|
277
280
|
subagent: Type.Object({
|
|
278
281
|
agent_id: Type.String(),
|