pi-subagents 0.76.1 → 0.78.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 (391) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +1 -1
  3. package/agents/evidence-auditor.md +1 -0
  4. package/agents/oracle.md +9 -19
  5. package/agents/researcher.md +0 -3
  6. package/agents/reviewer.md +18 -61
  7. package/agents/scout.md +1 -4
  8. package/agents/worker.md +8 -25
  9. package/docs/agents.md +71 -4
  10. package/docs/configuration.md +75 -10
  11. package/docs/extension-api.md +38 -9
  12. package/docs/missions.md +24 -17
  13. package/docs/models.md +1 -1
  14. package/docs/observability.md +12 -5
  15. package/docs/tool-reference.md +103 -85
  16. package/docs/watchdog.md +8 -6
  17. package/docs/workflows.md +17 -8
  18. package/package.json +1 -1
  19. package/prompts/council.md +1 -1
  20. package/skills/pi-subagents/SKILL.md +2 -2
  21. package/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
  22. package/skills/pi-subagents/references/execution-controls.md +16 -16
  23. package/skills/pi-subagents/references/management-authoring-rpc.md +16 -12
  24. package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
  25. package/skills/pi-subagents/references/prompting-and-roles.md +3 -3
  26. package/src/agents/advertised-agent-prompt.d.ts +5 -1
  27. package/src/agents/advertised-agent-prompt.d.ts.map +1 -1
  28. package/src/agents/advertised-agent-prompt.js +8 -2
  29. package/src/agents/advertised-agent-prompt.js.map +1 -1
  30. package/src/agents/agent-management.d.ts.map +1 -1
  31. package/src/agents/agent-management.js +5 -0
  32. package/src/agents/agent-management.js.map +1 -1
  33. package/src/agents/agent-scope.d.ts +1 -0
  34. package/src/agents/agent-scope.d.ts.map +1 -1
  35. package/src/agents/agent-scope.js +3 -0
  36. package/src/agents/agent-scope.js.map +1 -1
  37. package/src/agents/agent-serializer.d.ts.map +1 -1
  38. package/src/agents/agent-serializer.js +3 -0
  39. package/src/agents/agent-serializer.js.map +1 -1
  40. package/src/agents/agents.d.ts +14 -2
  41. package/src/agents/agents.d.ts.map +1 -1
  42. package/src/agents/agents.js +94 -36
  43. package/src/agents/agents.js.map +1 -1
  44. package/src/api/external-runs.d.ts.map +1 -1
  45. package/src/api/external-runs.js +5 -4
  46. package/src/api/external-runs.js.map +1 -1
  47. package/src/api/preflight.d.ts +2 -0
  48. package/src/api/preflight.d.ts.map +1 -1
  49. package/src/api/preflight.js +7 -3
  50. package/src/api/preflight.js.map +1 -1
  51. package/src/extension/active-runs-prompt.d.ts +8 -0
  52. package/src/extension/active-runs-prompt.d.ts.map +1 -0
  53. package/src/extension/active-runs-prompt.js +30 -0
  54. package/src/extension/active-runs-prompt.js.map +1 -0
  55. package/src/extension/config.d.ts.map +1 -1
  56. package/src/extension/config.js +29 -2
  57. package/src/extension/config.js.map +1 -1
  58. package/src/extension/control-notices.d.ts +0 -2
  59. package/src/extension/control-notices.d.ts.map +1 -1
  60. package/src/extension/control-notices.js +1 -7
  61. package/src/extension/control-notices.js.map +1 -1
  62. package/src/extension/declaration-pinning.d.ts +19 -0
  63. package/src/extension/declaration-pinning.d.ts.map +1 -0
  64. package/src/extension/declaration-pinning.js +154 -0
  65. package/src/extension/declaration-pinning.js.map +1 -0
  66. package/src/extension/fanout-child.d.ts.map +1 -1
  67. package/src/extension/fanout-child.js +6 -8
  68. package/src/extension/fanout-child.js.map +1 -1
  69. package/src/extension/index.d.ts +1 -2
  70. package/src/extension/index.d.ts.map +1 -1
  71. package/src/extension/index.js +104 -121
  72. package/src/extension/index.js.map +1 -1
  73. package/src/extension/rpc.d.ts.map +1 -1
  74. package/src/extension/rpc.js +12 -6
  75. package/src/extension/rpc.js.map +1 -1
  76. package/src/extension/schemas.d.ts +137 -1
  77. package/src/extension/schemas.d.ts.map +1 -1
  78. package/src/extension/schemas.js +22 -22
  79. package/src/extension/schemas.js.map +1 -1
  80. package/src/extension/subagent-guide.d.ts +1 -0
  81. package/src/extension/subagent-guide.d.ts.map +1 -1
  82. package/src/extension/subagent-guide.js +80 -6
  83. package/src/extension/subagent-guide.js.map +1 -1
  84. package/src/extension/subagent-options.d.ts +8 -0
  85. package/src/extension/subagent-options.d.ts.map +1 -0
  86. package/src/extension/subagent-options.js +52 -0
  87. package/src/extension/subagent-options.js.map +1 -0
  88. package/src/extension/tool-activation.d.ts.map +1 -1
  89. package/src/extension/tool-activation.js +7 -4
  90. package/src/extension/tool-activation.js.map +1 -1
  91. package/src/extension/tool-description.d.ts +4 -7
  92. package/src/extension/tool-description.d.ts.map +1 -1
  93. package/src/extension/tool-description.js +45 -59
  94. package/src/extension/tool-description.js.map +1 -1
  95. package/src/inspectors/actions.d.ts +2 -0
  96. package/src/inspectors/actions.d.ts.map +1 -1
  97. package/src/inspectors/actions.js +41 -13
  98. package/src/inspectors/actions.js.map +1 -1
  99. package/src/inspectors/plugins.d.ts.map +1 -1
  100. package/src/inspectors/plugins.js +3 -2
  101. package/src/inspectors/plugins.js.map +1 -1
  102. package/src/inspectors/tmux/actions.d.ts +26 -0
  103. package/src/inspectors/tmux/actions.d.ts.map +1 -0
  104. package/src/inspectors/tmux/actions.js +182 -0
  105. package/src/inspectors/tmux/actions.js.map +1 -0
  106. package/src/inspectors/tmux/client.d.ts +28 -0
  107. package/src/inspectors/tmux/client.d.ts.map +1 -0
  108. package/src/inspectors/tmux/client.js +65 -0
  109. package/src/inspectors/tmux/client.js.map +1 -0
  110. package/src/inspectors/tmux/plugin.d.ts +8 -0
  111. package/src/inspectors/tmux/plugin.d.ts.map +1 -0
  112. package/src/inspectors/tmux/plugin.js +15 -0
  113. package/src/inspectors/tmux/plugin.js.map +1 -0
  114. package/src/integrations/program-status.d.ts +31 -0
  115. package/src/integrations/program-status.d.ts.map +1 -0
  116. package/src/integrations/program-status.js +189 -0
  117. package/src/integrations/program-status.js.map +1 -0
  118. package/src/intercom/native-supervisor-channel.d.ts +16 -1
  119. package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  120. package/src/intercom/native-supervisor-channel.js +101 -8
  121. package/src/intercom/native-supervisor-channel.js.map +1 -1
  122. package/src/intercom/result-intercom.js +1 -1
  123. package/src/intercom/result-intercom.js.map +1 -1
  124. package/src/intercom/supervisor-ui.d.ts +2 -12
  125. package/src/intercom/supervisor-ui.d.ts.map +1 -1
  126. package/src/intercom/supervisor-ui.js +2 -154
  127. package/src/intercom/supervisor-ui.js.map +1 -1
  128. package/src/missions/store.d.ts.map +1 -1
  129. package/src/missions/store.js +27 -5
  130. package/src/missions/store.js.map +1 -1
  131. package/src/runs/background/active-async-capacity.d.ts +2 -1
  132. package/src/runs/background/active-async-capacity.d.ts.map +1 -1
  133. package/src/runs/background/active-async-capacity.js +10 -6
  134. package/src/runs/background/active-async-capacity.js.map +1 -1
  135. package/src/runs/background/async-execution.d.ts +9 -1
  136. package/src/runs/background/async-execution.d.ts.map +1 -1
  137. package/src/runs/background/async-execution.js +253 -144
  138. package/src/runs/background/async-execution.js.map +1 -1
  139. package/src/runs/background/async-job-tracker.d.ts +4 -1
  140. package/src/runs/background/async-job-tracker.d.ts.map +1 -1
  141. package/src/runs/background/async-job-tracker.js +3 -2
  142. package/src/runs/background/async-job-tracker.js.map +1 -1
  143. package/src/runs/background/async-resume.d.ts.map +1 -1
  144. package/src/runs/background/async-resume.js +9 -3
  145. package/src/runs/background/async-resume.js.map +1 -1
  146. package/src/runs/background/await-async-run.d.ts +8 -4
  147. package/src/runs/background/await-async-run.d.ts.map +1 -1
  148. package/src/runs/background/await-async-run.js +14 -8
  149. package/src/runs/background/await-async-run.js.map +1 -1
  150. package/src/runs/background/binary-bootstrap.d.ts.map +1 -1
  151. package/src/runs/background/binary-bootstrap.js +2 -1
  152. package/src/runs/background/binary-bootstrap.js.map +1 -1
  153. package/src/runs/background/chain-root-attachment.d.ts +2 -0
  154. package/src/runs/background/chain-root-attachment.d.ts.map +1 -1
  155. package/src/runs/background/chain-root-attachment.js +9 -6
  156. package/src/runs/background/chain-root-attachment.js.map +1 -1
  157. package/src/runs/background/control-channel.d.ts +1 -0
  158. package/src/runs/background/control-channel.d.ts.map +1 -1
  159. package/src/runs/background/control-channel.js +27 -3
  160. package/src/runs/background/control-channel.js.map +1 -1
  161. package/src/runs/background/fleet-view.js +5 -5
  162. package/src/runs/background/fleet-view.js.map +1 -1
  163. package/src/runs/background/notify.d.ts +6 -1
  164. package/src/runs/background/notify.d.ts.map +1 -1
  165. package/src/runs/background/notify.js +130 -14
  166. package/src/runs/background/notify.js.map +1 -1
  167. package/src/runs/background/result-files.d.ts +27 -0
  168. package/src/runs/background/result-files.d.ts.map +1 -1
  169. package/src/runs/background/result-files.js +100 -6
  170. package/src/runs/background/result-files.js.map +1 -1
  171. package/src/runs/background/result-watcher.d.ts.map +1 -1
  172. package/src/runs/background/result-watcher.js +60 -64
  173. package/src/runs/background/result-watcher.js.map +1 -1
  174. package/src/runs/background/resume-guidance.js +2 -2
  175. package/src/runs/background/resume-guidance.js.map +1 -1
  176. package/src/runs/background/run-child-session.d.ts.map +1 -1
  177. package/src/runs/background/run-child-session.js +9 -15
  178. package/src/runs/background/run-child-session.js.map +1 -1
  179. package/src/runs/background/run-id-resolver.d.ts.map +1 -1
  180. package/src/runs/background/run-id-resolver.js +9 -6
  181. package/src/runs/background/run-id-resolver.js.map +1 -1
  182. package/src/runs/background/run-status.d.ts.map +1 -1
  183. package/src/runs/background/run-status.js +19 -15
  184. package/src/runs/background/run-status.js.map +1 -1
  185. package/src/runs/background/runner-aliases.d.ts.map +1 -1
  186. package/src/runs/background/runner-aliases.js +11 -8
  187. package/src/runs/background/runner-aliases.js.map +1 -1
  188. package/src/runs/background/runner-child-launch.d.ts.map +1 -1
  189. package/src/runs/background/runner-child-launch.js +1 -0
  190. package/src/runs/background/runner-child-launch.js.map +1 -1
  191. package/src/runs/background/runner-http-dispatcher.d.ts +3 -0
  192. package/src/runs/background/runner-http-dispatcher.d.ts.map +1 -1
  193. package/src/runs/background/runner-http-dispatcher.js +2 -0
  194. package/src/runs/background/runner-http-dispatcher.js.map +1 -1
  195. package/src/runs/background/scheduled-runs.d.ts +9 -0
  196. package/src/runs/background/scheduled-runs.d.ts.map +1 -1
  197. package/src/runs/background/scheduled-runs.js +124 -36
  198. package/src/runs/background/scheduled-runs.js.map +1 -1
  199. package/src/runs/background/subagent-runner-bootstrap.d.ts.map +1 -1
  200. package/src/runs/background/subagent-runner-bootstrap.js +5 -1
  201. package/src/runs/background/subagent-runner-bootstrap.js.map +1 -1
  202. package/src/runs/background/subagent-runner.d.ts +3 -1
  203. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  204. package/src/runs/background/subagent-runner.js +211 -283
  205. package/src/runs/background/subagent-runner.js.map +1 -1
  206. package/src/runs/background/subagent-wait.d.ts +2 -0
  207. package/src/runs/background/subagent-wait.d.ts.map +1 -1
  208. package/src/runs/background/subagent-wait.js +34 -20
  209. package/src/runs/background/subagent-wait.js.map +1 -1
  210. package/src/runs/background/terminal-run-index.d.ts +1 -0
  211. package/src/runs/background/terminal-run-index.d.ts.map +1 -1
  212. package/src/runs/background/terminal-run-index.js +47 -1
  213. package/src/runs/background/terminal-run-index.js.map +1 -1
  214. package/src/runs/background/wait-tool.d.ts.map +1 -1
  215. package/src/runs/background/wait-tool.js +36 -23
  216. package/src/runs/background/wait-tool.js.map +1 -1
  217. package/src/runs/background/workflow-terminal-proof.d.ts +1 -1
  218. package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -1
  219. package/src/runs/background/workflow-terminal-proof.js +12 -3
  220. package/src/runs/background/workflow-terminal-proof.js.map +1 -1
  221. package/src/runs/foreground/async-stop-action.d.ts +7 -1
  222. package/src/runs/foreground/async-stop-action.d.ts.map +1 -1
  223. package/src/runs/foreground/async-stop-action.js +27 -23
  224. package/src/runs/foreground/async-stop-action.js.map +1 -1
  225. package/src/runs/foreground/execution.d.ts.map +1 -1
  226. package/src/runs/foreground/execution.js +91 -69
  227. package/src/runs/foreground/execution.js.map +1 -1
  228. package/src/runs/foreground/subagent-executor.d.ts +4 -1
  229. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  230. package/src/runs/foreground/subagent-executor.js +174 -79
  231. package/src/runs/foreground/subagent-executor.js.map +1 -1
  232. package/src/runs/shared/child-hooks.js +6 -5
  233. package/src/runs/shared/child-hooks.js.map +1 -1
  234. package/src/runs/shared/child-launch.d.ts +2 -0
  235. package/src/runs/shared/child-launch.d.ts.map +1 -1
  236. package/src/runs/shared/child-launch.js +1 -0
  237. package/src/runs/shared/child-launch.js.map +1 -1
  238. package/src/runs/shared/child-session.d.ts +4 -0
  239. package/src/runs/shared/child-session.d.ts.map +1 -1
  240. package/src/runs/shared/child-session.js +28 -23
  241. package/src/runs/shared/child-session.js.map +1 -1
  242. package/src/runs/shared/child-tool-plan.d.ts.map +1 -1
  243. package/src/runs/shared/child-tool-plan.js +11 -10
  244. package/src/runs/shared/child-tool-plan.js.map +1 -1
  245. package/src/runs/shared/dynamic-fanout.js +1 -1
  246. package/src/runs/shared/dynamic-fanout.js.map +1 -1
  247. package/src/runs/shared/effective-system-prompt.d.ts +4 -4
  248. package/src/runs/shared/effective-system-prompt.d.ts.map +1 -1
  249. package/src/runs/shared/effective-system-prompt.js +5 -4
  250. package/src/runs/shared/effective-system-prompt.js.map +1 -1
  251. package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
  252. package/src/runs/shared/external-cli-runner.js +3 -2
  253. package/src/runs/shared/external-cli-runner.js.map +1 -1
  254. package/src/runs/shared/herdr-placed-run.d.ts +1 -0
  255. package/src/runs/shared/herdr-placed-run.d.ts.map +1 -1
  256. package/src/runs/shared/herdr-placed-run.js +10 -6
  257. package/src/runs/shared/herdr-placed-run.js.map +1 -1
  258. package/src/runs/shared/model-resolution-diagnostic.d.ts +17 -5
  259. package/src/runs/shared/model-resolution-diagnostic.d.ts.map +1 -1
  260. package/src/runs/shared/model-resolution-diagnostic.js +37 -10
  261. package/src/runs/shared/model-resolution-diagnostic.js.map +1 -1
  262. package/src/runs/shared/model-resolution.d.ts.map +1 -1
  263. package/src/runs/shared/model-resolution.js +29 -1
  264. package/src/runs/shared/model-resolution.js.map +1 -1
  265. package/src/runs/shared/nested-events.d.ts +2 -0
  266. package/src/runs/shared/nested-events.d.ts.map +1 -1
  267. package/src/runs/shared/nested-events.js +4 -0
  268. package/src/runs/shared/nested-events.js.map +1 -1
  269. package/src/runs/shared/orca-progress-tabs.js +1 -1
  270. package/src/runs/shared/orca-progress-tabs.js.map +1 -1
  271. package/src/runs/shared/parallel-handoff.js +2 -2
  272. package/src/runs/shared/parallel-handoff.js.map +1 -1
  273. package/src/runs/shared/parallel-utils.d.ts +2 -0
  274. package/src/runs/shared/parallel-utils.d.ts.map +1 -1
  275. package/src/runs/shared/parallel-utils.js.map +1 -1
  276. package/src/runs/shared/partial-output.d.ts +7 -0
  277. package/src/runs/shared/partial-output.d.ts.map +1 -1
  278. package/src/runs/shared/partial-output.js +7 -0
  279. package/src/runs/shared/partial-output.js.map +1 -1
  280. package/src/runs/shared/runner-launcher.d.ts +12 -0
  281. package/src/runs/shared/runner-launcher.d.ts.map +1 -0
  282. package/src/runs/shared/runner-launcher.js +25 -0
  283. package/src/runs/shared/runner-launcher.js.map +1 -0
  284. package/src/runs/shared/single-output.d.ts +31 -1
  285. package/src/runs/shared/single-output.d.ts.map +1 -1
  286. package/src/runs/shared/single-output.js +100 -21
  287. package/src/runs/shared/single-output.js.map +1 -1
  288. package/src/runs/shared/structured-output.d.ts +2 -0
  289. package/src/runs/shared/structured-output.d.ts.map +1 -1
  290. package/src/runs/shared/structured-output.js +26 -8
  291. package/src/runs/shared/structured-output.js.map +1 -1
  292. package/src/runs/shared/subagent-control.js +3 -3
  293. package/src/runs/shared/subagent-control.js.map +1 -1
  294. package/src/runs/shared/subagent-prompt-runtime.d.ts +37 -2
  295. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  296. package/src/runs/shared/subagent-prompt-runtime.js +127 -20
  297. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  298. package/src/runs/shared/tool-budget.js +1 -1
  299. package/src/runs/shared/tool-budget.js.map +1 -1
  300. package/src/runs/shared/workflow-async-child-guidance.js +1 -1
  301. package/src/runs/shared/workflow-async-child-guidance.js.map +1 -1
  302. package/src/runs/shared/worktree-cleanup-plan.js +1 -1
  303. package/src/runs/shared/worktree-cleanup-plan.js.map +1 -1
  304. package/src/shared/atomic-json.d.ts +4 -3
  305. package/src/shared/atomic-json.d.ts.map +1 -1
  306. package/src/shared/atomic-json.js +3 -1
  307. package/src/shared/atomic-json.js.map +1 -1
  308. package/src/shared/child-transcript.js +1 -1
  309. package/src/shared/child-transcript.js.map +1 -1
  310. package/src/shared/edit-distance.d.ts +5 -0
  311. package/src/shared/edit-distance.d.ts.map +1 -0
  312. package/src/shared/edit-distance.js +33 -0
  313. package/src/shared/edit-distance.js.map +1 -0
  314. package/src/shared/extension-context.d.ts +5 -0
  315. package/src/shared/extension-context.d.ts.map +1 -1
  316. package/src/shared/extension-context.js +7 -0
  317. package/src/shared/extension-context.js.map +1 -1
  318. package/src/shared/formatters.d.ts.map +1 -1
  319. package/src/shared/formatters.js +1 -6
  320. package/src/shared/formatters.js.map +1 -1
  321. package/src/shared/model-info.d.ts +8 -0
  322. package/src/shared/model-info.d.ts.map +1 -1
  323. package/src/shared/model-info.js +22 -0
  324. package/src/shared/model-info.js.map +1 -1
  325. package/src/shared/parent-wake.d.ts +7 -1
  326. package/src/shared/parent-wake.d.ts.map +1 -1
  327. package/src/shared/parent-wake.js +36 -12
  328. package/src/shared/parent-wake.js.map +1 -1
  329. package/src/shared/pruned-fork.d.ts +1 -1
  330. package/src/shared/pruned-fork.d.ts.map +1 -1
  331. package/src/shared/pruned-fork.js +6 -0
  332. package/src/shared/pruned-fork.js.map +1 -1
  333. package/src/shared/runtime-module-path.d.ts +11 -0
  334. package/src/shared/runtime-module-path.d.ts.map +1 -0
  335. package/src/shared/runtime-module-path.js +17 -0
  336. package/src/shared/runtime-module-path.js.map +1 -0
  337. package/src/shared/types.d.ts +33 -10
  338. package/src/shared/types.d.ts.map +1 -1
  339. package/src/shared/types.js +7 -4
  340. package/src/shared/types.js.map +1 -1
  341. package/src/shared/utils.d.ts +2 -0
  342. package/src/shared/utils.d.ts.map +1 -1
  343. package/src/shared/utils.js +10 -7
  344. package/src/shared/utils.js.map +1 -1
  345. package/src/slash/slash-commands.d.ts.map +1 -1
  346. package/src/slash/slash-commands.js +21 -10
  347. package/src/slash/slash-commands.js.map +1 -1
  348. package/src/slash/subagents-admin.d.ts.map +1 -1
  349. package/src/slash/subagents-admin.js +3 -1
  350. package/src/slash/subagents-admin.js.map +1 -1
  351. package/src/tui/fleet-status.d.ts +5 -0
  352. package/src/tui/fleet-status.d.ts.map +1 -1
  353. package/src/tui/fleet-status.js +24 -3
  354. package/src/tui/fleet-status.js.map +1 -1
  355. package/src/tui/fleet-transcript.d.ts +2 -0
  356. package/src/tui/fleet-transcript.d.ts.map +1 -1
  357. package/src/tui/fleet-transcript.js +7 -2
  358. package/src/tui/fleet-transcript.js.map +1 -1
  359. package/src/tui/fleet.d.ts.map +1 -1
  360. package/src/tui/fleet.js +11 -6
  361. package/src/tui/fleet.js.map +1 -1
  362. package/src/tui/render.d.ts +2 -2
  363. package/src/tui/render.d.ts.map +1 -1
  364. package/src/tui/render.js +19 -17
  365. package/src/tui/render.js.map +1 -1
  366. package/src/tui/subagent-messages.d.ts +23 -0
  367. package/src/tui/subagent-messages.d.ts.map +1 -0
  368. package/src/tui/subagent-messages.js +270 -0
  369. package/src/tui/subagent-messages.js.map +1 -0
  370. package/src/watchdog/change-signature.d.ts.map +1 -1
  371. package/src/watchdog/change-signature.js +1 -3
  372. package/src/watchdog/change-signature.js.map +1 -1
  373. package/src/watchdog/register-main.d.ts.map +1 -1
  374. package/src/watchdog/register-main.js +1 -19
  375. package/src/watchdog/register-main.js.map +1 -1
  376. package/src/watchdog/render.d.ts +2 -10
  377. package/src/watchdog/render.d.ts.map +1 -1
  378. package/src/watchdog/render.js +1 -19
  379. package/src/watchdog/render.js.map +1 -1
  380. package/src/watchdog/tool-actions.js +2 -2
  381. package/src/watchdog/tool-actions.js.map +1 -1
  382. package/src/workflows/scripted-workflow.d.ts.map +1 -1
  383. package/src/workflows/scripted-workflow.js +33 -10
  384. package/src/workflows/scripted-workflow.js.map +1 -1
  385. package/src/workflows/workflow-resources.d.ts.map +1 -1
  386. package/src/workflows/workflow-resources.js +12 -0
  387. package/src/workflows/workflow-resources.js.map +1 -1
  388. package/src/runs/shared/run-history.d.ts +0 -67
  389. package/src/runs/shared/run-history.d.ts.map +0 -1
  390. package/src/runs/shared/run-history.js +0 -270
  391. package/src/runs/shared/run-history.js.map +0 -1
