pi-subagents 0.52.0 → 0.53.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 (54) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +4 -0
  3. package/docs/configuration.md +11 -1
  4. package/docs/extension-api.md +3 -1
  5. package/docs/workflows.md +2 -0
  6. package/package.json +2 -1
  7. package/prompts/council.md +48 -0
  8. package/skills/council-mode/SKILL.md +230 -0
  9. package/skills/pi-subagents/SKILL.md +2 -0
  10. package/skills/pi-subagents/references/constraints-and-recipes.md +1 -0
  11. package/skills/pi-subagents/references/execution-controls.md +11 -0
  12. package/skills/pi-subagents/references/multi-lane-orchestration.md +39 -0
  13. package/src/agents/agent-management.ts +22 -3
  14. package/src/agents/agent-serializer.ts +2 -0
  15. package/src/agents/agents.ts +29 -13
  16. package/src/agents/builtin-names.ts +9 -0
  17. package/src/agents/runtime-agent-registry.ts +418 -0
  18. package/src/api/agents.ts +7 -0
  19. package/src/api/external-job-provider.ts +3 -2
  20. package/src/api/preflight.ts +1 -1
  21. package/src/extension/config.ts +3 -0
  22. package/src/extension/doctor.ts +1 -0
  23. package/src/extension/index.ts +17 -2
  24. package/src/extension/rpc.ts +41 -1
  25. package/src/extension/schemas.ts +7 -4
  26. package/src/extension/tool-description.ts +2 -2
  27. package/src/runs/background/async-execution.ts +2 -1
  28. package/src/runs/background/async-job-tracker.ts +4 -3
  29. package/src/runs/background/async-resume.ts +2 -1
  30. package/src/runs/background/async-status-snapshot.ts +14 -5
  31. package/src/runs/background/auto-drain.ts +1 -0
  32. package/src/runs/background/result-watcher.ts +8 -0
  33. package/src/runs/background/subagent-runner.ts +7 -4
  34. package/src/runs/background/subagent-wait.ts +9 -5
  35. package/src/runs/background/terminal-run-index.ts +15 -6
  36. package/src/runs/background/wait-tool.ts +1 -0
  37. package/src/runs/foreground/execution.ts +5 -1
  38. package/src/runs/foreground/subagent-executor.ts +182 -46
  39. package/src/runs/foreground/workflow-detach-reconcile.ts +83 -15
  40. package/src/runs/shared/acceptance.ts +44 -1
  41. package/src/runs/shared/model-exclusions.ts +242 -0
  42. package/src/runs/shared/model-fallback.ts +55 -2
  43. package/src/runs/shared/subagent-control.ts +25 -3
  44. package/src/shared/fork-context.ts +17 -1
  45. package/src/shared/model-info.ts +20 -0
  46. package/src/shared/settings.ts +2 -2
  47. package/src/shared/types.ts +35 -0
  48. package/src/slash/slash-commands.ts +20 -6
  49. package/src/slash/slash-live-state.ts +3 -3
  50. package/src/tui/fleet-status.ts +86 -1
  51. package/src/tui/fleet.ts +55 -2
  52. package/src/tui/render.ts +73 -3
  53. package/src/workflows/scripted-workflow.ts +100 -12
  54. package/src/workflows/workflow-receipt.ts +140 -0
