pi-subagents 0.70.1 → 0.72.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 (275) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +4 -2
  3. package/agents/worker.md +2 -2
  4. package/docs/agents.md +1 -1
  5. package/docs/configuration.md +18 -2
  6. package/docs/extension-api.md +67 -3
  7. package/docs/models.md +1 -1
  8. package/docs/observability.md +17 -13
  9. package/docs/tool-reference.md +14 -10
  10. package/docs/workflows.md +3 -1
  11. package/package.json +11 -4
  12. package/prompts/council.md +6 -3
  13. package/skills/pi-subagents/references/constraints-and-recipes.md +5 -2
  14. package/skills/pi-subagents/references/execution-controls.md +3 -3
  15. package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  16. package/src/agents/agent-management.d.ts +2 -1
  17. package/src/agents/agent-management.d.ts.map +1 -1
  18. package/src/agents/agent-management.js +32 -29
  19. package/src/agents/agent-management.js.map +1 -1
  20. package/src/agents/agents.d.ts +7 -3
  21. package/src/agents/agents.d.ts.map +1 -1
  22. package/src/agents/agents.js +16 -15
  23. package/src/agents/agents.js.map +1 -1
  24. package/src/agents/global-npm-root.d.ts +7 -0
  25. package/src/agents/global-npm-root.d.ts.map +1 -0
  26. package/src/agents/global-npm-root.js +58 -0
  27. package/src/agents/global-npm-root.js.map +1 -0
  28. package/src/agents/proactive-skills.d.ts +1 -0
  29. package/src/agents/proactive-skills.d.ts.map +1 -1
  30. package/src/agents/proactive-skills.js +3 -1
  31. package/src/agents/proactive-skills.js.map +1 -1
  32. package/src/agents/skills.d.ts +2 -0
  33. package/src/agents/skills.d.ts.map +1 -1
  34. package/src/agents/skills.js +41 -8
  35. package/src/agents/skills.js.map +1 -1
  36. package/src/api/delegation.d.ts +14 -0
  37. package/src/api/delegation.d.ts.map +1 -1
  38. package/src/api/inspectors.d.ts +21 -0
  39. package/src/api/inspectors.d.ts.map +1 -0
  40. package/src/api/inspectors.js +12 -0
  41. package/src/api/inspectors.js.map +1 -0
  42. package/src/extension/fanout-child.d.ts.map +1 -1
  43. package/src/extension/fanout-child.js +9 -0
  44. package/src/extension/fanout-child.js.map +1 -1
  45. package/src/extension/index.d.ts.map +1 -1
  46. package/src/extension/index.js +76 -29
  47. package/src/extension/index.js.map +1 -1
  48. package/src/extension/rpc.d.ts +1 -1
  49. package/src/extension/rpc.d.ts.map +1 -1
  50. package/src/extension/rpc.js +11 -1
  51. package/src/extension/rpc.js.map +1 -1
  52. package/src/extension/schemas.js +5 -5
  53. package/src/extension/schemas.js.map +1 -1
  54. package/src/extension/subagent-guide.d.ts +1 -1
  55. package/src/extension/subagent-guide.d.ts.map +1 -1
  56. package/src/extension/subagent-guide.js +11 -4
  57. package/src/extension/subagent-guide.js.map +1 -1
  58. package/src/extension/tool-activation.d.ts +9 -0
  59. package/src/extension/tool-activation.d.ts.map +1 -0
  60. package/src/extension/tool-activation.js +182 -0
  61. package/src/extension/tool-activation.js.map +1 -0
  62. package/src/extension/tool-description.d.ts +4 -4
  63. package/src/extension/tool-description.d.ts.map +1 -1
  64. package/src/extension/tool-description.js +1 -1
  65. package/src/inspectors/plugins.d.ts +7 -2
  66. package/src/inspectors/plugins.d.ts.map +1 -1
  67. package/src/inspectors/plugins.js +78 -3
  68. package/src/inspectors/plugins.js.map +1 -1
  69. package/src/intercom/intercom-bridge.d.ts.map +1 -1
  70. package/src/intercom/intercom-bridge.js +2 -0
  71. package/src/intercom/intercom-bridge.js.map +1 -1
  72. package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  73. package/src/intercom/native-supervisor-channel.js +3 -1
  74. package/src/intercom/native-supervisor-channel.js.map +1 -1
  75. package/src/runs/background/active-async-capacity.d.ts.map +1 -1
  76. package/src/runs/background/active-async-capacity.js +4 -33
  77. package/src/runs/background/active-async-capacity.js.map +1 -1
  78. package/src/runs/background/async-execution.d.ts.map +1 -1
  79. package/src/runs/background/async-execution.js +7 -33
  80. package/src/runs/background/async-execution.js.map +1 -1
  81. package/src/runs/background/async-job-tracker.d.ts.map +1 -1
  82. package/src/runs/background/async-job-tracker.js +26 -39
  83. package/src/runs/background/async-job-tracker.js.map +1 -1
  84. package/src/runs/background/async-resume.d.ts +1 -1
  85. package/src/runs/background/async-resume.d.ts.map +1 -1
  86. package/src/runs/background/async-resume.js +7 -2
  87. package/src/runs/background/async-resume.js.map +1 -1
  88. package/src/runs/background/async-status.d.ts +1 -0
  89. package/src/runs/background/async-status.d.ts.map +1 -1
  90. package/src/runs/background/async-status.js +1 -0
  91. package/src/runs/background/async-status.js.map +1 -1
  92. package/src/runs/background/binary-bootstrap.d.ts.map +1 -1
  93. package/src/runs/background/binary-bootstrap.js +34 -6
  94. package/src/runs/background/binary-bootstrap.js.map +1 -1
  95. package/src/runs/background/fleet-view.d.ts.map +1 -1
  96. package/src/runs/background/fleet-view.js +26 -7
  97. package/src/runs/background/fleet-view.js.map +1 -1
  98. package/src/runs/background/notify.d.ts +11 -0
  99. package/src/runs/background/notify.d.ts.map +1 -1
  100. package/src/runs/background/notify.js +73 -3
  101. package/src/runs/background/notify.js.map +1 -1
  102. package/src/runs/background/pid-namespace.d.ts +3 -0
  103. package/src/runs/background/pid-namespace.d.ts.map +1 -0
  104. package/src/runs/background/pid-namespace.js +20 -0
  105. package/src/runs/background/pid-namespace.js.map +1 -0
  106. package/src/runs/background/process-terminal-candidate.d.ts +18 -0
  107. package/src/runs/background/process-terminal-candidate.d.ts.map +1 -0
  108. package/src/runs/background/process-terminal-candidate.js +97 -0
  109. package/src/runs/background/process-terminal-candidate.js.map +1 -0
  110. package/src/runs/background/process-terminal.d.ts +3 -15
  111. package/src/runs/background/process-terminal.d.ts.map +1 -1
  112. package/src/runs/background/process-terminal.js +19 -96
  113. package/src/runs/background/process-terminal.js.map +1 -1
  114. package/src/runs/background/retained-children.d.ts.map +1 -1
  115. package/src/runs/background/retained-children.js +3 -2
  116. package/src/runs/background/retained-children.js.map +1 -1
  117. package/src/runs/background/run-child-session.d.ts +2 -0
  118. package/src/runs/background/run-child-session.d.ts.map +1 -1
  119. package/src/runs/background/run-child-session.js +2 -0
  120. package/src/runs/background/run-child-session.js.map +1 -1
  121. package/src/runs/background/run-status.d.ts.map +1 -1
  122. package/src/runs/background/run-status.js +5 -1
  123. package/src/runs/background/run-status.js.map +1 -1
  124. package/src/runs/background/runner-aliases.d.ts.map +1 -1
  125. package/src/runs/background/runner-aliases.js +2 -1
  126. package/src/runs/background/runner-aliases.js.map +1 -1
  127. package/src/runs/background/runner-startup-failure.d.ts +14 -0
  128. package/src/runs/background/runner-startup-failure.d.ts.map +1 -0
  129. package/src/runs/background/runner-startup-failure.js +47 -0
  130. package/src/runs/background/runner-startup-failure.js.map +1 -0
  131. package/src/runs/background/stale-run-reconciler.d.ts +1 -0
  132. package/src/runs/background/stale-run-reconciler.d.ts.map +1 -1
  133. package/src/runs/background/stale-run-reconciler.js +18 -3
  134. package/src/runs/background/stale-run-reconciler.js.map +1 -1
  135. package/src/runs/background/subagent-runner-bootstrap.d.ts +14 -0
  136. package/src/runs/background/subagent-runner-bootstrap.d.ts.map +1 -0
  137. package/src/runs/background/subagent-runner-bootstrap.js +277 -0
  138. package/src/runs/background/subagent-runner-bootstrap.js.map +1 -0
  139. package/src/runs/background/subagent-runner.d.ts +4 -2
  140. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  141. package/src/runs/background/subagent-runner.js +58 -180
  142. package/src/runs/background/subagent-runner.js.map +1 -1
  143. package/src/runs/background/workflow-terminal-proof.d.ts +18 -0
  144. package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -0
  145. package/src/runs/background/workflow-terminal-proof.js +68 -0
  146. package/src/runs/background/workflow-terminal-proof.js.map +1 -0
  147. package/src/runs/foreground/execution.d.ts.map +1 -1
  148. package/src/runs/foreground/execution.js +43 -14
  149. package/src/runs/foreground/execution.js.map +1 -1
  150. package/src/runs/foreground/prompt-audit.d.ts.map +1 -1
  151. package/src/runs/foreground/prompt-audit.js +2 -6
  152. package/src/runs/foreground/prompt-audit.js.map +1 -1
  153. package/src/runs/foreground/subagent-executor.d.ts +2 -1
  154. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  155. package/src/runs/foreground/subagent-executor.js +228 -24
  156. package/src/runs/foreground/subagent-executor.js.map +1 -1
  157. package/src/runs/shared/child-launch.d.ts.map +1 -1
  158. package/src/runs/shared/child-launch.js +3 -0
  159. package/src/runs/shared/child-launch.js.map +1 -1
  160. package/src/runs/shared/child-runtime-config.d.ts +4 -0
  161. package/src/runs/shared/child-runtime-config.d.ts.map +1 -1
  162. package/src/runs/shared/child-runtime-config.js.map +1 -1
  163. package/src/runs/shared/child-session.d.ts +1 -0
  164. package/src/runs/shared/child-session.d.ts.map +1 -1
  165. package/src/runs/shared/child-session.js +1 -0
  166. package/src/runs/shared/child-session.js.map +1 -1
  167. package/src/runs/shared/child-tool-plan.d.ts.map +1 -1
  168. package/src/runs/shared/child-tool-plan.js +4 -6
  169. package/src/runs/shared/child-tool-plan.js.map +1 -1
  170. package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
  171. package/src/runs/shared/external-cli-runner.js +3 -1
  172. package/src/runs/shared/external-cli-runner.js.map +1 -1
  173. package/src/runs/shared/external-job-bridge.d.ts +7 -0
  174. package/src/runs/shared/external-job-bridge.d.ts.map +1 -1
  175. package/src/runs/shared/external-job-bridge.js +63 -0
  176. package/src/runs/shared/external-job-bridge.js.map +1 -1
  177. package/src/runs/shared/git-environment.d.ts +3 -0
  178. package/src/runs/shared/git-environment.d.ts.map +1 -0
  179. package/src/runs/shared/git-environment.js +28 -0
  180. package/src/runs/shared/git-environment.js.map +1 -0
  181. package/src/runs/shared/mcp-config-sources.d.ts +3 -0
  182. package/src/runs/shared/mcp-config-sources.d.ts.map +1 -1
  183. package/src/runs/shared/mcp-config-sources.js.map +1 -1
  184. package/src/runs/shared/mcp-direct-tool-allowlist.js +1 -1
  185. package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
  186. package/src/runs/shared/mcp-direct-tool-grant.d.ts +3 -1
  187. package/src/runs/shared/mcp-direct-tool-grant.d.ts.map +1 -1
  188. package/src/runs/shared/mcp-direct-tool-grant.js +19 -5
  189. package/src/runs/shared/mcp-direct-tool-grant.js.map +1 -1
  190. package/src/runs/shared/model-resolution.d.ts.map +1 -1
  191. package/src/runs/shared/model-resolution.js +7 -1
  192. package/src/runs/shared/model-resolution.js.map +1 -1
  193. package/src/runs/shared/pi-spawn.d.ts +10 -1
  194. package/src/runs/shared/pi-spawn.d.ts.map +1 -1
  195. package/src/runs/shared/pi-spawn.js +86 -7
  196. package/src/runs/shared/pi-spawn.js.map +1 -1
  197. package/src/runs/shared/single-output.js +1 -1
  198. package/src/runs/shared/single-output.js.map +1 -1
  199. package/src/runs/shared/structured-output.d.ts +7 -0
  200. package/src/runs/shared/structured-output.d.ts.map +1 -1
  201. package/src/runs/shared/structured-output.js +74 -0
  202. package/src/runs/shared/structured-output.js.map +1 -1
  203. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  204. package/src/runs/shared/subagent-prompt-runtime.js +23 -7
  205. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  206. package/src/runs/shared/tool-availability.js +2 -2
  207. package/src/runs/shared/tool-availability.js.map +1 -1
  208. package/src/runs/shared/worktree.d.ts.map +1 -1
  209. package/src/runs/shared/worktree.js +9 -3
  210. package/src/runs/shared/worktree.js.map +1 -1
  211. package/src/shared/child-session-name.d.ts.map +1 -1
  212. package/src/shared/child-session-name.js +4 -2
  213. package/src/shared/child-session-name.js.map +1 -1
  214. package/src/shared/fork-context.d.ts +4 -0
  215. package/src/shared/fork-context.d.ts.map +1 -1
  216. package/src/shared/fork-context.js +9 -4
  217. package/src/shared/fork-context.js.map +1 -1
  218. package/src/shared/pruned-fork.d.ts.map +1 -1
  219. package/src/shared/pruned-fork.js +68 -56
  220. package/src/shared/pruned-fork.js.map +1 -1
  221. package/src/shared/types.d.ts +31 -3
  222. package/src/shared/types.d.ts.map +1 -1
  223. package/src/shared/types.js +2 -0
  224. package/src/shared/types.js.map +1 -1
  225. package/src/slash/delegation-adapters.d.ts +7 -1
  226. package/src/slash/delegation-adapters.d.ts.map +1 -1
  227. package/src/slash/delegation-adapters.js +17 -0
  228. package/src/slash/delegation-adapters.js.map +1 -1
  229. package/src/slash/prompt-template-bridge.d.ts.map +1 -1
  230. package/src/slash/prompt-template-bridge.js +14 -1
  231. package/src/slash/prompt-template-bridge.js.map +1 -1
  232. package/src/slash/prompt-workflows.d.ts.map +1 -1
  233. package/src/slash/prompt-workflows.js +16 -2
  234. package/src/slash/prompt-workflows.js.map +1 -1
  235. package/src/slash/slash-commands.d.ts.map +1 -1
  236. package/src/slash/slash-commands.js +7 -253
  237. package/src/slash/slash-commands.js.map +1 -1
  238. package/src/slash/subagent-cost.d.ts +30 -0
  239. package/src/slash/subagent-cost.d.ts.map +1 -0
  240. package/src/slash/subagent-cost.js +307 -0
  241. package/src/slash/subagent-cost.js.map +1 -0
  242. package/src/tui/fleet-status.d.ts +2 -0
  243. package/src/tui/fleet-status.d.ts.map +1 -1
  244. package/src/tui/fleet-status.js +25 -2
  245. package/src/tui/fleet-status.js.map +1 -1
  246. package/src/tui/fleet.d.ts +1 -1
  247. package/src/tui/fleet.d.ts.map +1 -1
  248. package/src/tui/fleet.js +5 -1
  249. package/src/tui/fleet.js.map +1 -1
  250. package/src/tui/render.d.ts.map +1 -1
  251. package/src/tui/render.js +8 -4
  252. package/src/tui/render.js.map +1 -1
  253. package/src/watchdog/diff-tool.d.ts +2 -1
  254. package/src/watchdog/diff-tool.d.ts.map +1 -1
  255. package/src/watchdog/diff-tool.js +9 -3
  256. package/src/watchdog/diff-tool.js.map +1 -1
  257. package/src/watchdog/permission-arbiter.d.ts.map +1 -1
  258. package/src/watchdog/permission-arbiter.js +2 -7
  259. package/src/watchdog/permission-arbiter.js.map +1 -1
  260. package/src/watchdog/register-child.d.ts +3 -1
  261. package/src/watchdog/register-child.d.ts.map +1 -1
  262. package/src/watchdog/register-child.js +12 -3
  263. package/src/watchdog/register-child.js.map +1 -1
  264. package/src/watchdog/review.d.ts +1 -1
  265. package/src/watchdog/review.d.ts.map +1 -1
  266. package/src/watchdog/review.js +2 -7
  267. package/src/watchdog/review.js.map +1 -1
  268. package/src/watchdog/runtime.d.ts +1 -1
  269. package/src/watchdog/runtime.d.ts.map +1 -1
  270. package/src/watchdog/runtime.js +2 -1
  271. package/src/watchdog/runtime.js.map +1 -1
  272. package/src/watchdog/turn-delta.d.ts +5 -1
  273. package/src/watchdog/turn-delta.d.ts.map +1 -1
  274. package/src/watchdog/turn-delta.js +9 -5
  275. package/src/watchdog/turn-delta.js.map +1 -1