@@ -13,7 +13,7 @@ import { performance } from "node:perf_hooks";
13
13
  import { pathToFileURL } from "node:url";
14
14
  import { installRunnerHttpDispatcher } from "./runner-http-dispatcher.js";
15
15
  import { writeAtomicJson } from "../../shared/atomic-json.js";
16
- import { writeAsyncResultFile, writePendingAsyncResultFile } from "./result-files.js";
16
+ import { withResultRunLease, writeAsyncResultFile, writePendingAsyncResultFile } from "./result-files.js";
17
17
  import { createFileCoalescer } from "../../shared/file-coalescer.js";
18
18
  import { createCapacityResilientJsonWriter } from "../../shared/capacity-resilient-json.js";
19
19
  import { isStorageCapacityError } from "../../shared/file-system-retry.js";
@@ -23,7 +23,8 @@ import { closeSteerInbox, closeStopInbox, consumeInterruptRequest, consumeSteerR
23
23
  import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths, writeArtifact, writeMetadata } from "../../shared/artifacts.js";
24
24
  import { PI_CODING_AGENT_PACKAGE, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.js";
25
25
  import { preflightLaunchCwd } from "../shared/launch-cwd.js";
26
- import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, injectSingleOutputInstruction, resolveSingleOutput } from "../shared/single-output.js";
26
+ import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectSingleOutputInstruction, isSettlementFatalOutputError, resolveSingleOutput } from "../shared/single-output.js";
27
+ import { timedOutRunSummary } from "../shared/partial-output.js";
27
28
  import { runSetupCommand } from "../shared/worktree-setup-command.js";
