pi-subagents 0.35.1 → 0.37.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 (89) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +224 -31
  3. package/agents/advisor.md +73 -0
  4. package/agents/delegate.md +2 -0
  5. package/agents/worker.md +2 -0
  6. package/package.json +11 -13
  7. package/skills/pi-subagents/SKILL.md +42 -13
  8. package/src/agents/agent-management.ts +7 -1
  9. package/src/agents/agents.ts +121 -17
  10. package/src/api/capability-ceiling.ts +17 -0
  11. package/src/api/delegation.ts +127 -0
  12. package/src/api/preflight.ts +399 -0
  13. package/src/extension/config.ts +7 -1
  14. package/src/extension/index.ts +52 -38
  15. package/src/extension/rpc.ts +31 -2
  16. package/src/extension/schemas.ts +29 -3
  17. package/src/extension/tool-description.ts +4 -2
  18. package/src/intercom/intercom-bridge.ts +1 -1
  19. package/src/intercom/native-supervisor-channel.ts +45 -6
  20. package/src/intercom/result-intercom.ts +7 -0
  21. package/src/runs/background/async-execution.ts +158 -17
  22. package/src/runs/background/async-job-tracker.ts +4 -0
  23. package/src/runs/background/async-resume.ts +47 -8
  24. package/src/runs/background/async-status.ts +94 -3
  25. package/src/runs/background/chain-append.ts +2 -0
  26. package/src/runs/background/completion-batcher.ts +6 -4
  27. package/src/runs/background/completion-dedupe.ts +2 -11
  28. package/src/runs/background/fleet-view.ts +9 -4
  29. package/src/runs/background/notify.ts +132 -120
  30. package/src/runs/background/process-terminal.ts +280 -0
  31. package/src/runs/background/result-watcher.ts +138 -78
  32. package/src/runs/background/run-status.ts +10 -2
  33. package/src/runs/background/scheduled-runs.ts +6 -1
  34. package/src/runs/background/stale-run-reconciler.ts +6 -0
  35. package/src/runs/background/subagent-runner.ts +406 -54
  36. package/src/runs/background/subagent-wait.ts +130 -4
  37. package/src/runs/background/wait-tool.ts +2 -2
  38. package/src/runs/foreground/chain-execution.ts +181 -111
  39. package/src/runs/foreground/execution.ts +147 -47
  40. package/src/runs/foreground/foreground-control.ts +90 -0
  41. package/src/runs/foreground/subagent-executor.ts +426 -165
  42. package/src/runs/shared/acceptance.ts +94 -41
  43. package/src/runs/shared/agent-contract.ts +38 -0
  44. package/src/runs/shared/capability-ceiling.ts +177 -0
  45. package/src/runs/shared/child-protocol.ts +1 -1
  46. package/src/runs/shared/completion-guard.ts +36 -5
  47. package/src/runs/shared/context-mode.ts +44 -0
  48. package/src/runs/shared/dynamic-fanout.ts +5 -5
  49. package/src/runs/shared/long-running-guard.ts +4 -0
  50. package/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  51. package/src/runs/shared/nested-events.ts +35 -3
  52. package/src/runs/shared/parallel-handoff.ts +154 -0
  53. package/src/runs/shared/parallel-utils.ts +11 -0
  54. package/src/runs/shared/pi-args.ts +148 -56
  55. package/src/runs/shared/run-history.ts +90 -5
  56. package/src/runs/shared/session-lease.ts +25 -5
  57. package/src/runs/shared/structured-output.ts +112 -7
  58. package/src/runs/shared/subagent-control.ts +4 -0
  59. package/src/runs/shared/subagent-prompt-runtime.ts +31 -19
  60. package/src/runs/shared/task-intent.ts +10 -5
  61. package/src/runs/shared/tool-availability.ts +21 -3
  62. package/src/runs/shared/tool-budget.ts +11 -5
  63. package/src/runs/shared/turn-budget.ts +2 -1
  64. package/src/runs/shared/worktree.ts +63 -14
  65. package/src/shared/accessible-dir.ts +25 -0
  66. package/src/shared/artifacts.ts +37 -7
  67. package/src/shared/atomic-json.ts +14 -42
  68. package/src/shared/child-transcript.ts +52 -0
  69. package/src/shared/file-system-retry.ts +47 -0
  70. package/src/shared/launch-contract.ts +123 -0
  71. package/src/shared/settings.ts +9 -1
  72. package/src/shared/types.ts +314 -28
  73. package/src/shared/utils.ts +17 -42
  74. package/src/slash/delegation-adapters.ts +153 -6
  75. package/src/slash/delegation-json.ts +108 -0
  76. package/src/slash/delegation-request.ts +182 -36
  77. package/src/slash/prompt-template-bridge.ts +222 -37
  78. package/src/slash/selector.ts +147 -0
  79. package/src/slash/slash-commands.ts +15 -6
  80. package/src/slash/slash-live-state.ts +2 -2
  81. package/src/slash/subagents-admin.ts +42 -42
  82. package/src/tui/fleet-status.ts +362 -0
  83. package/src/tui/fleet-transcript.ts +472 -0
  84. package/src/tui/fleet.ts +318 -59
  85. package/src/tui/render.ts +17 -15
  86. package/src/watchdog/change-signature.ts +105 -12
  87. package/src/watchdog/review.ts +7 -2
  88. package/src/watchdog/runtime.ts +5 -3
  89. package/src/slash/subagents-editor.ts +0 -86