@@ -12,10 +12,6 @@ import * as path from "node:path";
12
12
  import { performance } from "node:perf_hooks";
13
13
  import { pathToFileURL } from "node:url";
14
14
  import { installRunnerHttpDispatcher } from "./runner-http-dispatcher.js";
15
- const isRunnerEntrypoint = Boolean(process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href);
16
- // Detached Node runners skip Pi's CLI dispatcher setup; install the runner's own.
17
- if (isRunnerEntrypoint)
18
- installRunnerHttpDispatcher({ agentDir: getAgentDir(), cwd: process.cwd() });
19
15
  import { writeAtomicJson } from "../../shared/atomic-json.js";
20
16
  import { writeAsyncResultFile, writePendingAsyncResultFile } from "./result-files.js";
21
17
  import { createFileCoalescer } from "../../shared/file-coalescer.js";
@@ -41,7 +37,7 @@ import { SUBAGENT_CHILD_ENV } from "../shared/child-runtime-config.js";
41
37
  import { deriveChildSessionName } from "../../shared/child-session-name.js";
42
38
  import { alignForkedSessionCwd } from "../../shared/fork-session-cwd.js";
43
39
  import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.js";
44
- import { clearStructuredOutputCaptures, createStructuredOutputFileCapture, createStructuredOutputRuntime, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructuredOutputAcceptanceReport } from "../shared/structured-output.js";
40
+ import { clearStructuredOutputCaptures, createStructuredOutputFileCapture, createStructuredOutputRuntime, formatStructuredOutputRejectionError, MISSING_STRUCTURED_OUTPUT_CALL_ERROR, readStructuredOutput, readStructuredOutputAcceptanceReport } from "../shared/structured-output.js";
45
41
  import { formatMidToolExitError, isOrdinaryToolForMidToolExit, isUnexplainedProcessSignal } from "../shared/process-signal.js";