28
29
  import { DEFAULT_MAX_OUTPUT, SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, truncateOutput, } from "../../shared/types.js";
29
30
  import { DEFAULT_CONTROL_CONFIG, buildControlEvent, deriveActivityState, claimControlNotification, formatControlIntercomMessage, formatControlNoticeMessage, shouldEmitOpenToolAttention, } from "../shared/subagent-control.js";
@@ -49,13 +50,12 @@ import { processTerminalPath, writeProcessTerminalCandidate } from "./process-te
49
50
  import { persistRunnerStartupFailure } from "./runner-startup-failure.js";
50
51
  import { currentPidNamespaceScope } from "./pid-namespace.js";
51
52
  import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, unconsumedSteerReason, updateSteeringTarget } from "./steering.js";
52
- import { PROMPT_REDACTED, detectSubagentError, extractTextFromContent, extractToolArgsPreview, formatEmptyTerminalAssistantResponseError, getAgentDir, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.js";
53
- import { planBackgroundRunHistory, recordRun } from "../shared/run-history.js";
53
+ import { PROMPT_REDACTED, SUBAGENT_STOPPED_MESSAGE, SUBAGENT_TIMED_OUT_MESSAGE, detectSubagentError, extractTextFromContent, extractToolArgsPreview, formatEmptyTerminalAssistantResponseError, getAgentDir, hasEmptyTerminalAssistantResponse, readStatus } from "../../shared/utils.js";
54
54
  import { planAbortRecovery } from "../shared/abort-recovery.js";
55
55
  import { createMutatingFailureState, didMutatingToolFail, isMutatingTool, nextLongRunningTrigger, recordMutatingFailure, resetMutatingFailureState, resolveCurrentPath, shouldEscalateMutatingFailures, summarizeRecentMutatingFailures, } from "../shared/long-running-guard.js";
56
56
  import { parseSessionTokens } from "../../shared/session-tokens.js";
57
57
  import { cleanupWorktrees, createWorktrees, withWorktreeTransaction, WorktreeSetupError, diffWorktrees, findWorktreeTaskCwdConflict, formatWorktreeDiffSummary, formatWorktreeTaskCwdConflict, WORKTREE_AGENT_CWD_PLACEHOLDER, } from "../shared/worktree.js";
58
- import { findModelInfo, resolveEffectiveThinking } from "../../shared/model-info.js";
58
+ import { findModelInfo, qualifyModelWithProvider, resolveEffectiveThinking } from "../../shared/model-info.js";
59
59
  import { assertThinkingWithinCeiling } from "../../shared/thinking-ceiling.js";
60
60
  import { resolveLaunchBinding } from "../../shared/launch-contract.js";
61
61
  import { writeInitialProgressFile } from "../../shared/settings.js";
@@ -65,7 +65,7 @@ import { attachContractProjections, isAgentContract } from "../shared/agent-cont
65
65
  import { waitForImportedAsyncRoot } from "./chain-root-attachment.js";
66
66
  import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests, statusStepDescription } from "./chain-append.js";
67
67
  import { asyncStatusChildIdentity } from "../shared/child-identity.js";
68
- import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.js";
68
+ import { initialToolBudgetState, isToolBudgetBlockedMessage, toolBudgetState } from "../shared/tool-budget.js";
69
69
  import { toolTimeoutCallKey } from "../shared/tool-timeout.js";
70
70
  import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.js";
71
71
  import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup, writeWorktreeSetupHandoff } from "../shared/parallel-handoff.js";
@@ -467,7 +467,7 @@ export async function runSingleStepInner(step, ctx) {
467
467
  }
468
468
  const stopped = importStopped || imported.stopped === true || ctx.stopSignal?.aborted === true;
469
469
  const timedOut = !stopped && (importTimedOut || imported.timedOut === true || ctx.timeoutSignal?.aborted === true || ctx.skipAcceptance?.() === true);
