@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
@@ -19,9 +19,9 @@ import {
19
19
  wrapForkTask,
20
20
  } from "../../shared/types.ts";
21
21
  import { compactForegroundDetails, getSingleResultOutput } from "../../shared/utils.ts";
22
+ import { updateForegroundNestedProjection } from "../inprocess/runtime-support/nested-api.ts";
22
23
  import { inheritedIntercomGroup, resolveChildIntercomGroup } from "../shared/intercom-group.ts";
23
24
  import { currentModelFullId, resolveModelCandidate } from "../shared/model-fallback.ts";
24
- import { updateForegroundNestedProjection } from "../shared/nested-events.ts";
25
25
  import { recordRun } from "../shared/run-history.ts";
26
26
  import {
27
27
  finalizeSingleOutput,
@@ -238,7 +238,7 @@ export async function runSinglePath(
238
238
  foregroundControl.toolCount = r.progress?.toolCount;
239
239
  foregroundControl.updatedAt = Date.now();
240
240
  }
241
- recordRun(params.agent!, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0);
241
+ recordRun(params.agent!, cleanTask, r.status, r.progressSummary?.durationMs ?? 0);
242
242
 
243
243
  if (r.progress) allProgress.push(r.progress);
244
244
  if (r.artifactPaths) allArtifactPaths.push(r.artifactPaths);
@@ -249,7 +249,7 @@ export async function runSinglePath(
249
249
  truncatedOutput: r.truncation?.text,
250
250
  outputPath,
251
251
  outputMode: r.outputMode,
252
- exitCode: r.exitCode,
252
+ status: r.status,
253
253
  savedPath: r.savedOutputPath,
254
254
  outputReference: r.outputReference,
255
255
  saveError: r.outputSaveError,
@@ -278,7 +278,7 @@ export async function runSinglePath(
278
278
  return {
279
279
  content: [{ type: "text", text: intercomReceipt.text }],
280
280
  details: intercomReceipt.details,
281
- ...(r.exitCode !== 0 ? { isError: true } : {}),
281
+ ...(r.status === "error" ? { isError: true } : {}),
282
282
  };
283
283
  }
284
284
  }
@@ -304,7 +304,7 @@ export async function runSinglePath(
304
304
  };
305
305
  }
306
306
 