46
42
  import { formatChildToolDiagnostic } from "../shared/tool-availability.js";
47
43
  import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.js";
@@ -49,7 +45,9 @@ import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelSt
49
45
  import { claimRunFanoutBatch, getRunFanoutBudgetSnapshot } from "../shared/run-fanout-budget.js";
50
46
  import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent } from "../shared/nested-events.js";
51
47
  import { isContextOverflow } from "../shared/model-resolution.js";
52
- import { markProcessTerminalCandidateLeaseRelease, processTerminalPath, writeProcessTerminalCandidate } from "./process-terminal.js";
48
+ import { processTerminalPath, writeProcessTerminalCandidate } from "./process-terminal.js";
49
+ import { persistRunnerStartupFailure } from "./runner-startup-failure.js";
50
+ import { currentPidNamespaceScope } from "./pid-namespace.js";
53
51
  import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, unconsumedSteerReason, updateSteeringTarget } from "./steering.js";
54
52
  import { PROMPT_REDACTED, detectSubagentError, extractTextFromContent, extractToolArgsPreview, formatEmptyTerminalAssistantResponseError, getAgentDir, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.js";
55
53
  import { planAbortRecovery } from "../shared/abort-recovery.js";
@@ -71,7 +69,6 @@ import { toolTimeoutCallKey } from "../shared/tool-timeout.js";
71
69
  import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.js";
72
70
  import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.js";
73
71
  import { resolveWatchdogConfig } from "../../watchdog/settings.js";
74
- import { acquireSessionLease } from "../shared/session-lease.js";
75
72
  import { buildExternalCliPrompt, runExternalCli } from "../shared/external-cli-runner.js";
76
73
  import { resolveClaudeCodeLaunch } from "../shared/claude-code-adapter.js";
77
74
  import { resolveCodexExecLaunch } from "../shared/codex-exec-adapter.js";
@@ -814,9 +811,9 @@ export async function runSingleStepInner(step, ctx) {
814
811
  const message = error instanceof Error ? error.message : String(error);
815
812
  return omitUndefinedProperties({ agent: step.agent, output: message, error: message, exitCode: 1, context: step.context, thinkingCeiling: step.thinkingCeiling });
816
813
  }
814
+ const attemptModel = omitUndefinedProperties({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) });
817
815
  ctx.onAttemptStart?.(omitUndefinedProperties({
818
- model: candidate,
819
- thinking: resolveEffectiveThinking(candidate, step.thinking),
816
+ ...attemptModel,
820
817
  contextLimit: findModelInfo(candidate, step.modelVerificationRegistry)?.contextWindow,
821
818
  }));