470
- const message = stopped ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.";
470
+ const message = stopped ? ctx.stopMessage ?? SUBAGENT_STOPPED_MESSAGE : ctx.timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE;
471
471
  return omitUndefinedProperties({
472
472
  agent: imported.agent,
473
473
  output: timedOut || stopped ? message : imported.output,
@@ -554,6 +554,47 @@ export async function runSingleStepInner(step, ctx) {
554
554
  }
555
555
  }
556
556
  transcriptWriter?.writeInitialUserMessage(`${PROMPT_REDACTED}; live Prompt Audit only.`);
557
+ // External CLI and external job runs settle their output the same way; only their runner metadata differs.
558
+ const settleExternalOutput = (external, outputSnapshot, runnerMetadata) => {
559
+ try {
560
+ fs.writeFileSync(ctx.outputFile, external.output, "utf-8");
561
+ }
562
+ catch { /* Observability output is best-effort. */ }
563
+ const resolvedOutput = step.outputPath && external.exitCode === 0
564
+ ? resolveSingleOutput(step.outputPath, external.output, outputSnapshot, step.outputClaimPath)
565
+ : { fullOutput: external.output };
566
+ const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
567
+ const settlementFatalOutputError = isSettlementFatalOutputError(resolvedOutput, step.outputMode);
568
+ const exitCode = settlementFatalOutputError ? 1 : external.exitCode;
569
+ const error = settlementFatalOutputError && resolvedOutput.saveError
570
+ ? external.error ? `${external.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError
571
+ : external.error;
572
+ const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
573
+ fullOutput: resolvedOutput.fullOutput,
574
+ outputPath: step.outputPath,
575
+ outputMode: step.outputMode,
576
+ exitCode: exitCode ?? 1,
577
+ savedPath: resolvedOutput.savedPath,
578
+ outputReference,
579
+ saveError: resolvedOutput.saveError,
580
+ }));
581
+ const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
582
+ ? persistStepArtifacts({
583
+ artifactPaths,
584
+ artifactConfig: ctx.artifactConfig,
585
+ output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, error: error, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })),
586
+ metadata: { runId: ctx.id, parentSessionId: step.parentSessionId, agent: step.agent, task: PROMPT_REDACTED, ...runnerMetadata, exitCode: exitCode, error: error, timestamp: Date.now() },
587
+ })
588
+ : {};
589
+ return {
590
+ output: finalizedOutput.displayOutput,
591
+ exitCode,
592
+ error,
593
+ outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined,
594
+ artifactOutputSaveFailed: artifactErrors.outputSaveError ? true : undefined,
595
+ metadataSaveError: artifactErrors.metadataSaveError,
596
+ };
597
+ };
557
598
  if (step.runner?.type === "external-cli") {
558
599
  const externalCwd = step.machine?.cwd ?? step.cwd ?? ctx.cwd;
559
600
  const externalAbortSignal = combinedAbortSignal([ctx.timeoutSignal, ctx.stopSignal]);
@@ -561,7 +602,7 @@ export async function runSingleStepInner(step, ctx) {
561
602
  await ctx.prepareExternalActivity?.(externalCwd, externalAbortSignal);
562
603
  if (externalAbortSignal?.aborted) {
563
604
  const stopped = ctx.stopSignal?.aborted === true;
564
- const message = stopped ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.";
605
+ const message = stopped ? ctx.stopMessage ?? SUBAGENT_STOPPED_MESSAGE : ctx.timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE;
565
606
  return omitUndefinedProperties({ agent: step.agent, context: step.context, output: message, error: message, exitCode: 1, stopped: stopped || undefined, timedOut: stopped ? undefined : true });
566
607
  }
567
608
  if (step.machine) {
@@ -584,7 +625,7 @@ export async function runSingleStepInner(step, ctx) {
584
625
  else if (raced.kind === "timeout")
585
626
  settled = createHerdrExternalAdapter(step.runner.adapter).normalize(evidenceInput, "Placed external run timed out; truthful pane retained for inspection.");
586
627
  else
587
- return { agent: step.agent, context: step.context, output: "Placed external run stopped by user.", outputState: "present", exitCode: 1, stopped: true, runner, execution: { status: "stopped", success: false, exitCode: 1, stopped: true } };
628
+ return { agent: step.agent, context: step.context, output: "Placed external run stopped.", outputState: "present", exitCode: 1, stopped: true, runner, execution: { status: "stopped", success: false, exitCode: 1, stopped: true } };
588
629
  }
589
630
  catch (error) {
590
631
  retain = true;
@@ -598,8 +639,8 @@ export async function runSingleStepInner(step, ctx) {
598
639
  const resolvedOutput = step.outputPath ? resolveSingleOutput(step.outputPath, output, outputSnapshot, step.outputClaimPath) : { fullOutput: output };
599
640
  const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
600
641
  const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({ fullOutput: resolvedOutput.fullOutput, outputPath: step.outputPath, outputMode: step.outputMode, exitCode: 1, preserveSavedOutput: true, savedPath: resolvedOutput.savedPath, outputReference, saveError: resolvedOutput.saveError }));
601
- const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false ? persistStepArtifacts({ artifactPaths, artifactConfig: ctx.artifactConfig, output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })), metadata: { runId: ctx.id, agent: step.agent, task: PROMPT_REDACTED, runner, placement: session.owner.identity, settlement: settled.settlement, outcome: settled.outcome, timestamp: Date.now() } }) : {};
602
- return omitUndefinedProperties({ agent: step.agent, ...(childSessionName ? { sessionName: childSessionName } : {}), context: step.context, output: finalizedOutput.displayOutput, outputState: output.trim() ? "present" : "absent", exitCode: 1, error: resolvedOutput.fatalError ? resolvedOutput.saveError : undefined, timedOut, stopped, artifactPaths, outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined, metadataSaveError: artifactErrors.metadataSaveError, runner, execution: { status: "partial", success: false, exitCode: 1 } });
642
+ const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false ? persistStepArtifacts({ artifactPaths, artifactConfig: ctx.artifactConfig, output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })), metadata: { runId: ctx.id, parentSessionId: step.parentSessionId, agent: step.agent, task: PROMPT_REDACTED, runner, placement: session.owner.identity, settlement: settled.settlement, outcome: settled.outcome, timestamp: Date.now() } }) : {};
643
+ return omitUndefinedProperties({ agent: step.agent, ...(childSessionName ? { sessionName: childSessionName } : {}), context: step.context, output: finalizedOutput.displayOutput, outputState: output.trim() ? "present" : "absent", exitCode: 1, error: isSettlementFatalOutputError(resolvedOutput, step.outputMode) ? resolvedOutput.saveError : undefined, timedOut, stopped, artifactPaths, outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined, metadataSaveError: artifactErrors.metadataSaveError, runner, execution: { status: "partial", success: false, exitCode: 1 } });
603
644
  }
604
645
  catch (error) {
605
646
  // Any post-allocation uncertainty retains the pane; only explicit stop
@@ -655,50 +696,22 @@ export async function runSingleStepInner(step, ctx) {
655
696
  const ran = await runExternalCli(preparedExternal.input);
656
697
  const externalProcess = preparedExternal.decorateProcess(ran.externalProcess);
657
698
  const external = step.machine ? decorateHerdrMachineResult(ran, step.machine, step.runner.adapter) : ran;
658
- try {
659
- fs.writeFileSync(ctx.outputFile, external.output, "utf-8");
660
- }
661
- catch { /* Observability output is best-effort. */ }
662
- const resolvedOutput = step.outputPath && external.exitCode === 0
663
- ? resolveSingleOutput(step.outputPath, external.output, outputSnapshot, step.outputClaimPath)
664
- : { fullOutput: external.output };
665
- const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
666
- const exitCode = resolvedOutput.fatalError ? 1 : external.exitCode;
667
- const error = resolvedOutput.fatalError && resolvedOutput.saveError
668
- ? external.error ? `${external.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError
669
- : external.error;
670
- const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
671
- fullOutput: resolvedOutput.fullOutput,
672
- outputPath: step.outputPath,
673
- outputMode: step.outputMode,
674
- exitCode: exitCode ?? 1,
675
- savedPath: resolvedOutput.savedPath,
676
- outputReference,
677
- saveError: resolvedOutput.saveError,
678
- }));
679
- const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
680
- ? persistStepArtifacts({
681
- artifactPaths,
682
- artifactConfig: ctx.artifactConfig,
683
- output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, error: external.error, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })),
684
- metadata: { runId: ctx.id, agent: step.agent, task: PROMPT_REDACTED, runner, externalProcess: externalProcess, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
685
- })
686
- : {};
699
+ const settled = settleExternalOutput(external, outputSnapshot, { runner, externalProcess });
687
700
  return omitUndefinedProperties({
688
701
  agent: step.agent,
689
702
  ...(childSessionName ? { sessionName: childSessionName } : {}),
690
703
  context: step.context,
691
- output: finalizedOutput.displayOutput,
704
+ output: settled.output,
692
705
  outputState: external.output.trim() ? "present" : "absent",
693
- exitCode,
694
- error,
706
+ exitCode: settled.exitCode,
707
+ error: settled.error,
695
708
  timedOut: external.timedOut,
696
709
  stopped: external.stopped,
697
710
  processSignal: external.processSignal,
698
711
  artifactPaths,
699
- outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined,
700
- artifactOutputSaveFailed: artifactErrors.outputSaveError ? true : undefined,
701
- metadataSaveError: artifactErrors.metadataSaveError,
712
+ outputSaveError: settled.outputSaveError,
713
+ artifactOutputSaveFailed: settled.artifactOutputSaveFailed,
714
+ metadataSaveError: settled.metadataSaveError,
702
715
  runner,
703
716
  externalProcess: externalProcess,
704
717
  });
@@ -728,49 +741,21 @@ export async function runSingleStepInner(step, ctx) {
728
741
  onExternalJob: ctx.onExternalJob,
729
742
  followUp: step.externalJobFollowUp,
730
743
  }));
731
- try {
732
- fs.writeFileSync(ctx.outputFile, external.output, "utf-8");
733
- }
734
- catch { /* Observability output is best-effort. */ }
735
- const resolvedOutput = step.outputPath && external.exitCode === 0
736
- ? resolveSingleOutput(step.outputPath, external.output, outputSnapshot, step.outputClaimPath)
737
- : { fullOutput: external.output };
738
- const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
739
- const exitCode = resolvedOutput.fatalError ? 1 : external.exitCode;
740
- const error = resolvedOutput.fatalError && resolvedOutput.saveError
741
- ? external.error ? `${external.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError
742
- : external.error;
743
- const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
744
- fullOutput: resolvedOutput.fullOutput,
745
- outputPath: step.outputPath,
746
- outputMode: step.outputMode,
747
- exitCode: exitCode ?? 1,
748
- savedPath: resolvedOutput.savedPath,
749
- outputReference,
750
- saveError: resolvedOutput.saveError,
751
- }));
752
- const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
753
- ? persistStepArtifacts({
754
- artifactPaths,
755
- artifactConfig: ctx.artifactConfig,
756
- output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, error: external.error, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })),
757
- metadata: { runId: ctx.id, agent: step.agent, task: PROMPT_REDACTED, runner, externalJob: external.externalJob, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
758
- })
759
- : {};
744
+ const settled = settleExternalOutput(external, outputSnapshot, { runner, externalJob: external.externalJob });
760
745
  return omitUndefinedProperties({
761
746
  agent: step.agent,
762
747
  ...(childSessionName ? { sessionName: childSessionName } : {}),
763
748
  context: step.context,
764
- output: finalizedOutput.displayOutput,
749
+ output: settled.output,
765
750
  outputState: external.output.trim() ? "present" : "absent",
766
- exitCode,
767
- error,
751
+ exitCode: settled.exitCode,
752
+ error: settled.error,
768
753
  timedOut: external.timedOut,
769
754
  stopped: external.stopped,
770
755
  artifactPaths,
771
- outputSaveError: [resolvedOutput.saveError, artifactErrors.outputSaveError].filter(Boolean).join("\n") || undefined,
772
- artifactOutputSaveFailed: artifactErrors.outputSaveError ? true : undefined,
773
- metadataSaveError: artifactErrors.metadataSaveError,
756
+ outputSaveError: settled.outputSaveError,
757
+ artifactOutputSaveFailed: settled.artifactOutputSaveFailed,
758
+ metadataSaveError: settled.metadataSaveError,
774
759
  runner,
775
760
  externalJob: external.externalJob,
776
761
  });
@@ -1020,7 +1005,11 @@ export async function runSingleStepInner(step, ctx) {
1020
1005
  const mutationEvidence = run.nativeMachine ? { source: "tracked-files", trackedOnly: true, changedFiles: [], attemptedMutation: remoteGitChanged === true, ...(remoteGitChanged === undefined ? { unavailable: "Remote Git before/after evidence was incomplete." } : {}) } : collectTrackedMutationEvidence(mutationSnapshot, step.cwd ?? ctx.cwd);
1021
1006
  finalMutationEvidence = mutationEvidence;
1022
1007
  const mutationAttemptObserved = run.observedMutationAttempt === true || mutationEvidence.attemptedMutation === true;
1023
- const finalOutputHasPersistableFileContent = run.exitCode === 0 && !run.error && !emptyOutputError && Boolean(stripAcceptanceReport(run.finalOutput).trim());
1008
+ // Validated structured output is persistable file content even when the final text is only
1009
+ // an acceptance-report fence; otherwise the required-output precheck forces exitCode 1 before
1010
+ // resolveSingleOutput can publish the canonical JSON into the bound file-only path.
1011
+ const finalOutputHasPersistableFileContent = run.exitCode === 0 && !run.error && !emptyOutputError
1012
+ && (Boolean(stripAcceptanceReport(run.finalOutput).trim()) || validatedStructuredOutput);
1024
1013
  const requiredOutput = step.outputMode === "file-only" && step.outputPath
1025
1014
  ? { kind: "file-only", path: step.outputPath, missing: !fs.existsSync(step.outputPath) && !finalOutputHasPersistableFileContent }
1026
1015
  : effectiveStructuredOutput
@@ -1104,7 +1093,7 @@ export async function runSingleStepInner(step, ctx) {
1104
1093
  const resolvedOutput = step.outputPath && finalResult?.exitCode === 0
1105
1094
  ? resolveSingleOutput(step.outputPath, structuredText ?? replyOutput, finalOutputSnapshot, step.outputClaimPath)
1106
1095
  : { fullOutput: replyOutput };
1107
- if (resolvedOutput.fatalError) {
1096
+ if (isSettlementFatalOutputError(resolvedOutput, step.outputMode)) {
1108
1097
  if (finalResult) {
1109
1098
  finalResult.exitCode = 1;
1110
1099
  finalResult.error = finalResult.error ? `${finalResult.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError;
@@ -1114,7 +1103,7 @@ export async function runSingleStepInner(step, ctx) {
1114
1103
  const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, output) : undefined;
1115
1104
  let outputForSummary = output;
1116
1105
  if (finalResult?.stopped && !outputForSummary.trim()) {
1117
- outputForSummary = ctx.stopMessage ?? "Subagent stopped by user.";
1106
+ outputForSummary = ctx.stopMessage ?? SUBAGENT_STOPPED_MESSAGE;
1118
1107
  }
1119
1108
  // Unfinished streamed text never stands in for the child's completed reply.
1120
1109
  const outputForAcceptance = finalResult?.outputPartial ? "" : rawOutput;
@@ -1167,7 +1156,7 @@ export async function runSingleStepInner(step, ctx) {
1167
1156
  cwd: step.cwd ?? ctx.cwd,
1168
1157
  stagedIndexBaseline,
1169
1158
  signal: combinedAbortSignal([ctx.timeoutSignal, ctx.stopSignal]),
1170
- abortMessage: ctx.stopSignal?.aborted ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.",
1159
+ abortMessage: ctx.stopSignal?.aborted ? ctx.stopMessage ?? SUBAGENT_STOPPED_MESSAGE : ctx.timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE,
1171
1160
  reportOptional: isAgentContract(step.agentContract),
1172
1161
  artifactsDir: ctx.artifactsDir,
1173
1162
  runId: ctx.id,
@@ -1194,9 +1183,9 @@ export async function runSingleStepInner(step, ctx) {
1194
1183
  }
1195
1184
  const intercomDetachReceipt = finalResult?.finalOutput === INTERCOM_DETACH_RECEIPT;
1196
1185
  const baseFinalError = stoppedAfterAcceptance
1197
- ? ctx.stopMessage ?? "Subagent stopped by user."
1186
+ ? ctx.stopMessage ?? SUBAGENT_STOPPED_MESSAGE
1198
1187
  : timedOutAfterAcceptance
1199
- ? finalResult?.error ?? ctx.timeoutMessage ?? "Subagent timed out."
1188
+ ? finalResult?.error ?? ctx.timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE
1200
1189
  : acceptanceCanFailRun
1201
1190
  ? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
1202
1191
  : finalResult?.error ?? (intercomDetachReceipt ? INTERCOM_DETACH_RECEIPT : undefined);
@@ -1219,6 +1208,7 @@ export async function runSingleStepInner(step, ctx) {
1219
1208
  })),
