pi-subagents 0.66.0 → 0.68.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.
Files changed (172) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/README.md +5 -4
  3. package/agents/evidence-auditor.md +34 -0
  4. package/agents/reviewer.md +3 -2
  5. package/docs/agents.md +43 -15
  6. package/docs/configuration.md +67 -23
  7. package/docs/extension-api.md +38 -19
  8. package/docs/missions.md +10 -2
  9. package/docs/models.md +11 -79
  10. package/docs/observability.md +22 -12
  11. package/docs/standalone-background.md +59 -0
  12. package/docs/tool-reference.md +33 -20
  13. package/docs/watchdog.md +39 -10
  14. package/docs/workflows.md +37 -13
  15. package/index.ts +5 -2
  16. package/inspector-runner.mjs +2 -2
  17. package/package.json +4 -2
  18. package/prompts/parallel-review.md +1 -1
  19. package/runner-peer-loader.mjs +24 -0
  20. package/runner-peer-preload.mjs +32 -0
  21. package/skills/pi-subagents/SKILL.md +32 -21
  22. package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
  23. package/skills/pi-subagents/references/execution-controls.md +11 -9
  24. package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
  25. package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
  26. package/skills/pi-subagents/references/prompting-and-roles.md +17 -13
  27. package/skills/pi-subagents/references/review-and-validation.md +3 -3
  28. package/src/agents/advertised-agent-prompt.ts +34 -3
  29. package/src/agents/agent-management.ts +57 -58
  30. package/src/agents/agent-serializer.ts +4 -3
  31. package/src/agents/agents.ts +190 -71
  32. package/src/agents/builtin-names.ts +1 -0
  33. package/src/agents/chain-serializer.ts +5 -0
  34. package/src/agents/runtime-agent-registry.ts +7 -6
  35. package/src/api/delegation.ts +4 -0
  36. package/src/api/preflight.ts +94 -59
  37. package/src/api/required-child-extensions.ts +6 -0
  38. package/src/api/shared-types.ts +2 -0
  39. package/src/extension/config.ts +10 -37
  40. package/src/extension/fanout-child.ts +66 -4
  41. package/src/extension/herdr-pi-bridge.ts +160 -0
  42. package/src/extension/index.ts +62 -39
  43. package/src/extension/public-execution.ts +7 -5
  44. package/src/extension/rpc.ts +4 -0
  45. package/src/extension/schemas.ts +81 -81
  46. package/src/extension/tool-description.ts +30 -82
  47. package/src/inspectors/actions.ts +148 -0
  48. package/src/inspectors/ghostty/actions.ts +74 -0
  49. package/src/inspectors/ghostty/plugin.ts +17 -0
  50. package/src/inspectors/herdr/actions.ts +99 -179
  51. package/src/inspectors/herdr/plugin.ts +20 -0
  52. package/src/inspectors/herdr/project-panes.ts +1 -1
  53. package/src/inspectors/{herdr/inspector-runner.ts → inspector-runner.ts} +12 -12
  54. package/src/inspectors/plugins.ts +8 -0
  55. package/src/inspectors/{herdr/session-roots-codec.ts → session-roots-codec.ts} +3 -14
  56. package/src/inspectors/types.ts +51 -0
  57. package/src/intercom/intercom-bridge.ts +50 -8
  58. package/src/intercom/native-supervisor-channel.ts +44 -31
  59. package/src/policy/authority.ts +4 -0
  60. package/src/profiles/profiles.ts +12 -6
  61. package/src/runs/background/active-async-capacity.ts +4 -0
  62. package/src/runs/background/active-run-index.ts +17 -1
  63. package/src/runs/background/async-execution.ts +348 -176
  64. package/src/runs/background/async-job-tracker.ts +8 -6
  65. package/src/runs/background/async-resume.ts +17 -12
  66. package/src/runs/background/async-status.ts +15 -4
  67. package/src/runs/background/auto-drain.ts +23 -10
  68. package/src/runs/background/binary-bootstrap.ts +38 -0
  69. package/src/runs/background/chain-append.ts +1 -1
  70. package/src/runs/background/chain-root-attachment.ts +14 -33
  71. package/src/runs/background/fleet-view.ts +30 -2
  72. package/src/runs/background/notify.ts +105 -7
  73. package/src/runs/background/owned-process-tree.ts +29 -2
  74. package/src/runs/background/result-files.ts +8 -4
  75. package/src/runs/background/result-watcher.ts +19 -2
  76. package/src/runs/background/run-child-session.ts +81 -33
  77. package/src/runs/background/run-status.ts +3 -0
  78. package/src/runs/background/runner-aliases.ts +12 -33
  79. package/src/runs/background/runner-child-launch.ts +6 -1
  80. package/src/runs/background/runner-child-sessions.ts +5 -4
  81. package/src/runs/background/runner-http-dispatcher.ts +119 -0
  82. package/src/runs/background/scheduled-runs.ts +51 -18
  83. package/src/runs/background/stale-run-reconciler.ts +35 -11
  84. package/src/runs/background/steering.ts +20 -2
  85. package/src/runs/background/subagent-runner.ts +441 -304
  86. package/src/runs/background/subagent-wait.ts +176 -28
  87. package/src/runs/background/wait-completions.ts +75 -27
  88. package/src/runs/background/wait-subscriptions.ts +9 -3
  89. package/src/runs/background/wait-tool.ts +5 -3
  90. package/src/runs/foreground/async-steering-action.ts +18 -7
  91. package/src/runs/foreground/async-stop-action.ts +93 -3
  92. package/src/runs/foreground/execution.ts +134 -248
  93. package/src/runs/foreground/foreground-history.ts +2 -1
  94. package/src/runs/foreground/prompt-audit.ts +3 -1
  95. package/src/runs/foreground/subagent-executor.ts +374 -178
  96. package/src/runs/foreground/workflow-detach-reconcile.ts +2 -0
  97. package/src/runs/foreground/workflow-foreground-steering.ts +2 -1
  98. package/src/runs/shared/acceptance.ts +38 -11
  99. package/src/runs/shared/async-status-projection.ts +127 -33
  100. package/src/runs/shared/capability-ceiling.ts +2 -0
  101. package/src/runs/shared/child-hooks.ts +25 -10
  102. package/src/runs/shared/child-launch-plan.ts +15 -3
  103. package/src/runs/shared/child-launch.ts +28 -5
  104. package/src/runs/shared/child-lifecycle.ts +6 -3
  105. package/src/runs/shared/child-runtime-config.ts +8 -1
  106. package/src/runs/shared/child-session.ts +127 -52
  107. package/src/runs/shared/child-tool-plan.ts +142 -11
  108. package/src/runs/shared/completion-guard.ts +5 -3
  109. package/src/runs/shared/dynamic-fanout.ts +2 -2
  110. package/src/runs/shared/effective-system-prompt.ts +33 -0
  111. package/src/runs/shared/external-cli-contract.ts +11 -1
  112. package/src/runs/shared/external-cli-preflight.ts +6 -2
  113. package/src/runs/shared/external-cli-runner.ts +9 -7
  114. package/src/runs/shared/herdr-connection.ts +134 -0
  115. package/src/runs/shared/herdr-external-adapters.ts +169 -0
  116. package/src/runs/shared/herdr-machine.ts +279 -0
  117. package/src/runs/shared/herdr-pi-protocol.ts +59 -0
  118. package/src/runs/shared/herdr-placed-run.ts +263 -0
  119. package/src/runs/shared/llm-intent-arbiter.ts +12 -3
  120. package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
  121. package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -235
  122. package/src/runs/shared/model-scope.ts +1 -1
  123. package/src/runs/shared/nested-events.ts +11 -2
  124. package/src/runs/shared/orca-progress-tabs.ts +1 -1
  125. package/src/runs/shared/parallel-utils.ts +7 -2
  126. package/src/runs/shared/pi-spawn.ts +10 -0
  127. package/src/runs/shared/subagent-prompt-runtime.ts +12 -4
  128. package/src/runs/shared/task-intent.ts +46 -13
  129. package/src/runs/shared/workflow-async-child-guidance.ts +18 -0
  130. package/src/runs/shared/worktree-setup-command.ts +27 -4
  131. package/src/runs/shared/worktree.ts +45 -15
  132. package/src/shared/child-cache-retention.ts +43 -0
  133. package/src/shared/fork-context.ts +15 -72
  134. package/src/shared/launch-contract.ts +68 -8
  135. package/src/shared/opencode-session-headers.ts +30 -0
  136. package/src/shared/pruned-fork.ts +1 -1
  137. package/src/shared/required-child-extensions.ts +81 -0
  138. package/src/shared/settings.ts +5 -2
  139. package/src/shared/shortcuts.ts +0 -4
  140. package/src/shared/types.ts +74 -30
  141. package/src/slash/delegation-adapters.ts +3 -1
  142. package/src/slash/delegation-request.ts +14 -0
  143. package/src/slash/slash-commands.ts +2 -7
  144. package/src/slash/subagents-admin.ts +24 -13
  145. package/src/tui/fleet-status.ts +164 -19
  146. package/src/tui/fleet.ts +16 -14
  147. package/src/tui/render.ts +168 -37
  148. package/src/watchdog/child-status.ts +28 -28
  149. package/src/watchdog/lsp-diagnostics.ts +1 -1
  150. package/src/watchdog/model-selection.ts +21 -1
  151. package/src/watchdog/permission-arbiter.ts +3 -1
  152. package/src/watchdog/register-child.ts +10 -2
  153. package/src/watchdog/register-main.ts +39 -35
  154. package/src/watchdog/render.ts +1 -1
  155. package/src/watchdog/review.ts +123 -74
  156. package/src/watchdog/rules.ts +1 -1
  157. package/src/watchdog/runtime.ts +100 -27
  158. package/src/watchdog/scope.ts +1 -1
  159. package/src/watchdog/settings.ts +3 -0
  160. package/src/watchdog/tool-actions.ts +13 -12
  161. package/src/watchdog/turn-delta.ts +23 -0
  162. package/src/watchdog/types.ts +5 -3
  163. package/src/watchdog/warning-format.ts +1 -1
  164. package/src/workflows/scripted-workflow.ts +279 -10
  165. package/src/workflows/workflow-checklist.ts +2 -2
  166. package/src/workflows/workflow-receipt.ts +21 -3
  167. package/src/workflows/workflow-resources.ts +13 -2
  168. package/runner-server-preload.mjs +0 -13
  169. package/src/runs/shared/model-exclusions.ts +0 -374
  170. package/src/runs/shared/readonly-model-continuation.ts +0 -69
  171. package/src/runs/shared/readonly-session-evidence.ts +0 -307
  172. /package/src/inspectors/{herdr/shell-command.ts → shell-command.ts} +0 -0