@@ -35,6 +35,7 @@ export interface AgentMemoryConfig {
35
35
  }
36
36
 
37
37
  export const BUILTIN_AGENT_NAMES = [
38
+ "advisor",
38
39
  "context-builder",
39
40
  "delegate",
40
41
  "oracle",
@@ -72,6 +73,7 @@ export interface BuiltinAgentOverrideBase {
72
73
  skillPath?: string[];
73
74
  tools?: string[];
74
75
  mcpDirectTools?: string[];
76
+ extensions?: string[];
75
77
  subagentOnlyExtensions?: string[];
76
78
  completionGuard?: boolean;
77
79
  toolBudget?: ToolBudgetConfig;
@@ -90,6 +92,7 @@ interface BuiltinAgentOverrideConfig {
90
92
  systemPrompt?: string;
91
93
  skills?: string[] | false;
92
94
  tools?: string[] | false;
95
+ extensions?: string[] | false;
93
96
  subagentOnlyExtensions?: string[] | false;
94
97
  completionGuard?: boolean;
95
98
  toolBudget?: ToolBudgetConfig | false;
@@ -133,6 +136,7 @@ export interface AgentConfig {
133
136
  skills?: string[];
134
137
  skillPath?: string[];
135
138
  extensions?: string[];
139
+ extensionsFromDefault?: boolean;
136
140
  subagentOnlyExtensions?: string[];
137
141
  output?: string;
138
142
  defaultReads?: string[];
@@ -151,6 +155,8 @@ export interface AgentConfig {
151
155
  interface SubagentSettings {
152
156
  overrides: Record<string, BuiltinAgentOverrideConfig>;
153
157
  defaultModel?: string;
158
+ defaultThinking?: string;
159
+ defaultExtensions?: string[];
154
160
  disableBuiltins?: boolean;
155
161
  disableThinking?: boolean;
156
162
  modelScope?: ModelScopeConfig;
@@ -476,7 +482,7 @@ function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpD
476
482
  }
477
483
  }
478
484
  return {
479
- ...(tools.length > 0 ? { tools } : {}),
485
+ ...(rawTools !== undefined ? { tools } : {}),
480
486
  ...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),
481
487
  };
482
488
  }
@@ -515,6 +521,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
515
521
  skillPath: agent.skillPath ? [...agent.skillPath] : undefined,
516
522
  tools: agent.tools ? [...agent.tools] : undefined,
517
523
  mcpDirectTools: agent.mcpDirectTools ? [...agent.mcpDirectTools] : undefined,
524
+ extensions: agent.extensionsFromDefault ? undefined : agent.extensions ? [...agent.extensions] : undefined,
518
525
  subagentOnlyExtensions: agent.subagentOnlyExtensions ? [...agent.subagentOnlyExtensions] : undefined,
519
526
  completionGuard: agent.completionGuard,
520
527
  toolBudget: agent.toolBudget,
@@ -537,6 +544,7 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
537
544
  ...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),
538
545
  ...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),