1220
1209
  metadata: {
1221
1210
  runId: ctx.id,
1211
+ parentSessionId: step.parentSessionId,
1222
1212
  agent: step.agent,
1223
1213
  task: PROMPT_REDACTED,
1224
1214
  exitCode: effectiveFinalExitCode,
@@ -1342,8 +1332,8 @@ function markParallelGroupSetupFailure(input) {
1342
1332
  const paused = !stopped && input.statusPayload.state === "paused";
1343
1333
  const timedOut = !stopped && !paused && input.statusPayload.timedOut === true;
1344
1334
  statusStep.status = stopped ? "stopped" : paused ? "paused" : "failed";
1345
- // Mirror the run-level timeout onto the step so consumers (status readers,
1346
- // run-history recording) see timed_out rather than a bare failure — the
1335
+ // Mirror the run-level timeout onto the step so status readers see
1336
+ // timed_out rather than a bare failure — the
1347
1337
  // StepResult below already carries it, the status step must too.
1348
1338
  if (timedOut)
1349
1339
  statusStep.timedOut = true;
@@ -1517,11 +1507,6 @@ export async function runSubagent(config, childSessions) {
1517
1507
  let previousOutput = "";
1518
1508
  const outputs = {};
1519
1509
  const results = [];
1520
- // Flat indices of steps a child session was actually dispatched for — the
1521
- // ground truth for run-history: stopRunner/timeoutRunner/fail-fast/budget
1522
- // skips relabel never-launched steps to terminal statuses, so status alone
1523
- // cannot distinguish them from steps that really ran.
1524
- const launchedFlatIndices = new Set();
1525
1510
  const overallStartTime = Date.now();
1526
1511
  const shareEnabled = config.share === true;
1527
1512
  const asyncDir = config.asyncDir;
@@ -1548,7 +1533,7 @@ export async function runSubagent(config, childSessions) {
1548
1533
  let stopped = false;
1549
1534
  let usageBudgetExceeded = false;
1550
1535
  const timeoutMessage = config.timeoutMs !== undefined ? `Subagent timed out after ${config.timeoutMs}ms.` : undefined;
1551
- const stopMessage = "Subagent stopped by user.";
1536
+ const stopMessage = SUBAGENT_STOPPED_MESSAGE;
1552
1537
  const timeoutAbortController = new AbortController();
1553
1538
  const stopAbortController = new AbortController();
1554
1539
  const setupInterruptController = new AbortController();
@@ -1679,6 +1664,7 @@ export async function runSubagent(config, childSessions) {
1679
1664
  const statusPayload = omitUndefinedProperties({
1680
1665
  lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
1681
1666
  runId: id,
1667
+ ...(config.toolCallId ? { toolCallId: config.toolCallId } : {}),
1682
1668
  ...(config.sessionId ? { sessionId: config.sessionId } : {}),
1683
1669
  ...(config.completionOwnerId ? { completionOwnerId: config.completionOwnerId } : {}),
1684
1670
  mode: config.resultMode ?? (flatSteps.length > 1 ? "chain" : "single"),
@@ -1707,6 +1693,7 @@ export async function runSubagent(config, childSessions) {
1707
1693
  ...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
1708
1694
  ...(config.lane ? { lane: config.lane } : {}),
1709
1695
  ...(config.runnerProcessInstanceId ? { processTerminal: { version: 1, state: "pending", runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
1696
+ ...(config.launcher ? { launcher: config.launcher } : {}),
1710
1697
  steps: initialStatusSteps,
1711
1698
  artifactsDir,
1712
1699
  sessionDir: config.sessionDir,
@@ -1731,6 +1718,9 @@ export async function runSubagent(config, childSessions) {
1731
1718
  };
1732
1719
  let finalResultCommitted = false;
1733
1720
  let finalResultPublication;
1721
+ // The paused and final results replace each other under one run id; the lease keeps a consumer
1722
+ // of the older one from retiring the newer one. A lease timeout fails the publication.
1723
+ const publishRunResult = (filePath, write) => withResultRunLease(path.dirname(filePath), id, write);
1734
1724
  const runPersistence = createCapacityResilientJsonWriter({
1735
1725
  keepAlive: true,
1736
1726
  onSuccess: (filePath, payload) => {
@@ -1917,7 +1907,7 @@ export async function runSubagent(config, childSessions) {
1917
1907
  sessionId: config.sessionId,
1918
1908
  completionOwnerId: config.completionOwnerId,
1919
1909
  sessionFile: statusPayload.sessionFile ?? latestSessionFile,
1920
- }), (filePath, payload) => writePendingAsyncResultFile(filePath, payload));
1910
+ }), (filePath, payload) => publishRunResult(filePath, () => writePendingAsyncResultFile(filePath, payload)));
1921
1911
  };
1922
1912
  const writeStatusPayloadNow = () => {
1923
1913
  if (finalResultPublication)
@@ -2205,8 +2195,8 @@ export async function runSubagent(config, childSessions) {
2205
2195
  agent,
2206
2196
  sessionName,
2207
2197
  context,
2208
- output: timeoutMessage ?? "Subagent timed out.",
2209
- error: timeoutMessage ?? "Subagent timed out.",
2198
+ output: timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE,
2199
+ error: timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE,
2210
2200
  exitCode: 1,
2211
2201
  timedOut: true,
2212
2202
  });
@@ -2245,6 +2235,7 @@ export async function runSubagent(config, childSessions) {
2245
2235
  });
2246
2236
  mutatingFailureStates.push(...Array.from({ length: added.addedFlatSteps }, () => createMutatingFailureState()));
2247
2237
  pendingToolResults.push(...Array.from({ length: added.addedFlatSteps }, () => undefined));
2238
+ pendingToolResultsByCallId.push(...Array.from({ length: added.addedFlatSteps }, () => new Map()));
2248
2239
  if (config.childIntercomTargets) {
2249
2240
  config.childIntercomTargets = statusPayload.steps.map((statusStep, index) => resolveSubagentIntercomTarget(id, statusStep.agent, index));
2250
2241
  }
@@ -2341,6 +2332,9 @@ export async function runSubagent(config, childSessions) {
2341
2332
  const activeLongRunningSteps = new Set();
2342
2333
  const mutatingFailureStates = initialStatusSteps.map(() => createMutatingFailureState());
2343
2334
  const pendingToolResults = initialStatusSteps.map(() => undefined);
2335
+ // Pi's parallel tool execution emits every tool_execution_start before the first result message, so each
2336
+ // step matches results to calls by toolCallId; pendingToolResults keeps the last-started call for events without one.
2337
+ const pendingToolResultsByCallId = initialStatusSteps.map(() => new Map());
2344
2338
  const activeToolCalls = initialStatusSteps.map(() => new Map());
2345
2339
  const activeToolKeysByName = initialStatusSteps.map(() => new Map());
2346
2340
  const activeToolSequences = initialStatusSteps.map(() => 0);
@@ -2692,11 +2686,72 @@ export async function runSubagent(config, childSessions) {
2692
2686
  if (!step)
2693
2687
  return;
2694
2688
  setOptionalProperty(step, "model", model);
2689
+ setOptionalProperty(step, "launchModel", undefined);
2695
2690
  setOptionalProperty(step, "thinking", thinking);
2696
2691
  setOptionalProperty(step, "contextLimit", contextLimit);
2697
2692
  statusPayload.lastUpdate = now;
2698
2693
  writeStatusPayload();
2699
2694
  };
2695
+ // Records a finished child's result on its status step; the sequential and both parallel paths share it.
2696
+ const recordStepResult = (fi, singleResult, startedAt, endedAt, recordLaunchContractDigest = false) => {
2697
+ const step = requiredStatusStep(statusPayload, fi);
2698
+ const childStopped = singleResult.stopped === true;
2699
+ const childInterrupted = singleResult.interrupted === true;
2700
+ step.status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.execution?.status === "partial" ? "partial" : singleResult.exitCode === 0 ? "complete" : "failed";
2701
+ step.endedAt = endedAt;
2702
+ step.durationMs = endedAt - startedAt;
2703
+ step.exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
2704
+ setOptionalProperty(step, "timedOut", timedOut || singleResult.timedOut ? true : undefined);
2705
+ setOptionalProperty(step, "stopped", stopped || childStopped ? true : undefined);
2706
+ setOptionalProperty(step, "toolBudget", singleResult.toolBudget);
2707
+ setOptionalProperty(step, "toolBudgetBlocked", singleResult.toolBudgetBlocked);
2708
+ if (singleResult.toolBudget)
2709
+ statusPayload.toolBudget = singleResult.toolBudget;
2710
+ if (singleResult.toolBudgetBlocked)
2711
+ statusPayload.toolBudgetBlocked = true;
2712
+ setOptionalProperty(step, "sessionName", singleResult.sessionName);
2713
+ // Keep the model the child was observed running on; a host extension can switch it
2714
+ // after launch, and singleResult.model only names the launch candidate.
2715
+ setOptionalProperty(step, "model", step.model ?? singleResult.model);
2716
+ setOptionalProperty(step, "thinking", resolveEffectiveThinking(singleResult.model, step.thinking));
2717
+ setOptionalProperty(step, "requestedModel", singleResult.requestedModel);
2718
+ setOptionalProperty(step, "contextOverflow", singleResult.contextOverflow);
2719
+ setOptionalProperty(step, "totalCost", singleResult.totalCost);
2720
+ setOptionalProperty(step, "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE) : singleResult.error);
2721
+ setOptionalProperty(step, "transcriptPath", singleResult.transcriptPath ?? step.transcriptPath);
2722
+ setOptionalProperty(step, "transcriptError", singleResult.transcriptError);
2723
+ setOptionalProperty(step, "agentContract", singleResult.agentContract);
2724
+ if (recordLaunchContractDigest)
2725
+ setOptionalProperty(step, "launchContractDigest", singleResult.launchContractDigest);
2726
+ setOptionalProperty(step, "launchResolvedExtensions", singleResult.launchResolvedExtensions);
2727
+ setOptionalProperty(step, "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
2728
+ setOptionalProperty(step, "effects", singleResult.effects);
2729
+ setOptionalProperty(step, "execution", singleResult.execution);
2730
+ setOptionalProperty(step, "review", singleResult.review);
2731
+ setOptionalProperty(step, "structuredOutput", singleResult.structuredOutput);
2732
+ setOptionalProperty(step, "structuredOutputPath", singleResult.structuredOutputPath);
2733
+ setOptionalProperty(step, "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
2734
+ setOptionalProperty(step, "acceptance", singleResult.acceptance);
2735
+ setOptionalProperty(step, "timeoutRecovery", singleResult.timeoutRecovery);
2736
+ setOptionalProperty(step, "watchdog", singleResult.watchdog);
2737
+ setOptionalProperty(step, "capabilityCeiling", singleResult.capabilityCeiling);
2738
+ setOptionalProperty(step, "capabilityAudit", singleResult.capabilityAudit);
2739
+ if (singleResult.capabilityCeiling)
2740
+ statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
2741
+ if (singleResult.capabilityAudit)
2742
+ statusPayload.capabilityAudit = singleResult.capabilityAudit;
2743
+ };
2744
+ // Adds a parallel child's cost to the in-flight usage ledger.
2745
+ const addParallelUsageCost = (totalCost) => {
2746
+ if (!totalCost)
2747
+ return;
2748
+ pendingParallelUsageCost = {
2749
+ inputTokens: pendingParallelUsageCost.inputTokens + totalCost.inputTokens,
2750
+ outputTokens: pendingParallelUsageCost.outputTokens + totalCost.outputTokens,
2751
+ costUsd: pendingParallelUsageCost.costUsd + totalCost.costUsd,
2752
+ };
2753
+ refreshUsageBudget();
2754
+ };
2700
2755
  const updateStepFromChildEvent = (flatIndex, event) => {
2701
2756
  const step = statusPayload.steps[flatIndex];
2702
2757
  if (!step)
@@ -2739,11 +2794,15 @@ export async function runSubagent(config, childSessions) {
2739
2794
  step.toolCount = (step.toolCount ?? 0) + 1;
2740
2795
  const configuredToolBudget = flatSteps[flatIndex]?.toolBudget;
2741
2796
  if (configuredToolBudget) {
2742
- step.toolBudget = toolBudgetState(configuredToolBudget, step.toolCount);
2797
+ step.toolBudget = toolBudgetState(configuredToolBudget, step.toolCount, step.toolBudget?.blockedTool);
2743
2798
  statusPayload.toolBudget = step.toolBudget;
2744
2799
  }
2745
2800
  recordActiveToolCall(flatIndex, { toolCallId: event.toolCallId, toolName: event.toolName }, { argsPreview, currentPath, blocksSupervisor, now });
2746
- pendingToolResults[flatIndex] = omitUndefinedProperties({ tool: event.toolName, path: currentPath, mutates, startedAt: now });
2801
+ const pending = omitUndefinedProperties({ tool: event.toolName, path: currentPath, mutates, startedAt: now });
2802
+ pendingToolResults[flatIndex] = pending;
2803
+ const startedCallId = event.toolCallId;
2804
+ if (typeof startedCallId === "string" && startedCallId)
2805
+ pendingToolResultsByCallId[flatIndex].set(startedCallId, pending);
2747
2806
  statusPayload.toolCount = (statusPayload.toolCount ?? 0) + 1;
2748
2807
  syncTopLevelCurrentTool();
2749
2808
  if (controlConfig.enabled && blocksSupervisor && step.activityState !== "needs_attention") {
@@ -2788,18 +2847,25 @@ export async function runSubagent(config, childSessions) {
2788
2847
  }
2789
2848
  syncTopLevelCurrentTool();
2790
2849
  }
2791
- else if (event.type === "tool_result_end" && event.message) {
2792
- const toolSnapshot = pendingToolResults[flatIndex];
2793
- pendingToolResults[flatIndex] = undefined;
2850
+ else if (event.type === "message_end" && event.message?.role === "toolResult") {
2851
+ // Pi delivers every tool result, including a blocked call, as a toolResult message after tool_execution_end.
2852
+ const resultCallId = event.message.toolCallId;
2853
+ const byCallId = pendingToolResultsByCallId[flatIndex];
2854
+ const keyedSnapshot = typeof resultCallId === "string" ? byCallId.get(resultCallId) : undefined;
2855
+ if (keyedSnapshot)
2856
+ byCallId.delete(resultCallId);
2857
+ const toolSnapshot = keyedSnapshot ?? pendingToolResults[flatIndex];
2858
+ if (!keyedSnapshot || pendingToolResults[flatIndex] === keyedSnapshot)
2859
+ pendingToolResults[flatIndex] = undefined;
2794
2860
  const resultText = extractTextFromContent(event.message.content);
2795
- if (toolSnapshot && resultText.includes("Tool budget hard limit reached")) {
2796
- const configuredToolBudget = flatSteps[flatIndex]?.toolBudget;
2797
- if (configuredToolBudget) {
2798
- step.toolBudget = toolBudgetState(configuredToolBudget, step.toolCount ?? 0, toolSnapshot.tool);
2799
- step.toolBudgetBlocked = true;
2800
- statusPayload.toolBudget = step.toolBudget;
2801
- statusPayload.toolBudgetBlocked = true;
2802
- }
2861
+ const resultToolName = event.message.toolName;
2862
+ const blockedTool = (typeof resultToolName === "string" && resultToolName.length > 0 ? resultToolName : undefined) ?? toolSnapshot?.tool;
2863
+ const configuredToolBudget = flatSteps[flatIndex]?.toolBudget;
2864
+ if (configuredToolBudget && isToolBudgetBlockedMessage(configuredToolBudget, resultText, blockedTool)) {
2865
+ step.toolBudget = toolBudgetState(configuredToolBudget, step.toolCount ?? 0, blockedTool);
2866
+ step.toolBudgetBlocked = true;
2867
+ statusPayload.toolBudget = step.toolBudget;
2868
+ statusPayload.toolBudgetBlocked = true;
2803
2869
  }
2804
2870
  appendRecentStepOutput(step, resultText.split("\n").slice(-10));
2805
2871
  if (toolSnapshot?.mutates && didMutatingToolFail(resultText)) {
@@ -2841,6 +2907,17 @@ export async function runSubagent(config, childSessions) {
2841
2907
  else if (event.type === "message_end" && event.message?.role === "assistant") {
2842
2908
  appendRecentStepOutput(step, stripAcceptanceReport(extractTextFromContent(event.message.content)).split("\n").slice(-10));
2843
2909
  step.turnCount = (step.turnCount ?? 0) + 1;
2910
+ // The launch model is only a candidate: a host extension (e.g. a model
2911
+ // router) can switch the child's model on its first input, so report the
2912
+ // model each assistant message actually ran on. Mirrors the foreground
2913
+ // path's `progress.model = observedModel`.
2914
+ if (event.message.model) {
2915
+ const observedModel = qualifyModelWithProvider(event.message.model, event.message.provider, flatSteps[flatIndex]?.modelVerificationRegistry) ?? event.message.model;
2916
+ if (observedModel !== step.model) {
2917
+ step.launchModel ??= step.model;
2918
+ step.model = observedModel;
2919
+ }
2920
+ }
2844
2921
  const usage = event.message.usage;
2845
2922
  if (config.usageBudget) {
2846
2923
  const known = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
@@ -3093,7 +3170,7 @@ export async function runSubagent(config, childSessions) {
3093
3170
  return;
3094
3171
  timedOut = true;
3095
3172
  const now = Date.now();
3096
- const message = timeoutMessage ?? "Subagent timed out.";
3173
+ const message = timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE;
3097
3174
  statusPayload.timedOut = true;
3098
3175
  statusPayload.error = message;
3099
3176
  currentActivityState = undefined;
@@ -3287,7 +3364,7 @@ export async function runSubagent(config, childSessions) {
3287
3364
  }),
3288
3365
  cwd,
3289
3366
  signal: combinedAbortSignal([timeoutAbortController.signal, stopAbortController.signal]),
3290
- abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? "Subagent timed out.",
3367
+ abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE,
3291
3368
  reportOptional: isAgentContract(step.agentContract),
3292
3369
  }))
3293
3370
  : undefined;
@@ -3298,7 +3375,7 @@ export async function runSubagent(config, childSessions) {
3298
3375
  placeholder.acceptance = effectiveGroupAcceptance;
3299
3376
  const groupAcceptanceFailure = effectiveGroupAcceptance && (!isAgentContract(step.agentContract) || step.gateOn === "acceptance") ? acceptanceFailureMessage(effectiveGroupAcceptance) : undefined;
3300
3377
  if (groupTimedOut || groupStopped || groupAcceptanceFailure) {
3301
- const errorMessage = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? "Subagent timed out." : groupAcceptanceFailure;
3378
+ const errorMessage = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE : groupAcceptanceFailure;
3302
3379
  statusPayload.state = groupStopped ? "stopped" : "failed";
3303
3380
  statusPayload.error = errorMessage;
3304
3381
  setOptionalProperty(statusPayload, "stopped", groupStopped ? true : statusPayload.stopped);
@@ -3346,7 +3423,6 @@ export async function runSubagent(config, childSessions) {
3346
3423
  dynamic: step.parallel.acceptanceInput === undefined,
3347
3424
  agentContract: step.parallel.agentContract ?? step.agentContract,
3348
3425
  })),
3349
- systemPrompt: step.parallel.namespaceOutputPath ? injectOutputPathSystemPrompt(step.parallel.systemPrompt ?? "", outputPath, step.parallel) : step.parallel.systemPrompt,
3350
3426
  outputPath,
3351
3427
  label: task.label ?? step.parallel.label,
3352
3428
  ...(step.sessionFiles?.[itemIndex] ? { sessionFile: step.sessionFiles[itemIndex] } : {}),
@@ -3391,6 +3467,7 @@ export async function runSubagent(config, childSessions) {
3391
3467
  }
3392
3468
  mutatingFailureStates.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps.map(() => createMutatingFailureState()));
3393
3469
  pendingToolResults.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps.map(() => undefined));
3470
+ pendingToolResultsByCallId.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps.map(() => new Map()));
3394
3471
  const materializedDelta = dynamicStatusSteps.length - 1;
3395
3472
  for (const group of statusPayload.parallelGroups) {
3396
3473
  if (group.stepIndex === stepIndex) {
@@ -3471,7 +3548,6 @@ export async function runSubagent(config, childSessions) {
3471
3548
  return omitUndefinedProperties({ agent: task.agent, ...(task.sessionName ? { sessionName: task.sessionName } : {}), context: task.context, output: "(skipped — fail-fast)", exitCode: -1, skipped: true });
3472
3549
  }
3473
3550
  const taskStartTime = Date.now();
3474
- launchedFlatIndices.add(fi);
3475
3551
  statusPayload.currentStep = fi;
3476
3552
  requiredStatusStep(statusPayload, fi).status = "running";
3477
3553
  delete requiredStatusStep(statusPayload, fi).error;
@@ -3525,54 +3601,8 @@ export async function runSubagent(config, childSessions) {
3525
3601
  const taskEndTime = Date.now();
3526
3602
  const childInterrupted = singleResult.interrupted === true;
3527
3603
  const childStopped = singleResult.stopped === true;
3528
- requiredStatusStep(statusPayload, fi).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.execution?.status === "partial" ? "partial" : singleResult.exitCode === 0 ? "complete" : "failed";
3529
- requiredStatusStep(statusPayload, fi).endedAt = taskEndTime;
3530
- requiredStatusStep(statusPayload, fi).durationMs = taskEndTime - taskStartTime;
3531
- requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
3532
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
3533
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
3534
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
3535
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
3536
- if (singleResult.toolBudget)
3537
- statusPayload.toolBudget = singleResult.toolBudget;
3538
- if (singleResult.toolBudgetBlocked)
3539
- statusPayload.toolBudgetBlocked = true;
3540
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "sessionName", singleResult.sessionName);
3541
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
3542
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
3543
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "requestedModel", singleResult.requestedModel);
3544
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "contextOverflow", singleResult.contextOverflow);
3545
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
3546
- if (singleResult.totalCost) {
3547
- pendingParallelUsageCost = {
3548
- inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
3549
- outputTokens: pendingParallelUsageCost.outputTokens + singleResult.totalCost.outputTokens,
3550
- costUsd: pendingParallelUsageCost.costUsd + singleResult.totalCost.costUsd,
3551
- };
3552
- refreshUsageBudget();
3553
- }
3554
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
3555
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, fi).transcriptPath);
3556
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptError", singleResult.transcriptError);
3557
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "agentContract", singleResult.agentContract);
3558
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchContractDigest", singleResult.launchContractDigest);
3559
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
3560
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
3561
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "effects", singleResult.effects);
3562
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "execution", singleResult.execution);
3563
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "review", singleResult.review);
3564
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutput", singleResult.structuredOutput);
3565
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
3566
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
3567
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
3568
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "timeoutRecovery", singleResult.timeoutRecovery);
3569
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
3570
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
3571
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
3572
- if (singleResult.capabilityCeiling)
3573
- statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
3574
- if (singleResult.capabilityAudit)
3575
- statusPayload.capabilityAudit = singleResult.capabilityAudit;
3604
+ recordStepResult(fi, singleResult, taskStartTime, taskEndTime, true);
3605
+ addParallelUsageCost(singleResult.totalCost);
3576
3606
  statusPayload.lastUpdate = taskEndTime;
3577
3607
  writeStatusPayload();
3578
3608
  appendCapabilityCeilingAppliedEvent(eventsPath, id, fi, task.agent, singleResult);
@@ -3585,7 +3615,7 @@ export async function runSubagent(config, childSessions) {
3585
3615
  appendTerminalChildStatusEvent(fi, taskEndTime);
3586
3616
  if (singleResult.exitCode !== 0 && failFast && !childStopped)
3587
3617
  aborted = true;
3588
- return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: singleResult.output || (timeoutMessage ?? "Subagent timed out."), error: singleResult.error ?? timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
3618
+ return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: singleResult.output || (timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE), error: singleResult.error ?? timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE, exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
3589
3619
  }, globalSemaphore);
3590
3620
  flatIndex += dynamicSteps.length;
3591
3621
  for (const pr of parallelResults) {
@@ -3618,6 +3648,7 @@ export async function runSubagent(config, childSessions) {
3618
3648
  totalCost: pr.totalCost,
3619
3649
  usage: pr.usage,
3620
3650
  artifactPaths: pr.artifactPaths,
3651
+ savedOutputPath: pr.savedOutputPath,
3621
3652
  outputSaveError: pr.outputSaveError,
3622
3653
  artifactOutputSaveFailed: pr.artifactOutputSaveFailed,
3623
3654
  transcriptPath: pr.transcriptPath,
@@ -3671,7 +3702,7 @@ export async function runSubagent(config, childSessions) {
3671
3702
  }),
3672
3703
  cwd,
3673
3704
  signal: combinedAbortSignal([timeoutAbortController.signal, stopAbortController.signal]),
3674
- abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? "Subagent timed out.",
3705
+ abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE,
3675
3706
  reportOptional: isAgentContract(step.agentContract),
3676
3707
  }))
3677
3708
  : undefined;
@@ -3679,7 +3710,7 @@ export async function runSubagent(config, childSessions) {
3679
3710
  const groupTimedOut = !groupStopped && (timedOut || timeoutAbortController.signal.aborted);
3680
3711
  const effectiveGroupAcceptance = groupTimedOut || groupStopped ? undefined : groupAcceptance;
3681
3712
  const groupAcceptanceFailure = effectiveDynamicGroupAcceptance.explicit && effectiveGroupAcceptance && (!isAgentContract(step.agentContract) || step.gateOn === "acceptance") ? acceptanceFailureMessage(effectiveGroupAcceptance) : undefined;
3682
- const groupError = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? "Subagent timed out." : groupAcceptanceFailure;
3713
+ const groupError = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE : groupAcceptanceFailure;
3683
3714
  markDynamicGraphGroup(stepIndex, groupError ? groupStopped ? "stopped" : "failed" : "completed", groupError, effectiveGroupAcceptance);
3684
3715
  if (groupError) {
3685
3716
  results.push(omitUndefinedProperties({
@@ -3794,7 +3825,7 @@ export async function runSubagent(config, childSessions) {
3794
3825
  if (config.deadlineAt !== undefined && Date.now() >= config.deadlineAt)
3795
3826
  timeoutRunner();
3796
3827
  if (setupSignal.aborted)
3797
- throw new Error(stopped ? stopMessage : timedOut ? timeoutMessage ?? "Subagent timed out." : "Subagent paused during worktree setup.");
3828
+ throw new Error(stopped ? stopMessage : timedOut ? timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE : "Subagent paused during worktree setup.");
3798
3829
  }
3799
3830
  catch (error) {
3800
3831
  if (worktreeSetup)
@@ -3889,7 +3920,6 @@ export async function runSubagent(config, childSessions) {
3889
3920
  return omitUndefinedProperties({ agent: task.agent, ...(task.sessionName ? { sessionName: task.sessionName } : {}), context: task.context, output: "(skipped — fail-fast)", exitCode: -1, skipped: true });
3890
3921
  }
3891
3922
  const taskStartTime = Date.now();
3892
- launchedFlatIndices.add(fi);
3893
3923
  statusPayload.currentStep = fi;
3894
3924
  requiredStatusStep(statusPayload, fi).status = "running";
3895
3925
  delete requiredStatusStep(statusPayload, fi).error;
@@ -3955,53 +3985,8 @@ export async function runSubagent(config, childSessions) {
3955
3985
  const taskDuration = taskEndTime - taskStartTime;
3956
3986
  const childInterrupted = singleResult.interrupted === true;
3957
3987
  const childStopped = singleResult.stopped === true;
3958
- requiredStatusStep(statusPayload, fi).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.execution?.status === "partial" ? "partial" : singleResult.exitCode === 0 ? "complete" : "failed";
3959
- requiredStatusStep(statusPayload, fi).endedAt = taskEndTime;
3960
- requiredStatusStep(statusPayload, fi).durationMs = taskDuration;
3961
- requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
3962
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
3963
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
3964
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
3965
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
3966
- if (singleResult.toolBudget)
3967
- statusPayload.toolBudget = singleResult.toolBudget;
3968
- if (singleResult.toolBudgetBlocked)
3969
- statusPayload.toolBudgetBlocked = true;
3970
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "sessionName", singleResult.sessionName);
3971
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
3972
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
3973
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "requestedModel", singleResult.requestedModel);
3974
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "contextOverflow", singleResult.contextOverflow);
3975
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
3976
- if (singleResult.totalCost) {
3977
- pendingParallelUsageCost = {
3978
- inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
3979
- outputTokens: pendingParallelUsageCost.outputTokens + singleResult.totalCost.outputTokens,
3980
- costUsd: pendingParallelUsageCost.costUsd + singleResult.totalCost.costUsd,
3981
- };
3982
- refreshUsageBudget();
3983
- }
3984
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
3985
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, fi).transcriptPath);
3986
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptError", singleResult.transcriptError);
3987
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "agentContract", singleResult.agentContract);
3988
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
3989
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
3990
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "effects", singleResult.effects);
3991
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "execution", singleResult.execution);
3992
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "review", singleResult.review);
3993
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutput", singleResult.structuredOutput);
3994
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
3995
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
3996
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
3997
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "timeoutRecovery", singleResult.timeoutRecovery);
3998
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
3999
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
4000
- setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
4001
- if (singleResult.capabilityCeiling)
4002
- statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
4003
- if (singleResult.capabilityAudit)
4004
- statusPayload.capabilityAudit = singleResult.capabilityAudit;
3988
+ recordStepResult(fi, singleResult, taskStartTime, taskEndTime);
3989
+ addParallelUsageCost(singleResult.totalCost);
4005
3990
  statusPayload.lastUpdate = taskEndTime;
4006
3991
  writeStatusPayload();
4007
3992
  appendCapabilityCeilingAppliedEvent(eventsPath, id, fi, task.agent, singleResult);
@@ -4014,7 +3999,7 @@ export async function runSubagent(config, childSessions) {
4014
3999
  appendTerminalChildStatusEvent(fi, taskEndTime);
4015
4000
  if (singleResult.exitCode !== 0 && failFast && !childStopped)
4016
4001
  aborted = true;
4017
- return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: singleResult.output || (timeoutMessage ?? "Subagent timed out."), error: singleResult.error ?? timeoutMessage ?? "Subagent timed out.", exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
4002
+ return stopped || childStopped ? { ...singleResult, output: stopMessage, error: stopMessage, exitCode: 1, interrupted: false, timedOut: false, stopped: true, skipped: false } : timedOut ? { ...singleResult, output: singleResult.output || (timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE), error: singleResult.error ?? timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE, exitCode: 1, interrupted: false, timedOut: true, skipped: false } : { ...singleResult, skipped: false };
4018
4003
  }, globalSemaphore);