@@ -0,0 +1,81 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+
4
+ const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
5
+ const MAX_REQUIRED_EXTENSIONS = 32;
6
+ const MAX_PATH_BYTES = 4096;
7
+ const EMPTY_SNAPSHOT: RequiredChildExtensionSnapshot = Object.freeze([]);
8
+
9
+ export interface RequiredChildExtension {
10
+ /** Safe host-owned identity exposed in launch evidence. */
11
+ id: string;
12
+ /** Existing importable module path. Snapshotted to its canonical absolute path. */
13
+ path: string;
14
+ }
15
+
16
+ export interface RegisterRequiredChildExtensionsInput {
17
+ sessionId: string;
18
+ extensions: readonly RequiredChildExtension[];
19
+ }
20
+
21
+ export interface RequiredChildExtensionRegistration { dispose(): void }
22
+ export type RequiredChildExtensionSnapshot = ReadonlyArray<Readonly<RequiredChildExtension>>;
23
+
24
+ /** Validate and freeze a snapshot; registration canonicalizes once, while retained launches preserve that identity. */
25
+ export function snapshotRequiredChildExtensions(value: unknown, label = "Required child extensions", canonicalizeFiles = false): RequiredChildExtensionSnapshot {
26
+ if (!Array.isArray(value) || value.length > MAX_REQUIRED_EXTENSIONS) throw new Error(`${label} must be an array of at most ${MAX_REQUIRED_EXTENSIONS} entries.`);
27
+ const ids = new Set<string>();
28
+ const paths = new Set<string>();
29
+ return Object.freeze(value.map((entry, index) => {
30
+ if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).some((key) => key !== "id" && key !== "path")) throw new Error(`${label} entry ${index} requires only id and path.`);
31
+ const id = "id" in entry ? entry.id : undefined;
32
+ const rawPath = "path" in entry ? entry.path : undefined;
33
+ if (typeof id !== "string" || !ID_PATTERN.test(id)) throw new Error(`${label} entry ${index} requires a safe id of at most 128 characters.`);
34
+ if (ids.has(id)) throw new Error(`${label} id '${id}' is duplicated.`);
35
+ if (typeof rawPath !== "string" || !rawPath.trim() || rawPath.includes("\0") || Buffer.byteLength(rawPath, "utf8") > MAX_PATH_BYTES || (!canonicalizeFiles && !path.isAbsolute(rawPath))) throw new Error(`${label} '${id}' requires ${canonicalizeFiles ? "a" : "an absolute"} non-empty path of at most ${MAX_PATH_BYTES} bytes without NUL.`);
36
+ let extensionPath = rawPath;
37
+ if (canonicalizeFiles) {
38
+ try {
39
+ extensionPath = fs.realpathSync(path.resolve(rawPath));
40
+ if (!fs.statSync(extensionPath).isFile()) throw new Error("not a file");
41
+ } catch (error) {
42
+ throw new Error(`${label} '${id}' is not an importable file: ${error instanceof Error ? error.message : String(error)}`);
43
+ }
44
+ }
45
+ if (paths.has(extensionPath)) throw new Error(`${label} path '${extensionPath}' is duplicated.`);
46
+ ids.add(id);
47
+ paths.add(extensionPath);
48
+ return Object.freeze({ id, path: extensionPath });
49
+ }));
50
+ }
51
+
52
+ interface Registry { version: 1; bySession: Map<string, RequiredChildExtensionSnapshot> }
53
+
54
+ function registry(): Registry {
55
+ const key = Symbol.for("pi-subagents.required-child-extensions.v1");
56
+ const root = globalThis as Record<PropertyKey, unknown>;
57
+ const existing = root[key];
58
+ if (existing === undefined) {
59
+ const created: Registry = { version: 1, bySession: new Map() };
60
+ root[key] = created;
61
+ return created;
62
+ }
63
+ if (!existing || typeof existing !== "object" || !("version" in existing) || existing.version !== 1 || !("bySession" in existing) || !(existing.bySession instanceof Map)) throw new Error("Malformed or unsupported required child extension registry.");
64
+ return { version: 1, bySession: existing.bySession };
65
+ }
66
+
67
+ /** Register one immutable host-required extension snapshot for a parent session. */
68
+ export function registerRequiredChildExtensions(input: RegisterRequiredChildExtensionsInput): RequiredChildExtensionRegistration {
69
+ if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).some((key) => key !== "sessionId" && key !== "extensions")) throw new Error("Required child extension registration requires only sessionId and extensions.");
70
+ if (typeof input.sessionId !== "string" || !input.sessionId || input.sessionId.trim() !== input.sessionId || input.sessionId.length > 256 || input.sessionId.includes("\0")) throw new Error("Required child extension registration requires a non-empty trimmed sessionId of at most 256 characters without NUL.");
71
+ const frozen = snapshotRequiredChildExtensions(input.extensions, "Required child extensions", true);
72
+ const store = registry();
73
+ if (store.bySession.has(input.sessionId)) throw new Error(`Required child extensions are already registered for session '${input.sessionId}'; dispose them first.`);
74
+ store.bySession.set(input.sessionId, frozen);
75
+ return { dispose() { if (store.bySession.get(input.sessionId) === frozen) store.bySession.delete(input.sessionId); } };
76
+ }
77
+
78
+ export function resolveRequiredChildExtensions(sessionId: string | undefined): RequiredChildExtensionSnapshot {
79
+ if (!sessionId) return EMPTY_SNAPSHOT;
80
+ return registry().bySession.get(sessionId) ?? EMPTY_SNAPSHOT;
81
+ }
@@ -32,8 +32,9 @@ export interface SequentialStep {
32
32
  phase?: string;
33
33
  label?: string;
34
34
  as?: string;
35
- outputSchema?: JsonSchemaObject;
35
+ outputSchema?: JsonSchemaObject | false;
36
36
  cwd?: string;
37
+ machine?: string;
37
38
  output?: OutputOverrideInput;
38
39
  outputMode?: OutputMode;
39
40
  reads?: string[] | false;
@@ -56,8 +57,9 @@ export interface ParallelTaskItem {
56
57
  phase?: string;
57
58
  label?: string;
58
59
  as?: string;
59
- outputSchema?: JsonSchemaObject;
60
+ outputSchema?: JsonSchemaObject | false;
60
61
  cwd?: string;
62
+ machine?: string;
61
63
  count?: number;
62
64
  output?: OutputOverrideInput;
63
65
  outputMode?: OutputMode;
@@ -110,6 +112,7 @@ export interface ParallelStep {
110
112
  failFast?: boolean;
111
113
  worktree?: boolean;
112
114
  cwd?: string;
115
+ machine?: string;
113
116
  agentContract?: AgentContract;
114
117
  gateOn?: ChainGateLayer;
115
118
  }
@@ -1,7 +1,3 @@
1
- import { Key, type KeyId } from "@earendil-works/pi-tui";
2
-
3
- export const FLEET_OPEN_SHORTCUT: KeyId = Key.ctrlAlt("f");
4
-
5
1
  export function formatShortcutLabel(shortcut: string): string {
6
2
  return shortcut
7
3
  .split("+")
@@ -16,6 +16,7 @@ import type { GlobalMissionIndexRecord, MissionRecord, MissionStoreConfig } from
16
16
  import type { ExtensionBindings } from "../runs/shared/extension-bindings.ts";
17
17
  import type { WorkflowChildPermitContext } from "./workflow-child-permit.ts";
18
18
  import type { WatchdogWarningDetails } from "../watchdog/types.ts";
19
+ import type { RequiredChildExtensionSnapshot } from "./required-child-extensions.ts";
19
20
 
20
21
  // ============================================================================
21
22
  // Basic Types
@@ -230,6 +231,7 @@ export interface WorkflowReceipt {
230
231
  state: WorkflowReceiptState;
231
232
  createdAt: number;
232
233
  entries: Record<string, WorkflowReceiptEntry>;
234
+ argsDigest?: string;
233
235
  resource?: WorkflowResourceProvenance;
234
236
  hostSteps?: HostStepNode[];
235
237
  workflowChildren?: WorkflowChildSummary;
@@ -655,6 +657,12 @@ export type ProcessTreeTerminal =
655
657
  processGroupId: number;
656
658
  verifiedAt: number;
657
659
  }
660
+ | {
661
+ state: "observed";
662
+ mechanism: "windows-taskkill";
663
+ pid: number;
664
+ verifiedAt: number;
665
+ }
658
666
  | {
659
667
  state: "unknown";
660
668
  reason: "unsupported-platform" | "signal-failed" | "verification-failed";
@@ -708,6 +716,7 @@ export type ProcessTerminal =
708
716
  export interface ScheduleOrigin {
709
717
  id: string;
710
718
  name?: string;
719
+ quiet?: boolean;
711
720
  }
712
721
 
713
722
  export type SteeringActionState = "delivered" | "scheduled" | "pending" | "partial" | "recovered" | "failed";
@@ -799,6 +808,7 @@ export interface SteeringRecoveryDescriptor {
799
808
  version: 1;
800
809
  launchContractDigest?: string;
801
810
  extensionBindings?: ExtensionBindings;
811
+ requiredExtensions?: RequiredChildExtensionSnapshot;
802
812
  runFanoutBudget: RunFanoutBudgetDescriptor;
803
813
  sourceRunId: string;
804
814
  agentContract?: AgentContract;
@@ -811,7 +821,6 @@ export interface SteeringRecoveryDescriptor {
811
821
  modelProvider?: string;
812
822
  modelOverrideFromParent?: boolean;
813
823
  modelOrigin?: "explicit" | "inherited" | "configured";
814
- fallbackModels?: string[];
815
824
  fast?: boolean;
816
825
  thinking?: string;
817
826
  thinkingCeiling?: ThinkingLevel;
@@ -915,7 +924,7 @@ export interface SubagentResultIntercomPayload {
915
924
  // Progress Tracking
916
925
  // ============================================================================
917
926
 
918
- export interface ChildWatchdogWarningSummary extends Pick<WatchdogWarningDetails, "severity" | "category" | "summary" | "evidence" | "recommendedAction" | "displayedAt"> {
927
+ export interface ChildWatchdogWarningSummary extends Pick<WatchdogWarningDetails, "severity" | "importance" | "category" | "summary" | "evidence" | "recommendedAction" | "displayedAt"> {
919
928
  /** True when a later assistant turn in the child followed the warning. */
920
929
  addressed: boolean;
921
930
  stalemate: boolean;
@@ -992,14 +1001,6 @@ interface ProgressSummary {
992
1001
  // Results
993
1002
  // ============================================================================
994
1003
 
995
- export interface ModelAttempt {
996
- model: string;
997
- success: boolean;
998
- exitCode?: number | null;
999
- error?: string;
1000
- usage?: Usage;
1001
- }
1002
-
1003
1004
  export type AcceptanceLevel = "auto" | "none" | "attested" | "checked" | "verified";
1004
1005
 
1005
1006
  export type AcceptanceEvidenceKind =
@@ -1186,10 +1187,13 @@ export interface LaunchResolvedChildExtensions {
1186
1187
  disableAmbientExtensions: boolean;
1187
1188
  runtime: string[];
1188
1189
  configured: string[];
1190
+ /** Bounded host-supplied identities; paths are intentionally not exposed. */
1191
+ required: string[];
1189
1192
  effective: string[];
1190
1193
  omitted: {
1191
1194
  runtime: number;
1192
1195
  configured: number;
1196
+ required: number;
1193
1197
  effective: number;
1194
1198
  };
1195
1199
  }
@@ -1260,16 +1264,16 @@ export interface SingleResult {
1260
1264
  messages?: Message[];
1261
1265
  usage: Usage;
1262
1266
  model?: string;
1267
+ /** Authoritative before/after Git evidence captured by a pane-native remote machine. */
1268
+ nativeMachine?: { provider: "herdr"; machineId: string; initialGit?: HerdrRemoteGitStatus; finalGit?: HerdrRemoteGitStatus };
1263
1269
  /** Effective thinking level used by this foreground child, when known. */
1264
1270
  thinking?: string;
1265
- attemptedModels?: string[];
1266
- modelAttempts?: ModelAttempt[];
1271
+ requestedModel?: string;
1267
1272
  controlEvents?: ControlEvent[];
1268
1273
  error?: string;
1269
1274
  /**
1270
1275
  * True when the dispatch failed because the input exceeded the model's
1271
- * context window. The model fallback loop stops immediately (retrying the
1272
- * same input on another model cannot succeed). Callers should treat this as
1276
+ * context window. Callers should treat this as
1273
1277
  * a signal to reduce input size or re-decompose the task.
1274
1278
  */
1275
1279
  contextOverflow?: boolean;
@@ -1380,10 +1384,11 @@ export interface AgentCapabilityRow {
1380
1384
  executable: boolean;
1381
1385
  restrictionSources?: string[];
1382
1386
  aliases?: string[];
1383
- runner: { type: "pi" } | { type: "external-cli"; adapter?: string; command: string; available: boolean; unavailableReason?: string; capabilities: ExternalCliCapabilities } | { type: "external-job"; provider: string; available?: boolean; capabilities: ExternalJobRunnerStatus["capabilities"] };
1387
+ runner: { type: "pi" } | { type: "external-cli"; adapter?: string; command: string; machine?: string; available: boolean; unavailableReason?: string; capabilities: ExternalCliCapabilities } | { type: "external-job"; provider: string; available?: boolean; capabilities: ExternalJobRunnerStatus["capabilities"] };
1384
1388
  tools: { ambient: boolean; names: string[]; excludeTools?: string[]; mcpDirectTools: string[]; mutationTools?: string[] };
1385
- model?: { value?: string; fallbackModels?: string[]; thinking?: string | false };
1389
+ model?: { value?: string; thinking?: string | false };
1386
1390
  execution?: { defaultAsync?: boolean; timeoutMs?: number };
1391
+ acceptance?: { policy?: AcceptanceInput; role?: AcceptanceRole };
1387
1392
  output?: { path?: string; mode?: OutputMode };
1388
1393
  extensions?: { names?: string[]; subagentOnly?: string[]; skills?: string[] };
1389
1394
  }
@@ -1410,6 +1415,12 @@ export interface Details {
1410
1415
  timedOut: true;
1411
1416
  activeRunIds: string[];
1412
1417
  activeProviderItems: Array<{ provider: string; id: string }>;
1418
+ } | {
1419
+ /** Non-terminal internal auto-drain yield; tracked work remains active. */
1420
+ reason: "supervisor_request";
1421
+ timedOut: false;
1422
+ activeRunIds: string[];
1423
+ activeProviderItems: Array<{ provider: string; id: string }>;
1413
1424
  };
1414
1425
  controlEvents?: ControlEvent[];
1415
1426
  steering?: SteerActionResult;
@@ -1471,6 +1482,8 @@ export interface Details {
1471
1482
  mission?: MissionRecord;
1472
1483
  workflow?: {
1473
1484
  value?: unknown;
1485
+ args?: Record<string, unknown>;
1486
+ argsDigest?: string;
1474
1487
  resource?: WorkflowResourceProvenance;
1475
1488
  preflightWarnings?: string[];
1476
1489
  trace: Array<{
@@ -1706,6 +1719,26 @@ export type AgentRunnerConfig =
1706
1719
 
1707
1720
  export type ExternalCliCapabilityNarrowing = Partial<Record<"steer" | "resume" | "structuredOutput" | "toolEvents" | "supervisor" | "forkContext" | "extensionBindings", false>>;
1708
1721
 
1722
+ export interface HerdrRemoteGitStatus {
1723
+ head?: string;
1724
+ branch?: string;
1725
+ dirty?: boolean;
1726
+ }
1727
+
1728
+ /** A Herdr saved SSH machine resolved for one launch. `cwd` is the directory on that machine. */
1729
+ export interface HerdrMachineReference {
1730
+ provider: "herdr";
1731
+ id: string;
1732
+ label?: string;
1733
+ target: string;
1734
+ session?: string;
1735
+ cwd: string;
1736
+ }
1737
+
1738
+ export interface ExternalCliMachineStatus extends HerdrMachineReference {
1739
+ remoteGit?: HerdrRemoteGitStatus;
1740
+ }
1741
+
1709
1742
  export interface ExternalCliCapabilities {
1710
1743
  stop: true;
1711
1744
  steer: false;
@@ -1720,6 +1753,7 @@ export interface ExternalCliCapabilities {
1720
1753
  export interface ExternalCliReceiptMetadata {
1721
1754
  adapter: { id: "external-cli" | "codex-exec" | "codex-exec-writer" | "claude-code" | "claude-code-writer" | "cursor-agent" | "cursor-agent-writer" | "grok-build"; version: 1; executionMode: "one-shot-stdin" | "one-shot-prompt-file" };
1722
1755
  capabilities: ExternalCliCapabilities;
1756
+ machine?: ExternalCliMachineStatus;
1723
1757
  safety?:
1724
1758
  | { sandbox: "read-only"; approvalPolicy: "never"; ephemeral: true }
1725
1759
  | { access: "workspace-write"; sandbox: "workspace-write"; approvalPolicy: "never"; ephemeral: true }
@@ -1744,6 +1778,7 @@ export interface ExternalCliRunnerStatus {
1744
1778
  capabilities: ExternalCliCapabilities;
1745
1779
  unsupportedReasons: Record<Exclude<keyof ExternalCliCapabilities, "stop">, string>;
1746
1780
  nonResumableReason: string;
1781
+ machine?: HerdrMachineReference;
1747
1782
  }
1748
1783
 
1749
1784
  export interface ExternalJobRunnerStatus {
@@ -1795,6 +1830,7 @@ export interface ExternalProcessStatus {
1795
1830
  stderrBytes?: number;
1796
1831
  stdoutTruncated?: boolean;
1797
1832
  stderrTruncated?: boolean;
1833
+ machine?: ExternalCliMachineStatus;
1798
1834
  }
1799
1835
 
1800
1836
  export interface AsyncStatus {
@@ -1927,8 +1963,7 @@ export interface AsyncStatus {
1927
1963
  thinking?: string;
1928
1964
  contextLimit?: number;
1929
1965
  thinkingCeiling?: ThinkingLevel;
1930
- attemptedModels?: string[];
1931
- modelAttempts?: ModelAttempt[];
1966
+ requestedModel?: string;
1932
1967
  /** True when the child input exceeded the model context window. */
1933
1968
  contextOverflow?: boolean;
1934
1969
  totalCost?: CostSummary;
@@ -2069,7 +2104,7 @@ export interface ForegroundResumeChild {
2069
2104
  /** Private bounded launch fields needed to preserve the child contract on resume. */
2070
2105
  resumeContract?: {
2071
2106
  modelResponseAliases?: Record<string, string[]>;
2072
- outputSchema?: JsonSchemaObject;
2107
+ outputSchema?: JsonSchemaObject | false;
2073
2108
  agentContract?: AgentContract;
2074
2109
  acceptance?: AcceptanceInput;
2075
2110
  output?: string | boolean;
@@ -2078,6 +2113,7 @@ export interface ForegroundResumeChild {
2078
2113
  launchContractDigest?: string;
2079
2114
  /** Private retained launch authority. Never project into status or result output. */
2080
2115
  extensionBindings?: ExtensionBindings;
2116
+ requiredExtensions?: RequiredChildExtensionSnapshot;
2081
2117
  launchResolvedExtensions?: LaunchResolvedChildExtensions;
2082
2118
  runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensions;
2083
2119
  execution?: ExecutionProjection;
@@ -2255,8 +2291,8 @@ export interface SubagentState {
2255
2291
  lastUiContext: ExtensionContext | null;
2256
2292
  poller: NodeJS.Timeout | null;
2257
2293
  completionSeen: Map<string, number>;
2258
- /** Terminal result payloads observed by the result watcher, keyed by run id and pruned by the completion TTL. */
2259
- completedResults?: Map<string, { seenAt: number; completion: WaitCompletion }>;
2294
+ /** Session-owned terminal result payloads observed by the result watcher, keyed by run id and pruned by the completion TTL. */
2295
+ completedResults?: Map<string, { sessionId: string; seenAt: number; completion: WaitCompletion }>;
2260
2296
  watcher: FSWatcher | null;
2261
2297
  watcherRestartTimer: ReturnType<typeof setTimeout> | null;
2262
2298
  resultFileCoalescer: {
@@ -2359,6 +2395,8 @@ export interface RunSyncOptions {
2359
2395
  unknownAgentDiagnosticContext?: import("../agents/agents.ts").UnknownAgentDiagnosticContext;
2360
2396
  /** Session factory for the in-process child; defaults to the process-wide factory. */
2361
2397
  childSessionFactory?: import("../runs/shared/child-session.ts").ChildSessionFactory;
2398
+ /** Invoking parent registry inherited only by its local foreground launch. */
2399
+ parentProviderRegistry?: import("../runs/shared/child-session.ts").ParentProviderRegistry;
2362
2400
  /** The launching executor's own child runtime when it is itself an in-process child. */
2363
2401
  childRuntime?: import("../runs/shared/child-runtime-config.ts").ChildRuntimeConfig;
2364
2402
  /** Fires once the child session exists and can be steered. */
@@ -2370,6 +2408,10 @@ export interface RunSyncOptions {
2370
2408
  /** Resolved launch context for this child. */
2371
2409
  context?: "fresh" | "fork";
2372
2410
  cwd?: string;
2411
+ /** Resolved pane-native saved-machine placement. */
2412
+ machine?: HerdrMachineReference;
2413
+ /** Explicit read override resolved by the remote ambient agent profile. */
2414
+ remoteReads?: string[] | false;
2373
2415
  /** Original cwd input retained for launch diagnostics. */
2374
2416
  requestedCwd?: string;
2375
2417
  signal?: AbortSignal;
@@ -2430,6 +2472,7 @@ export interface RunSyncOptions {
2430
2472
  /** Override the agent's default thinking level for this run */
2431
2473
  thinkingOverride?: AgentConfig["thinking"];
2432
2474
  thinkingCeiling?: ThinkingLevel;
2475
+ requiredExtensions?: RequiredChildExtensionSnapshot;
2433
2476
  extensionBindings?: ExtensionBindings;
2434
2477
  /** Package-internal one-use authorization for one foreground workflow child. */
2435
2478
  workflowChildPermitLaunch?: WorkflowChildPermitContext;
@@ -2440,7 +2483,9 @@ export interface RunSyncOptions {
2440
2483
  preferredModelProvider?: string;
2441
2484
  /** Parent Pi event host used to snapshot runtime-registered MCP servers before child launch. */
2442
2485
  runtimeSnapshotHost?: import("../runs/shared/mcp-direct-tool-allowlist.ts").McpRuntimeSnapshotHost;
2443
- /** Optional subagent model-scope enforcement for fallback candidates */
2486
+ /** Builtin tool names the host runtime provides; used to intersect agent-declared tools. */
2487
+ hostAvailableBuiltins?: readonly string[];
2488
+ /** Optional subagent model-scope enforcement. */
2444
2489
  modelScope?: ModelScopeRule | ModelScopeRule[];
2445
2490
  /** Skills to make available (overrides agent default if provided) */
2446
2491
  skills?: string[];
@@ -2502,11 +2547,6 @@ export interface ScheduledRunsConfig {
2502
2547
  storeRoot?: string;
2503
2548
  }
2504
2549
 
2505
- export interface ModelExclusionsConfig {
2506
- /** Default duration in milliseconds. A lower configured value also shortens active cached exclusions. */
2507
- defaultTtlMs?: number;
2508
- }
2509
-
2510
2550
  export type FleetViewPlacement = "aboveEditor" | "belowEditor";
2511
2551
 
2512
2552
  export const FLEET_KEYBINDING_ACTIONS = [
@@ -2569,8 +2609,6 @@ export interface ExtensionConfig {
2569
2609
  fleetKeybindings?: FleetKeybindingsConfig;
2570
2610
  /** Show the under-editor async runs widget. Defaults to true, including when FleetView is enabled. */
2571
2611
  asyncWidget?: boolean;
2572
- /** Configure the process-wide TTL policy for persisted model exclusions. */
2573
- modelExclusions?: ModelExclusionsConfig;
2574
2612
  /** Exact provider/model candidates mapped to operator-declared equivalent response IDs. Empty arrays add no accepted IDs. */
2575
2613
  modelResponseAliases?: Record<string, string[]>;
2576
2614
  /** Tool description variant registered for the parent-facing subagent tool. Defaults to split metadata. */
@@ -2615,6 +2653,12 @@ export interface ExtensionConfig {
2615
2653
  * are rejected with an error.
2616
2654
  */
2617
2655
  toolTimeoutMs?: number;
2656
+ /**
2657
+ * Global default for the async single-agent `checkpointBeforeDeadlineMs` launch option: the runner requests that
2658
+ * the child checkpoint and stop this many milliseconds before its run deadline (best-effort). The call param wins; values that
2659
+ * leave no run time before the checkpoint disarm it.
2660
+ */
2661
+ checkpointBeforeDeadlineMs?: number;
2618
2662
  control?: ControlConfig;
2619
2663
  completionBatch?: CompletionBatchConfig;
2620
2664
  toolBudget?: ToolBudgetConfig;
@@ -2754,7 +2798,7 @@ export const POLL_INTERVAL_MS = 250;
2754
2798
  export const WIDGET_ANIMATION_INTERVAL_MS = 1000;
2755
2799
  export const MAX_WIDGET_JOBS = 4;
2756
2800
  export const DEFAULT_SUBAGENT_MAX_DEPTH = 2;
2757
- export const SUBAGENT_ACTIONS = ["list", "get", "models", "children.list", "guide", "validate", "create", "update", "delete", "eject", "disable", "enable", "reset", "mission.create", "mission.list", "mission.show", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "worktree.discard", "worktree.cleanup", "lane.status", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.show", "refine.rollback", "inspector.open", "inspector.status", "inspector.close", "project.open", "project.status", "project.close", "status", "debug.run", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "doctor", "watchdog.status", "watchdog.check", "watchdog.configure", "watchdog.recommend-model", "schedule.create", "schedule.list", "schedule.show", "schedule.history", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"] as const;
2801
+ export const SUBAGENT_ACTIONS = ["list", "get", "models", "children.list", "guide", "validate", "create", "update", "delete", "eject", "disable", "enable", "reset", "mission.create", "mission.list", "mission.show", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "worktree.discard", "worktree.cleanup", "lane.status", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.show", "refine.rollback", "inspector.open", "inspector.command", "inspector.status", "inspector.close", "project.open", "project.status", "project.close", "status", "debug.run", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "doctor", "watchdog.status", "watchdog.check", "watchdog.configure", "watchdog.recommend-model", "schedule.create", "schedule.list", "schedule.show", "schedule.history", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"] as const;
2758
2802
 
2759
2803
  export const DEFAULT_FORK_PREAMBLE =
2760
2804
  "You are a delegated subagent running from a fork of the parent session. " +
@@ -6,7 +6,7 @@ import {
6
6
  type SubagentDelegationUpdate,
7
7
  type SubagentDelegationValue,
8
8
  } from "../api/delegation.ts";
9
- import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, JsonSchemaObject, ReviewProjection, ToolBudgetConfig, Usage } from "../shared/types.ts";
9
+ import type { AcceptanceInput, AgentContract, EffectsProjection, ExecutionProjection, IntercomBridgeConfig, JsonSchemaObject, ReviewProjection, ToolBudgetConfig, Usage } from "../shared/types.ts";
10
10
  import { cloneJsonWithinByteLimit } from "./delegation-json.ts";
11
11
 
12
12
  export interface PromptTemplateDelegationRequest {
@@ -127,6 +127,7 @@ export interface DelegatedSubagentExecutionParams {
127
127
  agentContract?: AgentContract;
128
128
  acceptance?: AcceptanceInput;
129
129
  artifacts?: boolean;
130
+ intercomBridge?: IntercomBridgeConfig;
130
131
  /** Internal-only thinking override accepted by executeDelegated. */
131
132
  delegatedThinkingOverride?: SubagentDelegationThinking;
132
133
  /** Internal-only capability accepted and stripped by executeDelegated. */
@@ -295,6 +296,7 @@ export function toSubagentDelegationExecutionParams(request: SubagentDelegationR
295
296
  ...(request.result.kind === "structured" ? { outputSchema: request.result.schema } : {}),
296
297
  acceptance: false,
297
298
  artifacts: request.artifacts,
299
+ ...(request.intercomBridge !== undefined ? { intercomBridge: request.intercomBridge } : {}),
298
300
  delegatedThinkingOverride: request.thinking,
299
301
  delegatedAllowZeroToolBudget: true,
300
302
  async: false,
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  type SubagentDelegationRequest,
3
3
  } from "../api/delegation.ts";
4
+ import { validateIntercomBridgeConfig } from "../intercom/intercom-bridge.ts";
4
5
  import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
6
+ import type { IntercomBridgeConfig } from "../shared/types.ts";
5
7
  import { cloneJsonWithinByteLimit } from "./delegation-json.ts";
6
8
 
7
9
  export type SubagentDelegationParseResult =
@@ -22,6 +24,7 @@ const supportedFields = new Set([
22
24
  "toolBudget",
23
25
  "skill",
24
26
  "artifacts",
27
+ "intercomBridge",
25
28
  "result",
26
29
  ]);
27
30
 
@@ -97,6 +100,15 @@ export function parseSubagentDelegationRequest(data: unknown): SubagentDelegatio
97
100
  if (value.artifacts !== undefined && typeof value.artifacts !== "boolean") {
98
101
  return { ok: false, ...identity, error: "artifacts must be a boolean." };
99
102
  }
103
+ let intercomBridge: IntercomBridgeConfig | undefined;
104
+ if (value.intercomBridge !== undefined) {
105
+ const bridge = validateIntercomBridgeConfig({ value: value.intercomBridge, label: "intercomBridge" });
106
+ if (!bridge.ok) return { ok: false, ...identity, error: bridge.error };
107
+ if (typeof bridge.value.instructionFile === "string" && Buffer.byteLength(bridge.value.instructionFile, "utf8") > MAX_SHORT_TEXT_BYTES) {
108
+ return { ok: false, ...identity, error: "intercomBridge.instructionFile exceeds 1 KiB when UTF-8 encoded." };
109
+ }
110
+ intercomBridge = bridge.value;
111
+ }
100
112
  if (Buffer.byteLength(value.task as string, "utf8") > MAX_TASK_BYTES) {
101
113
  return { ok: false, ...identity, error: "Delegation task exceeds 1 MiB when UTF-8 encoded." };
102
114
  }
@@ -154,6 +166,8 @@ export function parseSubagentDelegationRequest(data: unknown): SubagentDelegatio
154
166
  ok: true,
155
167
  request: {
156
168
  ...value,
169
+ // The validated copy replaces the caller's object so the request never aliases untrusted input.
170
+ ...(intercomBridge ? { intercomBridge } : {}),
157
171
  result: structuredSchema
158
172
  ? { kind: "structured", schema: structuredSchema }
159
173
  : { kind: "text" },
@@ -25,12 +25,12 @@ import { resolveAsyncStatusChild } from "../runs/shared/child-identity.ts";
25
25
  import { readStatus } from "../shared/utils.ts";
26
26
  import { getArtifactPaths, getArtifactsDir } from "../shared/artifacts.ts";
27
27
  import { readWorkflowReceipt } from "../workflows/workflow-receipt.ts";
28
- import { FLEET_OPEN_SHORTCUT } from "../shared/shortcuts.ts";
29
28
  import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
30
29
  import { registerPromptWorkflowCommands } from "./prompt-workflows.ts";
31
30
  import { openSubagentsAdmin } from "./subagents-admin.ts";
32
31
  import { SUBAGENT_GUIDE_TOPICS } from "../extension/subagent-guide.ts";
33
32
  import { openSubagentFleet } from "../tui/fleet.ts";
33
+ import { createBuiltinInspectorPlugins } from "../inspectors/plugins.ts";
34
34
  import {
35
35
  applySlashUpdate,
36
36
  buildSlashInitialResult,
@@ -860,7 +860,7 @@ export function registerSlashCommands(
860
860
  }
861
861
  fleetOpen = true;
862
862
  try {
863
- await openSubagentFleet(ctx, state, { asyncDirRoot: DIRS.async, resultsDir: DIRS.results, fleetKeybindings: options.fleetKeybindings });
863
+ await openSubagentFleet(ctx, state, { asyncDirRoot: DIRS.async, inspectorPlugins: createBuiltinInspectorPlugins(), resultsDir: DIRS.results, fleetKeybindings: options.fleetKeybindings });
864
864
  } finally {
865
865
  fleetOpen = false;
866
866
  }
@@ -975,11 +975,6 @@ export function registerSlashCommands(
975
975
  handler: async (_args, ctx) => showFleet(ctx),
976
976
  });
977
977
 
978
- pi.registerShortcut(FLEET_OPEN_SHORTCUT, {
979
- description: "Open subagent fleet inspector",
980
- handler: async (ctx) => showFleet(ctx),
981
- });
982
-
983
978
  const detachForegroundRun = (args: string, ctx: ExtensionContext): void => {
984
979
  const id = args.trim();
985
980
  let control: ReturnType<typeof selectForegroundDetachControl>;
@@ -11,6 +11,7 @@ import {
11
11
  type BuiltinAgentOverrideBase,
12
12
  } from "../agents/agents.ts";
13
13
  import { serializeAgent } from "../agents/agent-serializer.ts";
14
+ import { mergeRuntimeAgents, type RuntimeAgentOwner } from "../agents/runtime-agent-registry.ts";
14
15
  import { editableAgentConfig, preservedAgentFrontmatterFields } from "../agents/agent-management.ts";
15
16
  import { findModelInfo, getSupportedThinkingLevels, toModelInfo } from "../shared/model-info.ts";
16
17
  import { SelectorComponent, type SelectorItem, type SelectorResult } from "./selector.ts";
@@ -28,11 +29,13 @@ function sourceRank(source: AgentConfig["source"]): number {
28
29
  return 3;
29
30
  }
30
31
 
31
- function allVisibleAgents(cwd: string): AgentConfig[] {
32
+ function allVisibleAgents(pi: RuntimeAgentOwner, cwd: string): AgentConfig[] {
32
33
  const d = discoverAgentsAll(cwd);
33
- return [...d.project, ...d.user, ...d.package, ...d.builtin]
34
- .filter((agent) => !agent.disabled)
35
- .sort((a, b) => a.name.localeCompare(b.name) || sourceRank(a.source) - sourceRank(b.source));
34
+ const allConfigured = [...d.project, ...d.user, ...d.package, ...d.builtin];
35
+ const visibleConfigured = allConfigured.filter((agent) => !agent.disabled);
36
+ // Disabled definitions remain in collision checks even though the panel hides them.
37
+ const agents = mergeRuntimeAgents(pi, { agents: visibleConfigured }, allConfigured).agents;
38
+ return agents.sort((a, b) => a.name.localeCompare(b.name) || sourceRank(a.source) - sourceRank(b.source));
36
39
  }
37
40
 
38
41
  function agentLabel(agent: AgentConfig): string {
@@ -71,9 +74,16 @@ function modelFullId(model: ModelInfo): string {
71
74
  return `${model.provider}/${model.id}`;
72
75
  }
73
76
 
74
- function liveAvailableModels(ctx: ExtensionContext) {
77
+ async function liveAvailableModels(ctx: ExtensionContext) {
75
78
  try {
76
- ctx.modelRegistry.refresh?.();
79
+ // Reload local configuration and cached catalogs without network discovery on picker open.
80
+ const result = await ctx.modelRegistry.refresh?.({ allowNetwork: false, signal: AbortSignal.timeout(5_000) });
81
+ const firstError = result?.errors.entries().next().value;
82
+ if (firstError) {
83
+ ctx.ui.notify(`Could not refresh ${firstError[0]}; using the currently loaded choices. ${firstError[1].message}`, "warning");
84
+ } else if (result?.aborted) {
85
+ ctx.ui.notify("Model registry refresh timed out; using the currently loaded choices.", "warning");
86
+ }
77
87
  } catch (error) {
78
88
  const message = error instanceof Error ? error.message : String(error);
79
89
  ctx.ui.notify(`Could not refresh the model registry; using the last loaded choices. ${message}`, "warning");
@@ -84,7 +94,6 @@ function liveAvailableModels(ctx: ExtensionContext) {
84
94
  function buildBuiltinBase(agent: AgentConfig): BuiltinAgentOverrideBase {
85
95
  return {
86
96
  ...(agent.model !== undefined ? { model: agent.model } : {}),
87
- ...(agent.fallbackModels !== undefined ? { fallbackModels: [...agent.fallbackModels] } : {}),
88
97
  ...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
89
98
  systemPromptMode: agent.systemPromptMode,
90
99
  inheritProjectContext: agent.inheritProjectContext,
@@ -139,6 +148,9 @@ function isReadOnlyExtraAgent(agent: AgentConfig): boolean {
139
148
  }
140
149
 
141
150
  function readOnlyAgentMessage(agent: AgentConfig, field: EditableOverrideField): string | undefined {
151
+ if (agent.source === "runtime") {
152
+ return `Cannot update '${agent.name}' ${field} because that agent is runtime-registered by an extension; edit its source definition instead.`;
153
+ }
142
154
  if (agent.source === "package") {
143
155
  return `Cannot update '${agent.name}' ${field} because that field is owned by its read-only package definition.`;
144
156
  }
@@ -147,8 +159,8 @@ function readOnlyAgentMessage(agent: AgentConfig, field: EditableOverrideField):
147
159
  : undefined;
148
160
  }
149
161
 
150
- async function selectAgent(ctx: ExtensionContext, args: string): Promise<AgentSelection> {
151
- const agents = allVisibleAgents(ctx.cwd);
162
+ async function selectAgent(pi: RuntimeAgentOwner, ctx: ExtensionContext, args: string): Promise<AgentSelection> {
163
+ const agents = allVisibleAgents(pi, ctx.cwd);
152
164
  const requestedName = args.trim().split(/\s+/)[0] ?? "";
153
165
  if (agents.length === 0) return { kind: "not-found", agents, requestedName: requestedName || undefined };
154
166
 
@@ -182,7 +194,6 @@ function metadataFor(agent: AgentConfig): string {
182
194
  lines.push(`Package: ${agent.packageName}`);
183
195
  }
184
196
  lines.push(`Model: ${agent.model ?? "default / inherit"}`);
185
- if (agent.fallbackModels?.length) lines.push(`Fallback models: ${agent.fallbackModels.join(", ")}`);
186
197
  if (agent.thinking !== undefined) lines.push(`Thinking: ${agent.thinking === false ? "off" : agent.thinking}`);
187
198
  if (tools.length) lines.push(`Tools: ${tools.join(", ")}`);
188
199
  if (agent.excludeTools?.length) lines.push(`Excluded tools: ${agent.excludeTools.join(", ")}`);
@@ -217,7 +228,7 @@ async function selectFromList(ctx: ExtensionContext, title: string, subtitle: st
217
228
  }
218
229
 
219
230
  async function chooseModel(ctx: ExtensionContext, agent: AgentConfig): Promise<string | undefined | null> {
220
- const models = liveAvailableModels(ctx);
231
+ const models = await liveAvailableModels(ctx);
221
232
  const current = agent.model ?? INHERIT_MODEL_CHOICE;
222
233
  const items: SelectorItem[] = [{ value: INHERIT_MODEL_CHOICE, label: INHERIT_MODEL_CHOICE, current: !agent.model }];
223
234
  if (agent.model && !models.some((model) => modelFullId(model) === agent.model)) {
@@ -233,7 +244,7 @@ async function chooseModel(ctx: ExtensionContext, agent: AgentConfig): Promise<s
233
244
  }
234
245
 
235
246
  async function chooseThinking(ctx: ExtensionContext, agent: AgentConfig): Promise<string | undefined | null> {
236
- const availableModels = liveAvailableModels(ctx).map(toModelInfo);
247
+ const availableModels = (await liveAvailableModels(ctx)).map(toModelInfo);
237
248
  const effectiveModel = agent.model ?? (ctx.model ? modelFullId(ctx.model) : undefined);
238
249
  const modelInfo = findModelInfo(effectiveModel, availableModels, ctx.model?.provider);
239
250
  const levels = getSupportedThinkingLevels(modelInfo);
@@ -383,7 +394,7 @@ async function editSystemPrompt(ctx: ExtensionContext, agent: AgentConfig): Prom
383
394
  }
384
395
 
385
396
  export async function openSubagentsAdmin(pi: ExtensionAPI, ctx: ExtensionContext, args = ""): Promise<void> {
386
- const selection = await selectAgent(ctx, args);
397
+ const selection = await selectAgent(pi, ctx, args);
387
398
  if (selection.kind === "cancelled") return;
388
399
  if (selection.kind === "ambiguous") {
389
400
  sendAdminMessage(pi, `Subagent '${selection.requestedName}' is ambiguous. Choose a scope in interactive mode:\n${selection.matches.map((agent) => `- ${agent.source}: ${agent.filePath}`).join("\n")}`);