539
546
  ...(override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {}),
547
+ ...(override.extensions !== undefined ? { extensions: override.extensions === false ? false : [...override.extensions] } : {}),
540
548
  ...(override.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: override.subagentOnlyExtensions === false ? false : [...override.subagentOnlyExtensions] } : {}),
541
549
  ...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),
542
550
  ...(override.toolBudget !== undefined ? { toolBudget: override.toolBudget === false ? false : { ...override.toolBudget, ...(Array.isArray(override.toolBudget.block) ? { block: [...override.toolBudget.block] } : {}) } } : {}),
@@ -716,6 +724,9 @@ function parseBuiltinOverrideEntry(
716
724
  const tools = parseOverrideStringArrayOrFalse(input.tools, { filePath, name, field: "tools" });
717
725
  if (tools !== undefined) override.tools = tools;
718
726
 
727
+ const extensions = parseOverrideStringArrayOrFalse(input.extensions, { filePath, name, field: "extensions" });
728
+ if (extensions !== undefined) override.extensions = extensions;
729
+
719
730
  const subagentOnlyExtensions = parseOverrideStringArrayOrFalse(input.subagentOnlyExtensions, { filePath, name, field: "subagentOnlyExtensions" });
720
731
  if (subagentOnlyExtensions !== undefined) override.subagentOnlyExtensions = subagentOnlyExtensions;
721
732
 
@@ -753,18 +764,34 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
753
764
  throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultModel'; expected a non-empty string.`);
754
765
  }
755
766
  }
767
+ let defaultThinking: string | undefined;
768
+ if ("defaultThinking" in subagentsObject) {
769
+ if (typeof subagentsObject.defaultThinking === "string" && subagentsObject.defaultThinking.trim()) {
770
+ defaultThinking = subagentsObject.defaultThinking.trim();
771
+ } else {
772
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultThinking'; expected a non-empty string.`);
773
+ }
774
+ }
775
+ let defaultExtensions: string[] | undefined;
776
+ if ("defaultExtensions" in subagentsObject) {
777
+ if (!Array.isArray(subagentsObject.defaultExtensions)
778
+ || subagentsObject.defaultExtensions.some((item) => typeof item !== "string" || !item.trim())) {
779
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultExtensions'; expected an array of non-empty strings.`);
780
+ }
781
+ defaultExtensions = subagentsObject.defaultExtensions.map((item) => item.trim());
782
+ }
756
783
  const modelScope = parseModelScopeConfig(subagentsObject.modelScope, { filePath });
757
784
 
758
785
  const parsed: Record<string, BuiltinAgentOverrideConfig> = {};
759
786
  const agentOverrides = subagentsObject.agentOverrides;
760
787
  if (!agentOverrides || typeof agentOverrides !== "object" || Array.isArray(agentOverrides)) {
761
- return { overrides: parsed, defaultModel, disableBuiltins, disableThinking, modelScope };
788
+ return { overrides: parsed, defaultModel, defaultThinking, defaultExtensions, disableBuiltins, disableThinking, modelScope };
762
789
  }
763
790
  for (const [name, value] of Object.entries(agentOverrides)) {
764
791
  const override = parseBuiltinOverrideEntry(name, value, filePath);
765
792
  if (override) parsed[name] = override;
766
793
  }
767
- return { overrides: parsed, defaultModel, disableBuiltins, disableThinking, modelScope };
794
+ return { overrides: parsed, defaultModel, defaultThinking, defaultExtensions, disableBuiltins, disableThinking, modelScope };
768
795
  }
769
796
 
770
797
  function resolveSubagentDefaultModel(
@@ -792,6 +819,58 @@ function applySubagentDefaultModel(agents: AgentConfig[], defaultModel: AgentMod
792
819
  });
793
820
  }
794
821
 
