pi-subagents 0.70.1 → 0.71.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 (209) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +3 -1
  3. package/agents/worker.md +2 -2
  4. package/docs/agents.md +1 -1
  5. package/docs/configuration.md +15 -1
  6. package/docs/extension-api.md +3 -1
  7. package/docs/observability.md +16 -12
  8. package/docs/tool-reference.md +6 -4
  9. package/docs/workflows.md +1 -1
  10. package/package.json +2 -2
  11. package/skills/pi-subagents/references/constraints-and-recipes.md +5 -2
  12. package/skills/pi-subagents/references/execution-controls.md +2 -2
  13. package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  14. package/src/agents/proactive-skills.d.ts +1 -0
  15. package/src/agents/proactive-skills.d.ts.map +1 -1
  16. package/src/agents/proactive-skills.js +3 -1
  17. package/src/agents/proactive-skills.js.map +1 -1
  18. package/src/agents/skills.d.ts +2 -0
  19. package/src/agents/skills.d.ts.map +1 -1
  20. package/src/agents/skills.js +41 -8
  21. package/src/agents/skills.js.map +1 -1
  22. package/src/api/delegation.d.ts +14 -0
  23. package/src/api/delegation.d.ts.map +1 -1
  24. package/src/extension/index.d.ts.map +1 -1
  25. package/src/extension/index.js +4 -0
  26. package/src/extension/index.js.map +1 -1
  27. package/src/extension/rpc.d.ts +1 -1
  28. package/src/extension/rpc.d.ts.map +1 -1
  29. package/src/extension/rpc.js +11 -1
  30. package/src/extension/rpc.js.map +1 -1
  31. package/src/extension/tool-activation.d.ts +9 -0
  32. package/src/extension/tool-activation.d.ts.map +1 -0
  33. package/src/extension/tool-activation.js +172 -0
  34. package/src/extension/tool-activation.js.map +1 -0
  35. package/src/extension/tool-description.d.ts +4 -4
  36. package/src/extension/tool-description.d.ts.map +1 -1
  37. package/src/extension/tool-description.js +1 -1
  38. package/src/intercom/intercom-bridge.d.ts.map +1 -1
  39. package/src/intercom/intercom-bridge.js +2 -0
  40. package/src/intercom/intercom-bridge.js.map +1 -1
  41. package/src/runs/background/active-async-capacity.d.ts.map +1 -1
  42. package/src/runs/background/active-async-capacity.js +4 -33
  43. package/src/runs/background/active-async-capacity.js.map +1 -1
  44. package/src/runs/background/async-execution.d.ts.map +1 -1
  45. package/src/runs/background/async-execution.js +5 -33
  46. package/src/runs/background/async-execution.js.map +1 -1
  47. package/src/runs/background/async-job-tracker.d.ts.map +1 -1
  48. package/src/runs/background/async-job-tracker.js +25 -19
  49. package/src/runs/background/async-job-tracker.js.map +1 -1
  50. package/src/runs/background/async-resume.d.ts +1 -1
  51. package/src/runs/background/async-resume.d.ts.map +1 -1
  52. package/src/runs/background/async-resume.js +7 -2
  53. package/src/runs/background/async-resume.js.map +1 -1
  54. package/src/runs/background/async-status.d.ts +1 -0
  55. package/src/runs/background/async-status.d.ts.map +1 -1
  56. package/src/runs/background/async-status.js +1 -0
  57. package/src/runs/background/async-status.js.map +1 -1
  58. package/src/runs/background/binary-bootstrap.d.ts.map +1 -1
  59. package/src/runs/background/binary-bootstrap.js +28 -6
  60. package/src/runs/background/binary-bootstrap.js.map +1 -1
  61. package/src/runs/background/fleet-view.d.ts.map +1 -1
  62. package/src/runs/background/fleet-view.js +26 -7
  63. package/src/runs/background/fleet-view.js.map +1 -1
  64. package/src/runs/background/notify.d.ts +11 -0
  65. package/src/runs/background/notify.d.ts.map +1 -1
  66. package/src/runs/background/notify.js +71 -3
  67. package/src/runs/background/notify.js.map +1 -1
  68. package/src/runs/background/process-terminal-candidate.d.ts +18 -0
  69. package/src/runs/background/process-terminal-candidate.d.ts.map +1 -0
  70. package/src/runs/background/process-terminal-candidate.js +97 -0
  71. package/src/runs/background/process-terminal-candidate.js.map +1 -0
  72. package/src/runs/background/process-terminal.d.ts +3 -15
  73. package/src/runs/background/process-terminal.d.ts.map +1 -1
  74. package/src/runs/background/process-terminal.js +19 -96
  75. package/src/runs/background/process-terminal.js.map +1 -1
  76. package/src/runs/background/retained-children.d.ts.map +1 -1
  77. package/src/runs/background/retained-children.js +3 -2
  78. package/src/runs/background/retained-children.js.map +1 -1
  79. package/src/runs/background/run-child-session.d.ts +1 -0
  80. package/src/runs/background/run-child-session.d.ts.map +1 -1
  81. package/src/runs/background/run-child-session.js.map +1 -1
  82. package/src/runs/background/run-status.d.ts.map +1 -1
  83. package/src/runs/background/run-status.js +5 -1
  84. package/src/runs/background/run-status.js.map +1 -1
  85. package/src/runs/background/runner-aliases.d.ts.map +1 -1
  86. package/src/runs/background/runner-aliases.js +2 -1
  87. package/src/runs/background/runner-aliases.js.map +1 -1
  88. package/src/runs/background/runner-startup-failure.d.ts +14 -0
  89. package/src/runs/background/runner-startup-failure.d.ts.map +1 -0
  90. package/src/runs/background/runner-startup-failure.js +47 -0
  91. package/src/runs/background/runner-startup-failure.js.map +1 -0
  92. package/src/runs/background/stale-run-reconciler.d.ts.map +1 -1
  93. package/src/runs/background/stale-run-reconciler.js +9 -1
  94. package/src/runs/background/stale-run-reconciler.js.map +1 -1
  95. package/src/runs/background/subagent-runner-bootstrap.d.ts +14 -0
  96. package/src/runs/background/subagent-runner-bootstrap.d.ts.map +1 -0
  97. package/src/runs/background/subagent-runner-bootstrap.js +277 -0
  98. package/src/runs/background/subagent-runner-bootstrap.js.map +1 -0
  99. package/src/runs/background/subagent-runner.d.ts +4 -2
  100. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  101. package/src/runs/background/subagent-runner.js +53 -178
  102. package/src/runs/background/subagent-runner.js.map +1 -1
  103. package/src/runs/background/workflow-terminal-proof.d.ts +18 -0
  104. package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -0
  105. package/src/runs/background/workflow-terminal-proof.js +68 -0
  106. package/src/runs/background/workflow-terminal-proof.js.map +1 -0
  107. package/src/runs/foreground/execution.d.ts.map +1 -1
  108. package/src/runs/foreground/execution.js +43 -14
  109. package/src/runs/foreground/execution.js.map +1 -1
  110. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  111. package/src/runs/foreground/subagent-executor.js +108 -15
  112. package/src/runs/foreground/subagent-executor.js.map +1 -1
  113. package/src/runs/shared/child-launch.d.ts.map +1 -1
  114. package/src/runs/shared/child-launch.js +3 -0
  115. package/src/runs/shared/child-launch.js.map +1 -1
  116. package/src/runs/shared/child-runtime-config.d.ts +4 -0
  117. package/src/runs/shared/child-runtime-config.d.ts.map +1 -1
  118. package/src/runs/shared/child-runtime-config.js.map +1 -1
  119. package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
  120. package/src/runs/shared/external-cli-runner.js +3 -1
  121. package/src/runs/shared/external-cli-runner.js.map +1 -1
  122. package/src/runs/shared/git-environment.d.ts +3 -0
  123. package/src/runs/shared/git-environment.d.ts.map +1 -0
  124. package/src/runs/shared/git-environment.js +28 -0
  125. package/src/runs/shared/git-environment.js.map +1 -0
  126. package/src/runs/shared/mcp-config-sources.d.ts +3 -0
  127. package/src/runs/shared/mcp-config-sources.d.ts.map +1 -1
  128. package/src/runs/shared/mcp-config-sources.js.map +1 -1
  129. package/src/runs/shared/mcp-direct-tool-allowlist.js +1 -1
  130. package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
  131. package/src/runs/shared/mcp-direct-tool-grant.d.ts +3 -1
  132. package/src/runs/shared/mcp-direct-tool-grant.d.ts.map +1 -1
  133. package/src/runs/shared/mcp-direct-tool-grant.js +19 -5
  134. package/src/runs/shared/mcp-direct-tool-grant.js.map +1 -1
  135. package/src/runs/shared/pi-spawn.d.ts +10 -1
  136. package/src/runs/shared/pi-spawn.d.ts.map +1 -1
  137. package/src/runs/shared/pi-spawn.js +86 -7
  138. package/src/runs/shared/pi-spawn.js.map +1 -1
  139. package/src/runs/shared/single-output.js +1 -1
  140. package/src/runs/shared/single-output.js.map +1 -1
  141. package/src/runs/shared/structured-output.d.ts +7 -0
  142. package/src/runs/shared/structured-output.d.ts.map +1 -1
  143. package/src/runs/shared/structured-output.js +74 -0
  144. package/src/runs/shared/structured-output.js.map +1 -1
  145. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  146. package/src/runs/shared/subagent-prompt-runtime.js +23 -7
  147. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  148. package/src/runs/shared/tool-availability.js +1 -1
  149. package/src/runs/shared/tool-availability.js.map +1 -1
  150. package/src/shared/child-session-name.d.ts.map +1 -1
  151. package/src/shared/child-session-name.js +4 -2
  152. package/src/shared/child-session-name.js.map +1 -1
  153. package/src/shared/fork-context.d.ts +4 -0
  154. package/src/shared/fork-context.d.ts.map +1 -1
  155. package/src/shared/fork-context.js +9 -4
  156. package/src/shared/fork-context.js.map +1 -1
  157. package/src/shared/pruned-fork.d.ts.map +1 -1
  158. package/src/shared/pruned-fork.js +68 -56
  159. package/src/shared/pruned-fork.js.map +1 -1
  160. package/src/shared/types.d.ts +29 -3
  161. package/src/shared/types.d.ts.map +1 -1
  162. package/src/shared/types.js +2 -0
  163. package/src/shared/types.js.map +1 -1
  164. package/src/slash/delegation-adapters.d.ts +7 -1
  165. package/src/slash/delegation-adapters.d.ts.map +1 -1
  166. package/src/slash/delegation-adapters.js +17 -0
  167. package/src/slash/delegation-adapters.js.map +1 -1
  168. package/src/slash/prompt-template-bridge.d.ts.map +1 -1
  169. package/src/slash/prompt-template-bridge.js +14 -1
  170. package/src/slash/prompt-template-bridge.js.map +1 -1
  171. package/src/slash/prompt-workflows.d.ts.map +1 -1
  172. package/src/slash/prompt-workflows.js +16 -2
  173. package/src/slash/prompt-workflows.js.map +1 -1
  174. package/src/slash/slash-commands.d.ts.map +1 -1
  175. package/src/slash/slash-commands.js +4 -250
  176. package/src/slash/slash-commands.js.map +1 -1
  177. package/src/slash/subagent-cost.d.ts +29 -0
  178. package/src/slash/subagent-cost.d.ts.map +1 -0
  179. package/src/slash/subagent-cost.js +271 -0
  180. package/src/slash/subagent-cost.js.map +1 -0
  181. package/src/tui/fleet.d.ts.map +1 -1
  182. package/src/tui/fleet.js +4 -0
  183. package/src/tui/fleet.js.map +1 -1
  184. package/src/tui/render.d.ts.map +1 -1
  185. package/src/tui/render.js +8 -4
  186. package/src/tui/render.js.map +1 -1
  187. package/src/watchdog/diff-tool.d.ts +2 -1
  188. package/src/watchdog/diff-tool.d.ts.map +1 -1
  189. package/src/watchdog/diff-tool.js +9 -3
  190. package/src/watchdog/diff-tool.js.map +1 -1
  191. package/src/watchdog/permission-arbiter.d.ts.map +1 -1
  192. package/src/watchdog/permission-arbiter.js +1 -2
  193. package/src/watchdog/permission-arbiter.js.map +1 -1
  194. package/src/watchdog/register-child.d.ts +3 -1
  195. package/src/watchdog/register-child.d.ts.map +1 -1
  196. package/src/watchdog/register-child.js +12 -3
  197. package/src/watchdog/register-child.js.map +1 -1
  198. package/src/watchdog/review.d.ts +1 -1
  199. package/src/watchdog/review.d.ts.map +1 -1
  200. package/src/watchdog/review.js +1 -2
  201. package/src/watchdog/review.js.map +1 -1
  202. package/src/watchdog/runtime.d.ts +1 -1
  203. package/src/watchdog/runtime.d.ts.map +1 -1
  204. package/src/watchdog/runtime.js +2 -1
  205. package/src/watchdog/runtime.js.map +1 -1
  206. package/src/watchdog/turn-delta.d.ts +5 -1
  207. package/src/watchdog/turn-delta.d.ts.map +1 -1
  208. package/src/watchdog/turn-delta.js +9 -5
  209. package/src/watchdog/turn-delta.js.map +1 -1