@@ -7,7 +7,7 @@ import { findBlockingAgentDiagnostic, resolveAgentName, type AgentConfig, type A
7
7
  import { getArtifactsDir, getChainRunsDir, getProjectArtifactPackagingWarning, getProjectSubagentsDir } from "../../shared/artifacts.ts";
8
8
  import { writeAtomicJson } from "../../shared/atomic-json.ts";
9
9
  import { createCapacityResilientJsonWriter } from "../../shared/capacity-resilient-json.ts";
10
- import { isRetryableFileSystemError, isStorageCapacityError } from "../../shared/file-system-retry.ts";
10
+ import { isStorageCapacityError } from "../../shared/file-system-retry.ts";
11
11
  import { resolveEffectiveThinking, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
12
12
  import {
13
13
  beginForegroundChild,
@@ -118,7 +118,8 @@ import { createMissionWorkflowState } from "../../missions/workflow-state.ts";
118
118
  import { resolveAuthorityDecision } from "../../policy/authority.ts";
119
119
  import { handleHerdrInspectorAction, HERDR_INSPECTOR_ACTIONS } from "../../inspectors/herdr/actions.ts";
120
120
  import { handleHerdrProjectPaneAction, HERDR_PROJECT_PANE_ACTIONS } from "../../inspectors/herdr/project-panes.ts";
121
- import { previewSimpleWorkflowRun, runWorkflowScript, WorkflowScriptError, type WorkflowScriptChildResult, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
121
+ import { previewSimpleWorkflowRun, runWorkflowScript, WorkflowScriptError, type WorkflowReceiptResumeReference, type WorkflowScriptChildResult, type WorkflowSteerOptions, type WorkflowSteerResult } from "../../workflows/scripted-workflow.ts";
122
+ import { buildWorkflowReceipt, resolveWorkflowReceiptResumeEntry, writeWorkflowReceipt, type WorkflowReceipt, type WorkflowReceiptState } from "../../workflows/workflow-receipt.ts";
122
123
  import { resolveWorkflowChatProgress, type WorkflowChatProgressProjection } from "../../workflows/chat-progress.ts";
123
124
  import {
124
125
  cleanupWorktrees,
@@ -308,7 +309,7 @@ export interface SubagentParamsLike {
308
309
  tasks?: TaskParam[];
309
310
  concurrency?: number;
310
311
  worktree?: boolean;
311
- context?: "fresh" | "fork";
312
+ context?: "fresh" | "fork" | "profile";
312
313
  /** Per-run intercom bridge config. It replaces the global config for this launch only. */
313
314
  intercomBridge?: IntercomBridgeConfig;
314
315
  async?: boolean;
@@ -795,12 +796,13 @@ function updateRememberedForegroundChild(state: SubagentState, input: { runId: s
795
796
  });
796
797
  }
797
798
 
798
- function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState): { runId: string; mode: SubagentRunMode; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
799
+ function resolveForegroundResumeTarget(params: SubagentParamsLike, state: SubagentState, options: { exactOnly?: boolean } = {}): { runId: string; mode: SubagentRunMode; state: "complete"; agent: string; index: number; cwd: string; sessionFile: string; model?: string; thinking?: string; launchContractDigest?: string; capabilityCeiling?: ResolvedSubagentCapabilityCeiling } | undefined {
799
800
  const requested = (params.id ?? params.runId)?.trim();
800
801
  if (!requested || !state.foregroundRuns?.size || !state.currentSessionId) return undefined;
801
- const sessionRuns = [...state.foregroundRuns.values()].filter((run) => run.sessionId === state.currentSessionId);
802
- const direct = sessionRuns.find((run) => run.runId === requested);
803
- const matches = direct ? [direct] : sessionRuns.filter((run) => run.runId.startsWith(requested));
802
+ const direct = state.foregroundRuns.get(requested);
803
+ const matches = direct?.sessionId === state.currentSessionId
804
+ ? [direct]
805
+ : options.exactOnly ? [] : [...state.foregroundRuns.values()].filter((run) => run.sessionId === state.currentSessionId && run.runId.startsWith(requested));
804
806
  if (matches.length === 0) return undefined;
805
807
  if (matches.length > 1) throw new Error(`Ambiguous foreground run id prefix '${requested}' matched: ${matches.map((run) => run.runId).join(", ")}. Provide a longer id.`);
806
808
  const run = matches[0]!;
@@ -868,7 +870,7 @@ function isExactResumeError(error: unknown, source: "async" | "foreground", requ
868
870
  return new RegExp(`\\b${source} run '${escapeRegExp(requested)}'`, "i").test(error.message);
869
871
  }
870
872
 
871
- function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, options: { asyncRequireSessionFile?: boolean } = {}): ResumeSourceTarget {
873
+ function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, options: { asyncRequireSessionFile?: boolean; exactOnly?: boolean } = {}): ResumeSourceTarget {
872
874
  const requested = (params.id ?? params.runId)?.trim() ?? "";
873
875
  let foregroundTarget: ForegroundResumeSourceTarget | undefined;
874
876
  let foregroundError: unknown;
@@ -876,15 +878,18 @@ function resolveResumeTarget(params: SubagentParamsLike, state: SubagentState, o
876
878
  let asyncError: unknown;
877
879
 
878
880
  try {
879
- const target = resolveForegroundResumeTarget(params, state);
881
+ const target = resolveForegroundResumeTarget(params, state, options);
880
882
  if (target) foregroundTarget = { kind: "revive", source: "foreground", ...target };
881
883
  } catch (error) {
882
884
  foregroundError = error;
883
885
  }
884
886
  try {
887
+ const asyncParams = options.exactOnly && requested && !params.dir
888
+ ? { ...params, dir: path.join(DIRS.async, requested) }
889
+ : params;
885
890
  asyncTarget = {
886
891
  source: "async",
887
- ...resolveAsyncResumeTarget(params, {}, compactOptional<NonNullable<Parameters<typeof resolveAsyncResumeTarget>[2]>>({
892
+ ...resolveAsyncResumeTarget(asyncParams, {}, compactOptional<NonNullable<Parameters<typeof resolveAsyncResumeTarget>[2]>>({
888
893
  requireSessionFile: options.asyncRequireSessionFile,
889
894
  sessionId: state.currentSessionId ?? undefined,
890
895
  })),
@@ -1566,10 +1571,11 @@ async function resumeAsyncRun(input: {
1566
1571
  const modelScope = discovered.modelScope;
1567
1572
  const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
1568
1573
  const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
1574
+ const recoveryContext = recoveryDescriptor?.context ?? (input.params.context === "profile" ? undefined : input.params.context);
1569
1575
  const intercomBridge = resolveIntercomBridge({
1570
1576
  config: input.deps.config.intercomBridge,
1571
1577
  override: input.params.intercomBridge ?? recoveryDescriptor?.intercomBridge,
1572
- context: input.params.context,
1578
+ context: recoveryContext,
1573
1579
  orchestratorTarget: sessionName,
1574
1580
  });
1575
1581
  const agents = intercomBridge.active
@@ -1765,6 +1771,7 @@ async function resumeAsyncRun(input: {
1765
1771
  sourceRunId: target.runId,
1766
1772
  ...(input.deps.state.currentSessionId ? { parentSessionId: input.deps.state.currentSessionId } : {}),
1767
1773
  },
1774
+ context: recoveryContext,
1768
1775
  modelOverride: recoveryDescriptor?.model ?? target.model,
1769
1776
  modelOverrideFromParent: recoveryDescriptor?.modelOverrideFromParent,
1770
1777
  thinkingOverride: recoveryDescriptor?.thinking ?? target.thinking,
@@ -1916,9 +1923,12 @@ function formatFailedSingleRunOutput(result: SingleResult, displayOutput: string
1916
1923
  return lines.join("\n");
1917
1924
  }
1918
1925
 
1919
- function createForegroundControlNotifier(data: Pick<ExecutionContextData, "controlConfig" | "intercomBridge" | "params">, deps: Pick<ExecutorDeps, "pi" | "state">): (event: ControlEvent) => void {
1926
+ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "controlConfig" | "contextPolicy" | "intercomBridge" | "params">, deps: Pick<ExecutorDeps, "pi" | "state">): (event: ControlEvent) => void {
1920
1927
  return (event) => {
1921
1928
  applyControlEventToRememberedForegroundRun(deps.state, event);
1929
+ const eventBridge = intercomBridgeAppliesToAgent(data.intercomBridge, data.contextPolicy, event.agent)
1930
+ ? data.intercomBridge
1931
+ : { ...data.intercomBridge, active: false };
1922
1932
  const parentWorkflowRunId = data.params.workflowParentRunId;
1923
1933
  const asyncWorkflow = typeof parentWorkflowRunId === "string" ? deps.state.asyncJobs.get(parentWorkflowRunId) : undefined;
1924
1934
  const workflowKey = typeof data.params.workflowKey === "string" && data.params.workflowKey.trim()
@@ -1930,8 +1940,8 @@ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "contr
1930
1940
  job: asyncWorkflow,
1931
1941
  event: enriched,
1932
1942
  controlConfig: data.controlConfig,
1933
- intercomBridge: data.intercomBridge,
1934
- childIntercomTarget: data.intercomBridge.active
1943
+ intercomBridge: eventBridge,
1944
+ childIntercomTarget: eventBridge.active
1935
1945
  ? resolveSubagentIntercomTarget(enriched.runId, enriched.agent, enriched.index)
1936
1946
  : undefined,
1937
1947
  });
@@ -1939,7 +1949,7 @@ function createForegroundControlNotifier(data: Pick<ExecutionContextData, "contr
1939
1949
  emitControlNotification({
1940
1950
  pi: deps.pi,
1941
1951
  controlConfig: data.controlConfig,
1942
- intercomBridge: data.intercomBridge,
1952
+ intercomBridge: eventBridge,
1943
1953
  event: enriched,
1944
1954
  source: asyncWorkflow ? "async" : "foreground",
1945
1955
  });
@@ -2243,17 +2253,40 @@ interface AgentDefaultContextPolicy {
2243
2253
  usesFork: boolean;
2244
2254
  }
2245
2255
 
2256
+ type AgentDefaultContextPolicyResult = AgentDefaultContextPolicy | { error: string };
2257
+
2246
2258
  function resolveAgentDefaultContextPolicy(
2247
2259
  params: SubagentParamsLike,
2248
2260
  agents: AgentConfig[],
2249
2261
  defaultSubagentContext: ExtensionConfig["defaultSubagentContext"],
2250
2262
  canUseDefaultFork = false,
2251
- ): AgentDefaultContextPolicy {
2252
- if (params.context !== undefined) return resolveExplicitContextPolicy(params);
2263
+ ): AgentDefaultContextPolicyResult {
2264
+ if (params.context === "profile") {
2265
+ const byName = new Map(agents.map((agent) => [agent.name, agent]));
2266
+ for (const agentName of collectRequestedAgentNames(params)) {
2267
+ const agent = byName.get(agentName);
2268
+ if (agent && agent.defaultContext === undefined) {
2269
+ return { error: `context: "profile" requires agent '${agentName}' to declare defaultContext.` };
2270
+ }
2271
+ }
2272
+ const contextForAgent = (agentName: string): ContextMode => {
2273
+ const context = byName.get(agentName)?.defaultContext;
2274
+ if (context === undefined) throw new Error(`context: "profile" requires agent '${agentName}' to declare defaultContext.`);
2275
+ return context;
2276
+ };
2277
+ const contextSummary = summarizeContextModes(collectRequestedAgentNames(params).map(contextForAgent));
2278
+ return {
2279
+ params,
2280
+ contextForAgent,
2281
+ contextSummary,
2282
+ usesFork: contextSummary === "fork" || contextSummary === "mixed",
2283
+ };
2284
+ }
2285
+ if (params.context === "fresh" || params.context === "fork") return resolveExplicitContextPolicy(params);
2253
2286
  const byName = new Map(agents.map((agent) => [agent.name, agent]));
2254
2287
  const contextForAgent = (agentName: string): ContextMode =>
2255
2288
  resolveSubagentLaunchContext({
2256
- explicitContext: params.context,
2289
+ explicitContext: undefined,
2257
2290
  agentDefaultContext: byName.get(agentName)?.defaultContext,
2258
2291
  defaultSubagentContext,
2259
2292
  canUseImplicitFork: canUseDefaultFork,
@@ -2271,7 +2304,7 @@ function resolveAgentDefaultContextPolicy(
2271
2304
 
2272
2305
  function resolveExplicitContextPolicy(params: SubagentParamsLike): AgentDefaultContextPolicy {
2273
2306
  const context = resolveSubagentLaunchContext({
2274
- explicitContext: params.context,
2307
+ explicitContext: params.context === "profile" ? undefined : params.context,
2275
2308
  canUseImplicitFork: false,
2276
2309
  });
2277
2310
  return {
@@ -2294,6 +2327,31 @@ function shouldForkAgent(contextPolicy: AgentDefaultContextPolicy, agentName: st
2294
2327
  return contextPolicy.contextForAgent(agentName) === "fork";
2295
2328
  }
2296
2329
 
2330
+ function intercomBridgeAppliesToAgent(bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy, agentName: string): boolean {
2331
+ if (!bridge.active) return false;
2332
+ return bridge.mode !== "fork-only" || shouldForkAgent(contextPolicy, agentName);
2333
+ }
2334
+
2335
+ function applyScopedIntercomBridgeToAgents(agents: AgentConfig[], bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy): AgentConfig[] {
2336
+ if (!bridge.active) return agents;
2337
+ return agents.map((agent) => intercomBridgeAppliesToAgent(bridge, contextPolicy, agent.name)
2338
+ ? applyIntercomBridgeToAgent(agent, bridge)
2339
+ : agent);
2340
+ }
2341
+
2342
+ function resolveChildIntercomTargetFactory(bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy, runId: string): ((agent: string, index: number) => string | undefined) | undefined {
2343
+ if (!bridge.active) return undefined;
2344
+ return (agent, index) => intercomBridgeAppliesToAgent(bridge, contextPolicy, agent)
2345
+ ? resolveSubagentIntercomTarget(runId, agent, index)
2346
+ : undefined;
2347
+ }
2348
+
2349
+ function resolveRunLevelIntercomTarget(bridge: IntercomBridgeState, contextPolicy: AgentDefaultContextPolicy): string | undefined {
2350
+ if (!bridge.active) return undefined;
2351
+ if (bridge.mode === "fork-only" && contextPolicy.contextSummary === "mixed") return undefined;
2352
+ return bridge.orchestratorTarget;
2353
+ }
2354
+
2297
2355
  function summarizeResultContext(details: Details, fallback: ContextSummary | undefined): ContextSummary | undefined {
2298
2356
  return summarizeContextModes(details.results.map((result) => result.context)) ?? fallback;
2299
2357
  }
@@ -2305,7 +2363,7 @@ function buildRequestedModeError(params: SubagentParamsLike, message: string): A
2305
2363
  isError: true,
2306
2364
  details: { mode: getRequestedModeLabel(params), results: [] },
2307
2365
  },
2308
- params.context,
2366
+ params.context === "profile" ? undefined : params.context,
2309
2367
  );
2310
2368
  }
2311
2369
 
@@ -2810,8 +2868,8 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
2810
2868
  const availableModels: ModelInfo[] = ctx.modelRegistry.getAvailable().map(toModelInfo);
2811
2869
  const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
2812
2870
  const currentProvider = parentModel?.provider;
2813
- const controlIntercomTarget = intercomBridge.active ? intercomBridge.orchestratorTarget : undefined;
2814
- const childIntercomTarget = intercomBridge.active ? (agent: string, index: number) => resolveSubagentIntercomTarget(id, agent, index) : undefined;
2871
+ const controlIntercomTarget = resolveRunLevelIntercomTarget(intercomBridge, contextPolicy);
2872
+ const childIntercomTarget = resolveChildIntercomTargetFactory(intercomBridge, contextPolicy, id);
2815
2873
 
2816
2874
 
2817
2875
  if (hasSingle) {
@@ -2825,7 +2883,7 @@ function runAsyncPath(data: ExecutionContextData, deps: ExecutorDeps): AgentTool
2825
2883
  }
2826
2884
  const rawOutput = params.output !== undefined ? params.output : a.output;
2827
2885
  const effectiveOutput = normalizeSingleOutputOverride(rawOutput, a.output);
2828
- const effectiveOutputMode = params.outputMode ?? "inline";
2886
+ const effectiveOutputMode = params.outputMode ?? a.outputMode ?? "inline";
2829
2887
  const normalizedSkills = normalizeSkillInput(params.skill);
2830
2888
  const skills = normalizedSkills === false ? [] : normalizedSkills;
2831
2889
  const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, a.maxSubagentDepth);
@@ -3158,7 +3216,8 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
3158
3216
  contextPolicy,
3159
3217
  } = data;
3160
3218
  const onControlEvent = createForegroundControlNotifier(data, deps);
3161
- const childIntercomTarget = data.intercomBridge.active ? resolveSubagentIntercomTarget(runId, params.agent!, 0) : undefined;
3219
+ const childBridgeActive = intercomBridgeAppliesToAgent(data.intercomBridge, contextPolicy, params.agent!);
3220
+ const childIntercomTarget = childBridgeActive ? resolveSubagentIntercomTarget(runId, params.agent!, 0) : undefined;
3162
3221
  const allProgress: AgentProgress[] = [];
3163
3222
  const allArtifactPaths: ArtifactPaths[] = [];
3164
3223
  const agentConfig = agents.find((a) => a.name === params.agent);
@@ -3189,7 +3248,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
3189
3248
  let readsOverride: string[] | false | undefined = params.reads;
3190
3249
  const rawOutput = params.output !== undefined ? params.output : agentConfig.output;
3191
3250
  let effectiveOutput = normalizeSingleOutputOverride(rawOutput, agentConfig.output);
3192
- const effectiveOutputMode = params.outputMode ?? "inline";
3251
+ const effectiveOutputMode = params.outputMode ?? agentConfig.outputMode ?? "inline";
3193
3252
  const currentMaxSubagentDepth = resolveCurrentMaxSubagentDepth(deps.config.maxSubagentDepth);
3194
3253
  const maxSubagentDepth = resolveChildMaxSubagentDepth(currentMaxSubagentDepth, agentConfig.maxSubagentDepth);
3195
3254
 
@@ -3317,7 +3376,7 @@ async function runSinglePath(data: ExecutionContextData, deps: ExecutorDeps): Pr
3317
3376
  controlConfig,
3318
3377
  onControlEvent,
3319
3378
  intercomSessionName: childIntercomTarget,
3320
- orchestratorIntercomTarget: data.intercomBridge.active ? data.intercomBridge.orchestratorTarget : undefined,
3379
+ orchestratorIntercomTarget: childBridgeActive ? data.intercomBridge.orchestratorTarget : undefined,
3321
3380
  nestedRoute: foregroundControl?.nestedRoute,
3322
3381
  index: 0,
3323
3382
  modelOverride,
@@ -3579,7 +3638,12 @@ export function bindMissionWorkflowChildAsyncLaunch(
3579
3638
  return { ...params, workflowChildAsyncId: id };
3580
3639
  }
3581
3640
 
3582
- function workflowChildResult(key: string, result: AgentToolResult<Details>): WorkflowScriptChildResult {
3641
+ function workflowChildResult(
3642
+ key: string,
3643
+ result: AgentToolResult<Details>,
3644
+ childParams: Record<string, unknown> = {},
3645
+ resumeState?: SubagentState,
3646
+ ): WorkflowScriptChildResult {
3583
3647
  const receiptOutput = result.content.map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
3584
3648
  const output = result.details.results.length === 1 && result.details.results[0]?.finalOutput !== undefined
3585
3649
  ? result.details.results[0].finalOutput
@@ -3596,15 +3660,41 @@ function workflowChildResult(key: string, result: AgentToolResult<Details>): Wor
3596
3660
  }
3597
3661
  const structured = result.details.results.map((child) => child.structuredOutput).filter((value) => value !== undefined);
3598
3662
  const resolvedAgents = [...new Set(result.details.results.map((child) => child.agent).filter((agent): agent is string => Boolean(agent)))];
3663
+ const resolvedContexts = [...new Set(result.details.results.map((child) => child.context).filter((context): context is "fresh" | "fork" => context === "fresh" || context === "fork"))];
3664
+ const runId = result.details.runId ?? result.details.asyncId;
3665
+ let resumability: WorkflowScriptChildResult["resumability"];
3666
+ if (!runId || !resumeState) {
3667
+ resumability = { state: "not-resumable", reason: runId ? "resumability was not inspected" : "child produced no run id" };
3668
+ } else {
3669
+ try {
3670
+ const target = resolveResumeTarget({ id: runId }, resumeState, { asyncRequireSessionFile: true, exactOnly: true });
3671
+ resumability = target.kind === "revive"
3672
+ ? { state: "resumable" }
3673
+ : { state: "not-resumable", reason: "child is still running" };
3674
+ } catch (error) {
3675
+ resumability = { state: "not-resumable", reason: error instanceof Error ? error.message : String(error) };
3676
+ }
3677
+ }
3678
+ const requestedContext = childParams.context === "fresh" || childParams.context === "fork" ? childParams.context : undefined;
3679
+ const resolvedContext = result.details.context ?? (resolvedContexts.length === 1 ? resolvedContexts[0] : resolvedContexts.length > 1 ? "mixed" : undefined);
3680
+ const resumeSourceRunId = typeof childParams.resume === "string" && childParams.resume.trim() ? childParams.resume.trim() : undefined;
3681
+ const continuationRunIds = [...new Set([resumeSourceRunId, runId].filter((value): value is string => Boolean(value)))];
3682
+ const outputReference = result.details.results.find((child) => child.savedOutputPath)?.savedOutputPath
3683
+ ?? result.details.results.find((child) => child.outputReference?.path)?.outputReference?.path;
3599
3684
  return {
3600
3685
  key,
3601
3686
  ok,
3602
3687
  ...(resolvedAgents.length === 1 ? { agent: resolvedAgents[0] } : {}),
3603
- ...(result.details.runId || result.details.asyncId ? { runId: result.details.runId ?? result.details.asyncId } : {}),
3688
+ ...(runId ? { runId } : {}),
3604
3689
  output,
3605
3690
  ...(!ok ? { error: receiptOutput || output || "Child run failed." } : {}),
3606
3691
  ...(detached ? { detached: true } : {}),
3607
3692
  ...(structured.length === 1 ? { structuredOutput: structured[0] } : structured.length > 1 ? { structuredOutput: structured } : {}),
3693
+ ...(requestedContext ? { requestedContext } : {}),
3694
+ ...(resolvedContext ? { resolvedContext } : {}),
3695
+ ...(outputReference ? { outputReference } : {}),
3696
+ resumability,
3697
+ continuation: { runIds: continuationRunIds },
3608
3698
  artifactPaths: [...artifactPaths],
3609
3699
  results: result.details.results,
3610
3700
  };
@@ -3627,6 +3717,31 @@ function workflowSteerReceipt(key: string, result: AgentToolResult<Details>): Wo
3627
3717
  };
3628
3718
  }
3629
3719
 
3720
+ function resolveKeyedWorkflowResume(
3721
+ reference: WorkflowReceiptResumeReference,
3722
+ state: SubagentState,
3723
+ ): { runId: string; runIds: string[] } {
3724
+ const entry = resolveWorkflowReceiptResumeEntry({
3725
+ reference,
3726
+ asyncDirRoot: DIRS.async,
3727
+ assertResumable(runId) {
3728
+ const target = resolveResumeTarget({ id: runId }, state, { asyncRequireSessionFile: true, exactOnly: true });
3729
+ if (target.kind !== "revive") throw new Error(`Workflow receipt child '${reference.key}' latest run '${runId}' is still running.`);
3730
+ },
3731
+ });
3732
+ const runId = entry.latestRunId;
3733
+ if (!runId) throw new Error(`Workflow receipt child '${reference.key}' has no retained run id.`);
3734
+ return { runId, runIds: entry.continuation.runIds };
3735
+ }
3736
+
3737
+ function terminalWorkflowReceipt(
3738
+ workflowRunId: string,
3739
+ state: WorkflowReceiptState,
3740
+ children: WorkflowScriptChildResult[],
3741
+ ): WorkflowReceipt {
3742
+ return buildWorkflowReceipt({ workflowRunId, state, children });
3743
+ }
3744
+
3630
3745
  export async function steerWorkflowChildByKey(input: {
3631
3746
  state: SubagentState;
3632
3747
  workflowRunId: string;
@@ -4018,7 +4133,6 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4018
4133
  // The event log is a journal, not workflow truth. Callers append from
4019
4134
  // inside run-result handling, so losing an entry to a full disk or to a
4020
4135
  // transient Windows lock must not fail the run being recorded.
4021
- if (!isStorageCapacityError(error) && !isRetryableFileSystemError(error)) throw error;
4022
4136
  console.error(`Failed to append async workflow event '${eventsPath}':`, error);
4023
4137
  }
4024
4138
  };
@@ -4248,9 +4362,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4248
4362
  appendWorkflowEvent({ type: "subagent.workflow.emit", value: emits.at(-1) });
4249
4363
  },
4250
4364
  launch: async (key, childParams, workflowSignal, admission) => {
4251
- if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."));
4365
+ if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."), childParams, deps.state);
4252
4366
  const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
4253
- if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)));
4367
+ if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)), childParams, deps.state);
4254
4368
  const childPhase = typeof childParams.phase === "string" && childParams.phase.trim() ? childParams.phase.trim() : undefined;
4255
4369
  const childLabel = typeof childParams.label === "string" && childParams.label.trim() ? childParams.label.trim() : undefined;
4256
4370
  recordMissionWorkflowChild(missionBinding, workflowRunId, key, {
@@ -4307,7 +4421,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4307
4421
  for (const childResult of result.details.results) {
4308
4422
  if (childResult.savedOutputPath) producedChildOutputPaths.add(childResult.savedOutputPath);
4309
4423
  }
4310
- const child = workflowChildResult(key, result);
4424
+ const child = workflowChildResult(key, result, childParams, deps.state);
4311
4425
  if (child.runId) workflowChildRunIds.set(key, child.runId);
4312
4426
  const step = status.steps?.find((candidate) => candidate.workflowKey === key);
4313
4427
  if (step) {
@@ -4332,6 +4446,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4332
4446
  return child;
4333
4447
  },
4334
4448
  status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
4449
+ resolveResume: (reference) => resolveKeyedWorkflowResume(reference, deps.state),
4335
4450
  steer: (key, message, options, workflowSignal) => steerWorkflowChildByKey({ state: deps.state, workflowRunId, key, message, options, signal: workflowSignal, resolveRunId: () => workflowChildRunIds.get(key) }),
4336
4451
  });
4337
4452
  const returnPreview = formatWorkflowValue(workflow.value).slice(0, 1_000);
@@ -4341,7 +4456,14 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4341
4456
  const resultSummary = appendWorkflowOutputWarning(summary, outputWarning);
4342
4457
  const workflowUsage = sumResultsUsage(workflowResults);
4343
4458
  status = { ...status, state: "complete", endedAt: Date.now(), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, totalTokens: { input: workflowUsage.input, output: workflowUsage.output, total: workflowUsage.input + workflowUsage.output }, totalCost: sumResultsCost(workflowResults) };
4344
- if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, results: workflow.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
4459
+ const receipt = terminalWorkflowReceipt(workflowRunId, "complete", workflow.children);
4460
+ let workflowReceipt: { path: string; receipt: WorkflowReceipt } | undefined;
4461
+ try {
4462
+ workflowReceipt = { path: writeWorkflowReceipt(asyncDir, receipt), receipt };
4463
+ } catch (receiptError) {
4464
+ appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
4465
+ }
4466
+ if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, results: workflow.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
4345
4467
  persist();
4346
4468
  persistClosed = true;
4347
4469
  appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}) });
@@ -4373,7 +4495,15 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4373
4495
  : status.error ?? (pauseForDetached ? "Workflow paused." : "Workflow failed.");
4374
4496
  const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, terminalSummary, producedChildOutputPaths);
4375
4497
  const resultSummary = appendWorkflowOutputWarning(terminalSummary, outputWarning);
4376
- if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: status.state === "complete", state: status.state, summary: resultSummary, error: status.state === "complete" ? undefined : status.error, stopped: status.stopped, activityState: status.activityState, results: partial.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
4498
+ const receiptState: WorkflowReceiptState = status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
4499
+ const receipt = terminalWorkflowReceipt(workflowRunId, receiptState, partial.children);
4500
+ let workflowReceipt: { path: string; receipt: WorkflowReceipt } | undefined;
4501
+ try {
4502
+ workflowReceipt = { path: writeWorkflowReceipt(asyncDir, receipt), receipt };
4503
+ } catch (receiptError) {
4504
+ appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
4505
+ }
4506
+ if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: status.state === "complete", state: status.state, summary: resultSummary, error: status.state === "complete" ? undefined : status.error, stopped: status.stopped, activityState: status.activityState, results: partial.children.map((child) => ({ workflowKey: child.key, ...(child.agent ? { agent: child.agent } : {}), ...(child.runId ? { runId: child.runId } : {}), output: child.output, outputState: child.output.trim() || child.structuredOutput !== undefined ? "present" : "absent", structuredOutput: child.structuredOutput, success: child.ok, ...(child.detached && status.state !== "complete" ? { detached: true } : {}), ...(child.artifactPaths[0] ? { artifactPaths: { outputPath: child.artifactPaths[0] } } : {}) })), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt })) return;
4377
4507
  persist();
4378
4508
  persistClosed = true;
4379
4509
  appendWorkflowEvent({ type: "subagent.workflow.completed", state: status.state, ...(status.error ? { error: status.error } : {}), ...(status.activityState ? { activityState: status.activityState } : {}) });
@@ -4426,9 +4556,9 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4426
4556
  sendWorkflowProgress();
4427
4557
  },
4428
4558
  launch: async (key, childParams, workflowSignal, admission) => {
4429
- if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."));
4559
+ if (workflowUsageBudget.budget && childParams.async === true) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, "workflow usageBudget does not support async runs.run launches."), childParams, deps.state);
4430
4560
  const budgetState = usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults));