822
+ function resolveSubagentDefaultThinking(
823
+ userSettings: SubagentSettings,
824
+ projectSettings: SubagentSettings,
825
+ projectSettingsPath: string | null,
826
+ ): string | undefined {
827
+ if (projectSettingsPath && projectSettings.defaultThinking !== undefined) return projectSettings.defaultThinking;
828
+ return userSettings.defaultThinking;
829
+ }
830
+
831
+ function applySubagentDefaultThinking(agents: AgentConfig[], defaultThinking: string | undefined): AgentConfig[] {
832
+ if (defaultThinking === undefined) return agents;
833
+ return agents.map((agent) => {
834
+ if (agent.thinking !== undefined) return agent;
835
+ const next = { ...agent, thinking: defaultThinking };
836
+ const frontmatterFields = agentFrontmatterFields.get(agent);
837
+ if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
838
+ return next;
839
+ });
840
+ }
841
+
842
+ function resolveSubagentDefaultExtensions(
843
+ userSettings: SubagentSettings,
844
+ projectSettings: SubagentSettings,
845
+ projectSettingsPath: string | null,
846
+ ): string[] | undefined {
847
+ if (projectSettingsPath && projectSettings.defaultExtensions !== undefined) return projectSettings.defaultExtensions;
848
+ return userSettings.defaultExtensions;
849
+ }
850
+
851
+ function applySubagentDefaultExtensions(agents: AgentConfig[], defaultExtensions: string[] | undefined): AgentConfig[] {
852
+ if (defaultExtensions === undefined) return agents;
853
+ return agents.map((agent) => {
854
+ if (agent.extensions !== undefined) return agent;
855
+ const next = { ...agent, extensions: [...defaultExtensions], extensionsFromDefault: true };
856
+ const frontmatterFields = agentFrontmatterFields.get(agent);
857
+ if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
858
+ return next;
859
+ });
860
+ }
861
+
862
+ function applySubagentDefaults(
863
+ agents: AgentConfig[],
864
+ defaultModel: AgentModelSourceInfo | undefined,
865
+ defaultThinking: string | undefined,
866
+ defaultExtensions: string[] | undefined,
867
+ ): AgentConfig[] {
868
+ return applySubagentDefaultExtensions(
869
+ applySubagentDefaultThinking(applySubagentDefaultModel(agents, defaultModel), defaultThinking),
870
+ defaultExtensions,
871
+ );
872
+ }
873
+
795
874
  function applyBuiltinOverride(
796
875
  agent: AgentConfig,
797
876
  override: BuiltinAgentOverrideConfig,
@@ -820,6 +899,7 @@ function applyBuiltinOverride(
820
899
  next.tools = tools;
821
900
  next.mcpDirectTools = mcpDirectTools;
822
901
  }
902
+ if (override.extensions !== undefined) next.extensions = override.extensions === false ? undefined : [...override.extensions];
823
903
  if (override.subagentOnlyExtensions !== undefined) {
824
904
  next.subagentOnlyExtensions = override.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions];
825
905
  }
@@ -963,6 +1043,9 @@ function applyCustomAgentOverride(
963
1043
  target.mcpDirectTools = mcpDirectTools;
964
1044
  anyFilled = true;
965
1045
  }