@@ -53,7 +53,7 @@ import { normalizeExtensionBindings } from "../shared/extension-bindings.js";
53
53
  import { resolveRequiredChildExtensions } from "../../shared/required-child-extensions.js";
54
54
  import { finalizeSingleOutput, injectSingleOutputInstruction, normalizeSingleOutputOverride, outputPathMappingFromTask, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.js";
55
55
  import { assertJsonSchemaObject, cleanupStructuredOutputRuntime, createStructuredOutputRuntime } from "../shared/structured-output.js";
56
- import { compactForegroundDetails, getSingleResultOutput, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.js";
56
+ import { compactForegroundDetails, getSingleResultOutput, PROMPT_REDACTED, readStatus, resolveChildCwd, sumResultsCost, sumResultsUsage, toAgentToolUsage } from "../../shared/utils.js";
57
57
  import { discardPreservedWorktrees, formatParallelHandoffError, formatParallelHandoffReference, formatStoredParallelHandoffCleanup, parallelHandoffPath, readParallelHandoffManifest, recordParallelHandoffMerge, recordParallelHandoffSupersession, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.js";
58
58
  import { summarizeContextModes } from "../shared/context-mode.js";
59
59
  import { attachNestedChildrenToResultChildren, buildSubagentResultIntercomPayload, deliverSubagentResultIntercomEvent, formatSubagentResultReceipt, resolveSubagentResultStatus, stripDetailsOutputsForIntercomReceipt, } from "../../intercom/result-intercom.js";
@@ -100,7 +100,7 @@ import { deepFreezeWorkflowArgs, normalizeWorkflowArgs, resolveWorkflowResource
100
100
  import { stableJsonDigest } from "../../shared/launch-contract.js";
101
101
  import { cleanupWorktrees, createWorktrees, preflightWorktreeSource, withWorktreeTransaction, diffWorktrees, formatWorktreeDiffSummary, } from "../shared/worktree.js";
102
102
  import { createWorktreeCleanupPlan, formatWorktreeCleanupPlan } from "../shared/worktree-cleanup-plan.js";
103
- import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, wrapForkTask, } from "../../shared/types.js";
103
+ import { DIRS, DEFAULT_ARTIFACT_CONFIG, DEFAULT_FORK_PREAMBLE, SUBAGENT_ACTIONS, SUBAGENT_ASYNC_STARTED_EVENT, SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, SUBAGENT_CONTROL_INTERCOM_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT, SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, checkSubagentDepth, resolveChildMaxSubagentDepth, resolveCurrentMaxSubagentDepth, resolveMaxSubagentSpawnsPerRun, wrapForkTask, } from "../../shared/types.js";
104
104
  import { deriveChildSessionName } from "../../shared/child-session-name.js";
105
105
  const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete", "eject", "disable", "enable", "reset", "grant-spawn-budget", "watchdog.configure", "mission.create", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "inspector.open", "inspector.close", "project.open", "project.close", "worktree.discard", "worktree.cleanup", "lane.recordMerge", "lane.recordSupersession", "refine", "refine.rollback", "dismiss", "schedule.create", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"]);
106
106
  const DESTRUCTIVE_MANAGEMENT_ACTIONS = new Set(["delete", "eject", "disable", "reset", "mission.close", "worktree.discard", "refine.rollback", "inspector.close", "project.close", "stop", "interrupt", "schedule.delete"]);
@@ -1516,7 +1516,7 @@ async function resumeAsyncRun(input) {
1516
1516
  const discoveredAgents = discovered.agents;
1517
1517
  const unknownAgentDiagnosticContext = diagnosticContextFromDiscovery(discovered, effectiveCwd, scope);
1518
1518
  const modelScope = discovered.modelScope;
1519
- const sessionName = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
1519
+ const sessionName = resolveIntercomSessionTarget(input.deps.childRuntime?.intercomSessionName ?? input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
1520
1520
  const recoveryDescriptor = "recoveryDescriptor" in target ? target.recoveryDescriptor : undefined;
1521
1521
  const recoveryContext = recoveryDescriptor?.context ?? (input.params.context === "profile" ? undefined : input.params.context);
1522
1522
  const intercomBridge = resolveIntercomBridge({
@@ -1558,7 +1558,7 @@ async function resumeAsyncRun(input) {
1558
1558
  if (target.source === "async" && target.runner?.type === "external-job") {
1559
1559
  if (attachChain)
1560
1560
  return { content: [{ type: "text", text: "External-job follow-up does not support chain attachment. Use action='resume' with message instead." }], isError: true, details: { mode: "management", results: [] } };
1561
- return resumeExternalJobFollowUp({
1561
+ const resumed = await resumeExternalJobFollowUp({
1562
1562
  target,
1563
1563
  followUp,
1564
1564
  baseAgentConfig,
@@ -1572,6 +1572,10 @@ async function resumeAsyncRun(input) {
1572
1572
  parentSessionFile,
1573
1573
  absoluteDeadlineAt: input.absoluteDeadlineAt,
1574
1574
  });
1575
+ const resumedRunId = resumed.details.runId ?? resumed.details.asyncId;
1576
+ if (!resumed.isError && resumedRunId)
1577
+ input.onLaunch?.({ agent: target.agent, async: true, runId: resumedRunId });
1578
+ return resumed;
1575
1579
  }
1576
1580
  if (attachChain) {
1577
1581
  if (target.source !== "async") {
@@ -1679,6 +1683,7 @@ async function resumeAsyncRun(input) {
1679
1683
  return result;
1680
1684
  }
1681
1685
  const attachedId = result.details.asyncId ?? runId;
1686
+ input.onLaunch?.({ agent: target.agent, ...(target.sessionFile ? { sessionFile: target.sessionFile } : {}), async: true, runId: attachedId });
1682
1687
  const lines = [
1683
1688
  `Attached async subagent ${target.runId} as the first step of a new chain.`,
1684
1689
  `Chain run: ${attachedId}`,
@@ -1695,11 +1700,14 @@ async function resumeAsyncRun(input) {
1695
1700
  if (!revivalSessionFile) {
1696
1701
  return { content: [{ type: "text", text: `Async run '${target.runId}' child ${target.index} does not have a persisted session file to resume from.` }], isError: true, details: { mode: "management", results: [] } };
1697
1702
  }
1703
+ if (input.params.baseRef !== undefined && "managedWorktree" in target && target.managedWorktree === true) {
1704
+ return { content: [{ type: "text", text: "Cannot resume with baseRef: retained managed-worktree children continue in their existing worktree. Start a new worktree run from that base ref instead." }], isError: true, details: { mode: "management", results: [] } };
1705
+ }
1698
1706
  if (target.source === "async" && asyncReviveRequiresRecoveryDescriptor(target)) {
1699
1707
  return { content: [{ type: "text", text: `Async child '${target.runId}' is missing its required run fan-out recovery identity. Start a new run instead.` }], isError: true, details: { mode: "management", results: [] } };
1700
1708
  }
1701
- if (input.params.baseRef !== undefined && "managedWorktree" in target && target.managedWorktree === true) {
1702
- return { content: [{ type: "text", text: "Cannot resume with baseRef: retained managed-worktree children continue in their existing worktree. Start a new worktree run from that base ref instead." }], isError: true, details: { mode: "management", results: [] } };
1709
+ if (target.source === "nested" && !target.recoveryDescriptor) {
1710
+ return { content: [{ type: "text", text: `Nested child '${target.runId}' is missing its required recovery identity. Start a new run instead.` }], isError: true, details: { mode: "management", results: [] } };
1703
1711
  }
1704
1712
  const recoveryAgentConfig = recoveryDescriptor ? applySteeringRecoveryAgentConfig(baseAgentConfig, recoveryDescriptor) : baseAgentConfig;
1705
1713
  const agentConfig = intercomBridge.active ? applyIntercomBridgeToAgent(recoveryAgentConfig, intercomBridge) : recoveryAgentConfig;
@@ -1821,15 +1829,19 @@ async function resumeAsyncRun(input) {
1821
1829
  ...(input.params.timeoutMs !== undefined ? { timeoutMs: input.params.timeoutMs } : {}),
1822
1830
  ...(input.absoluteDeadlineAt !== undefined ? { absoluteDeadlineAt: input.absoluteDeadlineAt } : {}),
1823
1831
  ...(input.params.toolBudget !== undefined ? { toolBudget: input.params.toolBudget } : {}),
1824
- capabilityCeiling: intersectSubagentCapabilityCeilings("capabilityCeiling" in target ? target.capabilityCeiling : undefined, recoveryDescriptor?.capabilityCeiling, resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
1832
+ // Recovery descriptors, remembered foreground runs, and current workflow roots
1833
+ // preserve parent authority before the selected agent's descendant ceiling.
1834
+ capabilityCeiling: intersectSubagentCapabilityCeilings(recoveryDescriptor?.capabilityCeiling ?? (target.source === "foreground" || (target.source === "async" && target.mode === "workflow") ? target.capabilityCeiling : undefined), resolveCurrentSubagentCapabilityCeiling(input.deps.state.currentSessionId)),
1825
1835
  runFanoutBudget: input.params.runFanoutBudget ?? recoveryDescriptor?.runFanoutBudget ?? createRunFanoutBudget(runId, resolveMaxSubagentSpawnsPerRun(input.deps.config.maxSubagentSpawnsPerRun)),
1826
1836
  parentWorkflowRunId: input.params.workflowParentRunId,
1827
1837
  workflowKey: input.params.workflowKey,
1828
1838
  activeAsyncCapacity,
1829
1839
  }));
1840
+ const notifyLaunch = () => input.onLaunch?.({ agent: target.agent, sessionFile: revivalSessionFile, async: true, runId });
1830
1841
  if (result.isError) {
1831
1842
  const startedStatus = readStatus(revivalAsyncDir);
1832
1843
  if (input.params.workflowParentRunId !== undefined && startedStatus?.runId === runId && startedStatus.processTerminal?.runnerProcessInstanceId) {
1844
+ notifyLaunch();
1833
1845
  return {
1834
1846
  ...result,
1835
1847
  details: {
@@ -1844,6 +1856,7 @@ async function resumeAsyncRun(input) {
1844
1856
  activeAsyncCapacity?.rollback();
1845
1857
  return result;
1846
1858
  }
1859
+ notifyLaunch();
1847
1860
  for (const brief of queuedBriefs)
1848
1861
  fs.rmSync(brief.path, { force: true });
1849
1862
  if (queuedBriefs.length > 0 && sourceAsyncDir) {
@@ -2147,11 +2160,15 @@ function projectEffectiveAcceptanceSchemas(params, agents) {
2147
2160
  }
2148
2161
  function validateExecutionInput(params, agents, hasChain, hasTasks, hasSingle, allowClarifyTaskPrompt, context) {
2149
2162
  if (Number(hasChain) + Number(hasTasks) + Number(hasSingle) !== 1) {
2163
+ const agentList = agents.map((a) => a.name).join(", ") || "none";
2164
+ const noMode = !hasChain && !hasTasks && !hasSingle;
2150
2165
  return {
2151
2166
  content: [
2152
2167
  {
2153
2168
  type: "text",
2154
- text: `Provide exactly one mode. Agents: ${agents.map((a) => a.name).join(", ") || "none"}`,
2169
+ text: noMode && typeof params.workflowKey === "string"
2170
+ ? `Workflow child '${params.workflowKey}' has no agent. Pass { key, agent, task }. Agents: ${agentList}`
2171
+ : `Provide exactly one mode. Agents: ${agentList}`,
2155
2172
  },
2156
2173
  ],
2157
2174
  isError: true,
@@ -4662,6 +4679,7 @@ export function createSubagentExecutor(deps) {
4662
4679
  ...(workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {}),
4663
4680
  ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}),
4664
4681
  pid: process.pid,
4682
+ ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}),
4665
4683
  steps: [],
4666
4684
  ...(workflowPreflight ? { preflight: workflowPreflight } : {}),
4667
4685
  workflow: { trace: [], emits: [], console: [], ...(workflowArgsEvidence ?? {}), ...(workflowResource ? { resource: workflowResource.provenance } : {}) },
@@ -4730,11 +4748,15 @@ export function createSubagentExecutor(deps) {
4730
4748
  deps.refreshResultDelivery?.();
4731
4749
  return false;
4732
4750
  };
4751
+ const pendingWorkflowChildAnnouncements = new Map();
4752
+ let announcePersistedWorkflowChildren = () => { };
4733
4753
  const runPersistence = createCapacityResilientJsonWriter({
4734
4754
  keepAlive: true,
4735
4755
  onSuccess: (filePath, payload) => {
4736
- if (filePath === statusPath)
4756
+ if (filePath === statusPath) {
4757
+ announcePersistedWorkflowChildren();
4737
4758
  queueActiveRunIndex(payload);
4759
+ }
4738
4760
  if (filePath === resultPath)
4739
4761
  settleResultPublication?.(true);
4740
4762
  },
@@ -4775,7 +4797,8 @@ export function createSubagentExecutor(deps) {
4775
4797
  else if (options.tolerateStatusWriteFailure) {
4776
4798
  try {
4777
4799
  runPersistence.write(statusPath, { ...status });
4778
- statusPersistenceDegraded = false;
4800
+ if (runPersistence.pendingCount() === 0)
4801
+ statusPersistenceDegraded = false;
4779
4802
  }
4780
4803
  catch (error) {
4781
4804
  const message = `Failed to persist async workflow state ${statusPath}: ${error instanceof Error ? error.message : String(error)}`;
@@ -4871,6 +4894,25 @@ export function createSubagentExecutor(deps) {
4871
4894
  return { content: [{ type: "text", text: `Failed to create async workflow storage: ${error instanceof Error ? error.message : String(error)}` }], isError: true, details: { mode: "workflow", results: [] } };
4872
4895
  }
4873
4896
  appendWorkflowEvent({ type: "subagent.workflow.started", ...(workflowArgsDigest ? { argsDigest: workflowArgsDigest } : {}) });
4897
+ try {
4898
+ deps.pi.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
4899
+ lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
4900
+ id: workflowRunId,
4901
+ asyncDir,
4902
+ cwd: workflowCwd,
4903
+ ...(workflowSessionRoot ? { sessionRoot: workflowSessionRoot } : {}),
4904
+ pid: process.pid,
4905
+ sessionId: currentSessionId ?? undefined,
4906
+ completionOwnerId,
4907
+ mode: "workflow",
4908
+ agent: "workflow",
4909
+ goal: derivedObjective.trim() ? PROMPT_REDACTED : undefined,
4910
+ ...(timeout !== undefined ? { timeoutMs: timeout, deadlineAt: startedAt + timeout } : {}),
4911
+ });
4912
+ }
4913
+ catch (error) {
4914
+ console.error("Failed to emit async workflow start event:", error);
4915
+ }
4874
4916
  // The runner does not execute workflow scripts: this active owner must consume its own
4875
4917
  // durable steer inbox, deliver through in-process child controls, and persist receipts.
4876
4918
  const emitWorkflowSteerEvent = (type, requestId, index, extra = {}) => {
@@ -5039,6 +5081,44 @@ export function createSubagentExecutor(deps) {
5039
5081
  const childOutputClaimPaths = new Map();
5040
5082
  const producedChildOutputPaths = new Set();
5041
5083
  const workflowSteps = new Map();
5084
+ const announcedWorkflowChildren = new Set();
5085
+ const announceWorkflowChild = (key, step) => {
5086
+ if (announcedWorkflowChildren.has(key))
5087
+ return;
5088
+ announcedWorkflowChildren.add(key);
5089
+ const stepIndex = status.steps?.indexOf(step);
5090
+ const childEvent = {
5091
+ type: "subagent.child-status",
5092
+ version: 1,
5093
+ runId: workflowRunId,
5094
+ childId: key,
5095
+ status: "started",
5096
+ ts: Date.now(),
5097
+ source: "async",
5098
+ asyncDir,
5099
+ ...(stepIndex !== undefined ? { stepIndex } : {}),
5100
+ agent: step.agent,
5101
+ ...(step.runId ? { childRunId: step.runId } : {}),
5102
+ workflowKey: key,
5103
+ ...(step.phase ? { phase: step.phase } : {}),
5104
+ ...(step.label ? { label: step.label } : {}),
5105
+ };
5106
+ appendWorkflowEvent({ ...childEvent });
5107
+ try {
5108
+ deps.pi.events.emit(SUBAGENT_CHILD_STATUS_EVENT, childEvent);
5109
+ }
5110
+ catch (error) {
5111
+ console.error("Failed to emit workflow child status event:", error);
5112
+ }
5113
+ };
5114
+ announcePersistedWorkflowChildren = () => {
5115
+ for (const [key, step] of pendingWorkflowChildAnnouncements) {
5116
+ if (!step.runId)
5117
+ continue;
5118
+ announceWorkflowChild(key, step);
5119
+ pendingWorkflowChildAnnouncements.delete(key);
5120
+ }
5121
+ };
5042
5122
  const runHostCommand = workflowHostCommandRunner({
5043
5123
  workflowCwd,
5044
5124
  artifactsDir: workflowArtifactsDir,
@@ -5280,6 +5360,8 @@ export function createSubagentExecutor(deps) {
5280
5360
  step.runId = launch.runId;
5281
5361
  if (childRequest.lane)
5282
5362
  step.lane = childRequest.lane;
5363
+ if (step.runId)
5364
+ pendingWorkflowChildAnnouncements.set(key, step);
5283
5365
  persist({ tolerateStatusWriteFailure: true });
5284
5366
  }
5285
5367
  recordMissionWorkflowChild(missionBinding, workflowRunId, key, { status: "running", agent: launch.agent, ...(launch.sessionFile ? { sessionPath: launch.sessionFile } : {}) });
@@ -5376,7 +5458,7 @@ export function createSubagentExecutor(deps) {
5376
5458
  catch (receiptError) {
5377
5459
  appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
5378
5460
  }
5379
- if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflowResultChildren(workflow.children, status, false), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
5461
+ if (!writeWorkflowResult({ id: workflowRunId, runId: workflowRunId, toolCallId, agent: "workflow", mode: "workflow", success: true, state: "complete", summary: resultSummary, output: resultSummary, workflowChildren, results: workflowResultChildren(workflow.children, status, false), workflow: status.workflow, ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}), ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
5380
5462
  return;
5381
5463
  if (pendingResultPublication && !await pendingResultPublication)
5382
5464
  return;
@@ -5433,7 +5515,7 @@ export function createSubagentExecutor(deps) {
5433
5515
  catch (receiptError) {
5434
5516
  appendWorkflowEvent({ type: "subagent.workflow.receipt_write_failed", error: `Failed to persist async workflow receipt: ${receiptError instanceof Error ? receiptError.message : String(receiptError)}` });
5435
5517
  }
5436
- 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, workflowChildren, ...(terminalOutcome ? { terminalOutcome } : {}), results: workflowResultChildren(partial.children, status, true), workflow: status.workflow, ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
5518
+ 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, workflowChildren, ...(terminalOutcome ? { terminalOutcome } : {}), results: workflowResultChildren(partial.children, status, true), workflow: status.workflow, ...(workflowCapabilityCeiling ? { admissionCapabilityCeiling: workflowCapabilityCeiling } : {}), ...(workflowReceipt ? { workflowReceipt } : {}), asyncDir, cwd: workflowCwd, sessionId: currentSessionId, completionOwnerId, ...(requestParams.scheduleOrigin ? { scheduleOrigin: requestParams.scheduleOrigin } : {}), timestamp: Date.now(), durationMs: Date.now() - startedAt }))
5437
5519
  return;
5438
5520
  if (pendingResultPublication && !await pendingResultPublication)
5439
5521
  return;
@@ -6035,7 +6117,7 @@ export function createSubagentExecutor(deps) {
6035
6117
  }
6036
6118
  let orchestratorTarget;
6037
6119
  try {
6038
- orchestratorTarget = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
6120
+ orchestratorTarget = resolveIntercomSessionTarget(deps.childRuntime?.intercomSessionName ?? deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
6039
6121
  }
6040
6122
  catch (error) {
6041
6123
  if (!sessionError)
@@ -6117,7 +6199,18 @@ export function createSubagentExecutor(deps) {
6117
6199
  return withBudget(inspectSubagentStatus(paramsWithResolvedCwd, omitUndefinedProperties({ state: deps.state, nested: nestedScope, sessionRoots, abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(deps.config.capacity?.abandonedSlotReleaseAfterMs) })));
6118
6200
  }
6119
6201
  if (action === "resume") {
6120
- return resumeAsyncRun(omitUndefinedProperties({ params: paramsWithResolvedCwd, requestCwd, ctx, deps, parentModel: requestParentModel, signal }));
6202
+ return resumeAsyncRun(omitUndefinedProperties({
6203
+ params: paramsWithResolvedCwd,
6204
+ requestCwd,
6205
+ ctx,
6206
+ deps,
6207
+ parentModel: requestParentModel,
6208
+ signal,
6209
+ ...(workflowLaunchObserver ? { onLaunch: (launch) => {
6210
+ workflowLaunchObservers.delete(params);
6211
+ workflowLaunchObserver(launch);
6212
+ } } : {}),
6213
+ }));
6121
6214
  }
6122
6215
  if (action === "steer") {
6123
6216
  if (paramsWithResolvedCwd.mode !== undefined && resolveSteerDeliveryMode(paramsWithResolvedCwd.mode) === undefined) {
@@ -6468,7 +6561,7 @@ export function createSubagentExecutor(deps) {
6468
6561
  return buildRequestedModeError(effectiveParams, contextPolicyResult.error);
6469
6562
  const contextPolicy = contextPolicyResult;
6470
6563
  effectiveParams = contextPolicy.params;
6471
- const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
6564
+ const sessionName = resolveIntercomSessionTarget(deps.childRuntime?.intercomSessionName ?? deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
6472
6565
  const intercomBridge = resolveIntercomBridge({
6473
6566
  config: deps.config.intercomBridge,
6474
6567
  override: effectiveParams.intercomBridge,