4431
- if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)));
4561
+ if (budgetState?.exhausted) return workflowChildResult(key, buildRequestedModeError(childParams as SubagentParamsLike, usageBudgetExceededMessage(budgetState)), childParams, deps.state);
4432
4562
  const childPhase = typeof childParams.phase === "string" && childParams.phase.trim() ? childParams.phase.trim() : undefined;
4433
4563
  const childLabel = typeof childParams.label === "string" && childParams.label.trim() ? childParams.label.trim() : undefined;
4434
4564
  recordMissionWorkflowChild(missionBinding, _id, key, {
@@ -4464,7 +4594,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4464
4594
  if (childResult.savedOutputPath) producedChildOutputPaths.add(childResult.savedOutputPath);
4465
4595
  }
4466
4596
  if (result.details.asyncDir && missionBinding) writeMissionAsyncBinding(result.details.asyncDir, missionBinding);
4467
- const child = workflowChildResult(key, result);
4597
+ const child = workflowChildResult(key, result, childParams, deps.state);
4468
4598
  if (child.runId) workflowChildRunIds.set(key, child.runId);
4469
4599
  const childStatus = missionWorkflowChildStatus(result);
4470
4600
  recordMissionWorkflowChild(missionBinding, _id, key, {
@@ -4479,8 +4609,10 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4479
4609
  return child;
4480
4610
  },
4481
4611
  status: async (keyOrRunId, workflowSignal) => workflowChildResult(keyOrRunId, await execute(randomUUID(), { action: "status", id: keyOrRunId }, workflowSignal, undefined, ctx, preserveActiveSession)),
4612
+ resolveResume: (reference) => resolveKeyedWorkflowResume(reference, deps.state),
4482
4613
  steer: (key, message, options, workflowSignal) => steerWorkflowChildByKey({ state: deps.state, workflowRunId: _id, key, message, options, signal: workflowSignal, resolveRunId: () => workflowChildRunIds.get(key) }),
4483
4614
  });