1046
+ if (override.extensions !== undefined) {
1047
+ fill("extensions", ["extensions"], override.extensions === false ? undefined : [...override.extensions]);
1048
+ }
966
1049
  if (override.subagentOnlyExtensions !== undefined) {
967
1050
  fill(
968
1051
  "subagentOnlyExtensions",
@@ -1008,7 +1091,7 @@ function applyCustomAgentOverrides(
1008
1091
 
1009
1092
  export function buildBuiltinOverrideConfig(
1010
1093
  base: BuiltinAgentOverrideBase,
1011
- draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget">,
1094
+ draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget">,
1012
1095
  ): BuiltinAgentOverrideConfig | undefined {
1013
1096
  const override: BuiltinAgentOverrideConfig = {};
1014
1097
 
@@ -1027,6 +1110,7 @@ export function buildBuiltinOverrideConfig(
1027
1110
  const baseTools = joinToolList(base);
1028
1111
  const draftTools = joinToolList(draft);
1029
1112
  if (!arraysEqual(draftTools, baseTools)) override.tools = draftTools ? [...draftTools] : false;
1113
+ if (!arraysEqual(draft.extensions, base.extensions)) override.extensions = draft.extensions ? [...draft.extensions] : false;
1030
1114
  if (!arraysEqual(draft.subagentOnlyExtensions, base.subagentOnlyExtensions)) {
1031
1115
  override.subagentOnlyExtensions = draft.subagentOnlyExtensions ? [...draft.subagentOnlyExtensions] : false;
1032
1116
  }
@@ -1159,7 +1243,19 @@ export function removeBuiltinAgentOverrideFields(
1159
1243
  return { path: filePath, removed: true };
1160
1244
  }
1161
1245
 
1162
- function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean): string[] {
1246
+ const DISCOVERY_PRUNED_DIR_NAMES = new Set([".git", "node_modules"]);
1247
+
1248
+ function isDiscoveryNestedProjectRoot(dir: string): boolean {
1249
+ return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, ".agents"));
1250
+ }
1251
+
1252
+ function shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {
1253
+ if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;
1254
+ if (fs.existsSync(path.join(dir, ".git"))) return true;
1255
+ return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);
1256
+ }
1257
+
1258
+ function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {
1163
1259
  const files: string[] = [];
1164
1260
  if (!fs.existsSync(dir)) return files;
1165
1261
 
@@ -1173,7 +1269,9 @@ function listFilesRecursive(dir: string, predicate: (fileName: string) => boolea
1173
1269
  for (const entry of entries) {
1174
1270
  const filePath = path.join(dir, entry.name);
1175
1271
  if (entry.isDirectory()) {
1176
- files.push(...listFilesRecursive(filePath, predicate));
1272
+ if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {
1273
+ files.push(...listFilesRecursive(filePath, predicate, rootDir));
1274
+ }
1177
1275
  continue;
1178
1276
  }
1179
1277
  if (!entry.isFile() && !entry.isSymbolicLink()) continue;
@@ -1233,7 +1331,9 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1233
1331
  const runtimeName = buildRuntimeName(localName, packageName);
1234
1332
 
1235
1333
  const rawTools = parseFrontmatterList(frontmatter.tools);
1236
- const { tools = [], mcpDirectTools = [] } = splitToolList(rawTools);
1334
+ const parsedTools = splitToolList(rawTools);
1335
+ const tools = parsedTools.tools ?? [];
1336
+ const mcpDirectTools = parsedTools.mcpDirectTools ?? [];
1237
1337
  const defaultReads = parseFrontmatterList(frontmatter.defaultReads);
1238
1338
  const skillStr = frontmatter.skill || frontmatter.skills;
1239
1339
  const skills = parseFrontmatterList(skillStr);
@@ -1315,7 +1415,7 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1315
1415
  localName,
1316
1416
  packageName,
1317
1417
  description: frontmatter.description,
1318
- tools: tools.length > 0 ? tools : undefined,
1418
+ tools: rawTools !== undefined ? tools : undefined,
1319
1419
  mcpDirectTools: mcpDirectTools.length > 0 ? mcpDirectTools : undefined,
1320
1420
  model: frontmatter.model,
1321
1421
  fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,
@@ -1443,6 +1543,8 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1443
1543
  const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
1444
1544
  const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
1445
1545
  const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1546
+ const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
1547
+ const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
1446
1548
  const modelScope = projectSettings.modelScope ?? userSettings.modelScope;
1447
1549
  const packageSubagentPaths = collectPackageSubagentPaths(cwd, {
1448
1550
  includeUser: scope !== "project",
@@ -1450,7 +1552,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1450
1552
  });
1451
1553
 
1452
1554
  const builtinAgents = applyBuiltinOverrides(
1453
- applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel),
1555
+ applySubagentDefaults(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel, defaultThinking, defaultExtensions),
1454
1556
  userSettings,
1455
1557
  projectSettings,
1456
1558
  userSettingsPath,
@@ -1461,7 +1563,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1461
1563
  const userAgentsOld = scope === "project" ? [] : loadAgentsFromDir(userDirOld, "user");
1462
1564
  const userAgentsNew = scope === "project" ? [] : loadAgentsFromDir(userDirNew, "user");
1463
1565
  const userAgents = applyCustomAgentOverrides(
1464
- applySubagentDefaultModel([...userAgentsExtra, ...userAgentsOld, ...userAgentsNew], defaultModel),
1566
+ applySubagentDefaults([...userAgentsExtra, ...userAgentsOld, ...userAgentsNew], defaultModel, defaultThinking, defaultExtensions),
1465
1567
  userSettings,
1466
1568
  projectSettings,
1467
1569
  userSettingsPath,
@@ -1469,14 +1571,14 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1469
1571
  );
1470
1572
 
1471
1573
  const projectAgents = applyCustomAgentOverrides(
1472
- applySubagentDefaultModel(scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")), defaultModel),
1574
+ applySubagentDefaults(scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")), defaultModel, defaultThinking, defaultExtensions),
1473
1575
  userSettings,
1474
1576
  projectSettings,
1475
1577
  userSettingsPath,
1476
1578
  projectSettingsPath,
1477
1579
  );
1478
1580
  const packageAgents = applyCustomAgentOverrides(
1479
- applySubagentDefaultModel(packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package")), defaultModel),
1581
+ applySubagentDefaults(packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package")), defaultModel, defaultThinking, defaultExtensions),
1480
1582
  userSettings,
1481
1583
  projectSettings,
1482
1584
  userSettingsPath,
@@ -1512,21 +1614,23 @@ export function discoverAgentsAll(cwd: string): {
1512
1614
  const userSettings = readSubagentSettings(userSettingsPath);
1513
1615
  const projectSettings = readSubagentSettings(projectSettingsPath);
1514
1616
  const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1617
+ const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
1618
+ const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
1515
1619
  const packageSubagentPaths = collectPackageSubagentPaths(cwd);
1516
1620
 
1517
1621
  const builtin = applyBuiltinOverrides(
1518
- applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel),
1622
+ applySubagentDefaults(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel, defaultThinking, defaultExtensions),
1519
1623
  userSettings,
1520
1624
  projectSettings,
1521
1625
  userSettingsPath,
1522
1626
  projectSettingsPath,
1523
1627
  );
1524
1628
  const user = applyCustomAgentOverrides(
1525
- applySubagentDefaultModel([
1629
+ applySubagentDefaults([
1526
1630
  ...extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, "user")),
1527
1631
  ...loadAgentsFromDir(userDirOld, "user"),
1528
1632
  ...loadAgentsFromDir(userDirNew, "user"),
1529
- ], defaultModel),
1633
+ ], defaultModel, defaultThinking, defaultExtensions),
1530
1634
  userSettings,
1531
1635
  projectSettings,
1532
1636
  userSettingsPath,
@@ -1539,7 +1643,7 @@ export function discoverAgentsAll(cwd: string): {
1539
1643
  }
1540
1644
  }
1541
1645
  const packageAgents = applyCustomAgentOverrides(
1542
- applySubagentDefaultModel(Array.from(packageMap.values()), defaultModel),
1646
+ applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultThinking, defaultExtensions),
1543
1647
  userSettings,
1544
1648
  projectSettings,
1545
1649
  userSettingsPath,
@@ -1552,7 +1656,7 @@ export function discoverAgentsAll(cwd: string): {
1552
1656
  }
1553
1657
  }
1554
1658
  const project = applyCustomAgentOverrides(
1555
- applySubagentDefaultModel(Array.from(projectMap.values()), defaultModel),
1659
+ applySubagentDefaults(Array.from(projectMap.values()), defaultModel, defaultThinking, defaultExtensions),
1556
1660
  userSettings,
1557
1661
  projectSettings,
1558
1662
  userSettingsPath,
@@ -0,0 +1,17 @@
1
+ export {
2
+ SUBAGENT_CAPABILITY_CEILING_ENV,
3
+ SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY,
4
+ SUBAGENT_CAPABILITY_CEILING_VERSION,
5
+ decodeSubagentCapabilityCeiling,
6
+ encodeSubagentCapabilityCeiling,
7
+ intersectSubagentCapabilityCeilings,
8
+ parseSubagentCapabilityCeiling,
9
+ registerSubagentCapabilityCeiling,
10
+ resolveCurrentSubagentCapabilityCeiling,
11
+ resolveSubagentCapabilityCeiling,
12
+ type RegisterSubagentCapabilityCeilingOptions,
13
+ type ResolvedSubagentCapabilityCeiling,
14
+ type SubagentCapabilityCeiling,
15
+ type SubagentCapabilityCeilingHandle,
16
+ type SubagentCapabilityAudit,
17
+ } from "../runs/shared/capability-ceiling.ts";
@@ -1,4 +1,5 @@
1
1
  export const SUBAGENT_DELEGATION_PROTOCOL_VERSION = 1 as const;
2
+ export const SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION = 2 as const;
2
3
 
3
4
  // This is the established extension-to-extension transport. The public API
4
5
  // intentionally reuses it instead of adding a second event protocol.
@@ -19,6 +20,37 @@ export interface SubagentDelegationToolBudget {
19
20
  block?: string[] | "*";
20
21
  }
21
22
 
23
+ export interface SubagentDelegationAgentContract {
24
+ version: 1;
25
+ }
26
+
27
+ export type SubagentDelegationJsonSchemaObject = Record<string, unknown>;
28
+
29
+ export interface SubagentDelegationExecutionResult {
30
+ status: "completed" | "failed" | "paused" | "stopped" | "detached";
31
+ success: boolean;
32
+ exitCode: number;
33
+ error?: string;
34
+ interrupted?: boolean;
35
+ timedOut?: boolean;
36
+ stopped?: boolean;
37
+ detached?: boolean;
38
+ }
39
+
40
+ export interface SubagentDelegationReviewResult {
41
+ status: "not-requested" | "review-required" | "reviewed" | "blockers";
42
+ findings?: Array<{ severity: "blocker" | "non-blocking"; file?: string; issue: string; rationale: string }>;
43
+ }
44
+
45
+ export interface SubagentDelegationEffectsResult {
46
+ fileMutation?: {
47
+ status: "not-requested" | "not-applicable" | "observed" | "missing";
48
+ expected: boolean;
49
+ attempted: boolean;
50
+ message?: string;
51
+ };
52
+ }
53
+
22
54
  export type SubagentDelegationAcceptanceEvidence =
23
55
  | "changed-files"
24
56
  | "tests-added"
@@ -87,6 +119,8 @@ export interface SubagentDelegationRequest {
87
119
  skill?: string | string[] | boolean;
88
120
  output?: string | boolean;
89
121
  outputMode?: "inline" | "file-only";
122
+ outputSchema?: SubagentDelegationJsonSchemaObject;
123
+ agentContract?: SubagentDelegationAgentContract;
90
124
  acceptance?: SubagentDelegationAcceptance;
91
125
  artifacts?: boolean;
92
126
  }
@@ -116,6 +150,7 @@ export type SubagentDelegationStatus =
116
150
  | "interrupted"
117
151
  | "turn_budget_exhausted"
118
152
  | "tool_budget_exhausted"
153
+ | "structured_output_failed"
119
154
  | "acceptance_failed"
120
155
  | "invalid_request"
121
156
  | "unavailable_context";
@@ -127,12 +162,14 @@ export type SubagentDelegationAcceptanceStatus =
127
162
  | "attested"
128
163
  | "checked"
129
164
  | "verified"
165
+ | "review-required"
130
166
  | "reviewed"
131
167
  | "accepted"
132
168
  | "rejected";
133
169
 
134
170
  export interface SubagentDelegationAcceptanceResult {
135
171
  status: SubagentDelegationAcceptanceStatus;
172
+ evidenceStatus: Exclude<SubagentDelegationAcceptanceStatus, "review-required" | "reviewed" | "accepted">;
136
173
  explicit: boolean;
137
174
  }
138
175
 
@@ -144,10 +181,13 @@ export interface SubagentDelegationResponse extends SubagentDelegationStarted {
144
181
  agent?: string;
145
182
  model?: string;
146
183
  exitCode?: number;
184
+ execution?: SubagentDelegationExecutionResult;
147
185
  output?: string;
148
186
  outputPath?: string;
149
187
  sessionFile?: string;
150
188
  acceptance?: SubagentDelegationAcceptanceResult;
189
+ review?: SubagentDelegationReviewResult;
190
+ effects?: SubagentDelegationEffectsResult;
151
191
  turns?: number;
152
192
  toolCount?: number;
153
193
  durationMs?: number;
@@ -156,3 +196,90 @@ export interface SubagentDelegationResponse extends SubagentDelegationStarted {
156
196
  }
157
197
 
158
198
  export interface SubagentDelegationCancel extends SubagentDelegationStarted {}
199
+
200
+ export type SubagentDelegationV2Thinking = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
201
+
202
+ export type SubagentDelegationV2ResultRequest =
203
+ | { kind: "text" }
204
+ | { kind: "structured"; schema: SubagentDelegationJsonSchemaObject };
205
+
206
+ export interface SubagentDelegationV2Request {
207
+ version: typeof SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION;
208
+ requestId: string;
209
+ ownerRunId: string;
210
+ nodeId: string;
211
+ agent: string;
212
+ task: string;
213
+ context: "fresh" | "fork";
214
+ cwd: string;
215
+ model?: string;
216
+ thinking?: SubagentDelegationV2Thinking;
217
+ timeoutMs?: number;
218
+ turnBudget?: SubagentDelegationTurnBudget;
219
+ toolBudget?: SubagentDelegationToolBudget;
220
+ skill?: string | string[] | boolean;
221
+ artifacts?: boolean;
222
+ result: SubagentDelegationV2ResultRequest;
223
+ }
224
+
225
+ export interface SubagentDelegationV2Started {
226
+ version: typeof SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION;
227
+ requestId: string;
228
+ ownerRunId: string;
229
+ nodeId: string;
230
+ }
231
+
232
+ export interface SubagentDelegationV2Update extends SubagentDelegationV2Started {
233
+ currentTool?: string;
234
+ currentToolArgs?: string;
235
+ recentOutput?: string;
236
+ recentOutputLines?: string[];
237
+ recentTools?: Array<{ tool: string; args: string }>;
238
+ model?: string;
239
+ toolCount?: number;
240
+ durationMs?: number;
241
+ tokens?: number;
242
+ }
243
+
244
+ export type SubagentDelegationV2Status = SubagentDelegationStatus | "duplicate_node";
245
+
246
+ export type SubagentDelegationV2Value =
247
+ | { kind: "text"; text: string }
248
+ | { kind: "structured"; value: unknown };
249
+
250
+ export interface SubagentDelegationV2Usage {
251
+ input: number;
252
+ output: number;
253
+ cacheRead: number;
254
+ cacheWrite: number;
255
+ cost: number;
256
+ turns: number;
257
+ toolCalls: number;
258
+ durationMs: number;
259
+ }
260
+
261
+ export interface SubagentDelegationV2TerminalResponse extends SubagentDelegationV2Started {
262
+ status: Exclude<SubagentDelegationV2Status, "invalid_request">;
263
+ error?: string;
264
+ runId?: string;
265
+ agent?: string;
266
+ model?: string;
267
+ thinking?: string;
268
+ exitCode?: number;
269
+ result?: SubagentDelegationV2Value;
270
+ usage?: SubagentDelegationV2Usage;
271
+ }
272
+
273
+ /** A malformed V2 request can only be correlated by the valid identity fields it supplied. */
274
+ export interface SubagentDelegationV2InvalidResponse {
275
+ version: typeof SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION;
276
+ requestId: string;
277
+ ownerRunId?: string;
278
+ nodeId?: string;
279
+ status: "invalid_request";
280
+ error?: string;
281
+ }
282
+
283
+ export type SubagentDelegationV2Response = SubagentDelegationV2TerminalResponse | SubagentDelegationV2InvalidResponse;
284
+
285
+ export interface SubagentDelegationV2Cancel extends SubagentDelegationV2Started {}