307
- if (r.exitCode !== 0)
307
+ if (r.status === "error")
308
308
  return {
309
309
  content: [{ type: "text", text: formatFailedSingleRunOutput(r, finalizedOutput.displayOutput) }],
310
310
  details,
@@ -21,8 +21,8 @@ import {
21
21
  } from "../../shared/types.ts";
22
22
  import { compactForegroundDetails, compactForegroundResult, getSingleResultOutput } from "../../shared/utils.ts";
23
23
  import { deliverLocalCompletionNotification } from "../background/completion-notification.ts";
24
- import { updateForegroundNestedProjection } from "../shared/nested-events.ts";
25
- import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
24
+ import { updateForegroundNestedProjection } from "../inprocess/runtime-support/nested-api.ts";
25
+ import { formatNestedRunStatusLines } from "../inprocess/runtime-support/nested-rendering.ts";
26
26
  import {
27
27
  formatControlIntercomMessage,
28
28
  formatControlNoticeMessage,
@@ -141,7 +141,7 @@ export function rememberForegroundRun(
141
141
  agent: result.agent,
142
142
  index,
143
143
  status: resolveSubagentResultStatus({
144
- exitCode: result.exitCode,
144
+ status: result.status,
145
145
  interrupted: result.interrupted,
146
146
  detached: result.detached,
147
147
  }),
@@ -192,7 +192,7 @@ export function replaceForegroundRunChild(
192
192
  const child = run.children.find((entry) => entry.index === index);
193
193
  if (child?.status !== "detached") return;
194
194
  child.status = resolveSubagentResultStatus({
195
- exitCode: retainedResult.exitCode,
195
+ status: retainedResult.status,
196
196
  interrupted: retainedResult.interrupted,
197
197
  detached: retainedResult.detached,
198
198
  });
@@ -249,7 +249,7 @@ export function createForegroundControlNotifier(
249
249
 
250
250
  function resultSummaryForIntercom(result: SingleResult): string {
251
251
  const output = getSingleResultOutput(result);
252
- if (result.exitCode !== 0 && result.error) {
252
+ if (result.status === "error" && result.error) {
253
253
  return output ? `${result.error}\n\nOutput:\n${output}` : result.error;
254
254
  }
255
255
  return output || result.error || "(no output)";
@@ -278,9 +278,8 @@ export function notifyDetachedForegroundChildExit(input: {
278
278
  id: runId,
279
279
  runId,
280
280
  agent: result.agent,
281
- success: result.exitCode === 0 && !result.interrupted && !result.error,
281
+ status: result.status,
282
282
  summary: resultSummaryForIntercom(result),
283
- exitCode: result.exitCode,
284
283
  ...(result.interrupted ? { state: "paused" } : {}),
285
284
  timestamp: Date.now(),
286
285
  ...(result.progressSummary?.durationMs !== undefined ? { durationMs: result.progressSummary.durationMs } : {}),
@@ -311,7 +310,7 @@ async function emitForegroundResultIntercom(input: {
311
310
  {
312
311
  agent: result.agent,
313
312
  status: resolveSubagentResultStatus({
314
- exitCode: result.exitCode,
313
+ status: result.status,
315
314
  interrupted: result.interrupted,
316
315
  detached: result.detached,
317
316
  }),
@@ -14,11 +14,12 @@ import type {
14
14
  SubagentToolResult,
15
15
  } from "../../shared/types.ts";
16
16
  import type {
17
- executeAsyncChain,
18
- executeAsyncSingle,
17
+ AsyncExecutionResult,
18
+ AsyncSingleParams,
19
19
  formatAsyncStartedMessage,
20
20
  isAsyncAvailable,
21
- } from "../background/async-execution.ts";
21
+ } from "../inprocess/background.ts";
22
+ import type { ChildModePolicy } from "../inprocess/child-policy.ts";
22
23
  import type { runSync } from "./execution.ts";
23
24
 
24
25
  export interface TaskParam {
@@ -72,8 +73,7 @@ export interface SubagentParamsLike {
72
73
 
73
74
  export interface SubagentExecutorRuntimeDeps {
74
75
  runSync: typeof runSync;
75
- executeAsyncChain: typeof executeAsyncChain;
76
- executeAsyncSingle: typeof executeAsyncSingle;
76
+ executeAsyncSingle: (id: string, params: AsyncSingleParams) => AsyncExecutionResult | Promise<AsyncExecutionResult>;
77
77
  isAsyncAvailable: typeof isAsyncAvailable;
78
78
  formatAsyncStartedMessage: typeof formatAsyncStartedMessage;
79
79
  }
@@ -88,9 +88,18 @@ export interface ExecutorDeps {
88
88
  expandTilde: (p: string) => string;
89
89
  discoverAgents: (cwd: string, scope: AgentScope) => { agents: AgentConfig[] };
90
90
  allowMutatingManagementActions?: boolean;
91
+ /** Typed admission policy; when present it is authoritative over the legacy boolean. */
92
+ childPolicy?: ChildModePolicy;
91
93
  runtime?: Partial<SubagentExecutorRuntimeDeps>;
92
94
  }
93
95
 
96
+ export function isManagementActionsRestricted(
97
+ deps: Pick<ExecutorDeps, "childPolicy" | "allowMutatingManagementActions">,
98
+ ): boolean {
99
+ return deps.childPolicy
100
+ ? deps.childPolicy.managementActions === "restricted"
101
+ : deps.allowMutatingManagementActions === false;
102
+ }
94
103
  export interface ResolvedExecutorDeps extends Omit<ExecutorDeps, "runtime"> {
95
104
  runtime: SubagentExecutorRuntimeDeps;
96
105
  }
@@ -1,23 +1,39 @@
1
1
  import type { ExtensionContext } from "@bastani/atomic";
2
2
  import { handleManagementAction } from "../../agents/agent-management.ts";
3
+ import { resolveExecutionAgentScope } from "../../agents/agent-scope.ts";
3
4
  import { clearPendingForegroundControlNotices } from "../../extension/control-notices.ts";
4
5
  import { buildDoctorReport } from "../../extension/doctor.ts";
5
- import { resolveIntercomSessionTarget } from "../../intercom/intercom-bridge.ts";
6
- import { SUBAGENT_ACTIONS, type SubagentToolResult } from "../../shared/types.ts";
7
- import { type ResolvedSubagentRunId, resolveSubagentRunId } from "../background/run-id-resolver.ts";
8
- import { inspectSubagentStatus } from "../background/run-status.ts";
6
+ import {
7
+ resolveIntercomBridge,
8
+ resolveIntercomSessionTarget,
9
+ resolveSubagentIntercomTarget,
10
+ } from "../../intercom/intercom-bridge.ts";
11
+ import { requestSupervisorAuthorization } from "../../intercom/supervisor-authorization.ts";
12
+ import { getArtifactsDir } from "../../shared/artifacts.ts";
13
+ import { toModelInfo } from "../../shared/model-info.ts";
14
+ import { resolveSingleProgress } from "../../shared/settings.ts";
15
+ import {
16
+ DEFAULT_ARTIFACT_CONFIG,
17
+ isWorkflowStageOrchestrationContext,
18
+ resolveWorkflowStageMaxSubagentDepth,
19
+ SUBAGENT_ACTIONS,
20
+ type SubagentToolResult,
21
+ workflowSessionMetadataFromContext,
22
+ } from "../../shared/types.ts";
23
+ import {
24
+ inspectInProcessChildStatus,
25
+ interruptInProcessChild,
26
+ resumeInProcessChild,
27
+ } from "../inprocess/control-status.ts";
28
+ import { inheritedIntercomGroup } from "../shared/intercom-group.ts";
29
+ import { currentModelFullId } from "../shared/model-fallback.ts";
30
+ import { resolveControlConfig } from "../shared/subagent-control.ts";
9
31
  import { runAsyncPath } from "./subagent-executor-async.ts";
10
32
  import { runChainPath } from "./subagent-executor-chain.ts";
11
33
  import { checkDepthForExecution, prepareExecutionContext } from "./subagent-executor-context.ts";
12
34
  import { toExecutionErrorResult, withForkContext } from "./subagent-executor-input.ts";
13
35
  import { runParallelPath } from "./subagent-executor-parallel.ts";
14
- import {
15
- interruptAsyncRun,
16
- interruptNestedRun,
17
- nestedResolutionScopeForExecutor,
18
- resolveRequestedCwd,
19
- resumeAsyncRun,
20
- } from "./subagent-executor-resume.ts";
36
+ import { resolveRequestedCwd } from "./subagent-executor-resume.ts";
21
37
  import { resolveSubagentExecutorRuntimeDeps } from "./subagent-executor-runtime.ts";
22
38
  import { runSinglePath } from "./subagent-executor-single.ts";
23
39
  import {
@@ -25,8 +41,79 @@ import {
25
41
  getForegroundControl,
26
42
  retainedForegroundStatusResult,
27
43
  } from "./subagent-executor-status.ts";
28
- import type { ExecutorDeps, ResolvedExecutorDeps, SubagentParamsLike } from "./subagent-executor-types.ts";
44
+ import {
45
+ type ExecutorDeps,
46
+ isManagementActionsRestricted,
47
+ type ResolvedExecutorDeps,
48
+ type SubagentParamsLike,
49
+ } from "./subagent-executor-types.ts";
29
50
 
51
+ async function resumeRetainedForegroundChild(
52
+ params: SubagentParamsLike,
53
+ message: string,
54
+ ctx: ExtensionContext,
55
+ deps: ResolvedExecutorDeps,
56
+ ): Promise<SubagentToolResult | undefined> {
57
+ const requested = params.id ?? params.runId;
58
+ if (!requested) return undefined;
59
+ const run = deps.state.foregroundRuns?.get(requested);
60
+ if (!run) return undefined;
61
+ const child = run.children[params.index ?? 0];
62
+ if (!child) return undefined;
63
+ const agents = deps.discoverAgents(run.cwd, resolveExecutionAgentScope(params.agentScope)).agents;
64
+ const agentConfig = agents.find((agent) => agent.name === child.agent);
65
+ if (!agentConfig) {
66
+ return {
67
+ content: [{ type: "text", text: `Unknown agent for resume: ${child.agent}` }],
68
+ isError: true,
69
+ details: { mode: "single", results: [] },
70
+ };
71
+ }
72
+ const parentSessionFile = ctx.sessionManager.getSessionFile() ?? null;
73
+ const sessionName = resolveIntercomSessionTarget(deps.pi.getSessionName(), ctx.sessionManager.getSessionId());
74
+ const intercomBridge = resolveIntercomBridge({
75
+ config: deps.config.intercomBridge,
76
+ context: params.context,
77
+ orchestratorTarget: sessionName,
78
+ cwd: run.cwd,
79
+ });
80
+ const supervisedTarget = intercomBridge.active
81
+ ? resolveSubagentIntercomTarget(run.runId, child.agent, child.index)
82
+ : undefined;
83
+ const supervisorAuthorization = await requestSupervisorAuthorization(deps.pi.events, supervisedTarget);
84
+ return deps.runtime.executeAsyncSingle(run.runId, {
85
+ agent: child.agent,
86
+ agentConfig,
87
+ task: message,
88
+ ctx: {
89
+ pi: deps.pi,
90
+ cwd: run.cwd,
91
+ currentSessionId: ctx.sessionManager.getSessionId(),
92
+ currentModelProvider: ctx.model?.provider,
93
+ currentModel: currentModelFullId(ctx.model),
94
+ intercomGroup: inheritedIntercomGroup(ctx),
95
+ workflowSessionMetadata: workflowSessionMetadataFromContext(ctx),
96
+ },
97
+ cwd: run.cwd,
98
+ maxOutput: params.maxOutput,
99
+ artifactsDir: getArtifactsDir(parentSessionFile),
100
+ artifactConfig: { ...DEFAULT_ARTIFACT_CONFIG, enabled: params.artifacts !== false },
101
+ shareEnabled: params.share === true,
102
+ sessionRoot: deps.getSubagentSessionRoot(parentSessionFile),
103
+ sessionFile: child.sessionFile,
104
+ progress: resolveSingleProgress(agentConfig, params.progress, message),
105
+ modelOverride: params.model,
106
+ availableModels: ctx.modelRegistry.getAvailable().map(toModelInfo),
107
+ maxSubagentDepth: resolveWorkflowStageMaxSubagentDepth(ctx, deps.config.maxSubagentDepth),
108
+ workflowStageSubagentGuard: isWorkflowStageOrchestrationContext(ctx),
109
+ controlConfig: resolveControlConfig(deps.config.control, params.control),
110
+ controlIntercomTarget: intercomBridge.active ? intercomBridge.orchestratorTarget : undefined,
111
+ childIntercomTarget: intercomBridge.active
112
+ ? (agent, index) => resolveSubagentIntercomTarget(run.runId, agent, index)
113
+ : undefined,
114
+ supervisorAuthorization,
115
+ });
116
+ }
30
117
  const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete"]);
31
118
 
32
119
  export type { SubagentExecutorRuntimeDeps, SubagentParamsLike } from "./subagent-executor-types.ts";
@@ -84,43 +171,63 @@ async function handleManagementRequest(input: {
84
171
  }
85
172
  if (action === "status") {
86
173
  const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
174
+ const inProcess = inspectInProcessChildStatus(targetRunId);
175
+ if (inProcess) return inProcess;
176
+ const foreground = getForegroundControl(deps.state, targetRunId);
177
+ if (foreground) return foregroundStatusResult(foreground);
87
178
  if (targetRunId) {
88
- try {
89
- const nestedScope = nestedResolutionScopeForExecutor(deps);
90
- const resolved = resolveSubagentRunId(targetRunId, { state: deps.state, nested: nestedScope });
91
- if (resolved?.kind === "foreground") {
92
- const foreground = getForegroundControl(deps.state, resolved.id);
93
- if (foreground) return foregroundStatusResult(foreground);
94
- const retained = retainedForegroundStatusResult(deps.state, resolved.id);
95
- if (retained) return retained;
96
- }
97
- } catch (error) {
98
- const message = error instanceof Error ? error.message : String(error);
99
- return {
100
- content: [{ type: "text", text: message }],
101
- isError: true,
102
- details: { mode: "management", results: [] },
103
- };
104
- }
105
- } else {
106
- const foreground = getForegroundControl(deps.state, undefined);
107
- if (foreground) return foregroundStatusResult(foreground);
179
+ const retained = retainedForegroundStatusResult(deps.state, targetRunId);
180
+ if (retained) return retained;
108
181
  }
109
- return inspectSubagentStatus(
110
- {
111
- action: "status",
112
- id: paramsWithResolvedCwd.id,
113
- runId: paramsWithResolvedCwd.runId,
114
- dir: paramsWithResolvedCwd.dir,
115
- },
116
- { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) },
117
- );
182
+ return {
183
+ content: [
184
+ {
185
+ type: "text",
186
+ text: targetRunId ? `No in-process child found for '${targetRunId}'.` : "No in-process subagent found.",
187
+ },
188
+ ],
189
+ isError: true,
190
+ details: { mode: "management", results: [] },
191
+ };
118
192
  }
119
193
  if (action === "resume") {
120
- return resumeAsyncRun({ params: paramsWithResolvedCwd, requestCwd, ctx, deps });
194
+ const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
195
+ const message = paramsWithResolvedCwd.message ?? paramsWithResolvedCwd.task;
196
+ if (!targetRunId || !message) {
197
+ return {
198
+ content: [{ type: "text", text: "action='resume' requires id/runId and message." }],
199
+ isError: true,
200
+ details: { mode: "management", results: [] },
201
+ };
202
+ }
203
+ const inProcess = await resumeInProcessChild(targetRunId, message, { model: ctx.model });
204
+ if (inProcess) return inProcess;
205
+ const retained = await resumeRetainedForegroundChild(paramsWithResolvedCwd, message, ctx, deps);
206
+ if (retained) return retained;
207
+ return {
208
+ content: [{ type: "text", text: `No in-process child found for '${targetRunId}'.` }],
209
+ isError: true,
210
+ details: { mode: "management", results: [] },
211
+ };
121
212
  }
122
213
  if (action === "interrupt") {
123
- return handleInterruptRequest({ paramsWithResolvedCwd, deps });
214
+ const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
215
+ if (targetRunId) {
216
+ const inProcess = await interruptInProcessChild(targetRunId);
217
+ if (inProcess) return inProcess;
218
+ }
219
+ return {
220
+ content: [
221
+ {
222
+ type: "text",
223
+ text: targetRunId
224
+ ? `No running in-process child found for '${targetRunId}'.`
225
+ : "No interrupt-capable child found.",
226
+ },
227
+ ],
228
+ isError: true,
229
+ details: { mode: "management", results: [] },
230
+ };
124
231
  }
125
232
  if (!(SUBAGENT_ACTIONS as readonly string[]).includes(action)) {
126
233
  return {
@@ -129,7 +236,7 @@ async function handleManagementRequest(input: {
129
236
  details: { mode: "management" as const, results: [] },
130
237
  };
131
238
  }
132
- if (deps.allowMutatingManagementActions === false && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
239
+ if (isManagementActionsRestricted(deps) && MUTATING_MANAGEMENT_ACTIONS.has(action)) {
133
240
  return {
134
241
  content: [{ type: "text", text: `Action '${action}' is not available from child-safe subagent fanout mode.` }],
135
242
  isError: true,
@@ -139,55 +246,6 @@ async function handleManagementRequest(input: {
139
246
  return handleManagementAction(action, paramsWithResolvedCwd, { ...ctx, cwd: requestCwd });
140
247
  }
141
248
 
142
- async function handleInterruptRequest(input: {
143
- paramsWithResolvedCwd: SubagentParamsLike;
144
- deps: ResolvedExecutorDeps;
145
- }): Promise<SubagentToolResult> {
146
- const { paramsWithResolvedCwd, deps } = input;
147
- const targetRunId = paramsWithResolvedCwd.runId ?? paramsWithResolvedCwd.id;
148
- let resolved: ResolvedSubagentRunId | undefined;
149
- if (targetRunId) {
150
- try {
151
- resolved = resolveSubagentRunId(targetRunId, {
152
- state: deps.state,
153
- nested: nestedResolutionScopeForExecutor(deps),
154
- });
155
- } catch (error) {
156
- const message = error instanceof Error ? error.message : String(error);
157
- return {
158
- content: [{ type: "text", text: message }],
159
- isError: true,
160
- details: { mode: "management", results: [] },
161
- };
162
- }
163
- }
164
- if (resolved?.kind === "nested") return interruptNestedRun(resolved);
165
- const foreground = getForegroundControl(deps.state, resolved?.kind === "foreground" ? resolved.id : targetRunId);
166
- if (foreground?.interrupt) {
167
- const interrupted = foreground.interrupt();
168
- if (interrupted) {
169
- foreground.updatedAt = Date.now();
170
- foreground.currentActivityState = undefined;
171
- return {
172
- content: [{ type: "text", text: `Interrupt requested for foreground run ${foreground.runId}.` }],
173
- details: { mode: "management", results: [] },
174
- };
175
- }
176
- return {
177
- content: [{ type: "text", text: `Foreground run ${foreground.runId} has no active child step to interrupt.` }],
178
- isError: true,
179
- details: { mode: "management", results: [] },
180
- };
181
- }
182
- const asyncInterruptResult = interruptAsyncRun(deps.state, resolved?.kind === "async" ? resolved.id : targetRunId);
183
- if (asyncInterruptResult) return asyncInterruptResult;
184
- return {
185
- content: [{ type: "text", text: "No interrupt-capable run found in this session." }],
186
- isError: true,
187
- details: { mode: "management", results: [] },
188
- };
189
- }
190
-
191
249
  function inferExecutionMode(params: SubagentParamsLike): "single" | "parallel" | "chain" {
192
250
  if ((params.chain?.length ?? 0) > 0) return "chain";
193
251
  if ((params.tasks?.length ?? 0) > 0) return "parallel";
@@ -224,6 +282,13 @@ export function createSubagentExecutor(rawDeps: ExecutorDeps): {
224
282
  onUpdate: ((r: SubagentToolResult) => void) | undefined,
225
283
  ctx: ExtensionContext,
226
284
  ): Promise<SubagentToolResult> => {
285
+ if (deps.childPolicy && !deps.childPolicy.fanoutAuthorized) {
286
+ return {
287
+ content: [{ type: "text", text: "Subagent fanout is not authorized for this child." }],
288
+ isError: true,
289
+ details: { mode: "single", results: [] },
290
+ };
291
+ }
227
292
  deps.state.baseCwd = ctx.cwd;
228
293
  deps.state.foregroundRuns ??= new Map();
229
294
  deps.state.foregroundControls ??= new Map();
@@ -0,0 +1,179 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { buildSkillInjection, resolveSkillsWithFallback } from "../../agents/skills.ts";
4
+ import { injectSingleProgressInstruction, writeInitialProgressFile } from "../../shared/settings.ts";
5
+ import {
6
+ ASYNC_DIR,
7
+ resolveChildMaxSubagentDepth,
8
+ SUBAGENT_ASYNC_COMPLETE_EVENT,
9
+ SUBAGENT_ASYNC_STARTED_EVENT,
10
+ } from "../../shared/types.ts";
11
+ import { resolveChildCwd } from "../../shared/utils.ts";
12
+ import { runSingleInProcess } from "../foreground/inprocess-run-sync.ts";
13
+ import { resolveChildIntercomGroup } from "../shared/intercom-group.ts";
14
+ import { filterSpawnableModelCandidates } from "../shared/model-candidate-filter.ts";
15
+ import { buildModelCandidates } from "../shared/model-fallback.ts";
16
+ import {
17
+ injectSingleOutputInstruction,
18
+ normalizeSingleOutputOverride,
19
+ resolveSingleOutputPath,
20
+ validateFileOnlyOutputMode,
21
+ } from "../shared/single-output.ts";
22
+ import {
23
+ type AsyncExecutionResult,
24
+ type AsyncSingleParams,
25
+ formatAsyncStartError,
26
+ formatAsyncStartedMessage,
27
+ UNAVAILABLE_SUBAGENT_SKILL_ERROR,
28
+ } from "./background.ts";
29
+
30
+ /**
31
+ * Execute a single agent asynchronously using the in-process runner.
32
+ *
33
+ * The returned promise resolves after admission and continuation, not after the
34
+ * model attempt. Terminal delivery happens through the existing detached-exit
35
+ * callback and in-memory result path.
36
+ */
37
+ export async function executeAsyncSingle(id: string, params: AsyncSingleParams): Promise<AsyncExecutionResult> {
38
+ const {
39
+ agent,
40
+ agentConfig,
41
+ ctx,
42
+ cwd,
43
+ maxOutput,
44
+ artifactsDir,
45
+ artifactConfig,
46
+ sessionRoot,
47
+ sessionFile,
48
+ maxSubagentDepth,
49
+ workflowStageSubagentGuard,
50
+ controlConfig,
51
+ controlIntercomTarget,
52
+ childIntercomTarget,
53
+ } = params;
54
+ const task = params.task ?? "";
55
+ const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
56
+ const skillNames = params.skills ?? agentConfig.skills ?? [];
57
+ const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(
58
+ skillNames,
59
+ runnerCwd,
60
+ ctx.cwd,
61
+ );
62
+ if (missingSkills.includes("subagent")) return formatAsyncStartError("single", UNAVAILABLE_SUBAGENT_SKILL_ERROR);
63
+
64
+ let systemPrompt = agentConfig.systemPrompt?.trim() ?? "";
65
+ if (resolvedSkills.length > 0) {
66
+ const injection = buildSkillInjection(resolvedSkills);
67
+ systemPrompt = systemPrompt ? `${systemPrompt}\n\n${injection}` : injection;
68
+ }
69
+
70
+ const asyncDir = path.join(ASYNC_DIR, id);
71
+ try {
72
+ fs.mkdirSync(asyncDir, { recursive: true });
73
+ } catch (error) {
74
+ const message = error instanceof Error ? error.message : String(error);
75
+ return formatAsyncStartError("single", `Failed to create async run directory '${asyncDir}': ${message}`);
76
+ }
77
+
78
+ const effectiveOutput = normalizeSingleOutputOverride(params.output, agentConfig.output);
79
+ const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd, runnerCwd);
80
+ const outputMode = params.outputMode ?? "inline";
81
+ const validationError = validateFileOnlyOutputMode(outputMode, outputPath, `Async single run (${agent})`);
82
+ if (validationError) return formatAsyncStartError("single", validationError);
83
+ let taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath);
84
+ if (params.progress) {
85
+ const progressDir =
86
+ artifactConfig.enabled && artifactsDir
87
+ ? path.join(artifactsDir, "progress", id)
88
+ : path.join(asyncDir, "progress");
89
+ writeInitialProgressFile(progressDir);
90
+ taskWithOutputInstruction = injectSingleProgressInstruction(taskWithOutputInstruction, progressDir);
91
+ }
92
+
93
+ const availableModels = params.availableModels;
94
+ const knownModelProviders = params.knownModelProviders;
95
+ const rawModelCandidates = buildModelCandidates(
96
+ params.modelOverride ?? agentConfig.model,
97
+ agentConfig.fallbackModels,
98
+ availableModels,
99
+ ctx.currentModelProvider,
100
+ ctx.currentModel,
101
+ agentConfig.fallbackThinkingLevels,
102
+ );
103
+ const filteredCandidates = filterSpawnableModelCandidates({
104
+ candidates: rawModelCandidates,
105
+ availableModels,
106
+ knownModelProviders,
107
+ currentModel: ctx.currentModel,
108
+ });
109
+ if (rawModelCandidates.length > 0 && filteredCandidates.candidates.length === 0) {
110
+ return formatAsyncStartError("single", "No spawnable subagent model candidates after pre-spawn filtering.");
111
+ }
112
+
113
+ const childAgent = { ...agentConfig, systemPrompt };
114
+ const result = await runSingleInProcess(runnerCwd, childAgent, taskWithOutputInstruction, {
115
+ cwd: runnerCwd,
116
+ runId: id,
117
+ sessionDir: path.join(sessionRoot ?? asyncDir, "session"),
118
+ sessionFile,
119
+ artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
120
+ artifactConfig,
121
+ maxOutput,
122
+ outputPath,
123
+ outputMode,
124
+ backgroundContinuation: true,
125
+ maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
126
+ workflowStageSubagentGuard,
127
+ workflowSessionMetadata: ctx.workflowSessionMetadata,
128
+ controlConfig,
129
+ supervisorAuthorization: params.supervisorAuthorization,
130
+ intercomSessionName: childIntercomTarget?.(agent, 0),
131
+ orchestratorIntercomTarget: controlIntercomTarget,
132
+ intercomGroup: resolveChildIntercomGroup(params.group, ctx.intercomGroup, undefined),
133
+ modelOverride: filteredCandidates.candidates[0] ?? params.modelOverride ?? agentConfig.model,
134
+ availableModels,
135
+ knownModelProviders,
136
+ preferredModelProvider: ctx.currentModelProvider,
137
+ currentModel: ctx.currentModel,
138
+ skills: resolvedSkills.map((skill) => skill.name),
139
+ testSession: params.testSession,
140
+ onDetachedExit: (completed) => {
141
+ const envelope = completed.envelope?.trim() ? completed.envelope : "(no output)";
142
+ ctx.pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
143
+ id,
144
+ runId: id,
145
+ asyncDir,
146
+ agent,
147
+ status: completed.status,
148
+ summary: envelope,
149
+ envelope,
150
+ timestamp: Date.now(),
151
+ sessionFile: completed.sessionFile,
152
+ results: [
153
+ {
154
+ agent,
155
+ output: envelope,
156
+ status: completed.status,
157
+ index: 0,
158
+ intercomTarget: childIntercomTarget?.(agent, 0),
159
+ },
160
+ ],
161
+ result: completed,
162
+ });
163
+ },
164
+ });
165
+
166
+ ctx.pi.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
167
+ id,
168
+ asyncDir,
169
+ sessionId: result.path,
170
+ mode: "single",
171
+ agent,
172
+ agents: [agent],
173
+ });
174
+ return {
175
+ content: [{ type: "text", text: formatAsyncStartedMessage(`Async: ${agent} [${id}]`) }],
176
+ details: { mode: "single", runId: id, results: [result], asyncId: id, asyncDir },
177
+ ...(result.status === "error" ? { isError: true } : {}),
178
+ };
179
+ }