4615
+ const receipt = terminalWorkflowReceipt(_id, "complete", workflow.children);
4484
4616
  const traceLines = workflow.trace.map((entry) => `- ${entry.operation} ${entry.key}: ${entry.state}${entry.runId ? ` (${entry.runId})` : ""}${entry.durationMs !== undefined ? ` in ${entry.durationMs}ms` : ""}${entry.error ? ` — ${entry.error}` : ""}`);
4485
4617
  const sections = ["Workflow completed.", `Return:\n${formatWorkflowValue(workflow.value)}`];
4486
4618
  if (workflow.emits.length > 0) sections.push(`Emitted:\n${workflow.emits.map(formatWorkflowValue).join("\n")}`);
@@ -4491,7 +4623,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4491
4623
  const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
4492
4624
  return attachWorkflowMission(withRunFanoutBudget({
4493
4625
  content: [{ type: "text", text: displayText }],
4494
- details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console }, chatProgress }),
4626
+ details: compactOptional<Details>({ mode: "workflow", runId: _id, results: workflow.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { value: workflow.value, trace: workflow.trace, emits: workflow.emits, console: workflow.console, receipt }, chatProgress }),
4495
4627
  }, workflowFanoutBudget));
4496
4628
  } catch (error) {
4497
4629
  const partial = error instanceof WorkflowScriptError ? error.partial : { trace: [], emits: [], console: [], children: [] };
@@ -4504,10 +4636,11 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4504
4636
  const workflowText = sections.join("\n\n");
4505
4637
  const outputWarning = writeWorkflowAggregateOutput(workflowAggregateOutputPath, workflowText, producedChildOutputPaths);
4506
4638
  const displayText = appendWorkflowOutputWarning(workflowText, outputWarning);
4639
+ const receipt = terminalWorkflowReceipt(_id, "failed", partial.children);
4507
4640
  return attachWorkflowMission(withRunFanoutBudget({
4508
4641
  content: [{ type: "text", text: displayText }],
4509
4642
  isError: true,
4510
- details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console }, chatProgress }),
4643
+ details: compactOptional<Details>({ mode: "workflow", runId: _id, results: partial.children.flatMap((child) => (child.results ?? []) as SingleResult[]), totalChildUsage: sumResultsUsage(workflowResults), totalCost: sumResultsCost(workflowResults), usageBudget: usageBudgetState(workflowUsageBudget.budget, sumResultsCost(workflowResults)), workflow: { trace: partial.trace, emits: partial.emits, console: partial.console, receipt }, chatProgress }),
4511
4644
  }, workflowFanoutBudget));
