@bastani/atomic 0.9.12 → 0.9.13-alpha.1

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 (264) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/README.md +5 -12
  4. package/dist/builtin/intercom/broker/client.ts +11 -2
  5. package/dist/builtin/intercom/contact-supervisor-tool.ts +13 -3
  6. package/dist/builtin/intercom/index-heavy.ts +13 -3
  7. package/dist/builtin/intercom/index.ts +43 -19
  8. package/dist/builtin/intercom/intercom-utils.ts +15 -29
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/source-ownership.ts +9 -12
  11. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  12. package/dist/builtin/mcp/README.md +3 -1
  13. package/dist/builtin/mcp/index.ts +10 -16
  14. package/dist/builtin/mcp/package.json +1 -1
  15. package/dist/builtin/mcp/startup-warmup.ts +20 -8
  16. package/dist/builtin/subagents/CHANGELOG.md +30 -0
  17. package/dist/builtin/subagents/README.md +22 -30
  18. package/dist/builtin/subagents/package.json +1 -1
  19. package/dist/builtin/subagents/src/extension/doctor.ts +1 -1
  20. package/dist/builtin/subagents/src/extension/fanout-child.ts +76 -56
  21. package/dist/builtin/subagents/src/extension/index.ts +23 -32
  22. package/dist/builtin/subagents/src/extension/startup-maintenance.ts +25 -44
  23. package/dist/builtin/subagents/src/intercom/result-intercom.ts +7 -7
  24. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +166 -434
  25. package/dist/builtin/subagents/src/runs/background/notify.ts +29 -8
  26. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +2 -2
  27. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +4 -4
  28. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +2 -2
  29. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -2
  30. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -281
  31. package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +11 -75
  32. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +457 -0
  33. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +119 -246
  34. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +1 -1
  35. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +18 -9
  36. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +1 -1
  37. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +4 -4
  38. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +1 -646
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -7
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +5 -5
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +7 -8
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +14 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +158 -93
  44. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +179 -0
  45. package/dist/builtin/subagents/src/runs/inprocess/background.ts +89 -0
  46. package/dist/builtin/subagents/src/runs/inprocess/child-policy.ts +27 -0
  47. package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +55 -0
  48. package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +106 -0
  49. package/dist/builtin/subagents/src/runs/inprocess/index.ts +50 -0
  50. package/dist/builtin/subagents/src/runs/inprocess/nested-routing.ts +218 -0
  51. package/dist/builtin/subagents/src/runs/{shared/subagent-prompt-runtime.ts → inprocess/prompt-behavior.ts} +37 -75
  52. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +1138 -0
  53. package/dist/builtin/subagents/src/runs/{shared/nested-events.ts → inprocess/runtime-support/nested-api.ts} +13 -7
  54. package/dist/builtin/subagents/src/runs/{shared/nested-events-control.ts → inprocess/runtime-support/nested-control.ts} +18 -17
  55. package/dist/builtin/subagents/src/runs/{shared/nested-events-core.ts → inprocess/runtime-support/nested-core.ts} +14 -61
  56. package/dist/builtin/subagents/src/runs/{shared/nested-events-projection.ts → inprocess/runtime-support/nested-projection.ts} +4 -10
  57. package/dist/builtin/subagents/src/runs/{shared/nested-events-registry.ts → inprocess/runtime-support/nested-registry.ts} +19 -4
  58. package/dist/builtin/subagents/src/runs/{shared/nested-render.ts → inprocess/runtime-support/nested-rendering.ts} +3 -3
  59. package/dist/builtin/subagents/src/runs/{shared/nested-events-sanitize.ts → inprocess/runtime-support/nested-sanitize.ts} +3 -3
  60. package/dist/builtin/subagents/src/runs/inprocess.ts +1 -0
  61. package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +10 -4
  62. package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +0 -1
  63. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +15 -492
  64. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +13 -11
  65. package/dist/builtin/subagents/src/runs/shared/run-history.ts +3 -5
  66. package/dist/builtin/subagents/src/runs/shared/single-output.ts +4 -4
  67. package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +5 -5
  68. package/dist/builtin/subagents/src/shared/types-async.ts +0 -1
  69. package/dist/builtin/subagents/src/shared/types-config.ts +18 -0
  70. package/dist/builtin/subagents/src/shared/types-results.ts +9 -2
  71. package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +2 -3
  72. package/dist/builtin/subagents/src/slash/slash-live-state.ts +2 -2
  73. package/dist/builtin/subagents/src/tui/render-chain-graph.ts +10 -4
  74. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +12 -11
  75. package/dist/builtin/subagents/src/tui/render-result-compact.ts +49 -12
  76. package/dist/builtin/subagents/src/tui/render-result.ts +46 -17
  77. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
  78. package/dist/builtin/subagents/src/tui/render-status-progress.ts +8 -5
  79. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -8
  80. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -24
  81. package/dist/builtin/web-access/package.json +1 -1
  82. package/dist/builtin/workflows/CHANGELOG.md +25 -0
  83. package/dist/builtin/workflows/README.md +13 -3
  84. package/dist/builtin/workflows/package.json +1 -1
  85. package/dist/builtin/workflows/src/durable/backend.ts +7 -0
  86. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
  87. package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
  88. package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
  89. package/dist/builtin/workflows/src/durable/types.ts +5 -0
  90. package/dist/builtin/workflows/src/engine/run.ts +17 -1
  91. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
  92. package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
  93. package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
  94. package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
  95. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
  96. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
  97. package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
  98. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
  99. package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
  100. package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
  101. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
  102. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
  103. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
  104. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
  105. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
  106. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
  107. package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
  108. package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
  109. package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
  110. package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
  111. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
  112. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
  113. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
  114. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
  115. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
  116. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
  117. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
  118. package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
  119. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
  120. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
  121. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
  122. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
  123. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
  124. package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
  125. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  126. package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
  127. package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
  128. package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
  129. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
  130. package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
  131. package/dist/builtin/workflows/src/shared/timing.ts +10 -0
  132. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
  133. package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
  134. package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
  135. package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
  136. package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
  137. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
  138. package/dist/builtin/workflows/src/tui/widget.ts +16 -46
  139. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  140. package/dist/core/agent-session-auto-compaction.js +54 -11
  141. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  142. package/dist/core/agent-session-events.d.ts.map +1 -1
  143. package/dist/core/agent-session-events.js +49 -14
  144. package/dist/core/agent-session-events.js.map +1 -1
  145. package/dist/core/agent-session-methods.d.ts +13 -0
  146. package/dist/core/agent-session-methods.d.ts.map +1 -1
  147. package/dist/core/agent-session-methods.js.map +1 -1
  148. package/dist/core/agent-session-models.d.ts.map +1 -1
  149. package/dist/core/agent-session-models.js +12 -1
  150. package/dist/core/agent-session-models.js.map +1 -1
  151. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  152. package/dist/core/agent-session-prompt.js +4 -0
  153. package/dist/core/agent-session-prompt.js.map +1 -1
  154. package/dist/core/agent-session-retry.d.ts +21 -4
  155. package/dist/core/agent-session-retry.d.ts.map +1 -1
  156. package/dist/core/agent-session-retry.js +232 -106
  157. package/dist/core/agent-session-retry.js.map +1 -1
  158. package/dist/core/agent-session-state.d.ts.map +1 -1
  159. package/dist/core/agent-session-state.js +2 -1
  160. package/dist/core/agent-session-state.js.map +1 -1
  161. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  162. package/dist/core/agent-session-tool-hooks.js +12 -0
  163. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  164. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  165. package/dist/core/agent-session-tool-registry.js +1 -1
  166. package/dist/core/agent-session-tool-registry.js.map +1 -1
  167. package/dist/core/agent-session-types.d.ts +3 -1
  168. package/dist/core/agent-session-types.d.ts.map +1 -1
  169. package/dist/core/agent-session-types.js.map +1 -1
  170. package/dist/core/agent-session.d.ts +12 -1
  171. package/dist/core/agent-session.d.ts.map +1 -1
  172. package/dist/core/agent-session.js +7 -0
  173. package/dist/core/agent-session.js.map +1 -1
  174. package/dist/core/extensions/context-types.d.ts +25 -0
  175. package/dist/core/extensions/context-types.d.ts.map +1 -1
  176. package/dist/core/extensions/context-types.js.map +1 -1
  177. package/dist/core/extensions/index.d.ts +1 -1
  178. package/dist/core/extensions/index.d.ts.map +1 -1
  179. package/dist/core/extensions/index.js.map +1 -1
  180. package/dist/core/extensions/runner-context.d.ts +2 -1
  181. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  182. package/dist/core/extensions/runner-context.js +4 -0
  183. package/dist/core/extensions/runner-context.js.map +1 -1
  184. package/dist/core/extensions/runner.d.ts +3 -2
  185. package/dist/core/extensions/runner.d.ts.map +1 -1
  186. package/dist/core/extensions/runner.js +3 -1
  187. package/dist/core/extensions/runner.js.map +1 -1
  188. package/dist/core/model-fallback-failures.d.ts +30 -0
  189. package/dist/core/model-fallback-failures.d.ts.map +1 -0
  190. package/dist/core/model-fallback-failures.js +610 -0
  191. package/dist/core/model-fallback-failures.js.map +1 -0
  192. package/dist/core/retry-policy.d.ts +30 -0
  193. package/dist/core/retry-policy.d.ts.map +1 -0
  194. package/dist/core/retry-policy.js +25 -0
  195. package/dist/core/retry-policy.js.map +1 -0
  196. package/dist/core/sdk-types.d.ts +8 -2
  197. package/dist/core/sdk-types.d.ts.map +1 -1
  198. package/dist/core/sdk-types.js.map +1 -1
  199. package/dist/core/sdk.d.ts.map +1 -1
  200. package/dist/core/sdk.js +6 -1
  201. package/dist/core/sdk.js.map +1 -1
  202. package/dist/core/session-manager-core.d.ts +2 -0
  203. package/dist/core/session-manager-core.d.ts.map +1 -1
  204. package/dist/core/session-manager-core.js +7 -0
  205. package/dist/core/session-manager-core.js.map +1 -1
  206. package/dist/index-extensions.d.ts +1 -1
  207. package/dist/index-extensions.d.ts.map +1 -1
  208. package/dist/index-extensions.js.map +1 -1
  209. package/dist/index.d.ts +3 -0
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +2 -0
  212. package/dist/index.js.map +1 -1
  213. package/docs/intercom.md +5 -10
  214. package/docs/settings.md +7 -1
  215. package/docs/subagents.md +19 -19
  216. package/docs/workflows.md +21 -5
  217. package/examples/extensions/gondolin/package-lock.json +3 -3
  218. package/npm-shrinkwrap.json +29 -29
  219. package/package.json +2 -2
  220. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
  221. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
  222. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
  223. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
  224. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
  225. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
  226. package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
  227. package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
  228. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
  229. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
  230. package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
  231. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
  232. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
  233. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
  234. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
  235. package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
  236. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
  237. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
  238. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
  239. package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
  240. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
  241. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
  242. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
  243. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
  244. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
  245. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
  246. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
  247. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
  248. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
  249. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
  250. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
  251. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
  252. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
  253. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
  254. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
  255. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
  256. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
  257. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
  258. package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
  259. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
  260. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
  261. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
  262. package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
  263. package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
  264. /package/dist/builtin/subagents/src/runs/{shared/nested-path.ts → inprocess/runtime-support/nested-paths.ts} +0 -0