822
819
  const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
@@ -938,6 +935,7 @@ export async function runSingleStepInner(step, ctx) {
938
935
  timeoutMessage: ctx.timeoutMessage,
939
936
  stopMessage: ctx.stopMessage,
940
937
  onChildEvent: ctx.onChildEvent,
938
+ onContextWindow: (contextLimit) => ctx.onAttemptStart?.({ ...attemptModel, contextLimit }),
941
939
  transcriptWriter,
942
940
  toolTimeoutMs: ctx.toolTimeoutMs,
943
941
  runDeadlineAt: ctx.deadlineAt,
@@ -970,18 +968,24 @@ export async function runSingleStepInner(step, ctx) {
970
968
  let structuredOutput;
971
969
  let structuredError;
972
970
  let validatedStructuredOutput = false;
973
- if (terminalDiagnosticsEligible && effectiveStructuredOutput && run.exitCode === 0 && !run.error && !toolAvailabilityError && !midToolExitError) {
974
- if (!run.structuredOutputToolInvoked) {
971
+ if (effectiveStructuredOutput) {
972
+ const otherwiseSuccessful = terminalDiagnosticsEligible && run.exitCode === 0 && !run.error && !toolAvailabilityError && !midToolExitError;
973
+ if (!run.structuredOutputToolInvoked && otherwiseSuccessful) {
975
974
  structuredError = MISSING_STRUCTURED_OUTPUT_CALL_ERROR;
976
975
  }
977
- else {
976
+ else if (run.structuredOutputToolInvoked) {
978
977
  const structured = await readStructuredOutput({
979
978
  schema: effectiveStructuredOutput.schema,
980
979
  schemaPath: effectiveStructuredOutput.schemaPath,
981
980
  outputPath: effectiveStructuredOutput.outputPath,
982
981
  });
983
- if (structured.error)
984
- structuredError = structured.error;
982
+ if (structured.error) {
983
+ if (otherwiseSuccessful) {
984
+ structuredError = structured.error === MISSING_STRUCTURED_OUTPUT_CALL_ERROR
985
+ ? formatStructuredOutputRejectionError(run.messages)
986
+ : structured.error;
987
+ }
988
+ }
985
989
  else {
986
990
  structuredOutput = structured.value;
987
991
  const acceptanceReport = readStructuredOutputAcceptanceReport(effectiveStructuredOutput);
@@ -1055,7 +1059,7 @@ export async function runSingleStepInner(step, ctx) {
1055
1059
  afterCompactionSettlement: run.afterCompactionSettlement === true,
1056
1060
  } : undefined;
1057
1061
  const fileMutationEffect = missingRequiredOutputAfterMutation ? { status: "observed", attempted: true, evidence: mutationEvidence } : undefined;
1058
- finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput, runtimeAcknowledgedExtensions, ...(step.agentContract ? { agentContract: step.agentContract } : {}), ...(fileMutationEffect || settlementDiagnostic ? { effects: { ...(fileMutationEffect ? { fileMutation: fileMutationEffect } : {}), ...(settlementDiagnostic ? { settlementDiagnostic } : {}) } } : {}) };
1062
+ finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput, structuredOutputFailed: structuredError ? true : undefined, runtimeAcknowledgedExtensions, ...(step.agentContract ? { agentContract: step.agentContract } : {}), ...(fileMutationEffect || settlementDiagnostic ? { effects: { ...(fileMutationEffect ? { fileMutation: fileMutationEffect } : {}), ...(settlementDiagnostic ? { settlementDiagnostic } : {}) } } : {}) };
1059
1063
  if (run.stopped || run.timedOut || ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.())
1060
1064
  break singleLaunch;
1061
1065
  if (effectiveExitCode === 0 && !error)
@@ -1262,9 +1266,10 @@ export async function runSingleStepInner(step, ctx) {
1262
1266
  toolBudget,
1263
1267
  toolBudgetBlocked: toolBudgetBlocked || undefined,
1264
1268
  ...(finalResult?.effects ? { effects: finalResult.effects } : {}),
1265
- structuredOutput: timedOutAfterAcceptance || stoppedAfterAcceptance ? undefined : finalResult?.structuredOutput,
1266
- structuredOutputPath: timedOutAfterAcceptance || stoppedAfterAcceptance ? undefined : effectiveStructuredOutput?.outputPath,
1267
- structuredOutputSchemaPath: timedOutAfterAcceptance || stoppedAfterAcceptance ? undefined : effectiveStructuredOutput?.schemaPath,
1269
+ structuredOutput: finalResult?.structuredOutput,
1270
+ structuredOutputFailed: finalResult?.structuredOutputFailed,
1271
+ structuredOutputPath: effectiveStructuredOutput?.outputPath,
1272
+ structuredOutputSchemaPath: effectiveStructuredOutput?.schemaPath,
1268
1273
  acceptance: effectiveAcceptance,
1269
1274
  watchdog: finalResult?.watchdog,
1270
1275
  ...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
@@ -1670,6 +1675,7 @@ export async function runSubagent(config, childSessions) {
1670
1675
  ...(config.toolBudget ? { toolBudget: initialToolBudgetState(config.toolBudget) } : {}),
1671
1676
  ...(config.usageBudget ? { usageBudget: usageBudgetState(config.usageBudget, undefined) } : {}),
1672
1677
  pid: process.pid,
1678
+ pidNamespaceScope: currentPidNamespaceScope(),
1673
1679
  cwd,
1674
1680
  currentStep: 0,
1675
1681
  chainStepCount: steps.length,
@@ -3594,6 +3600,7 @@ export async function runSubagent(config, childSessions) {
3594
3600
  review: pr.review,
3595
3601
  timeoutRecovery: pr.timeoutRecovery,
3596
3602
  structuredOutput: pr.structuredOutput,
3603
+ structuredOutputFailed: pr.structuredOutputFailed,
3597
3604
  structuredOutputPath: pr.structuredOutputPath,
3598
3605
  structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
3599
3606
  acceptance: pr.acceptance,
@@ -4043,6 +4050,7 @@ export async function runSubagent(config, childSessions) {
4043
4050
  review: pr.review,
4044
4051
  timeoutRecovery: pr.timeoutRecovery,
4045
4052
  structuredOutput: pr.structuredOutput,
4053
+ structuredOutputFailed: pr.structuredOutputFailed,
4046
4054
  structuredOutputPath: pr.structuredOutputPath,
4047
4055
  structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
4048
4056
  acceptance: pr.acceptance,
@@ -4348,6 +4356,7 @@ export async function runSubagent(config, childSessions) {
4348
4356
  review: singleResult.review,
4349
4357
  timeoutRecovery: singleResult.timeoutRecovery,
4350
4358
  structuredOutput: singleResult.structuredOutput,
4359
+ structuredOutputFailed: singleResult.structuredOutputFailed,
4351
4360
  structuredOutputPath: singleResult.structuredOutputPath,
4352
4361
  structuredOutputSchemaPath: singleResult.structuredOutputSchemaPath,
4353
4362
  acceptance: singleResult.acceptance,
@@ -4758,6 +4767,7 @@ export async function runSubagent(config, childSessions) {
4758
4767
  review: r.review,
4759
4768
  effects: r.effects,
4760
4769
  structuredOutput: r.structuredOutput,
4770
+ structuredOutputFailed: r.structuredOutputFailed,
4761
4771
  structuredOutputPath: r.structuredOutputPath,
4762
4772
  structuredOutputSchemaPath: r.structuredOutputSchemaPath,
4763
4773
  acceptance: r.acceptance,
@@ -4875,178 +4885,46 @@ export async function runSubagent(config, childSessions) {
4875
4885
  }
4876
4886
  }
4877
4887
  }
4878
- async function waitForStartupControl(controlPath, token, action, timeoutMs = 30_000) {
4879
- const deadline = Date.now() + timeoutMs;
4880
- while (Date.now() <= deadline) {
4881
- if (fs.existsSync(controlPath)) {
4882
- let payload;
4883
- try {
4884
- payload = JSON.parse(fs.readFileSync(controlPath, "utf-8"));
4885
- }
4886
- catch (error) {
4887
- throw new Error(`Failed to read runner startup control '${controlPath}': ${error instanceof Error ? error.message : String(error)}`);
4888
- }
4889
- if (payload.token !== token)
4890
- throw new Error("Runner startup control token does not match.");
4891
- if (payload.action === action)
4892
- return;
4893
- if (payload.action !== "ack" && payload.action !== "confirm" && payload.action !== "proceed")
4894
- throw new Error("Runner startup control action is invalid.");
4895
- }
4896
- await new Promise((resolve) => setTimeout(resolve, 20));
4897
- }
4898
- throw new Error(`Timed out after ${timeoutMs}ms waiting for runner startup control '${action}'.`);
4899
- }
4900
- // Both hosts enter here: startup authorization, revival leases and disposal stay shared.
4901
- export async function runConfiguredSubagent(config, options) {
4902
- let lease;
4903
- let startupCommitted = config.revivalLease === undefined && config.launchBarrierToken === undefined;
4904
- const startupPath = path.join(config.asyncDir, "runner-startup.json");
4905
- const startupAckPath = path.join(config.asyncDir, "runner-startup-ack.json");
4906
- const startupConfirmPath = path.join(config.asyncDir, "runner-startup-confirm.json");
4907
- const startupProceedPath = path.join(config.asyncDir, "runner-startup-proceed.json");
4908
- const releaseOnExit = () => {
4909
- try {
4910
- lease?.release();
4911
- }
4912
- catch {
4913
- // Exit cleanup is best effort; a dead-owner lease is reclaimed on the next revival.
4914
- }
4915
- };
4916
- process.once("exit", releaseOnExit);
4888
+ /** Heavy execution entry loaded by the bootstrap only after startup commits. */
4889
+ export async function runConfiguredSubagentExecution(config, options) {
4890
+ let childSessions;
4917
4891
  try {
4918
- if (config.launchBarrierToken) {
4919
- await waitForStartupControl(startupProceedPath, config.launchBarrierToken, "proceed");
4920
- startupCommitted = true;
4921
- try {
4922
- fs.rmSync(startupProceedPath, { force: true });
4923
- }
4924
- catch {
4925
- // Startup control cleanup is best effort after the parent commits the run.
4926
- }
4927
- }
4928
- else if (config.revivalLease) {
4929
- lease = acquireSessionLease(config.revivalLease);
4930
- config.revivalLeaseToken = lease.owner.token;
4931
- writeAtomicJson(startupPath, { state: "ready", token: lease.owner.token, pid: process.pid, owner: lease.owner });
4932
- await waitForStartupControl(startupAckPath, lease.owner.token, "ack");
4933
- writeAtomicJson(startupPath, { state: "acknowledged", token: lease.owner.token, pid: process.pid });
4934
- await waitForStartupControl(startupConfirmPath, lease.owner.token, "confirm");
4935
- writeAtomicJson(startupPath, { state: "confirmed", token: lease.owner.token, pid: process.pid });
4936
- await waitForStartupControl(startupProceedPath, lease.owner.token, "proceed");
4937
- startupCommitted = true;
4938
- for (const controlPath of [startupAckPath, startupConfirmPath, startupProceedPath]) {
4939
- try {
4940
- fs.rmSync(controlPath, { force: true });
4941
- }
4942
- catch {
4943
- // Startup control cleanup is best effort after the parent commits the run.
4944
- }
4945
- }
4946
- }
4947
- const childSessions = await loadRunnerChildSessionFactory(config, options);
4948
- try {
4949
- await runSubagent(config, childSessions);
4950
- }
4951
- finally {
4952
- try {
4953
- await childSessions.dispose();
4954
- }
4955
- catch (error) {
4956
- console.error("Failed to dispose runner child sessions:", error);
4957
- }
4958
- }
4892
+ // Detached Node runners do not receive Pi's CLI dispatcher setup. Binary
4893
+ // hosts install the same dispatcher before entering the shared bootstrap.
4894
+ if (!options?.loadPiCodingAgent)
4895
+ installRunnerHttpDispatcher({ agentDir: getAgentDir(), cwd: process.cwd() });
4896
+ childSessions = await loadRunnerChildSessionFactory(config, options);
4959
4897
  }
4960
4898
  catch (error) {
4961
- if (!startupCommitted) {
4962
- try {
4963
- writeAtomicJson(startupPath, { state: "error", pid: process.pid, error: error instanceof Error ? error.message : String(error) });
4964
- }
4965
- catch {
4966
- // The parent will time out and terminate this runner if the handshake cannot be written.
4967
- }
4899
+ try {
4900
+ persistRunnerStartupFailure({
4901
+ asyncDir: config.asyncDir,
4902
+ runId: config.id,
4903
+ runnerProcessInstanceId: config.runnerProcessInstanceId ?? "unknown-runner-instance",
4904
+ message: `Subagent runner startup failed: ${error instanceof Error ? error.message : String(error)}`,
4905
+ ...(config.sessionId ? { sessionId: config.sessionId } : {}),
4906
+ ...(config.completionOwnerId ? { completionOwnerId: config.completionOwnerId } : {}),
4907
+ candidate: {
4908
+ ...(config.revivalLease?.sessionFile ? { sessionFile: config.revivalLease.sessionFile } : {}),
4909
+ ...(config.revivalLeaseToken ? { revivalLeaseToken: config.revivalLeaseToken } : {}),
4910
+ },
4911
+ });
4912
+ }
4913
+ catch (persistenceError) {
4914
+ console.error("Failed to persist runner setup failure:", persistenceError);
4968
4915
  }
4969
4916
  throw error;
4970
4917
  }
4971
- finally {
4972
- process.off("exit", releaseOnExit);
4973
- if (lease) {
4974
- let acknowledged = false;
4975
- try {
4976
- acknowledged = lease.release();
4977
- }
4978
- catch (error) {
4979
- console.error("Failed to release session revival lease:", error);
4980
- }
4981
- try {
4982
- markProcessTerminalCandidateLeaseRelease(config.asyncDir, lease.owner.token, acknowledged);
4983
- }
4984
- catch (error) {
4985
- console.error("Failed to record session revival lease release:", error);
4986
- }
4987
- }
4918
+ try {
4919
+ await runSubagent(config, childSessions);
4988
4920
  }
4989
- }
4990
- function startConfiguredSubagent(config) {
4991
- // Child sessions and the extensions loaded into them may leave handles
4992
- // behind even after shutdown; the run is fully persisted by now, so exit
4993
- // explicitly instead of waiting for the event loop to drain.
4994
- runConfiguredSubagent(config).then(() => process.exit(0), (runErr) => {
4995
- console.error("Subagent runner error:", runErr);
4996
- process.exit(1);
4997
- });
4998
- }
4999
- function monitorTestParent() {
5000
- const parentPid = Number(process.env.PI_SUBAGENTS_TEST_PARENT_PID);
5001
- if (!Number.isSafeInteger(parentPid) || parentPid <= 0 || parentPid === process.pid)
5002
- return;
5003
- const check = () => {
4921
+ finally {
5004
4922
  try {
5005
- process.kill(parentPid, 0);
5006
- }
5007
- catch {
5008
- process.exit(1);
4923
+ await childSessions.dispose();
5009
4924
  }
5010
- };
5011
- check();
5012
- setInterval(check, 250).unref();
5013
- }
5014
- if (isRunnerEntrypoint) {
5015
- monitorTestParent();
5016
- const configArg = process.argv[2];
5017
- if (configArg) {
5018
- try {
5019
- const configJson = fs.readFileSync(configArg, "utf-8");
5020
- const config = JSON.parse(configJson);
5021
- try {
5022
- fs.unlinkSync(configArg);
5023
- }
5024
- catch {
5025
- // Temp config cleanup is best effort.
5026
- }
5027
- startConfiguredSubagent(config);
5028
- }
5029
- catch (err) {
5030
- console.error("Subagent runner error:", err);
5031
- process.exit(1);
4925
+ catch (error) {
4926
+ console.error("Failed to dispose runner child sessions:", error);
5032
4927
  }
5033
4928
  }
5034
- else {
5035
- let input = "";
5036
- process.stdin.setEncoding("utf-8");
5037
- process.stdin.on("data", (chunk) => {
5038
- input += chunk;
5039
- });
5040
- process.stdin.on("end", () => {
5041
- try {
5042
- const config = JSON.parse(input);
5043
- startConfiguredSubagent(config);
5044
- }
5045
- catch (err) {
5046
- console.error("Subagent runner error:", err);
5047
- process.exit(1);
5048
- }
5049
- });
5050
- }
5051
4929
  }
5052
4930
  //# sourceMappingURL=subagent-runner.js.map