4512
4645
  }
4513
4646
  }
@@ -4757,7 +4890,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
4757
4890
  cwd: requestCwd,
4758
4891
  config: deps.config,
4759
4892
  state: deps.state,
4760
- context: paramsWithResolvedCwd.context,
4893
+ context: paramsWithResolvedCwd.context === "profile" ? undefined : paramsWithResolvedCwd.context,
4761
4894
  requestedSessionDir: paramsWithResolvedCwd.sessionDir,
4762
4895
  currentSessionFile,
4763
4896
  currentSessionId,
@@ -5071,6 +5204,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
5071
5204
  cwd: requestCwd,
5072
5205
  config: deps.config,
5073
5206
  currentSessionId: deps.state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined,
5207
+ runtimeAgentOwner: deps.pi,
5074
5208
  });
5075
5209
  }
5076
5210
 
@@ -5127,23 +5261,25 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
5127
5261
  // Prefer fork only when the parent session is persisted and has a current leaf;
5128
5262
  // otherwise use fresh immediately instead of launching a guaranteed-to-fail fork.
5129
5263
  // Explicit context:"fork" remains strict.
5130
- const contextPolicy = resolveAgentDefaultContextPolicy(
5264
+ const contextPolicyResult = resolveAgentDefaultContextPolicy(
5131
5265
  effectiveParams,
5132
5266
  discoveredAgents,
5133
5267
  deps.config.defaultSubagentContext,
5134
5268
  canPreferFork(ctx.sessionManager),
5135
5269
  );
5270
+ if ("error" in contextPolicyResult) return buildRequestedModeError(effectiveParams, contextPolicyResult.error);
5271
+ const contextPolicy = contextPolicyResult;
5136
5272
  effectiveParams = contextPolicy.params;
5137
5273
  const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
5138
5274
  const intercomBridge = resolveIntercomBridge({
5139
5275
  config: deps.config.intercomBridge,
5140
5276
  override: effectiveParams.intercomBridge,
5141
- context: effectiveParams.context ?? (contextPolicy.usesFork ? "fork" : undefined),
5277
+ context: effectiveParams.context === "fresh" || effectiveParams.context === "fork"
5278
+ ? effectiveParams.context
5279
+ : contextPolicy.usesFork ? "fork" : undefined,
5142
5280
  orchestratorTarget: sessionName,
5143
5281
  });
5144
- const agents = intercomBridge.active
5145
- ? discoveredAgents.map((agent) => applyIntercomBridgeToAgent(agent, intercomBridge))
5146
- : discoveredAgents;
5282
+ const agents = applyScopedIntercomBridgeToAgents(discoveredAgents, intercomBridge, contextPolicy);
5147
5283
  const runId = randomUUID();
5148
5284
  const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
5149
5285
  const nestedParentAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
@@ -5546,7 +5682,7 @@ export function createSubagentExecutor(deps: ExecutorDeps): {
5546
5682
  startedLaunches = selectedAgentNames.map((agent) => ({ agent }));
5547
5683
  }
5548
5684
  const agentsForSummary = startedLaunches.map((launch) => launch.agent);
5549
- const leafIntercomTarget = intercomBridge.active && agentsForSummary[0]
5685
+ const leafIntercomTarget = agentsForSummary[0] && intercomBridgeAppliesToAgent(intercomBridge, contextPolicy, agentsForSummary[0])
5550
5686
  ? resolveSubagentIntercomTarget(runId, agentsForSummary[0], 0)
5551
5687
  : undefined;
5552
5688
  try {