4019
4004
  flatIndex += group.parallel.length;
4020
4005
  for (let t = 0; t < group.parallel.length; t++) {
@@ -4071,6 +4056,7 @@ export async function runSubagent(config, childSessions) {
4071
4056
  totalCost: pr.totalCost,
4072
4057
  usage: pr.usage,
4073
4058
  artifactPaths: pr.artifactPaths,
4059
+ savedOutputPath: pr.savedOutputPath,
4074
4060
  outputSaveError: pr.outputSaveError,
4075
4061
  artifactOutputSaveFailed: pr.artifactOutputSaveFailed,
4076
4062
  transcriptPath: pr.transcriptPath,
@@ -4282,7 +4268,6 @@ export async function runSubagent(config, childSessions) {
4282
4268
  }
4283
4269
  const singleCwd = singleWorktreeSetup?.worktrees[0]?.agentCwd ?? cwd;
4284
4270
  const stepStartTime = Date.now();
4285
- launchedFlatIndices.add(flatIndex);
4286
4271
  statusPayload.currentStep = flatIndex;
4287
4272
  requiredStatusStep(statusPayload, flatIndex).status = "running";
4288
4273
  delete requiredStatusStep(statusPayload, flatIndex).activityState;
@@ -4364,10 +4349,10 @@ export async function runSubagent(config, childSessions) {
4364
4349
  launchContractDigest: singleResult.launchContractDigest,
4365
4350
  launchResolvedExtensions: singleResult.launchResolvedExtensions,
4366
4351
  runtimeAcknowledgedExtensions: singleResult.runtimeAcknowledgedExtensions,
4367
- output: stopped || childStopped ? stopMessage : timedOut ? singleResult.output || (timeoutMessage ?? "Subagent timed out.") : singleResult.output,
4352
+ output: stopped || childStopped ? stopMessage : timedOut ? singleResult.output || (timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE) : singleResult.output,
4368
4353
  outputState: singleResult.outputState,
4369
4354
  outputPartial: singleResult.outputPartial,
4370
- error: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error,
4355
+ error: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE) : singleResult.error,
4371
4356
  success: !stopped && !childStopped && !timedOut && singleResult.interrupted !== true && singleResult.exitCode === 0 && singleResult.execution?.status !== "partial",
4372
4357
  exitCode: stopped || childStopped ? 1 : timedOut ? 1 : singleResult.interrupted === true ? 0 : singleResult.exitCode,
4373
4358
  sessionFile: singleResult.sessionFile,
@@ -4446,45 +4431,7 @@ export async function runSubagent(config, childSessions) {
4446
4431
  }
4447
4432
  const stepEndTime = Date.now();
4448
4433
  const childInterrupted = singleResult.interrupted === true;
4449
- requiredStatusStep(statusPayload, flatIndex).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.execution?.status === "partial" ? "partial" : singleResult.exitCode === 0 ? "complete" : "failed";
4450
- requiredStatusStep(statusPayload, flatIndex).endedAt = stepEndTime;
4451
- requiredStatusStep(statusPayload, flatIndex).durationMs = stepEndTime - stepStartTime;
4452
- requiredStatusStep(statusPayload, flatIndex).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
4453
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
4454
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "stopped", stopped || childStopped ? true : undefined);
4455
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudget", singleResult.toolBudget);
4456
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
4457
- if (singleResult.toolBudget)
4458
- statusPayload.toolBudget = singleResult.toolBudget;
4459
- if (singleResult.toolBudgetBlocked)
4460
- statusPayload.toolBudgetBlocked = true;
4461
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "sessionName", singleResult.sessionName);
4462
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "model", singleResult.model);
4463
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, flatIndex).thinking));
4464
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "requestedModel", singleResult.requestedModel);
4465
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "contextOverflow", singleResult.contextOverflow);
4466
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "totalCost", singleResult.totalCost);
4467
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
4468
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, flatIndex).transcriptPath);
4469
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptError", singleResult.transcriptError);
4470
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "agentContract", singleResult.agentContract);
4471
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
4472
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
4473
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "effects", singleResult.effects);
4474
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "execution", singleResult.execution);
4475
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "review", singleResult.review);
4476
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutput", singleResult.structuredOutput);
4477
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputPath", singleResult.structuredOutputPath);
4478
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
4479
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "acceptance", singleResult.acceptance);
4480
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "timeoutRecovery", singleResult.timeoutRecovery);
4481
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "watchdog", singleResult.watchdog);
4482
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityCeiling", singleResult.capabilityCeiling);
4483
- setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityAudit", singleResult.capabilityAudit);
4484
- if (singleResult.capabilityCeiling)
4485
- statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
4486
- if (singleResult.capabilityAudit)
4487
- statusPayload.capabilityAudit = singleResult.capabilityAudit;
4434
+ recordStepResult(flatIndex, singleResult, stepStartTime, stepEndTime);
4488
4435
  if (stepTokens) {
4489
4436
  requiredStatusStep(statusPayload, flatIndex).tokens = stepTokens;
4490
4437
  statusPayload.totalTokens = { ...previousCumulativeTokens };
@@ -4714,7 +4661,7 @@ export async function runSubagent(config, childSessions) {
4714
4661
  }
4715
4662
  if (timedOut) {
4716
4663
  statusPayload.timedOut = true;
4717
- statusPayload.error = timeoutMessage ?? "Subagent timed out.";
4664
+ statusPayload.error = timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE;
4718
4665
  }
4719
4666
  if (usageBudgetExceeded && statusPayload.usageBudget && !statusPayload.error) {
4720
4667
  statusPayload.error = usageBudgetExceededMessage(statusPayload.usageBudget);
@@ -4754,17 +4701,18 @@ export async function runSubagent(config, childSessions) {
4754
4701
  runPersistence.write(resultPath, {
4755
4702
  lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
4756
4703
  id,
4704
+ ...(config.toolCallId ? { toolCallId: config.toolCallId } : {}),
4757
4705
  agent: agentName,
4758
4706
  mode: resultMode,
4759
4707
  success: statusPayload.state === "complete",
4760
4708
  state: statusPayload.state,
4761
- summary: stopped ? stopMessage : signalTerminated ? (statusPayload.error ?? "Subagent process terminated by signal.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : usageBudgetExceeded ? (statusPayload.error ?? "Usage budget exhausted.") : interrupted ? "Paused after interrupt. Waiting for explicit next action." : statusPayload.state === "partial" ? (statusPayload.error ?? summary) : summary,
4709
+ summary: stopped ? stopMessage : signalTerminated ? (statusPayload.error ?? "Subagent process terminated by signal.") : timedOut ? timedOutRunSummary(timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE, summary, results) : usageBudgetExceeded ? (statusPayload.error ?? "Usage budget exhausted.") : interrupted ? "Paused after interrupt. Waiting for explicit next action." : statusPayload.state === "partial" ? (statusPayload.error ?? summary) : summary,
4762
4710
  ...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),
4763
4711
  ...(config.deadlineAt !== undefined ? { deadlineAt: config.deadlineAt } : {}),
4764
4712
  ...(statusPayload.toolBudget ? { toolBudget: statusPayload.toolBudget } : {}),
4765
4713
  ...(statusPayload.toolBudgetBlocked ? { toolBudgetBlocked: true } : {}),
4766
4714
  ...(statusPayload.usageBudget ? { usageBudget: statusPayload.usageBudget } : {}),
4767
- ...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? "Subagent timed out." } : usageBudgetExceeded ? { error: statusPayload.error ?? "Usage budget exhausted." } : {}),
4715
+ ...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? SUBAGENT_TIMED_OUT_MESSAGE } : usageBudgetExceeded ? { error: statusPayload.error ?? "Usage budget exhausted." } : {}),
4768
4716
  results: results.map((r) => omitUndefinedProperties({
4769
4717
  agent: r.agent,
4770
4718
  ...(r.sessionName ? { sessionName: r.sessionName } : {}),
@@ -4846,7 +4794,7 @@ export async function runSubagent(config, childSessions) {
4846
4794
  shareError,
4847
4795
  ...(taskIndex !== undefined && { taskIndex }),
4848
4796
  ...(totalTasks !== undefined && { totalTasks }),
4849
- }, (filePath, payload) => { writeAsyncResultFile(filePath, payload); });
4797
+ }, (filePath, payload) => publishRunResult(filePath, () => { writeAsyncResultFile(filePath, payload); }));
4850
4798
  // Only capacity deferral releases settled sessions before terminal publication.
4851
4799
  if (!finalResultCommitted)
4852
4800
  await Promise.all([publication, disposeChildSessions()]);
@@ -4874,26 +4822,6 @@ export async function runSubagent(config, childSessions) {
4874
4822
  totalCost: finalTotalCost,
4875
4823
  usageBudget: statusPayload.usageBudget,
4876
4824
  }));
4877
- // Paused runs record an interrupted attempt; a later resume records another.
4878
- for (const historyEntry of planBackgroundRunHistory({
4879
- steps,
4880
- resultMode,
4881
- statusSteps: statusPayload.steps.map((step, index) => ({
4882
- agent: step.agent,
4883
- status: step.status,
4884
- durationMs: step.durationMs,
4885
- timedOut: step.timedOut,
4886
- stopped: step.stopped,
4887
- launched: launchedFlatIndices.has(index),
4888
- })),
4889
- stepResults: results,
4890
- runDurationMs: runEndedAt - overallStartTime,
4891
- stopped,
4892
- interrupted,
4893
- timedOut,
4894
- })) {
4895
- recordRun(historyEntry.agent, historyEntry.task, historyEntry.exitCode, historyEntry.durationMs, historyEntry.terminal);
4896
- }
4897
4825
  writeRunLog(logPath, omitUndefinedProperties({
4898
4826
  id,
4899
4827
  mode: statusPayload.mode,