@@ -1,330 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { getArtifactPaths } from "../../shared/artifacts.ts";
4
- import { resolveEffectiveThinking } from "../../shared/model-info.ts";
5
- import type { ArtifactPaths, ModelAttempt } from "../../shared/types.ts";
6
- import { detectSubagentError } from "../../shared/utils.ts";
7
- import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
8
- import { formatModelAttemptNote, isRetryableModelFailure } from "../shared/model-fallback.ts";
9
- import { buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
10
- import {
11
- captureSingleOutputSnapshot,
12
- finalizeSingleOutput,
13
- formatSavedOutputReference,
14
- resolveSingleOutput,
15
- type SingleOutputSnapshot,
16
- } from "../shared/single-output.ts";
17
- import {
18
- createStructuredOutputRuntime,
19
- formatStructuredOutputCorrectionPrompt,
20
- isStructuredOutputContractError,
21
- latestStructuredOutputToolErrorFromMessages,
22
- readStructuredOutput,
23
- STRUCTURED_OUTPUT_MAX_CORRECTIVE_PROMPTS,
24
- } from "../shared/structured-output.ts";
25
- import { runPiStreaming } from "./subagent-runner-streaming.ts";
26
- import type { RunPiStreamingResult, SingleStepContext, SubagentStep } from "./subagent-runner-types.ts";
27
- import { emptyUsage, fastModeForStepAttempt } from "./subagent-runner-utils.ts";
28
-
29
- export { outputEntryFromAsyncResult };
30
-
31
- export async function runSingleStep(
32
- step: SubagentStep,
33
- ctx: SingleStepContext,
34
- ): Promise<{
35
- agent: string;
36
- output: string;
37
- exitCode: number | null;
38
- error?: string;
39
- model?: string;
40
- fastMode?: boolean;
41
- attemptedModels?: string[];
42
- modelAttempts?: ModelAttempt[];
43
- artifactPaths?: ArtifactPaths;
44
- interrupted?: boolean;
45
- sessionFile?: string;
46
- intercomTarget?: string;
47
- structuredOutput?: unknown;
48
- structuredOutputPath?: string;
49
- structuredOutputSchemaPath?: string;
50
- }> {
51
- const effectiveStructuredOutput =
52
- step.structuredOutput ??
53
- (step.structuredOutputSchema
54
- ? createStructuredOutputRuntime(
55
- step.structuredOutputSchema,
56
- path.join(path.dirname(ctx.outputFile), "structured-output"),
57
- )
58
- : undefined);
59
- const placeholderRegex = new RegExp(ctx.placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
60
- let task = step.task.replace(placeholderRegex, () => ctx.previousOutput);
61
- task = resolveOutputReferences(task, ctx.outputs ?? {});
62
- const sessionEnabled = Boolean(step.sessionFile) || ctx.sessionEnabled;
63
- const sessionDir = step.sessionFile ? undefined : ctx.sessionDir;
64
-
65
- let artifactPaths: ArtifactPaths | undefined;
66
- if (ctx.artifactsDir && ctx.artifactConfig?.enabled !== false) {
67
- const index = ctx.flatStepCount > 1 ? ctx.flatIndex : undefined;
68
- artifactPaths = getArtifactPaths(ctx.artifactsDir, ctx.id, step.agent, index);
69
- fs.mkdirSync(ctx.artifactsDir, { recursive: true });
70
- if (ctx.artifactConfig?.includeInput !== false) {
71
- fs.writeFileSync(artifactPaths.inputPath, `# Task for ${step.agent}\n\n${task}`, "utf-8");
72
- }
73
- }
74
-
75
- // `!== undefined` is intentional: an explicitly empty array means every candidate
76
- // was removed by pre-spawn filtering (see filterSpawnableModelCandidates) and must
77
- // be respected — do not "simplify" this back to `.length > 0`, which would spawn a
78
- // doomed default attempt. Pre-spawn filtering always records each removal as a
79
- // skipped attempt in step.modelAttempts, so an empty array WITHOUT skipped attempts
80
- // means no candidates were configured at all (no primary model, no fallbacks, no
81
- // current model); mirror the foreground path (execution-run-sync.ts `modelsToTry`)
82
- // and run one default-model attempt instead of silently exiting with no attempt.
83
- // The filtered-to-empty case is surfaced as an error below.
84
- const preSkippedAttempts = step.modelAttempts ?? [];
85
- const candidates =
86
- step.modelCandidates !== undefined && (step.modelCandidates.length > 0 || preSkippedAttempts.length > 0)
87
- ? step.modelCandidates
88
- : step.model
89
- ? [step.model]
90
- : [undefined];
91
- const attemptedModels: string[] = [];
92
- const modelAttempts: ModelAttempt[] = [...preSkippedAttempts];
93
- const attemptNotes: string[] = modelAttempts
94
- .filter((attempt) => !attempt.success && attempt.exitCode === null && attempt.error)
95
- .map((attempt) => `[fallback] ${attempt.error}`);
96
- const pendingAttemptNotes: string[] = [];
97
- const eventsPath = path.join(path.dirname(ctx.outputFile), "events.jsonl");
98
- let finalResult: RunPiStreamingResult | undefined;
99
- let finalFastMode: boolean | undefined;
100
- let finalOutputSnapshot: SingleOutputSnapshot | undefined;
101
-
102
- for (let index = 0; index < candidates.length; index++) {
103
- const candidate = candidates[index];
104
- const attemptFastMode = fastModeForStepAttempt(step, candidate);
105
- ctx.onAttemptStart?.({
106
- model: candidate,
107
- thinking: resolveEffectiveThinking(candidate, step.thinking),
108
- fastMode: attemptFastMode ? true : undefined,
109
- });
110
- if (candidate) attemptedModels.push(candidate);
111
- let nextTask = task;
112
- let correctiveAttempts = 0;
113
- let tryNextModel = false;
114
-
115
- while (true) {
116
- const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
117
- if (effectiveStructuredOutput) {
118
- try {
119
- if (fs.existsSync(effectiveStructuredOutput.outputPath))
120
- fs.unlinkSync(effectiveStructuredOutput.outputPath);
121
- } catch {
122
- // Missing/stale structured-output files are handled after the child exits.
123
- }
124
- }
125
- const { args, env, tempDir } = buildPiArgs({
126
- baseArgs: ["--mode", "json", "-p"],
127
- task: nextTask,
128
- sessionEnabled,
129
- sessionDir,
130
- sessionFile: step.sessionFile,
131
- model: candidate,
132
- inheritProjectContext: step.inheritProjectContext,
133
- inheritSkills: step.inheritSkills,
134
- tools: step.tools,
135
- extensions: step.extensions,
136
- systemPrompt: step.systemPrompt,
137
- systemPromptMode: step.systemPromptMode,
138
- mcpDirectTools: step.mcpDirectTools,
139
- cwd: step.cwd ?? ctx.cwd,
140
- promptFileStem: step.agent,
141
- intercomSessionName: ctx.childIntercomTarget,
142
- orchestratorIntercomTarget: ctx.supervisorAuthorization ? ctx.orchestratorIntercomTarget : undefined,
143
- intercomGroup: step.intercomGroup,
144
- supervisorAuthorization: ctx.supervisorAuthorization,
145
- runId: ctx.id,
146
- childAgentName: step.agent,
147
- childIndex: ctx.flatIndex,
148
- parentEventSink: ctx.nestedRoute?.eventSink,
149
- parentControlInbox: ctx.nestedRoute?.controlInbox,
150
- parentRootRunId: ctx.nestedRoute?.rootRunId,
151
- parentCapabilityToken: ctx.nestedRoute?.capabilityToken,
152
- codexFastModeSettings: step.codexFastModeSettings,
153
- codexFastModeScope: step.codexFastModeScope,
154
- structuredOutput: effectiveStructuredOutput,
155
- });
156
- const run = await runPiStreaming(
157
- args,
158
- step.cwd ?? ctx.cwd,
159
- ctx.outputFile,
160
- env,
161
- ctx.piPackageRoot,
162
- ctx.piArgv1,
163
- step.maxSubagentDepth,
164
- step.workflowStageSubagentGuard ?? ctx.workflowStageSubagentGuard,
165
- { eventsPath, runId: ctx.id, stepIndex: ctx.flatIndex, agent: step.agent },
166
- ctx.registerInterrupt,
167
- ctx.onChildEvent,
168
- );
169
- cleanupTempDir(tempDir);
170
-
171
- const hiddenError = run.exitCode === 0 && !run.error ? detectSubagentError(run.messages) : null;
172
- let structuredOutput: unknown;
173
- let structuredError: string | undefined;
174
- if (effectiveStructuredOutput && run.exitCode === 0 && !run.error && !hiddenError?.hasError) {
175
- const structured = readStructuredOutput(effectiveStructuredOutput);
176
- if (structured.error) structuredError = structured.error;
177
- else structuredOutput = structured.value;
178
- }
179
- const structuredContractError = structuredError
180
- ? (latestStructuredOutputToolErrorFromMessages(run.messages) ?? structuredError)
181
- : undefined;
182
- const effectiveExitCode = structuredContractError
183
- ? 1
184
- : hiddenError?.hasError
185
- ? (hiddenError.exitCode ?? 1)
186
- : run.error && run.exitCode === 0
187
- ? 1
188
- : run.exitCode;
189
- const error =
190
- structuredContractError ??
191
- (hiddenError?.hasError
192
- ? hiddenError.details
193
- ? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
194
- : `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
195
- : run.error || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
196
- const attemptModel = candidate ?? run.model ?? step.model ?? "default";
197
- const attempt: ModelAttempt = {
198
- model: attemptModel,
199
- reasoningLevel: resolveEffectiveThinking(attemptModel, step.thinking),
200
- success: effectiveExitCode === 0 && !error,
201
- exitCode: effectiveExitCode,
202
- error,
203
- usage: run.usage,
204
- };
205
- modelAttempts.push(attempt);
206
- finalFastMode = attemptFastMode;
207
- finalOutputSnapshot = outputSnapshot;
208
- finalResult = {
209
- ...run,
210
- exitCode: effectiveExitCode,
211
- model: candidate ?? run.model,
212
- error,
213
- structuredOutput,
214
- } as RunPiStreamingResult & { structuredOutput?: unknown };
215
- if (attempt.success) break;
216
- if (
217
- effectiveStructuredOutput &&
218
- isStructuredOutputContractError(structuredContractError) &&
219
- correctiveAttempts < STRUCTURED_OUTPUT_MAX_CORRECTIVE_PROMPTS
220
- ) {
221
- correctiveAttempts += 1;
222
- nextTask = formatStructuredOutputCorrectionPrompt({
223
- originalTask: task,
224
- error: structuredContractError!,
225
- attempt: correctiveAttempts,
226
- });
227
- continue;
228
- }
229
- const retrySignal = run.modelFailureSignal ?? error;
230
- if (
231
- structuredContractError === undefined &&
232
- hiddenError?.hasError !== true &&
233
- isRetryableModelFailure(retrySignal) &&
234
- index < candidates.length - 1
235
- ) {
236
- pendingAttemptNotes.push(formatModelAttemptNote(attempt, candidates[index + 1]));
237
- tryNextModel = true;
238
- break;
239
- }
240
- attemptNotes.push(...pendingAttemptNotes);
241
- break;
242
- }
243
- if (!tryNextModel) break;
244
- }
245
-
246
- if (!finalResult && candidates.length === 0 && modelAttempts.length > 0) {
247
- finalResult = {
248
- stderr: "",
249
- exitCode: 1,
250
- messages: [],
251
- usage: emptyUsage(),
252
- error: "No spawnable subagent model candidates after pre-spawn filtering.",
253
- finalOutput: "",
254
- };
255
- }
256
-
257
- const rawOutput = finalResult?.finalOutput ?? "";
258
- const outputForPersistence = rawOutput;
259
- const resolvedOutput =
260
- step.outputPath && finalResult?.exitCode === 0
261
- ? resolveSingleOutput(step.outputPath, outputForPersistence, finalOutputSnapshot)
262
- : { fullOutput: outputForPersistence };
263
- const output = resolvedOutput.fullOutput;
264
- const outputReference = resolvedOutput.savedPath
265
- ? formatSavedOutputReference(resolvedOutput.savedPath, output)
266
- : undefined;
267
- let outputForSummary = output;
268
- if (attemptNotes.length > 0) {
269
- outputForSummary = `${attemptNotes.join("\n")}\n\n${outputForSummary}`.trim();
270
- }
271
- const finalizedOutput = finalizeSingleOutput({
272
- fullOutput: outputForSummary,
273
- outputPath: step.outputPath,
274
- outputMode: step.outputMode,
275
- exitCode: finalResult?.exitCode ?? 1,
276
- savedPath: resolvedOutput.savedPath,
277
- outputReference,
278
- saveError: resolvedOutput.saveError,
279
- });
280
- outputForSummary = finalizedOutput.displayOutput;
281
- const effectiveFinalExitCode = finalResult?.exitCode ?? 1;
282
- const effectiveFinalError = finalResult?.error;
283
-
284
- if (artifactPaths && ctx.artifactConfig?.enabled !== false) {
285
- if (ctx.artifactConfig?.includeOutput !== false) {
286
- fs.writeFileSync(artifactPaths.outputPath, output, "utf-8");
287
- }
288
- if (ctx.artifactConfig?.includeMetadata !== false) {
289
- fs.writeFileSync(
290
- artifactPaths.metadataPath,
291
- JSON.stringify(
292
- {
293
- runId: ctx.id,
294
- agent: step.agent,
295
- task,
296
- exitCode: effectiveFinalExitCode,
297
- model: finalResult?.model,
298
- ...(finalFastMode ? { fastMode: true } : {}),
299
- attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
300
- modelAttempts,
301
- skills: step.skills,
302
- timestamp: Date.now(),
303
- },
304
- null,
305
- 2,
306
- ),
307
- "utf-8",
308
- );
309
- }
310
- }
311
-
312
- return {
313
- agent: step.agent,
314
- output: outputForSummary,
315
- exitCode: effectiveFinalExitCode,
316
- error: effectiveFinalError,
317
- sessionFile: step.sessionFile,
318
- intercomTarget: ctx.childIntercomTarget,
319
- model: finalResult?.model,
320
- ...(finalFastMode ? { fastMode: true } : {}),
321
- attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
322
- modelAttempts,
323
- artifactPaths,
324
- interrupted: finalResult?.interrupted,
325
- structuredOutput: (finalResult as (RunPiStreamingResult & { structuredOutput?: unknown }) | undefined)
326
- ?.structuredOutput,
327
- structuredOutputPath: effectiveStructuredOutput?.outputPath,
328
- structuredOutputSchemaPath: effectiveStructuredOutput?.schemaPath,
329
- };
330
- }
@@ -1,330 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import * as fs from "node:fs";
3
- import type { Message } from "@earendil-works/pi-ai/compat";
4
- import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
5
- import { getSubagentDepthEnv } from "../../shared/types.ts";
6
- import {
7
- detectSubagentError,
8
- extractTextFromContent,
9
- extractToolArgsPreview,
10
- getFinalOutput,
11
- } from "../../shared/utils.ts";
12
- import { createAttemptWatchdog } from "../shared/attempt-watchdog.ts";
13
- import {
14
- assistantStopReason,
15
- isAssistantFailureStopReason,
16
- shouldStartSubagentFinalDrain,
17
- } from "../shared/final-drain.ts";
18
- import { modelFailureMessage } from "../shared/model-fallback.ts";
19
- import { formatPiSpawnError, getPiSpawnCommand, validatePiSpawnCwd } from "../shared/pi-spawn.ts";
20
- import { buildSubagentSpawnEnv } from "../shared/spawn-env.ts";
21
- import { createChildEventJournal } from "./async-event-journal.ts";
22
- import type { ChildEvent, ChildEventContext, RunPiStreamingResult } from "./subagent-runner-types.ts";
23
- import { emptyUsage } from "./subagent-runner-utils.ts";
24
-
25
- export function runPiStreaming(
26
- args: string[],
27
- cwd: string,
28
- outputFile: string,
29
- env?: Record<string, string | undefined>,
30
- piPackageRoot?: string,
31
- piArgv1?: string,
32
- maxSubagentDepth?: number,
33
- workflowStageSubagentGuard?: boolean,
34
- childEventContext?: ChildEventContext,
35
- registerInterrupt?: (interrupt: (() => void) | undefined) => void,
36
- onChildEvent?: (event: ChildEvent) => void,
37
- ): Promise<RunPiStreamingResult> {
38
- const cwdValidation = validatePiSpawnCwd(cwd);
39
- if (!cwdValidation.ok) {
40
- return Promise.resolve({
41
- stderr: "",
42
- exitCode: 1,
43
- messages: [],
44
- usage: emptyUsage(),
45
- error: cwdValidation.error,
46
- finalOutput: "",
47
- });
48
- }
49
- return new Promise((resolve) => {
50
- const outputStream = fs.createWriteStream(outputFile, { flags: "w" });
51
- // A write stream with no `error` listener turns any failure to open or write
52
- // the transcript -- a removed run directory, a full disk, EPERM -- into an
53
- // uncaught exception that takes the host process down, asynchronously and
54
- // long after the call that caused it returned. The transcript is diagnostic,
55
- // so degrade the way the child-event journal beside it already does.
56
- outputStream.on("error", (streamError) => {
57
- console.error(
58
- `Failed to write the subagent transcript to '${outputFile}'; continuing without it: ${String(streamError)}`,
59
- );
60
- });
61
- const spawnEnv = buildSubagentSpawnEnv(
62
- process.env,
63
- env,
64
- getSubagentDepthEnv(maxSubagentDepth, { workflowStageSubagentGuard }),
65
- );
66
- const spawnSpec = getPiSpawnCommand(args, {
67
- ...(piPackageRoot ? { piPackageRoot } : {}),
68
- ...(piArgv1 ? { argv1: piArgv1 } : {}),
69
- });
70
- const child = spawn(spawnSpec.command, spawnSpec.args, {
71
- cwd,
72
- stdio: ["ignore", "pipe", "pipe"],
73
- env: spawnEnv,
74
- windowsHide: true,
75
- });
76
- const childEventJournal = createChildEventJournal(childEventContext?.eventsPath, child.stdout, {
77
- runId: childEventContext?.runId ?? "",
78
- stepIndex: childEventContext?.stepIndex,
79
- agent: childEventContext?.agent ?? "",
80
- });
81
- let stderr = "";
82
- let stdoutBuf = "";
83
- let stderrBuf = "";
84
- const messages: Message[] = [];
85
- const usage = emptyUsage();
86
- let model: string | undefined;
87
- let error: string | undefined;
88
- let assistantError: string | undefined;
89
- let assistantFailureSignal: unknown;
90
- let spawnErrorText: string | undefined;
91
- let interrupted = false;
92
- let activeToolExecutions = 0;
93
- const rawStdoutLines: string[] = [];
94
-
95
- const writeOutputLine = (line: string) => {
96
- if (!line.trim()) return;
97
- outputStream.write(`${line}\n`);
98
- };
99
-
100
- const writeOutputText = (text: string) => {
101
- for (const line of text.split("\n")) {
102
- writeOutputLine(line);
103
- }
104
- };
105
-
106
- const appendChildEvent = (event: Record<string, unknown> | ChildEvent) => {
107
- if (!childEventContext) return;
108
- childEventJournal.append({ ...event });
109
- };
110
-
111
- const appendChildLine = (type: "subagent.child.stdout" | "subagent.child.stderr", line: string) => {
112
- appendChildEvent({ type, line });
113
- };
114
-
115
- const processStdoutLine = (line: string) => {
116
- if (!line.trim()) return;
117
- let event: ChildEvent;
118
- try {
119
- event = JSON.parse(line) as ChildEvent;
120
- } catch {
121
- rawStdoutLines.push(line);
122
- writeOutputLine(line);
123
- appendChildLine("subagent.child.stdout", line);
124
- return;
125
- }
126
-
127
- appendChildEvent(event);
128
- onChildEvent?.(event);
129
-
130
- // Track in-flight tool executions so the idle watchdog does not mistake a
131
- // slow, quiet tool call for a stalled attempt.
132
- if (event.type === "tool_execution_start") activeToolExecutions += 1;
133
- else if (event.type === "tool_execution_end") activeToolExecutions = Math.max(0, activeToolExecutions - 1);
134
-
135
- if (event.type === "tool_execution_start" && event.toolName) {
136
- const toolArgs = extractToolArgsPreview(event.args ?? {});
137
- writeOutputLine(toolArgs ? `${event.toolName}: ${toolArgs}` : event.toolName);
138
- return;
139
- }
140
-
141
- if ((event.type === "message_end" || event.type === "tool_result_end") && event.message) {
142
- messages.push(event.message);
143
- const text = extractTextFromContent(event.message.content);
144
- if (text) writeOutputText(text);
145
-
146
- if (event.type !== "message_end" || event.message.role !== "assistant") return;
147
- if (event.message.model) model = event.message.model;
148
- const eventUsage = event.message.usage;
149
- if (eventUsage) {
150
- usage.turns++;
151
- usage.input += eventUsage.input ?? eventUsage.inputTokens ?? 0;
152
- usage.output += eventUsage.output ?? eventUsage.outputTokens ?? 0;
153
- usage.cacheRead += eventUsage.cacheRead ?? 0;
154
- usage.cacheWrite += eventUsage.cacheWrite ?? 0;
155
- usage.cost += eventUsage.cost?.total ?? 0;
156
- }
157
- const stopReason = assistantStopReason(event.message);
158
- if (event.message.errorMessage) {
159
- assistantError = event.message.errorMessage;
160
- assistantFailureSignal = event.message;
161
- }
162
- if (isAssistantFailureStopReason(stopReason)) {
163
- assistantError = modelFailureMessage(event.message);
164
- assistantFailureSignal = event.message;
165
- }
166
- if (shouldStartSubagentFinalDrain(event.message)) {
167
- if (extractTextFromContent(event.message.content).trim()) {
168
- assistantError = undefined;
169
- assistantFailureSignal = undefined;
170
- }
171
- cleanTerminalAssistantStopReceived = true;
172
- startFinalDrain();
173
- }
174
- }
175
- };
176
-
177
- const processStderrText = (text: string) => {
178
- stderr += text;
179
- stderrBuf += text;
180
- outputStream.write(text);
181
- if (!childEventContext) return;
182
- const lines = stderrBuf.split("\n");
183
- stderrBuf = lines.pop() || "";
184
- for (const line of lines) {
185
- if (!line.trim()) continue;
186
- appendChildLine("subagent.child.stderr", line);
187
- }
188
- };
189
-
190
- const FINAL_STOP_GRACE_MS = 1000;
191
- const HARD_KILL_MS = 3000;
192
- let childExited = false;
193
- let forcedTerminationSignal = false;
194
- let cleanTerminalAssistantStopReceived = false;
195
- let finalDrainTimer: NodeJS.Timeout | undefined;
196
- let finalHardKillTimer: NodeJS.Timeout | undefined;
197
- let settled = false;
198
- const clearStdioGuard = attachPostExitStdioGuard(child, { idleMs: 2000, hardMs: 8000 });
199
- const attemptWatchdog = createAttemptWatchdog({
200
- child,
201
- isSettled: () => settled,
202
- // An in-flight tool execution counts as watchdog activity so a slow, quiet
203
- // tool call is not mistaken for a stalled attempt. Caveat: the counter only
204
- // decrements on tool_execution_end, so if a tool ends abnormally without its
205
- // end event the idle watchdog is deferred indefinitely and the wall-clock cap
206
- // becomes the sole backstop — do not lower the wall cap assuming idle fires.
207
- isToolActive: () => activeToolExecutions > 0,
208
- onTimeout(message) {
209
- forcedTerminationSignal = true;
210
- error ??= message;
211
- },
212
- });
213
- child.stdout.on("data", (chunk: Buffer) => {
214
- attemptWatchdog.activity();
215
- const text = chunk.toString();
216
- stdoutBuf += text;
217
- const lines = stdoutBuf.split("\n");
218
- stdoutBuf = lines.pop() || "";
219
- for (const line of lines) processStdoutLine(line);
220
- });
221
-
222
- child.stderr.on("data", (chunk: Buffer) => {
223
- attemptWatchdog.activity();
224
- processStderrText(chunk.toString());
225
- });
226
- registerInterrupt?.(() => {
227
- if (settled) return;
228
- interrupted = true;
229
- if (!error) error = "Interrupted. Waiting for explicit next action.";
230
- trySignalChild(child, "SIGINT");
231
- setTimeout(() => {
232
- if (!settled) trySignalChild(child, "SIGTERM");
233
- }, 1000).unref?.();
234
- });
235
- const clearDrainTimers = () => {
236
- if (finalDrainTimer) {
237
- clearTimeout(finalDrainTimer);
238
- finalDrainTimer = undefined;
239
- }
240
- if (finalHardKillTimer) {
241
- clearTimeout(finalHardKillTimer);
242
- finalHardKillTimer = undefined;
243
- }
244
- };
245
- function startFinalDrain(): void {
246
- if (childExited || finalDrainTimer || settled) return;
247
- finalDrainTimer = setTimeout(() => {
248
- if (settled) return;
249
- const termSent = trySignalChild(child, "SIGTERM");
250
- if (!termSent) return;
251
- forcedTerminationSignal = true;
252
- if (!cleanTerminalAssistantStopReceived && !error && !assistantError) {
253
- error = `Subagent process did not exit within ${FINAL_STOP_GRACE_MS}ms after its final message. Forcing termination.`;
254
- }
255
- finalHardKillTimer = setTimeout(() => {
256
- if (settled) return;
257
- forcedTerminationSignal = trySignalChild(child, "SIGKILL") || forcedTerminationSignal;
258
- }, HARD_KILL_MS);
259
- finalHardKillTimer.unref?.();
260
- }, FINAL_STOP_GRACE_MS);
261
- finalDrainTimer.unref?.();
262
- }
263
- child.on("exit", () => {
264
- childExited = true;
265
- clearDrainTimers();
266
- });
267
- child.on("close", async (exitCode, signal) => {
268
- settled = true;
269
- registerInterrupt?.(undefined);
270
- clearDrainTimers();
271
- clearStdioGuard();
272
- attemptWatchdog.clear();
273
- if (stdoutBuf.trim()) processStdoutLine(stdoutBuf);
274
- if (stderrBuf.trim()) appendChildLine("subagent.child.stderr", stderrBuf);
275
- outputStream.end();
276
- await childEventJournal.close();
277
- const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
278
- const finalError = error ?? assistantError ?? spawnErrorText;
279
- const forcedDrainAfterFinalSuccess =
280
- forcedTerminationSignal && cleanTerminalAssistantStopReceived && !finalError;
281
- resolve({
282
- stderr,
283
- exitCode:
284
- interrupted || forcedDrainAfterFinalSuccess
285
- ? 0
286
- : forcedTerminationSignal || signal
287
- ? (exitCode ?? 1)
288
- : exitCode,
289
- messages,
290
- usage,
291
- model,
292
- error: interrupted || forcedDrainAfterFinalSuccess ? undefined : finalError,
293
- finalOutput,
294
- interrupted,
295
- ...(assistantFailureSignal !== undefined && finalError === assistantError
296
- ? { modelFailureSignal: assistantFailureSignal }
297
- : {}),
298
- });
299
- });
300
-
301
- child.on("error", async (spawnError) => {
302
- // Capture the diagnostic before awaiting journal drain: `close` may fire
303
- // while this handler is suspended and win Promise settlement.
304
- spawnErrorText = formatPiSpawnError(spawnError, spawnSpec, cwd);
305
- settled = true;
306
- registerInterrupt?.(undefined);
307
- clearDrainTimers();
308
- clearStdioGuard();
309
- attemptWatchdog.clear();
310
- outputStream.end();
311
- await childEventJournal.close();
312
- const finalOutput = getFinalOutput(messages) || rawStdoutLines.join("\n").trim();
313
- const finalError = error ?? assistantError ?? spawnErrorText;
314
- resolve({
315
- stderr,
316
- exitCode: 1,
317
- messages,
318
- usage,
319
- model,
320
- error: finalError,
321
- finalOutput,
322
- ...(assistantFailureSignal !== undefined && finalError === assistantError
323
- ? { modelFailureSignal: assistantFailureSignal }
324
- : {}),
325
- });
326
- });
327
- });
328
- }
329
-
330
- export { detectSubagentError };