@bastani/atomic 0.9.18-alpha.5 → 0.9.18-alpha.7

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 (376) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +3 -3
  3. package/dist/builtin/intercom/CHANGELOG.md +39 -0
  4. package/dist/builtin/intercom/README.md +22 -2
  5. package/dist/builtin/intercom/broker/broker.ts +676 -128
  6. package/dist/builtin/intercom/broker/client.ts +151 -35
  7. package/dist/builtin/intercom/broker/delivered-message-cache.ts +497 -37
  8. package/dist/builtin/intercom/broker/framing.ts +4 -2
  9. package/dist/builtin/intercom/broker/paths.ts +10 -0
  10. package/dist/builtin/intercom/broker/pending-send-registry.ts +1 -2
  11. package/dist/builtin/intercom/broker/send-handler.ts +311 -52
  12. package/dist/builtin/intercom/broker/send-signature.ts +4 -2
  13. package/dist/builtin/intercom/broker/socket-writes.ts +103 -0
  14. package/dist/builtin/intercom/broker/spawn.ts +9 -4
  15. package/dist/builtin/intercom/index.bundle.mjs +1410 -212
  16. package/dist/builtin/intercom/package.json +2 -2
  17. package/dist/builtin/intercom/recoverable-disconnect.ts +52 -0
  18. package/dist/builtin/intercom/retry-policy.ts +8 -0
  19. package/dist/builtin/intercom/skills/intercom/SKILL.md +17 -9
  20. package/dist/builtin/intercom/types.ts +27 -8
  21. package/dist/builtin/intercom/workflow-stage-path-matching.ts +90 -0
  22. package/dist/builtin/intercom/workflow-stage-target.ts +57 -0
  23. package/dist/builtin/mcp/index.bundle.mjs +427 -126
  24. package/dist/builtin/mcp/package.json +2 -2
  25. package/dist/builtin/subagents/CHANGELOG.md +19 -0
  26. package/dist/builtin/subagents/README.md +3 -3
  27. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  28. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  29. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  30. package/dist/builtin/subagents/agents/codebase-online-researcher.md +11 -11
  31. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  32. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  33. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  34. package/dist/builtin/subagents/agents/debugger.md +3 -3
  35. package/dist/builtin/subagents/agents/worker.md +2 -2
  36. package/dist/builtin/subagents/package.json +3 -3
  37. package/dist/builtin/subagents/skills/qlty/SKILL.md +29 -101
  38. package/dist/builtin/subagents/skills/qlty/references/manual-configuration.md +52 -0
  39. package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
  40. package/dist/builtin/subagents/src/extension/index.bundle.mjs +49 -132
  41. package/dist/builtin/web-access/package.json +2 -2
  42. package/dist/builtin/workflows/CHANGELOG.md +46 -0
  43. package/dist/builtin/workflows/README.md +7 -7
  44. package/dist/builtin/workflows/builtin/adversarial-verification.js +2 -2
  45. package/dist/builtin/workflows/builtin/{chunk-szz1ajz9.js → chunk-42s7sw0b.js} +9 -2
  46. package/dist/builtin/workflows/builtin/{chunk-2dqb5s2q.js → chunk-79fjkcvh.js} +1 -1
  47. package/dist/builtin/workflows/builtin/{chunk-n58a7v26.js → chunk-b0v2xab1.js} +181 -10
  48. package/dist/builtin/workflows/builtin/{chunk-fghhy2a5.js → chunk-ed4jfn5t.js} +23 -5
  49. package/dist/builtin/workflows/builtin/{chunk-h3r2vkzc.js → chunk-hqpe2cyx.js} +60 -21
  50. package/dist/builtin/workflows/builtin/{chunk-hzzn6adg.js → chunk-k3w87x8y.js} +1 -1
  51. package/dist/builtin/workflows/builtin/{chunk-82ha8p41.js → chunk-n8h4yyew.js} +1 -1
  52. package/dist/builtin/workflows/builtin/{chunk-qwzvgxnq.js → chunk-reqr3sr3.js} +1 -1
  53. package/dist/builtin/workflows/builtin/{chunk-c53y8bdh.js → chunk-wgccch41.js} +1 -1
  54. package/dist/builtin/workflows/builtin/{chunk-0x6e303p.js → chunk-zbekjqew.js} +20 -7
  55. package/dist/builtin/workflows/builtin/{chunk-29wrp38a.js → chunk-ze5x3d1r.js} +1 -1
  56. package/dist/builtin/workflows/builtin/classify-and-act.js +2 -2
  57. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +2 -2
  58. package/dist/builtin/workflows/builtin/generate-and-filter.js +2 -2
  59. package/dist/builtin/workflows/builtin/goal.js +3 -3
  60. package/dist/builtin/workflows/builtin/index.js +11 -11
  61. package/dist/builtin/workflows/builtin/loop-until-done.js +2 -2
  62. package/dist/builtin/workflows/builtin/open-claude-design.js +2 -2
  63. package/dist/builtin/workflows/builtin/ralph.js +3 -3
  64. package/dist/builtin/workflows/builtin/steering-context.js +1 -1
  65. package/dist/builtin/workflows/builtin/tournament.js +2 -2
  66. package/dist/builtin/workflows/package.json +2 -2
  67. package/dist/builtin/workflows/skills/prompt-engineer/SKILL.md +39 -52
  68. package/dist/builtin/workflows/skills/prompt-engineer/references/advanced_patterns.md +9 -37
  69. package/dist/builtin/workflows/skills/prompt-engineer/references/claude_fable_5.md +49 -0
  70. package/dist/builtin/workflows/skills/prompt-engineer/references/claude_fable_5_1.md +57 -0
  71. package/dist/builtin/workflows/skills/prompt-engineer/references/claude_opus_4_8.md +57 -0
  72. package/dist/builtin/workflows/skills/prompt-engineer/references/claude_opus_5.md +47 -0
  73. package/dist/builtin/workflows/skills/prompt-engineer/references/claude_sonnet_5.md +57 -0
  74. package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_5_5.md +60 -0
  75. package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_5_6.md +58 -0
  76. package/dist/builtin/workflows/skills/prompt-engineer/references/gpt_6_astra.md +58 -0
  77. package/dist/builtin/workflows/skills/prompt-engineer/references/quality_improvement.md +18 -4
  78. package/dist/builtin/workflows/src/extension/index.bundle.mjs +3194 -737
  79. package/dist/builtin/workflows/src/index.js +899 -436
  80. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +0 -10
  81. package/dist/cli/list-models.d.ts.map +1 -1
  82. package/dist/cli/list-models.js +4 -0
  83. package/dist/cli/list-models.js.map +1 -1
  84. package/dist/client/index.d.ts +1 -2
  85. package/dist/client/index.d.ts.map +1 -1
  86. package/dist/client/index.js +1 -2
  87. package/dist/client/index.js.map +1 -1
  88. package/dist/config.d.ts +0 -9
  89. package/dist/config.d.ts.map +1 -1
  90. package/dist/config.js +0 -45
  91. package/dist/config.js.map +1 -1
  92. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  93. package/dist/core/agent-session-compaction.js +8 -6
  94. package/dist/core/agent-session-compaction.js.map +1 -1
  95. package/dist/core/agent-session-methods.d.ts +1 -0
  96. package/dist/core/agent-session-methods.d.ts.map +1 -1
  97. package/dist/core/agent-session-methods.js.map +1 -1
  98. package/dist/core/agent-session-models.d.ts.map +1 -1
  99. package/dist/core/agent-session-models.js +3 -4
  100. package/dist/core/agent-session-models.js.map +1 -1
  101. package/dist/core/agent-session-queue-pause.d.ts.map +1 -1
  102. package/dist/core/agent-session-queue-pause.js +6 -0
  103. package/dist/core/agent-session-queue-pause.js.map +1 -1
  104. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  105. package/dist/core/agent-session-runtime.js +13 -5
  106. package/dist/core/agent-session-runtime.js.map +1 -1
  107. package/dist/core/agent-session-tool-hooks.js +1 -1
  108. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  109. package/dist/core/agent-session-tree.d.ts.map +1 -1
  110. package/dist/core/agent-session-tree.js +8 -0
  111. package/dist/core/agent-session-tree.js.map +1 -1
  112. package/dist/core/agent-session.d.ts +2 -0
  113. package/dist/core/agent-session.d.ts.map +1 -1
  114. package/dist/core/agent-session.js +2 -0
  115. package/dist/core/agent-session.js.map +1 -1
  116. package/dist/core/compaction/branch-summarization.d.ts +2 -2
  117. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  118. package/dist/core/compaction/branch-summarization.js +4 -4
  119. package/dist/core/compaction/branch-summarization.js.map +1 -1
  120. package/dist/core/extensions/api-types.d.ts +8 -2
  121. package/dist/core/extensions/api-types.d.ts.map +1 -1
  122. package/dist/core/extensions/api-types.js.map +1 -1
  123. package/dist/core/extensions/context-types.d.ts +12 -0
  124. package/dist/core/extensions/context-types.d.ts.map +1 -1
  125. package/dist/core/extensions/context-types.js.map +1 -1
  126. package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -1
  127. package/dist/core/extensions/runner-shortcuts.js +0 -1
  128. package/dist/core/extensions/runner-shortcuts.js.map +1 -1
  129. package/dist/core/fast-model-routing-transport.d.ts +12 -0
  130. package/dist/core/fast-model-routing-transport.d.ts.map +1 -0
  131. package/dist/core/{codex-fast-mode-transport.js → fast-model-routing-transport.js} +29 -29
  132. package/dist/core/fast-model-routing-transport.js.map +1 -0
  133. package/dist/core/fast-model-routing.d.ts +57 -0
  134. package/dist/core/fast-model-routing.d.ts.map +1 -0
  135. package/dist/core/fast-model-routing.js +201 -0
  136. package/dist/core/fast-model-routing.js.map +1 -0
  137. package/dist/core/fast-model-variants.d.ts +98 -0
  138. package/dist/core/fast-model-variants.d.ts.map +1 -0
  139. package/dist/core/fast-model-variants.js +148 -0
  140. package/dist/core/fast-model-variants.js.map +1 -0
  141. package/dist/core/http-dispatcher.d.ts.map +1 -1
  142. package/dist/core/http-dispatcher.js +4 -2
  143. package/dist/core/http-dispatcher.js.map +1 -1
  144. package/dist/core/keybindings.d.ts +0 -10
  145. package/dist/core/keybindings.d.ts.map +1 -1
  146. package/dist/core/keybindings.js +0 -8
  147. package/dist/core/keybindings.js.map +1 -1
  148. package/dist/core/messages.d.ts +1 -1
  149. package/dist/core/messages.d.ts.map +1 -1
  150. package/dist/core/messages.js.map +1 -1
  151. package/dist/core/model-config.d.ts +15 -0
  152. package/dist/core/model-config.d.ts.map +1 -1
  153. package/dist/core/model-config.js +3 -0
  154. package/dist/core/model-config.js.map +1 -1
  155. package/dist/core/model-resolver-initial.js +1 -1
  156. package/dist/core/model-resolver-initial.js.map +1 -1
  157. package/dist/core/model-runtime-streaming.d.ts +14 -1
  158. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  159. package/dist/core/model-runtime-streaming.js +25 -3
  160. package/dist/core/model-runtime-streaming.js.map +1 -1
  161. package/dist/core/model-runtime.d.ts +39 -2
  162. package/dist/core/model-runtime.d.ts.map +1 -1
  163. package/dist/core/model-runtime.js +91 -7
  164. package/dist/core/model-runtime.js.map +1 -1
  165. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  166. package/dist/core/provider-composer-internal.js +8 -2
  167. package/dist/core/provider-composer-internal.js.map +1 -1
  168. package/dist/core/sdk.d.ts.map +1 -1
  169. package/dist/core/sdk.js +18 -18
  170. package/dist/core/sdk.js.map +1 -1
  171. package/dist/core/session-manager-archive.d.ts.map +1 -1
  172. package/dist/core/session-manager-archive.js +25 -2
  173. package/dist/core/session-manager-archive.js.map +1 -1
  174. package/dist/core/settings-manager-core.d.ts +0 -2
  175. package/dist/core/settings-manager-core.d.ts.map +1 -1
  176. package/dist/core/settings-manager-core.js +2 -9
  177. package/dist/core/settings-manager-core.js.map +1 -1
  178. package/dist/core/settings-manager-internals.d.ts +0 -1
  179. package/dist/core/settings-manager-internals.d.ts.map +1 -1
  180. package/dist/core/settings-manager-internals.js.map +1 -1
  181. package/dist/core/settings-manager-ui-accessors.d.ts +0 -8
  182. package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -1
  183. package/dist/core/settings-manager-ui-accessors.js +0 -53
  184. package/dist/core/settings-manager-ui-accessors.js.map +1 -1
  185. package/dist/core/settings-manager.d.ts +1 -1
  186. package/dist/core/settings-manager.d.ts.map +1 -1
  187. package/dist/core/settings-manager.js.map +1 -1
  188. package/dist/core/settings-types.d.ts +0 -5
  189. package/dist/core/settings-types.d.ts.map +1 -1
  190. package/dist/core/settings-types.js.map +1 -1
  191. package/dist/core/skills.d.ts +1 -1
  192. package/dist/core/skills.d.ts.map +1 -1
  193. package/dist/core/skills.js +4 -2
  194. package/dist/core/skills.js.map +1 -1
  195. package/dist/core/slash-commands.d.ts.map +1 -1
  196. package/dist/core/slash-commands.js +0 -1
  197. package/dist/core/slash-commands.js.map +1 -1
  198. package/dist/core/system-prompt.js +7 -7
  199. package/dist/core/system-prompt.js.map +1 -1
  200. package/dist/core/tools/edit.d.ts +1 -1
  201. package/dist/core/tools/edit.d.ts.map +1 -1
  202. package/dist/core/tools/edit.js +128 -3
  203. package/dist/core/tools/edit.js.map +1 -1
  204. package/dist/core/tools/hashline.d.ts +2 -2
  205. package/dist/core/tools/hashline.d.ts.map +1 -1
  206. package/dist/core/tools/hashline.js +40 -10
  207. package/dist/core/tools/hashline.js.map +1 -1
  208. package/dist/core/tools/write.d.ts.map +1 -1
  209. package/dist/core/tools/write.js +8 -8
  210. package/dist/core/tools/write.js.map +1 -1
  211. package/dist/core/workflow-stage-admission.d.ts +6 -0
  212. package/dist/core/workflow-stage-admission.d.ts.map +1 -1
  213. package/dist/core/workflow-stage-admission.js +14 -0
  214. package/dist/core/workflow-stage-admission.js.map +1 -1
  215. package/dist/index-extensions.d.ts +1 -1
  216. package/dist/index-extensions.d.ts.map +1 -1
  217. package/dist/index-extensions.js.map +1 -1
  218. package/dist/index.d.ts +5 -5
  219. package/dist/index.d.ts.map +1 -1
  220. package/dist/index.js +4 -5
  221. package/dist/index.js.map +1 -1
  222. package/dist/modes/interactive/components/atomic-working-status.d.ts +4 -0
  223. package/dist/modes/interactive/components/atomic-working-status.d.ts.map +1 -1
  224. package/dist/modes/interactive/components/atomic-working-status.js +26 -1
  225. package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
  226. package/dist/modes/interactive/components/custom-editor.d.ts +7 -0
  227. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  228. package/dist/modes/interactive/components/custom-editor.js +43 -0
  229. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  230. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/footer.js +0 -6
  232. package/dist/modes/interactive/components/footer.js.map +1 -1
  233. package/dist/modes/interactive/components/index.d.ts +1 -2
  234. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  235. package/dist/modes/interactive/components/index.js +0 -1
  236. package/dist/modes/interactive/components/index.js.map +1 -1
  237. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  238. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  239. package/dist/modes/interactive/components/model-selector.js +6 -11
  240. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  241. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -5
  242. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  243. package/dist/modes/interactive/components/scoped-models-selector.js +3 -19
  244. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  245. package/dist/modes/interactive/components/settings-selector-items.js +1 -1
  246. package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
  247. package/dist/modes/interactive/components/thinking-selector.d.ts +1 -2
  248. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  249. package/dist/modes/interactive/components/thinking-selector.js +4 -11
  250. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  251. package/dist/modes/interactive/components/transcript-follow-indicator.js +3 -3
  252. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
  253. package/dist/modes/interactive/interactive-agent-events.js +8 -8
  254. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  255. package/dist/modes/interactive/interactive-autocomplete.js +5 -16
  256. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  257. package/dist/modes/interactive/interactive-bash-compact.js +2 -9
  258. package/dist/modes/interactive/interactive-bash-compact.js.map +1 -1
  259. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  260. package/dist/modes/interactive/interactive-deferred-startup.js +3 -0
  261. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  262. package/dist/modes/interactive/interactive-editor-actions.js +2 -2
  263. package/dist/modes/interactive/interactive-editor-actions.js.map +1 -1
  264. package/dist/modes/interactive/interactive-extension-custom-ui.js +1 -0
  265. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  266. package/dist/modes/interactive/interactive-extension-dialogs.js +7 -0
  267. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  268. package/dist/modes/interactive/interactive-extension-runtime.js +20 -10
  269. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  270. package/dist/modes/interactive/interactive-hotkeys-debug.js +1 -5
  271. package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
  272. package/dist/modes/interactive/interactive-initial-session-binding.d.ts.map +1 -1
  273. package/dist/modes/interactive/interactive-initial-session-binding.js +3 -0
  274. package/dist/modes/interactive/interactive-initial-session-binding.js.map +1 -1
  275. package/dist/modes/interactive/interactive-input-handling.js +0 -8
  276. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  277. package/dist/modes/interactive/interactive-mode-base.d.ts +5 -1
  278. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  279. package/dist/modes/interactive/interactive-mode-base.js +15 -9
  280. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  281. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -3
  282. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  283. package/dist/modes/interactive/interactive-mode-deps.js +1 -3
  284. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  285. package/dist/modes/interactive/interactive-mode-surface.d.ts +9 -12
  286. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  287. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  288. package/dist/modes/interactive/interactive-model-routing.js +10 -13
  289. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  290. package/dist/modes/interactive/interactive-render-chat.js +29 -0
  291. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  292. package/dist/modes/interactive/interactive-selectors.js +2 -32
  293. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  294. package/dist/modes/interactive/interactive-session-routing.js +1 -5
  295. package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
  296. package/dist/modes/interactive/interactive-session-runtime.js +1 -5
  297. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  298. package/dist/modes/interactive/interactive-slash-commands.js +6 -13
  299. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
  300. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  301. package/dist/modes/interactive/interactive-startup.js +19 -13
  302. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  303. package/dist/modes/interactive/interactive-tui.d.ts.map +1 -1
  304. package/dist/modes/interactive/interactive-tui.js +27 -3
  305. package/dist/modes/interactive/interactive-tui.js.map +1 -1
  306. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  307. package/dist/modes/interactive-engine/engine-custom-ui.js +1 -0
  308. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  309. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  310. package/dist/modes/interactive-engine/isolated-runtime.js +4 -1
  311. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  312. package/dist/utils/child-process.d.ts.map +1 -1
  313. package/dist/utils/child-process.js +13 -6
  314. package/dist/utils/child-process.js.map +1 -1
  315. package/dist/utils/exif-orientation.d.ts.map +1 -1
  316. package/dist/utils/exif-orientation.js +2 -3
  317. package/dist/utils/exif-orientation.js.map +1 -1
  318. package/dist/utils/tools-manager.d.ts +1 -0
  319. package/dist/utils/tools-manager.d.ts.map +1 -1
  320. package/dist/utils/tools-manager.js +33 -18
  321. package/dist/utils/tools-manager.js.map +1 -1
  322. package/docs/custom-provider.md +2 -0
  323. package/docs/development.md +17 -0
  324. package/docs/docs.json +14 -2
  325. package/docs/extensions.md +9 -4
  326. package/docs/intercom.md +41 -7
  327. package/docs/keybindings.md +8 -6
  328. package/docs/models/evals.md +394 -0
  329. package/docs/models/model-selection.md +54 -27
  330. package/docs/models/pareto-efficiency.md +33 -16
  331. package/docs/models.md +37 -1
  332. package/docs/packages.md +2 -2
  333. package/docs/providers.md +44 -20
  334. package/docs/quickstart.md +8 -6
  335. package/docs/rpc.md +3 -3
  336. package/docs/sdk.md +2 -16
  337. package/docs/settings.md +19 -22
  338. package/docs/skills.md +4 -2
  339. package/docs/subagents.md +9 -3
  340. package/docs/tools/edit.md +373 -0
  341. package/docs/tools.md +3 -7
  342. package/docs/tui.md +2 -1
  343. package/docs/usage.md +3 -5
  344. package/docs/workflows/api-reference.md +1395 -0
  345. package/docs/workflows/authoring.md +678 -0
  346. package/docs/workflows/builtins.md +245 -0
  347. package/docs/workflows/operations.md +811 -0
  348. package/docs/workflows/reliable-design.md +2099 -0
  349. package/docs/workflows/verification.md +62 -0
  350. package/docs/workflows.md +15 -5183
  351. package/npm-shrinkwrap.json +584 -69
  352. package/package.json +7 -7
  353. package/dist/client/remote-session.d.ts +0 -64
  354. package/dist/client/remote-session.d.ts.map +0 -1
  355. package/dist/client/remote-session.js +0 -351
  356. package/dist/client/remote-session.js.map +0 -1
  357. package/dist/client/transcript.d.ts +0 -12
  358. package/dist/client/transcript.d.ts.map +0 -1
  359. package/dist/client/transcript.js +0 -98
  360. package/dist/client/transcript.js.map +0 -1
  361. package/dist/core/codex-fast-mode-transport.d.ts +0 -12
  362. package/dist/core/codex-fast-mode-transport.d.ts.map +0 -1
  363. package/dist/core/codex-fast-mode-transport.js.map +0 -1
  364. package/dist/core/codex-fast-mode.d.ts +0 -53
  365. package/dist/core/codex-fast-mode.d.ts.map +0 -1
  366. package/dist/core/codex-fast-mode.js +0 -249
  367. package/dist/core/codex-fast-mode.js.map +0 -1
  368. package/dist/modes/interactive/components/fast-mode-selector.d.ts +0 -27
  369. package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +0 -1
  370. package/dist/modes/interactive/components/fast-mode-selector.js +0 -107
  371. package/dist/modes/interactive/components/fast-mode-selector.js.map +0 -1
  372. package/dist/server/create-harness.d.ts +0 -53
  373. package/dist/server/create-harness.d.ts.map +0 -1
  374. package/dist/server/create-harness.js +0 -360
  375. package/dist/server/create-harness.js.map +0 -1
  376. package/docs/models/artificial-analysis-index.md +0 -83
@@ -219,6 +219,7 @@ class GraphFrontierTracker {
219
219
  nodes = new Map;
220
220
  onSpawn(stageId, stageName) {
221
221
  const parents = Array.from(this.frontier);
222
+ this.assertAcyclicParents(stageId, parents);
222
223
  this.stageParents.set(stageId, parents);
223
224
  this.nodes.set(stageId, {
224
225
  id: stageId,
@@ -232,6 +233,7 @@ class GraphFrontierTracker {
232
233
  }
233
234
  replaceParents(stageId, parentIds) {
234
235
  const parents = Array.from(parentIds);
236
+ this.assertAcyclicParents(stageId, parents);
235
237
  this.stageParents.set(stageId, parents);
236
238
  const node = this.nodes.get(stageId);
237
239
  if (node !== undefined) {
@@ -254,6 +256,19 @@ class GraphFrontierTracker {
254
256
  getParents(stageId) {
255
257
  return this.stageParents.get(stageId) ?? [];
256
258
  }
259
+ assertAcyclicParents(nodeId, parentIds) {
260
+ const pending = [...parentIds];
261
+ const visited = new Set;
262
+ while (pending.length > 0) {
263
+ const parentId = pending.pop();
264
+ if (parentId === nodeId)
265
+ throw new Error(`atomic-workflows: graph cycle at node ${nodeId}`);
266
+ if (visited.has(parentId))
267
+ continue;
268
+ visited.add(parentId);
269
+ pending.push(...this.stageParents.get(parentId) ?? []);
270
+ }
271
+ }
257
272
  reset() {
258
273
  this.frontier.clear();
259
274
  this.stageParents.clear();
@@ -993,6 +1008,96 @@ function queueStageMessage(messages, input, senderGroup, runGroup, stageIdentity
993
1008
  deduplicated: false
994
1009
  };
995
1010
  }
1011
+ function queueStickyStageMessage(messages, input, senderGroup, runGroup) {
1012
+ if (normalizeDeliveryGroup(senderGroup) !== normalizeDeliveryGroup(runGroup)) {
1013
+ return { ok: false, reason: "group_mismatch", runId: input.runId, stageKey: input.targetPath };
1014
+ }
1015
+ const messageId = input.message.id;
1016
+ const existing = messages.find((entry2) => entry2.runId === input.runId && entry2.id === messageId);
1017
+ if (existing !== undefined) {
1018
+ if (pendingStageMessageSignature(existing) !== pendingStageMessageSignature(input)) {
1019
+ return {
1020
+ ok: false,
1021
+ reason: "message_id_conflict",
1022
+ runId: input.runId,
1023
+ stageKey: input.targetPath,
1024
+ messageId
1025
+ };
1026
+ }
1027
+ const queuedForTarget = queuedStickyCount(messages, input.runId, input.targetPath);
1028
+ return {
1029
+ ok: true,
1030
+ messages,
1031
+ entry: existing,
1032
+ ...existing.status === "queued" ? { position: queuedForTarget } : {},
1033
+ deduplicated: true
1034
+ };
1035
+ }
1036
+ if (queuedStickyCount(messages, input.runId, input.targetPath) >= PENDING_STAGE_MESSAGE_LIMIT) {
1037
+ return {
1038
+ ok: false,
1039
+ reason: "capacity",
1040
+ limit: PENDING_STAGE_MESSAGE_LIMIT,
1041
+ runId: input.runId,
1042
+ stageKey: input.targetPath
1043
+ };
1044
+ }
1045
+ const entry = {
1046
+ ...input,
1047
+ id: messageId,
1048
+ stageKey: input.targetPath,
1049
+ sticky: true,
1050
+ deliveries: [],
1051
+ deliveryCount: 0,
1052
+ admissionOrder: nextAdmissionOrder(messages, input.runId),
1053
+ status: "queued"
1054
+ };
1055
+ return {
1056
+ ok: true,
1057
+ messages: [...messages, entry],
1058
+ entry,
1059
+ position: queuedStickyCount(messages, input.runId, input.targetPath) + 1,
1060
+ deduplicated: false
1061
+ };
1062
+ }
1063
+ function queuedStickyCount(messages, runId, targetPath) {
1064
+ return messages.filter((entry) => entry.runId === runId && entry.sticky === true && entry.targetPath === targetPath && entry.status === "queued").length;
1065
+ }
1066
+ function recordPendingStageMessageDeliveries(messages, runId, messageId, records, deliveredAt) {
1067
+ const index = messages.findIndex((entry2) => entry2.runId === runId && entry2.id === messageId && entry2.sticky === true && entry2.status === "queued");
1068
+ if (index < 0)
1069
+ return messages;
1070
+ const entry = messages[index];
1071
+ const recorded = new Set((entry.deliveries ?? []).map((delivery) => `${delivery.runId}\x00${delivery.stageId}`));
1072
+ const additions = [];
1073
+ for (const record of records) {
1074
+ const key = `${record.runId}\x00${record.stageId}`;
1075
+ if (recorded.has(key))
1076
+ continue;
1077
+ recorded.add(key);
1078
+ additions.push({
1079
+ runId: record.runId,
1080
+ stageId: record.stageId,
1081
+ ...record.stageName === undefined ? {} : { stageName: record.stageName },
1082
+ deliveredAt
1083
+ });
1084
+ }
1085
+ if (additions.length === 0)
1086
+ return messages;
1087
+ const deliveries = [...entry.deliveries ?? [], ...additions];
1088
+ const next = { ...entry, deliveries, deliveryCount: deliveries.length };
1089
+ const result = [...messages];
1090
+ result[index] = next;
1091
+ return result;
1092
+ }
1093
+ function settleStickyPendingStageMessageDelivered(messages, runId, messageId, settledAt) {
1094
+ const index = messages.findIndex((entry) => entry.runId === runId && entry.id === messageId && entry.sticky === true && entry.status === "queued" && (entry.deliveryCount ?? 0) > 0);
1095
+ if (index < 0)
1096
+ return messages;
1097
+ const next = [...messages];
1098
+ next[index] = { ...next[index], status: "delivered", deliveredAt: settledAt };
1099
+ return next;
1100
+ }
996
1101
  function pendingStageMessagesFor(messages, runId, stageKey, stageIdentity) {
997
1102
  return messages.map((entry, index) => ({ entry, index })).filter(({ entry }) => matchesPendingStage(entry, runId, stageKey, stageIdentity) && entry.status === "queued").sort((left, right) => (left.entry.admissionOrder ?? left.index + 1) - (right.entry.admissionOrder ?? right.index + 1) || left.index - right.index).map(({ entry }) => entry);
998
1103
  }
@@ -1012,7 +1117,7 @@ function markPendingStageMessageUndeliverable(messages, runId, stageKey, message
1012
1117
  }));
1013
1118
  }
1014
1119
  function markPendingStageMessageUndeliverableNotified(messages, runId, stageKey, messageId, notificationId, notifiedAt) {
1015
- const index = messages.findIndex((entry) => matchesPendingStage(entry, runId, stageKey) && entry.id === messageId && entry.status === "undeliverable" && entry.undeliverableNotificationId === notificationId && entry.undeliverableNotifiedAt === undefined);
1120
+ const index = messages.findIndex((entry) => (entry.sticky === true ? entry.runId === runId : matchesPendingStage(entry, runId, stageKey)) && entry.id === messageId && entry.status === "undeliverable" && entry.undeliverableNotificationId === notificationId && entry.undeliverableNotifiedAt === undefined);
1016
1121
  if (index < 0)
1017
1122
  return messages;
1018
1123
  const next = [...messages];
@@ -1028,14 +1133,21 @@ function pendingStageUndeliverableNotificationId(entry) {
1028
1133
  ].join(":");
1029
1134
  }
1030
1135
  function updateQueuedPendingStageMessage(messages, runId, stageKey, messageId, stageIdentity, update) {
1031
- const index = messages.findIndex((entry) => matchesPendingStage(entry, runId, stageKey, stageIdentity) && entry.id === messageId && entry.status === "queued");
1136
+ const index = messages.findIndex((entry) => queuedEntryMatches(entry, runId, stageKey, messageId, stageIdentity));
1032
1137
  if (index < 0)
1033
1138
  return messages;
1034
1139
  const next = [...messages];
1035
1140
  next[index] = update(next[index]);
1036
1141
  return next;
1037
1142
  }
1143
+ function queuedEntryMatches(entry, runId, stageKey, messageId, stageIdentity) {
1144
+ if (entry.runId !== runId || entry.id !== messageId || entry.status !== "queued")
1145
+ return false;
1146
+ return entry.sticky === true || matchesPendingStage(entry, runId, stageKey, stageIdentity);
1147
+ }
1038
1148
  function matchesPendingStage(entry, runId, stageKey, stageIdentity) {
1149
+ if (entry.sticky === true)
1150
+ return false;
1039
1151
  if (entry.runId !== runId)
1040
1152
  return false;
1041
1153
  if (stageIdentity === undefined)
@@ -1753,6 +1865,50 @@ function createPendingStageDeliveryStoreMethods(context) {
1753
1865
  context.bumpAndNotify();
1754
1866
  return true;
1755
1867
  });
1868
+ },
1869
+ async queueStickyStageMessage(input, senderGroup, runGroup, backend) {
1870
+ return await serialize(input.runId, async () => {
1871
+ const run = context.findRun(input.runId);
1872
+ if (run === undefined)
1873
+ return;
1874
+ const result = queueStickyStageMessage(run.pendingStageMessages ?? [], input, senderGroup, runGroup);
1875
+ if (result.ok && !result.deduplicated) {
1876
+ await persistTransition(backend, input.runId, result.messages);
1877
+ run.pendingStageMessages = [...result.messages];
1878
+ context.bumpAndNotify();
1879
+ }
1880
+ return result;
1881
+ });
1882
+ },
1883
+ async recordPendingStageMessageDeliveries(runId, messageId, records, deliveredAt, backend) {
1884
+ return await serialize(runId, async () => {
1885
+ const run = context.findRun(runId);
1886
+ if (run === undefined)
1887
+ return false;
1888
+ const current = run.pendingStageMessages ?? [];
1889
+ const next = recordPendingStageMessageDeliveries(current, runId, messageId, records, deliveredAt);
1890
+ if (next === current)
1891
+ return false;
1892
+ await persistTransition(backend, runId, next);
1893
+ run.pendingStageMessages = [...next];
1894
+ context.bumpAndNotify();
1895
+ return true;
1896
+ });
1897
+ },
1898
+ async settleStickyPendingStageMessageDelivered(runId, messageId, settledAt, backend) {
1899
+ return await serialize(runId, async () => {
1900
+ const run = context.findRun(runId);
1901
+ if (run === undefined)
1902
+ return false;
1903
+ const current = run.pendingStageMessages ?? [];
1904
+ const next = settleStickyPendingStageMessageDelivered(current, runId, messageId, settledAt);
1905
+ if (next === current)
1906
+ return false;
1907
+ await persistTransition(backend, runId, next);
1908
+ run.pendingStageMessages = [...next];
1909
+ context.bumpAndNotify();
1910
+ return true;
1911
+ });
1756
1912
  }
1757
1913
  };
1758
1914
  }
@@ -4472,7 +4628,6 @@ function durableStageCheckpointMetadata(stage, run, sourceOrder) {
4472
4628
  ...stage.sessionFile !== undefined ? { sessionFile: stage.sessionFile } : {},
4473
4629
  ...stage.durationMs !== undefined ? { durationMs: stage.durationMs } : {},
4474
4630
  ...stage.model !== undefined ? { model: stage.model } : {},
4475
- ...stage.fastMode !== undefined ? { fastMode: stage.fastMode } : {},
4476
4631
  ...stage.attemptedModels !== undefined ? { attemptedModels: [...stage.attemptedModels] } : {},
4477
4632
  ...stage.modelAttempts !== undefined ? { modelAttempts: [...stage.modelAttempts] } : {},
4478
4633
  ...stage.structured !== undefined ? { structured: stage.structured } : {},
@@ -4484,6 +4639,57 @@ function durableStageCheckpointMetadata(stage, run, sourceOrder) {
4484
4639
  // dist/builtin/workflows/src/durable/tool-primitive.ts
4485
4640
  import { runCallback } from "@bastani/atomic";
4486
4641
 
4642
+ // dist/builtin/workflows/src/engine/workflow-tool-abort.ts
4643
+ class WorkflowToolAbortError extends Error {
4644
+ runId;
4645
+ nodeId;
4646
+ toolName;
4647
+ scope;
4648
+ constructor(input) {
4649
+ super(`atomic-workflows: ctx.tool ${input.toolName} aborted by ${input.scope === "quit" ? "workflow quit" : "node abort"}`);
4650
+ this.name = "AbortError";
4651
+ this.runId = input.runId;
4652
+ this.nodeId = input.nodeId;
4653
+ this.toolName = input.toolName;
4654
+ this.scope = input.scope;
4655
+ }
4656
+ }
4657
+ function isWorkflowToolAbortError(value) {
4658
+ return value instanceof WorkflowToolAbortError;
4659
+ }
4660
+ var WORKFLOW_GRACEFUL_QUIT_EXIT_REASON = "quit";
4661
+
4662
+ class WorkflowGracefulQuitError extends Error {
4663
+ runId;
4664
+ constructor(runId, detail) {
4665
+ super(`atomic-workflows: ${detail} suspended by workflow quit`);
4666
+ this.name = "AbortError";
4667
+ this.runId = runId;
4668
+ }
4669
+ }
4670
+ function isGracefulQuitSignal(value) {
4671
+ if (value instanceof WorkflowGracefulQuitError)
4672
+ return true;
4673
+ return isWorkflowToolAbortError(value) && value.scope === "quit";
4674
+ }
4675
+ function findWorkflowGracefulQuit(value) {
4676
+ let current = value;
4677
+ for (let depth = 0;depth < 8; depth++) {
4678
+ if (isGracefulQuitSignal(current))
4679
+ return current;
4680
+ if (typeof current !== "object" || current === null)
4681
+ return;
4682
+ try {
4683
+ if (!("cause" in current))
4684
+ return;
4685
+ current = current.cause;
4686
+ } catch {
4687
+ return;
4688
+ }
4689
+ }
4690
+ return;
4691
+ }
4692
+
4487
4693
  // dist/builtin/workflows/src/runs/shared/retry.ts
4488
4694
  import { nextRetryDecision } from "@bastani/atomic";
4489
4695
  function abortReason(signal) {
@@ -4519,7 +4725,7 @@ function sleepOrAbort(ms, signal) {
4519
4725
  });
4520
4726
  }
4521
4727
  // dist/builtin/workflows/src/durable/tool-failure-checkpoint.ts
4522
- async function recordThrowingToolFailure(input, node, identity, error, attempts) {
4728
+ async function recordThrowingToolFailure(input, node, identity, error, attempts, cancelled = false) {
4523
4729
  const message = workflowToolFailure(error, attempts, false).error.message;
4524
4730
  const failedAt = Date.now();
4525
4731
  await input.backend.recordAdditiveCheckpointBestEffort({
@@ -4532,6 +4738,7 @@ async function recordThrowingToolFailure(input, node, identity, error, attempts)
4532
4738
  argsHash: identity.argsHash,
4533
4739
  output: null,
4534
4740
  throwingFailureError: message,
4741
+ ...cancelled ? { cancelled: true } : {},
4535
4742
  completedAt: failedAt,
4536
4743
  topology: {
4537
4744
  version: DURABLE_TOOL_TOPOLOGY_VERSION,
@@ -4837,7 +5044,7 @@ async function executeLiveToolInvocation(live) {
4837
5044
  const cancellation = timeoutFailure ? undefined : invocationCancellation(input, toolSignal);
4838
5045
  if (cancellation !== undefined) {
4839
5046
  control.noteCancelled();
4840
- if (returnFailure) {
5047
+ if (returnFailure || isWorkflowToolAbortError(cancellation) && cancellation.scope === "node") {
4841
5048
  await recordCancelledToolInspection(live, startedAt, cancellation, attempts);
4842
5049
  }
4843
5050
  const endedAt = Date.now();
@@ -4939,7 +5146,7 @@ async function recordCancelledToolInspection(live, startedAt, cancellation, atte
4939
5146
  argsHash: live.argsHash,
4940
5147
  ordinal: live.ordinal,
4941
5148
  startedAt
4942
- }, cancellation, attempts);
5149
+ }, cancellation, attempts, true);
4943
5150
  } catch {}
4944
5151
  }
4945
5152
  function invocationCancellation(input, signal) {
@@ -5346,7 +5553,6 @@ function completeTaskResult(name, base, checkpoint) {
5346
5553
  ...base.sessionFile !== undefined || checkpoint.sessionFile !== undefined ? { sessionFile: base.sessionFile ?? checkpoint.sessionFile } : {},
5347
5554
  ...base.artifacts !== undefined || checkpoint.artifacts !== undefined ? { artifacts: [...base.artifacts ?? checkpoint.artifacts ?? []] } : {},
5348
5555
  ...base.model !== undefined || checkpoint.model !== undefined ? { model: base.model ?? checkpoint.model } : {},
5349
- ...base.fastMode !== undefined || checkpoint.fastMode !== undefined ? { fastMode: base.fastMode ?? checkpoint.fastMode } : {},
5350
5556
  ...base.attemptedModels !== undefined || checkpoint.attemptedModels !== undefined ? { attemptedModels: [...base.attemptedModels ?? checkpoint.attemptedModels ?? []] } : {},
5351
5557
  ...base.modelAttempts !== undefined || checkpoint.modelAttempts !== undefined ? { modelAttempts: [...base.modelAttempts ?? checkpoint.modelAttempts ?? []] } : {},
5352
5558
  ...base.warnings !== undefined || checkpoint.warnings !== undefined ? { warnings: [...base.warnings ?? checkpoint.warnings ?? []] } : {}
@@ -5447,7 +5653,6 @@ function taskCheckpointMetadata(result) {
5447
5653
  ...result.sessionId !== undefined ? { sessionId: result.sessionId } : {},
5448
5654
  ...result.sessionFile !== undefined ? { sessionFile: result.sessionFile } : {},
5449
5655
  ...result.model !== undefined ? { model: result.model } : {},
5450
- ...result.fastMode !== undefined ? { fastMode: result.fastMode } : {},
5451
5656
  ...result.attemptedModels !== undefined ? { attemptedModels: [...result.attemptedModels] } : {},
5452
5657
  ...result.modelAttempts !== undefined ? { modelAttempts: [...result.modelAttempts] } : {},
5453
5658
  ...result.structured !== undefined ? { structured: result.structured } : {},
@@ -5477,7 +5682,6 @@ function mergeCheckpointHydrationMetadata(replayValueCheckpoint, checkpoints) {
5477
5682
  ...replayValueCheckpoint.sessionId === undefined ? metadataValue(checkpoints, "sessionId") : {},
5478
5683
  ...replayValueCheckpoint.sessionFile === undefined ? metadataValue(checkpoints, "sessionFile") : {},
5479
5684
  ...replayValueCheckpoint.model === undefined ? metadataValue(checkpoints, "model") : {},
5480
- ...replayValueCheckpoint.fastMode === undefined ? metadataValue(checkpoints, "fastMode") : {},
5481
5685
  ...replayValueCheckpoint.attemptedModels === undefined ? metadataValue(checkpoints, "attemptedModels") : {},
5482
5686
  ...replayValueCheckpoint.modelAttempts === undefined ? metadataValue(checkpoints, "modelAttempts") : {},
5483
5687
  ...replayValueCheckpoint.structured === undefined ? metadataValue(checkpoints, "structured") : {},
@@ -5567,7 +5771,6 @@ function recordCachedStageIntoStore(store2, runId, name, replayKey, output, comp
5567
5771
  ...checkpoint?.sessionId !== undefined ? { sessionId: checkpoint.sessionId } : {},
5568
5772
  ...checkpoint?.sessionFile !== undefined ? { sessionFile: checkpoint.sessionFile } : {},
5569
5773
  ...checkpoint?.model !== undefined ? { model: checkpoint.model } : {},
5570
- ...checkpoint?.fastMode !== undefined ? { fastMode: checkpoint.fastMode } : {},
5571
5774
  ...checkpoint?.attemptedModels !== undefined ? { attemptedModels: checkpoint.attemptedModels } : {},
5572
5775
  ...checkpoint?.modelAttempts !== undefined ? { modelAttempts: checkpoint.modelAttempts } : {},
5573
5776
  ...checkpoint?.structured !== undefined ? { structured: checkpoint.structured } : {},
@@ -5670,6 +5873,49 @@ function hasInvocationData(checkpoints, replayKey) {
5670
5873
  return checkpoints.some((checkpoint) => checkpoint.kind === "stage" ? checkpoint.replayKey === replayKey || checkpoint.replayKey.startsWith(prefix) : checkpoint.checkpointId.startsWith(prefix));
5671
5874
  }
5672
5875
 
5876
+ // dist/builtin/workflows/src/durable/backend-process-owner.ts
5877
+ var DURABLE_BACKEND_PROCESS_OWNER_KEY = Symbol.for("atomic-workflows/durable-backend-process-owner@1");
5878
+ function emptyOwner() {
5879
+ return {
5880
+ version: 1,
5881
+ injectedBackend: undefined,
5882
+ initializedBackend: undefined,
5883
+ initializing: undefined,
5884
+ warningSink: undefined,
5885
+ warningReported: false
5886
+ };
5887
+ }
5888
+ function ownerBag() {
5889
+ return globalThis;
5890
+ }
5891
+ function getDurableBackendProcessOwner() {
5892
+ const bag = ownerBag();
5893
+ const existing = bag[DURABLE_BACKEND_PROCESS_OWNER_KEY];
5894
+ if (existing !== undefined && existing.version === 1)
5895
+ return existing;
5896
+ const created = emptyOwner();
5897
+ bag[DURABLE_BACKEND_PROCESS_OWNER_KEY] = created;
5898
+ return created;
5899
+ }
5900
+
5901
+ // dist/builtin/workflows/src/shared/possible-stages.ts
5902
+ var BUILTIN_BARREL_SPECIFIERS = new Set([
5903
+ "@bastani/atomic/workflows/builtin",
5904
+ "@bastani/workflows/builtin"
5905
+ ]);
5906
+ var TRACKED_NODE_METHODS = new Set(["stage", "task", "chain", "parallel", "workflow", "tool"]);
5907
+ function coercePossibleStages(value) {
5908
+ if (!Array.isArray(value))
5909
+ return;
5910
+ const stages = [];
5911
+ for (const entry of value) {
5912
+ if (typeof entry !== "string")
5913
+ return;
5914
+ stages.push(entry);
5915
+ }
5916
+ return stages;
5917
+ }
5918
+
5673
5919
  // dist/builtin/workflows/src/shared/workflow-failures-contract.ts
5674
5920
  var WORKFLOW_AUTH_FAILURE_MESSAGE = "You must be logged in to run workflows. Run /login and try again.";
5675
5921
  var WORKFLOW_MISSING_API_KEY_FAILURE_MESSAGE = "A required model provider API key is missing. Configure the provider credentials and resume the workflow.";
@@ -6223,7 +6469,7 @@ function classifyWorkflowFailure(error) {
6223
6469
  }
6224
6470
  // dist/builtin/workflows/src/durable/dbos-process-owner.ts
6225
6471
  var DBOS_PROCESS_OWNER_KEY = Symbol.for("atomic-workflows/dbos-process-owner@1");
6226
- function emptyOwner() {
6472
+ function emptyOwner2() {
6227
6473
  return {
6228
6474
  version: 1,
6229
6475
  state: "uninitialized",
@@ -6235,15 +6481,15 @@ function emptyOwner() {
6235
6481
  wrappers: undefined
6236
6482
  };
6237
6483
  }
6238
- function ownerBag() {
6484
+ function ownerBag2() {
6239
6485
  return globalThis;
6240
6486
  }
6241
6487
  function getDbosProcessOwner() {
6242
- const bag = ownerBag();
6488
+ const bag = ownerBag2();
6243
6489
  const existing = bag[DBOS_PROCESS_OWNER_KEY];
6244
6490
  if (existing !== undefined && existing.version === 1)
6245
6491
  return existing;
6246
- const created = emptyOwner();
6492
+ const created = emptyOwner2();
6247
6493
  bag[DBOS_PROCESS_OWNER_KEY] = created;
6248
6494
  return created;
6249
6495
  }
@@ -6290,14 +6536,13 @@ function dbosLifecycleState() {
6290
6536
  }
6291
6537
 
6292
6538
  // dist/builtin/workflows/src/durable/factory.ts
6293
- var injectedBackend;
6294
- var initializedBackend;
6295
6539
  function isMemoizedBackendUsable(backend) {
6296
6540
  return !backend.persistent || dbosLifecycleState() === "ready";
6297
6541
  }
6298
6542
  function getDurableBackend() {
6299
- const memoized = initializedBackend !== undefined && isMemoizedBackendUsable(initializedBackend) ? initializedBackend : undefined;
6300
- const backend = injectedBackend ?? memoized ?? getReadyDbosBackendSync();
6543
+ const owner2 = getDurableBackendProcessOwner();
6544
+ const memoized = owner2.initializedBackend !== undefined && isMemoizedBackendUsable(owner2.initializedBackend) ? owner2.initializedBackend : undefined;
6545
+ const backend = owner2.injectedBackend ?? memoized ?? getReadyDbosBackendSync();
6301
6546
  if (backend === undefined)
6302
6547
  throw new DbosNotReadyError;
6303
6548
  return backend;
@@ -6638,7 +6883,7 @@ function stripOnePrefix(value, prefix) {
6638
6883
 
6639
6884
  // dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
6640
6885
  import { isAbsolute as isAbsolute7, join as join8, resolve as resolve8 } from "node:path";
6641
- import { CONFIG_DIR_NAME, isCodexFastModeCandidateModelId } from "@bastani/atomic";
6886
+ import { CONFIG_DIR_NAME } from "@bastani/atomic";
6642
6887
 
6643
6888
  // dist/builtin/workflows/src/shared/workflow-artifacts.ts
6644
6889
  import { mkdir, readdir, rm, stat } from "node:fs/promises";
@@ -6809,261 +7054,60 @@ async function ensureWorkflowArtifactRunDirectory(runId) {
6809
7054
  return directory;
6810
7055
  }
6811
7056
 
6812
- // dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts
6813
- function makeCandidate(id, value, level) {
7057
+ // dist/builtin/workflows/src/runs/shared/worktree-git.ts
7058
+ import * as fs3 from "node:fs";
7059
+ import * as path3 from "node:path";
7060
+
7061
+ // dist/builtin/workflows/src/runs/shared/worktree-generation.ts
7062
+ import * as fs from "node:fs";
7063
+ import * as path from "node:path";
7064
+ function sameFileIdentity(left, right) {
7065
+ return left.dev === right.dev && left.ino === right.ino;
7066
+ }
7067
+ function openMainCheckoutAnchor(gitDir) {
7068
+ let disposed = false;
6814
7069
  return {
6815
- id,
6816
- value,
6817
- ...level !== undefined ? { reasoningLevel: level } : {}
7070
+ assertCurrent() {
7071
+ if (disposed)
7072
+ throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
7073
+ if (!fs.lstatSync(gitDir).isDirectory()) {
7074
+ throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
7075
+ }
7076
+ },
7077
+ dispose() {
7078
+ disposed = true;
7079
+ }
6818
7080
  };
6819
7081
  }
6820
- var WORKFLOW_THINKING_LEVELS = [
6821
- "off",
6822
- "minimal",
6823
- "low",
6824
- "medium",
6825
- "high",
6826
- "xhigh",
6827
- "max"
6828
- ];
6829
- var WORKFLOW_THINKING_LEVEL_SET = new Set(WORKFLOW_THINKING_LEVELS);
6830
- function splitReasoningSuffix(model) {
6831
- const index = model.lastIndexOf(":");
6832
- if (index < 0)
6833
- return { baseModel: model };
6834
- const suffix = model.slice(index + 1);
6835
- if (WORKFLOW_THINKING_LEVEL_SET.has(suffix)) {
6836
- return { baseModel: model.slice(0, index), level: suffix };
6837
- }
6838
- return { baseModel: model };
6839
- }
6840
- function candidateKey(candidate) {
6841
- return `${candidate.id}::${candidate.reasoningLevel ?? ""}`;
6842
- }
6843
-
6844
- class WorkflowModelValidationError extends Error {
6845
- failures;
6846
- constructor(failures) {
6847
- super(formatModelValidationError(failures));
6848
- this.name = "WorkflowModelValidationError";
6849
- this.failures = failures;
6850
- }
6851
- }
6852
- function formatModelValidationError(failures) {
6853
- const lines = ["workflows: model validation failed before starting workflow.", "Unavailable or ambiguous models:"];
6854
- for (const failure2 of failures) {
6855
- lines.push(`- ${failure2.input} (${failure2.reason})`);
6856
- }
6857
- return lines.join(`
6858
- `);
6859
- }
6860
- function isModelObject(value) {
6861
- return typeof value !== "string";
6862
- }
6863
- function workflowModelId(value) {
6864
- if (value === undefined)
6865
- return;
6866
- if (typeof value === "string") {
6867
- const trimmed = value.trim();
6868
- return trimmed.length === 0 ? undefined : trimmed;
6869
- }
6870
- return `${String(value.provider)}/${value.id}`;
6871
- }
6872
- function normalizeInfo(info) {
6873
- const fullId = info.fullId.trim().length > 0 ? info.fullId : `${info.provider}/${info.id}`;
6874
- return { ...info, fullId };
6875
- }
6876
- function uniqueByFullId(models) {
6877
- const seen = new Set;
6878
- const result = [];
6879
- for (const info of models.map(normalizeInfo)) {
6880
- if (seen.has(info.fullId))
6881
- continue;
6882
- seen.add(info.fullId);
6883
- result.push(info);
6884
- }
6885
- return result;
6886
- }
6887
- function resolveStringModel(rawInput, availableModels, preferredProvider) {
6888
- const input = rawInput.trim();
6889
- if (!input)
6890
- return { input: rawInput, reason: "empty model id" };
6891
- const { baseModel, level } = splitReasoningSuffix(input);
6892
- const candidate = (id, value) => makeCandidate(id, value, level);
6893
- if (availableModels === undefined) {
6894
- return candidate(baseModel, baseModel);
6895
- }
6896
- const models = uniqueByFullId(availableModels);
6897
- const explicit = models.find((model) => model.fullId === baseModel);
6898
- if (explicit !== undefined) {
6899
- return candidate(explicit.fullId, explicit.model ?? explicit.fullId);
6900
- }
6901
- if (baseModel.includes("/")) {
6902
- return candidate(baseModel, baseModel);
6903
- }
6904
- const byBareId = models.filter((model) => model.id === baseModel);
6905
- if (byBareId.length === 0) {
6906
- return { input, reason: "not available" };
6907
- }
6908
- if (byBareId.length === 1) {
6909
- const only = byBareId[0];
6910
- return candidate(only.fullId, only.model ?? only.fullId);
6911
- }
6912
- const preferred = preferredProvider === undefined ? undefined : byBareId.find((model) => model.provider === preferredProvider);
6913
- if (preferred !== undefined) {
6914
- return candidate(preferred.fullId, preferred.model ?? preferred.fullId);
6915
- }
6916
- return {
6917
- input,
6918
- reason: `ambiguous: ${byBareId.map((model) => model.fullId).join(", ")}; specify provider/model`
6919
- };
6920
- }
6921
- function resolveModelValue(value, availableModels, preferredProvider) {
6922
- if (isModelObject(value)) {
6923
- return { id: workflowModelId(value), value };
6924
- }
6925
- return resolveStringModel(value, availableModels, preferredProvider);
6926
- }
6927
- function isFailure(value) {
6928
- return "reason" in value;
6929
- }
6930
- function buildModelCandidates(input) {
6931
- const rawValues = [];
6932
- if (input.primaryModel !== undefined)
6933
- rawValues.push(input.primaryModel);
6934
- for (const [index, fallback] of (input.fallbackModels ?? []).entries()) {
6935
- const trimmedFallback = fallback.trim();
6936
- const split = splitReasoningSuffix(trimmedFallback);
6937
- const compatLevel = input.fallbackThinkingLevels?.[index];
6938
- if (split.level === undefined && compatLevel !== undefined) {
6939
- if (!WORKFLOW_THINKING_LEVEL_SET.has(compatLevel)) {
6940
- throw new WorkflowModelValidationError([
6941
- {
6942
- input: trimmedFallback,
6943
- reason: `invalid fallbackThinkingLevels[${index}] "${compatLevel}"; expected one of ${WORKFLOW_THINKING_LEVELS.join(", ")}`
6944
- }
6945
- ]);
6946
- }
6947
- rawValues.push(`${trimmedFallback}:${compatLevel}`);
6948
- } else {
6949
- rawValues.push(trimmedFallback);
6950
- }
6951
- }
6952
- if (input.currentModel !== undefined)
6953
- rawValues.push(input.currentModel);
6954
- const failures = [];
6955
- const seen = new Set;
6956
- const candidates = [];
6957
- for (const value of rawValues) {
6958
- const resolved = resolveModelValue(value, input.availableModels, input.preferredProvider);
6959
- if (isFailure(resolved)) {
6960
- failures.push(resolved);
6961
- continue;
6962
- }
6963
- const key2 = candidateKey(resolved);
6964
- if (seen.has(key2))
6965
- continue;
6966
- seen.add(key2);
6967
- candidates.push(resolved);
6968
- }
6969
- if (failures.length > 0)
6970
- throw new WorkflowModelValidationError(failures);
6971
- return candidates;
6972
- }
6973
- function catalogUnavailableWarning() {
6974
- return "workflows: model catalog unavailable; using the current selected model for fallback validation.";
6975
- }
6976
- async function buildModelCandidatesFromCatalog(input) {
6977
- const hasExplicitModel = input.primaryModel !== undefined || (input.fallbackModels?.length ?? 0) > 0;
6978
- if (!hasExplicitModel)
6979
- return [];
6980
- if (input.catalog === undefined) {
6981
- return buildModelCandidates({
6982
- primaryModel: input.primaryModel,
6983
- fallbackModels: input.fallbackModels,
6984
- fallbackThinkingLevels: input.fallbackThinkingLevels
6985
- });
6986
- }
6987
- try {
6988
- const availableModels = await input.catalog.listModels();
6989
- return buildModelCandidates({
6990
- primaryModel: input.primaryModel,
6991
- fallbackModels: input.fallbackModels,
6992
- fallbackThinkingLevels: input.fallbackThinkingLevels,
6993
- currentModel: input.catalog.currentModel,
6994
- availableModels,
6995
- preferredProvider: input.catalog.preferredProvider
6996
- });
6997
- } catch (err) {
6998
- if (input.catalog.currentModel === undefined) {
6999
- throw err;
7000
- }
7001
- input.catalog.recordWarning?.(catalogUnavailableWarning());
7002
- return buildModelCandidates({ currentModel: input.catalog.currentModel });
7003
- }
7004
- }
7005
- // dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts
7006
- import {
7007
- errorMessage as errorMessage2,
7008
- isRetryableModelFailure,
7009
- isRetryableSameModelFailure,
7010
- modelFailureMessage,
7011
- normalizeModelFailureSignal
7012
- } from "@bastani/atomic";
7013
- // dist/builtin/workflows/src/runs/shared/worktree-git.ts
7014
- import * as fs3 from "node:fs";
7015
- import * as path3 from "node:path";
7016
-
7017
- // dist/builtin/workflows/src/runs/shared/worktree-generation.ts
7018
- import * as fs from "node:fs";
7019
- import * as path from "node:path";
7020
- function sameFileIdentity(left, right) {
7021
- return left.dev === right.dev && left.ino === right.ino;
7022
- }
7023
- function openMainCheckoutAnchor(gitDir) {
7024
- let disposed = false;
7025
- return {
7026
- assertCurrent() {
7027
- if (disposed)
7028
- throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
7029
- if (!fs.lstatSync(gitDir).isDirectory()) {
7030
- throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
7031
- }
7032
- },
7033
- dispose() {
7034
- disposed = true;
7035
- }
7036
- };
7037
- }
7038
- function openGitWorktreeGenerationAnchor(worktreeRoot) {
7039
- const gitFile = path.join(worktreeRoot, ".git");
7040
- if (fs.lstatSync(gitFile).isDirectory())
7041
- return openMainCheckoutAnchor(gitFile);
7042
- const descriptor = fs.openSync(gitFile, "r");
7043
- let disposed = false;
7044
- const anchor = {
7045
- assertCurrent() {
7046
- if (disposed)
7047
- throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
7048
- const held = fs.fstatSync(descriptor, { bigint: true });
7049
- const current = fs.lstatSync(gitFile, { bigint: true });
7050
- if (!current.isFile() || !sameFileIdentity(held, current)) {
7051
- throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
7052
- }
7053
- },
7054
- dispose() {
7055
- if (disposed)
7056
- return;
7057
- disposed = true;
7058
- fs.closeSync(descriptor);
7059
- }
7060
- };
7061
- try {
7062
- anchor.assertCurrent();
7063
- return anchor;
7064
- } catch (error) {
7065
- anchor.dispose();
7066
- throw error;
7082
+ function openGitWorktreeGenerationAnchor(worktreeRoot) {
7083
+ const gitFile = path.join(worktreeRoot, ".git");
7084
+ if (fs.lstatSync(gitFile).isDirectory())
7085
+ return openMainCheckoutAnchor(gitFile);
7086
+ const descriptor = fs.openSync(gitFile, "r");
7087
+ let disposed = false;
7088
+ const anchor = {
7089
+ assertCurrent() {
7090
+ if (disposed)
7091
+ throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
7092
+ const held = fs.fstatSync(descriptor, { bigint: true });
7093
+ const current = fs.lstatSync(gitFile, { bigint: true });
7094
+ if (!current.isFile() || !sameFileIdentity(held, current)) {
7095
+ throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
7096
+ }
7097
+ },
7098
+ dispose() {
7099
+ if (disposed)
7100
+ return;
7101
+ disposed = true;
7102
+ fs.closeSync(descriptor);
7103
+ }
7104
+ };
7105
+ try {
7106
+ anchor.assertCurrent();
7107
+ return anchor;
7108
+ } catch (error) {
7109
+ anchor.dispose();
7110
+ throw error;
7067
7111
  }
7068
7112
  }
7069
7113
 
@@ -8561,24 +8605,6 @@ function cleanupPreparedWorktrees(prepared) {
8561
8605
  if (prepared.setup !== undefined)
8562
8606
  cleanupWorktrees(prepared.setup);
8563
8607
  }
8564
- async function hasExplicitFastModeCandidate(input) {
8565
- const rawCandidate = isCodexFastModeCandidate(input.model) || Array.isArray(input.fallbackModels) && input.fallbackModels.some((candidate) => isCodexFastModeCandidate(candidate));
8566
- if (rawCandidate)
8567
- return true;
8568
- try {
8569
- const candidates = await buildModelCandidatesFromCatalog({
8570
- primaryModel: input.model,
8571
- fallbackModels: input.fallbackModels,
8572
- catalog: input.models
8573
- });
8574
- return candidates.some((candidate) => isCodexFastModeCandidate(candidate.id));
8575
- } catch {
8576
- return false;
8577
- }
8578
- }
8579
- function isCodexFastModeCandidate(model) {
8580
- return isCodexFastModeCandidateModelId(workflowModelId(model));
8581
- }
8582
8608
 
8583
8609
  // dist/builtin/workflows/src/shared/persistence-session-entries.ts
8584
8610
  function appendRunStart(api, payload) {
@@ -8925,24 +8951,24 @@ function stageReplayFields(stage) {
8925
8951
  };
8926
8952
  }
8927
8953
  function finalizeKilled(runId, runSnapshot, activeStore, persistence, onRunEnd) {
8928
- const errorMessage3 = "workflow killed";
8954
+ const errorMessage2 = "workflow killed";
8929
8955
  const metadata = {
8930
8956
  failureKind: "cancelled",
8931
8957
  failureCode: "cancelled",
8932
8958
  failureRecoverability: "non_recoverable",
8933
8959
  failureDisposition: "terminal_killed",
8934
- failureMessage: errorMessage3,
8960
+ failureMessage: errorMessage2,
8935
8961
  resumable: false
8936
8962
  };
8937
- const recorded = activeStore.recordRunEnd(runId, "killed", undefined, errorMessage3, metadata);
8963
+ const recorded = activeStore.recordRunEnd(runId, "killed", undefined, errorMessage2, metadata);
8938
8964
  appendRunEndWhenRecorded(persistence, recorded, {
8939
8965
  runId,
8940
8966
  status: "killed",
8941
- error: errorMessage3,
8967
+ error: errorMessage2,
8942
8968
  ...metadata,
8943
8969
  ts: Date.now()
8944
8970
  });
8945
- return reconcileTerminalRunResult(runId, runSnapshot, activeStore, { status: "killed", error: errorMessage3 }, onRunEnd);
8971
+ return reconcileTerminalRunResult(runId, runSnapshot, activeStore, { status: "killed", error: errorMessage2 }, onRunEnd);
8946
8972
  }
8947
8973
  function finalizeKilledByFailure(runId, runSnapshot, activeStore, persistence, onRunEnd, metadata) {
8948
8974
  const recorded = activeStore.recordRunEnd(runId, "killed", undefined, metadata.errorMessage, metadata);
@@ -9216,7 +9242,7 @@ function createContinuationReplayIndex(continuation, sourceToContinuationNodeIds
9216
9242
  markPromptAnswerReplayed: () => {}
9217
9243
  };
9218
9244
  }
9219
- if (continuation.resumeFromStageId === undefined) {
9245
+ if (continuation.resumeFromStageId === undefined && continuation.resumeFromToolNodeId === undefined) {
9220
9246
  if (continuation.source.stages.length > 0)
9221
9247
  throw new Error(`atomic-workflows: insufficient_state: continuation has no resume stage in source run ${continuation.source.id}`);
9222
9248
  return {
@@ -9228,9 +9254,9 @@ function createContinuationReplayIndex(continuation, sourceToContinuationNodeIds
9228
9254
  markPromptAnswerReplayed: () => {}
9229
9255
  };
9230
9256
  }
9231
- const resumeStage = continuation.source.stages.find((stage) => stage.id === continuation.resumeFromStageId);
9232
- if (resumeStage === undefined) {
9233
- throw new Error(`atomic-workflows: insufficient_state: resume stage ${continuation.resumeFromStageId} was not found in source run ${continuation.source.id}`);
9257
+ const resumeNode = continuation.resumeFromToolNodeId === undefined ? continuation.source.stages.find((stage) => stage.id === continuation.resumeFromStageId) : continuation.source.toolNodes?.find((node) => node.id === continuation.resumeFromToolNodeId);
9258
+ if (resumeNode === undefined) {
9259
+ throw new Error(`atomic-workflows: insufficient_state: resume frontier ${continuation.resumeFromStageId ?? continuation.resumeFromToolNodeId} was not found in source run ${continuation.source.id}`);
9234
9260
  }
9235
9261
  const stagesByReplayIdentity = new Map;
9236
9262
  const stagesByDisplayName = new Map;
@@ -9662,6 +9688,8 @@ function createRunFinalizers(input) {
9662
9688
  }
9663
9689
  let outputs;
9664
9690
  try {
9691
+ if (signal.status === "completed")
9692
+ input.assertSuccessfulCompletion();
9665
9693
  outputs = normalizeWorkflowExitOutput(input.def.name, signal.outputSnapshot);
9666
9694
  assertWorkflowExitOutputs(input.def.name, outputs, input.def.outputs);
9667
9695
  } catch (err) {
@@ -10728,14 +10756,19 @@ function createParallelPrimitive(input) {
10728
10756
  function createTaskPrimitive(runtime) {
10729
10757
  return async (name, options, stageFailFastScope) => {
10730
10758
  runtime.exit.throwIfWorkflowExitSelected();
10731
- const runTaskOnce = async (taskOptions) => {
10759
+ const runTaskOnce = async (taskOptions, prepareLiveOptions) => {
10732
10760
  runtime.exit.throwIfWorkflowExitSelected();
10733
- const resolvedTaskOptions = stageOptionsWithGitWorktree(stageOptionsWithInputDefaults(taskOptions, runtime.inputRuntimeDefaults), runtime.workflowInvocationCwd, runtime.gitWorktreeSetupCache) ?? taskOptions;
10761
+ let resolvedTaskOptions = stageOptionsWithInputDefaults(taskOptions, runtime.inputRuntimeDefaults) ?? taskOptions;
10734
10762
  const stageOptions = taskStageOptions(resolvedTaskOptions);
10735
10763
  const stageHandle = runtime.spawnStage(name, {
10736
10764
  kind: "agent",
10737
10765
  ...stageOptions !== undefined ? { options: stageOptions } : {},
10738
- ...stageFailFastScope !== undefined ? { failFastScope: stageFailFastScope } : {}
10766
+ ...stageFailFastScope !== undefined ? { failFastScope: stageFailFastScope } : {},
10767
+ prepareLiveOptions: () => {
10768
+ const preparedOptions = prepareLiveOptions?.() ?? taskOptions;
10769
+ resolvedTaskOptions = stageOptionsWithGitWorktree(stageOptionsWithInputDefaults(preparedOptions, runtime.inputRuntimeDefaults), runtime.workflowInvocationCwd, runtime.gitWorktreeSetupCache) ?? preparedOptions;
10770
+ return taskStageOptions(resolvedTaskOptions);
10771
+ }
10739
10772
  });
10740
10773
  const stage = stageHandle.context;
10741
10774
  const promptText = resolvedTaskOptions.resumeFromSessionFile !== undefined ? RESUME_CONTINUATION_PROMPT : applyTaskContext(`${taskReadInstruction(resolvedTaskOptions)}${taskPrompt(resolvedTaskOptions)}`, taskPrevious(resolvedTaskOptions));
@@ -10758,7 +10791,6 @@ function createTaskPrimitive(runtime) {
10758
10791
  ...sessionId !== undefined ? { sessionId } : {},
10759
10792
  ...stage.sessionFile !== undefined ? { sessionFile: stage.sessionFile } : {},
10760
10793
  ...stageMeta.model !== undefined ? { model: stageMeta.model } : {},
10761
- ...stageMeta.fastMode === true ? { fastMode: stageMeta.fastMode } : {},
10762
10794
  ...stageMeta.attemptedModels !== undefined ? { attemptedModels: stageMeta.attemptedModels } : {},
10763
10795
  ...stageMeta.modelAttempts !== undefined ? { modelAttempts: stageMeta.modelAttempts } : {},
10764
10796
  ...stageMeta.warnings !== undefined ? { warnings: stageMeta.warnings } : {}
@@ -10766,22 +10798,25 @@ function createTaskPrimitive(runtime) {
10766
10798
  };
10767
10799
  if (options.worktree !== true)
10768
10800
  return runTaskOnce(options);
10769
- const prepared = prepareTaskWorktrees([{ ...options, name }], { ...options, worktree: true }, `${runtime.runId}-${name}-${crypto.randomUUID()}`, name, runtime.workflowInvocationCwd, runtime.worktreeSymlinkDirectories);
10770
- const preparedTask = prepared.tasks[0];
10801
+ let prepared;
10771
10802
  let collected;
10772
10803
  const collect = () => {
10773
- collected ??= collectWorktreeDiffs(prepared, options.artifacts !== false).artifacts;
10804
+ collected ??= prepared === undefined ? [] : collectWorktreeDiffs(prepared, options.artifacts !== false).artifacts;
10774
10805
  return collected;
10775
10806
  };
10776
- const replayKey = preparedTask.durableReplayKey;
10777
- if (replayKey !== undefined)
10778
- runtime.registerTerminalArtifactCollector(replayKey, collect);
10779
10807
  try {
10780
- const result = await runTaskOnce(preparedTask);
10808
+ const result = await runTaskOnce(options, () => {
10809
+ prepared = prepareTaskWorktrees([{ ...options, name }], { ...options, worktree: true }, `${runtime.runId}-${name}-${crypto.randomUUID()}`, name, runtime.workflowInvocationCwd, runtime.worktreeSymlinkDirectories);
10810
+ const preparedTask = prepared.tasks[0];
10811
+ if (preparedTask.durableReplayKey !== undefined)
10812
+ runtime.registerTerminalArtifactCollector(preparedTask.durableReplayKey, collect);
10813
+ return preparedTask;
10814
+ });
10781
10815
  const artifacts = collect();
10782
10816
  return artifacts.length === 0 ? result : { ...result, artifacts: [...result.artifacts ?? [], ...artifacts] };
10783
10817
  } finally {
10784
- cleanupPreparedWorktrees(prepared);
10818
+ if (prepared !== undefined)
10819
+ cleanupPreparedWorktrees(prepared);
10785
10820
  }
10786
10821
  };
10787
10822
  }
@@ -10993,57 +11028,6 @@ function buildExitGatedUiContext(input) {
10993
11028
  };
10994
11029
  }
10995
11030
 
10996
- // dist/builtin/workflows/src/engine/workflow-tool-abort.ts
10997
- class WorkflowToolAbortError extends Error {
10998
- runId;
10999
- nodeId;
11000
- toolName;
11001
- scope;
11002
- constructor(input) {
11003
- super(`atomic-workflows: ctx.tool ${input.toolName} aborted by ${input.scope === "quit" ? "workflow quit" : "node abort"}`);
11004
- this.name = "AbortError";
11005
- this.runId = input.runId;
11006
- this.nodeId = input.nodeId;
11007
- this.toolName = input.toolName;
11008
- this.scope = input.scope;
11009
- }
11010
- }
11011
- function isWorkflowToolAbortError(value) {
11012
- return value instanceof WorkflowToolAbortError;
11013
- }
11014
- var WORKFLOW_GRACEFUL_QUIT_EXIT_REASON = "quit";
11015
-
11016
- class WorkflowGracefulQuitError extends Error {
11017
- runId;
11018
- constructor(runId, detail) {
11019
- super(`atomic-workflows: ${detail} suspended by workflow quit`);
11020
- this.name = "AbortError";
11021
- this.runId = runId;
11022
- }
11023
- }
11024
- function isGracefulQuitSignal(value) {
11025
- if (value instanceof WorkflowGracefulQuitError)
11026
- return true;
11027
- return isWorkflowToolAbortError(value) && value.scope === "quit";
11028
- }
11029
- function findWorkflowGracefulQuit(value) {
11030
- let current = value;
11031
- for (let depth = 0;depth < 8; depth++) {
11032
- if (isGracefulQuitSignal(current))
11033
- return current;
11034
- if (typeof current !== "object" || current === null)
11035
- return;
11036
- try {
11037
- if (!("cause" in current))
11038
- return;
11039
- current = current.cause;
11040
- } catch {
11041
- return;
11042
- }
11043
- }
11044
- return;
11045
- }
11046
-
11047
11031
  // dist/builtin/workflows/src/engine/primitives/workflow.ts
11048
11032
  function createChildWorkflowRunner(input) {
11049
11033
  return async (child, ...args) => {
@@ -11078,6 +11062,7 @@ function createChildWorkflowRunner(input) {
11078
11062
  await durableInvocation?.recordTerminal("completed", boundary.replayedChild);
11079
11063
  return boundary.replayedChild;
11080
11064
  }
11065
+ runtime.assertLiveWorkAllowed?.();
11081
11066
  const childInputs = resolveAndValidateInputs(child.inputs, options.inputs ?? {}, `child workflow "${childName}" (${child.name})`);
11082
11067
  runtime.exit.throwIfWorkflowExitSelected();
11083
11068
  childRunId = durableInvocation?.identity.childRunId ?? crypto.randomUUID();
@@ -11186,7 +11171,8 @@ function durableRootRegistrationForRun(args) {
11186
11171
  status: "running",
11187
11172
  rootWorkflowId: args.runId,
11188
11173
  resumable: true,
11189
- ...args.hasPersistence ? { sessionFile: undefined } : {}
11174
+ ...args.hasPersistence ? { sessionFile: undefined } : {},
11175
+ ...args.possibleStages !== undefined ? { possibleStages: args.possibleStages } : {}
11190
11176
  };
11191
11177
  }
11192
11178
  async function admitDurableRootRun(args) {
@@ -11630,7 +11616,6 @@ function mergeStageDraft(existing, checkpoint, sequence) {
11630
11616
  ...valueOrExisting("endedAt", checkpoint, existing),
11631
11617
  ...valueOrExisting("durationMs", checkpoint, existing),
11632
11618
  ...valueOrExisting("model", checkpoint, existing),
11633
- ...valueOrExisting("fastMode", checkpoint, existing),
11634
11619
  ...valueOrExisting("attemptedModels", checkpoint, existing),
11635
11620
  ...valueOrExisting("modelAttempts", checkpoint, existing),
11636
11621
  ...checkpoint.topology !== undefined ? { topology: checkpoint.topology } : existing?.topology !== undefined ? { topology: existing.topology } : {}
@@ -11765,9 +11750,9 @@ function completedToolNodes(checkpoints, runId, rootRunId, sourceIds, firstSeque
11765
11750
  argsHash: checkpoint.argsHash,
11766
11751
  ordinal: topology?.ordinal ?? index + 1,
11767
11752
  parentIds: Object.freeze([...topology?.parentIds ?? []].map((parentId) => sourceIds.get(parentId) ?? parentId)),
11768
- replayed: true,
11753
+ ...checkpoint.throwingFailureError === undefined ? { replayed: true } : {},
11769
11754
  ...topology === undefined ? { topologyState: "unavailable" } : {},
11770
- status: failed ? "failed" : "cached",
11755
+ status: checkpoint.cancelled === true ? "cancelled" : failed ? "failed" : "cached",
11771
11756
  executionOrder: topology?.order ?? firstSequenceByHash.get(checkpoint.argsHash),
11772
11757
  ...topology?.startedAt !== undefined ? { startedAt: topology.startedAt } : {},
11773
11758
  endedAt: topology?.endedAt ?? checkpoint.completedAt,
@@ -12027,7 +12012,6 @@ function stageSnapshotFromDraft(draft, id, parentIds) {
12027
12012
  ...draft.sessionId !== undefined ? { sessionId: draft.sessionId } : {},
12028
12013
  ...draft.sessionFile !== undefined ? { sessionFile: draft.sessionFile } : {},
12029
12014
  ...draft.model !== undefined ? { model: draft.model } : {},
12030
- ...draft.fastMode !== undefined ? { fastMode: draft.fastMode } : {},
12031
12015
  ...draft.attemptedModels !== undefined ? { attemptedModels: draft.attemptedModels } : {},
12032
12016
  ...draft.modelAttempts !== undefined ? { modelAttempts: draft.modelAttempts } : {}
12033
12017
  };
@@ -12548,6 +12532,7 @@ function createAdmittedToolExecutionTracker(options = {}) {
12548
12532
  const inFlight = new Set;
12549
12533
  const admissions = [];
12550
12534
  const failures = [];
12535
+ const cancellations = [];
12551
12536
  let nextAdmissionOrder2 = 0;
12552
12537
  let state = "OPEN";
12553
12538
  let closing;
@@ -12609,8 +12594,10 @@ function createAdmittedToolExecutionTracker(options = {}) {
12609
12594
  const observed = execution.then(() => {
12610
12595
  return;
12611
12596
  }, (error) => {
12612
- if (admission.cancelled)
12597
+ if (admission.cancelled) {
12598
+ cancellations.push({ admissionOrder: admission.admissionOrder, error, nodeId: admission.nodeId });
12613
12599
  return;
12600
+ }
12614
12601
  recordFailure(admission, error, admission.nodeId);
12615
12602
  reportDrainFailure();
12616
12603
  });
@@ -12657,7 +12644,7 @@ function createAdmittedToolExecutionTracker(options = {}) {
12657
12644
  return failures[0];
12658
12645
  },
12659
12646
  uniqueFailureFor(error) {
12660
- const matching = failures.filter((failure2) => Object.is(failure2.error, error));
12647
+ const matching = [...failures, ...cancellations].filter((failure2) => Object.is(failure2.error, error));
12661
12648
  return matching.length === 1 ? matching[0] : undefined;
12662
12649
  }
12663
12650
  };
@@ -12668,10 +12655,20 @@ function createToolNodeLifecycle(input) {
12668
12655
  const { store: store2, tracker, run: run2, sourceToContinuationNodeIds } = input;
12669
12656
  const ownsCurrentRun = () => store2.runs().some((candidate) => candidate === run2);
12670
12657
  const replayedToolNodeIds = new Set;
12658
+ let pendingFrontier = input.resumeToolNode;
12671
12659
  return {
12660
+ assertFrontierConsumed: () => {
12661
+ if (pendingFrontier !== undefined) {
12662
+ throw new Error(`${REPLAY_TOPOLOGY_MISMATCH_MESSAGE} for unfinished tool ${pendingFrontier.id}: pending frontier was not consumed`);
12663
+ }
12664
+ },
12672
12665
  onNodeStart: (node) => {
12666
+ const frontier = node.replayed === true ? undefined : pendingFrontier;
12667
+ if (frontier !== undefined && (node.id !== frontier.id || node.argsHash !== frontier.argsHash || node.ordinal !== frontier.ordinal)) {
12668
+ throw new Error(`${REPLAY_TOPOLOGY_MISMATCH_MESSAGE} for unfinished tool ${frontier.id}`);
12669
+ }
12673
12670
  const inferredParents = tracker.onSpawn(node.id, node.name);
12674
- const sourceParents = node.replayed === true && node.topologyState !== "unavailable" ? node.parentIds : undefined;
12671
+ const sourceParents = frontier?.parentIds ?? (node.replayed === true && node.topologyState !== "unavailable" ? node.parentIds : undefined);
12675
12672
  const restored = sourceParents?.map((sourceId) => sourceToContinuationNodeIds.get(sourceId));
12676
12673
  const translated = restored?.every((id) => id !== undefined) ? restored : undefined;
12677
12674
  if (run2.resumedFromRunId !== undefined && sourceParents !== undefined && translated === undefined) {
@@ -12688,6 +12685,8 @@ function createToolNodeLifecycle(input) {
12688
12685
  replayedToolNodeIds.add(node.id);
12689
12686
  if (ownsCurrentRun())
12690
12687
  store2.recordToolNodeStart(run2.id, node);
12688
+ if (frontier !== undefined)
12689
+ pendingFrontier = undefined;
12691
12690
  },
12692
12691
  onNodeRunning: (nodeId, startedAt) => {
12693
12692
  if (ownsCurrentRun())
@@ -12779,7 +12778,13 @@ function createTrackedToolPrimitive(input) {
12779
12778
  return;
12780
12779
  abandonInFlightAsCancelled(input.controller.signal.reason);
12781
12780
  }, { once: true });
12782
- return { tool, admittedTools, abandonInFlightAsCancelled, observedQuitCancellation: () => observedQuit };
12781
+ return {
12782
+ tool,
12783
+ admittedTools,
12784
+ assertFrontierConsumed: lifecycle.assertFrontierConsumed,
12785
+ abandonInFlightAsCancelled,
12786
+ observedQuitCancellation: () => observedQuit
12787
+ };
12783
12788
  }
12784
12789
 
12785
12790
  // dist/builtin/workflows/src/runs/foreground/executor-child-boundary.ts
@@ -13154,11 +13159,7 @@ function createTrackedStageCaller(input) {
13154
13159
  const now = Date.now();
13155
13160
  const hasNoExplicitModelConfig = input.options?.model === undefined && input.options?.fallbackModels === undefined;
13156
13161
  const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
13157
- if (callOptions.eagerSession && !promptAdapterHandlesInitialPrompt && (hasNoExplicitModelConfig || await hasExplicitFastModeCandidate({
13158
- model: input.options?.model,
13159
- fallbackModels: input.options?.fallbackModels,
13160
- models: runtime.opts.models
13161
- }))) {
13162
+ if (callOptions.eagerSession && !promptAdapterHandlesInitialPrompt && hasNoExplicitModelConfig) {
13162
13163
  try {
13163
13164
  await runtime.innerCtx.__ensureSession();
13164
13165
  } catch (err) {
@@ -13930,7 +13931,6 @@ function createReplayStageContext(input) {
13930
13931
  __pendingMessageCount: () => 0,
13931
13932
  __modelFallbackMeta: () => ({
13932
13933
  ...replaySource.model !== undefined ? { model: replaySource.model } : {},
13933
- ...replaySource.fastMode === true ? { fastMode: replaySource.fastMode } : {},
13934
13934
  ...replaySource.attemptedModels !== undefined ? { attemptedModels: replaySource.attemptedModels } : {},
13935
13935
  ...replaySource.modelAttempts !== undefined ? { modelAttempts: replaySource.modelAttempts } : {}
13936
13936
  }),
@@ -13988,13 +13988,140 @@ function workflowPendingStageRouteCapability(store2, runId) {
13988
13988
  return capability;
13989
13989
  }
13990
13990
 
13991
+ // dist/builtin/workflows/src/shared/workflow-stage-path-matching.ts
13992
+ function matchStagePathSegments(patternSegments, candidateSegments) {
13993
+ return matchSegmentsFrom(patternSegments, 0, candidateSegments, 0);
13994
+ }
13995
+ function matchSegmentsFrom(pattern, patternIndex, candidate, candidateIndex) {
13996
+ let p = patternIndex;
13997
+ let c = candidateIndex;
13998
+ while (p < pattern.length) {
13999
+ const segment = pattern[p];
14000
+ if (segment === "**") {
14001
+ for (let skip = c;skip <= candidate.length; skip += 1) {
14002
+ if (matchSegmentsFrom(pattern, p + 1, candidate, skip))
14003
+ return true;
14004
+ }
14005
+ return false;
14006
+ }
14007
+ if (c >= candidate.length)
14008
+ return false;
14009
+ if (!matchSegmentGlob(segment, candidate[c]))
14010
+ return false;
14011
+ p += 1;
14012
+ c += 1;
14013
+ }
14014
+ return c === candidate.length;
14015
+ }
14016
+ function matchSegmentGlob(pattern, value) {
14017
+ if (!pattern.includes("*"))
14018
+ return pattern === value;
14019
+ let p = 0;
14020
+ let v = 0;
14021
+ let star = -1;
14022
+ let mark = -1;
14023
+ while (v < value.length) {
14024
+ if (p < pattern.length && pattern[p] === "*") {
14025
+ star = p;
14026
+ mark = v;
14027
+ p += 1;
14028
+ continue;
14029
+ }
14030
+ if (p < pattern.length && pattern[p] === value[v]) {
14031
+ p += 1;
14032
+ v += 1;
14033
+ continue;
14034
+ }
14035
+ if (star >= 0) {
14036
+ p = star + 1;
14037
+ mark += 1;
14038
+ v = mark;
14039
+ continue;
14040
+ }
14041
+ return false;
14042
+ }
14043
+ while (p < pattern.length && pattern[p] === "*")
14044
+ p += 1;
14045
+ return p === pattern.length;
14046
+ }
14047
+
14048
+ // dist/builtin/workflows/src/shared/workflow-stage-target.ts
14049
+ var WORKFLOW_RUN_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
14050
+ var WORKFLOW_TARGET_PREFIX = "workflow:";
14051
+ function parseWorkflowStageTarget(target) {
14052
+ if (!target.startsWith(WORKFLOW_TARGET_PREFIX))
14053
+ return;
14054
+ const slash = target.indexOf("/", WORKFLOW_TARGET_PREFIX.length);
14055
+ if (slash < 0)
14056
+ return;
14057
+ const rootRunId = target.slice(WORKFLOW_TARGET_PREFIX.length, slash);
14058
+ if (!WORKFLOW_RUN_ID_PATTERN.test(rootRunId))
14059
+ return;
14060
+ const segments = target.slice(slash + 1).split("/");
14061
+ if (segments.length === 0 || segments.some((segment) => segment.length === 0))
14062
+ return;
14063
+ const kind = segments.includes("**") ? "deep-pattern" : segments.some((segment) => segment.includes("*")) ? "pattern" : "path";
14064
+ return { rootRunId, segments, kind };
14065
+ }
14066
+
14067
+ // dist/builtin/workflows/src/shared/pending-stage-status.ts
14068
+ function workflowBoundaryHops(runs, runId) {
14069
+ const runById = new Map(runs.map((run2) => [run2.id, run2]));
14070
+ const hops = [];
14071
+ let current = runById.get(runId);
14072
+ while (current !== undefined && current.parentRunId !== undefined) {
14073
+ const parent = runById.get(current.parentRunId);
14074
+ const boundary = parent?.stages.find((stage) => stage.id === current?.parentStageId);
14075
+ if (parent === undefined || boundary === undefined)
14076
+ return;
14077
+ hops.unshift({ name: boundary.name, runId: current.id });
14078
+ current = parent;
14079
+ }
14080
+ return current === undefined ? undefined : hops;
14081
+ }
14082
+ function workflowStagePathVariants(hops, stageSegments) {
14083
+ let prefixes = [[]];
14084
+ for (const hop of hops) {
14085
+ prefixes = prefixes.flatMap((prefix) => {
14086
+ const withName = [...prefix, hop.name];
14087
+ return hop.runId === hop.name ? [withName] : [withName, [...prefix, hop.runId]];
14088
+ });
14089
+ }
14090
+ return prefixes.flatMap((prefix) => stageSegments.map((stage) => [...prefix, stage]));
14091
+ }
14092
+ function stageMatchesPathPattern(patternSegments, hops, stageSegments) {
14093
+ return workflowStagePathVariants(hops, stageSegments).some((candidate) => matchStagePathSegments(patternSegments, candidate));
14094
+ }
14095
+
13991
14096
  // dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
13992
14097
  var pendingDeliveryClaims = new WeakMap;
14098
+
14099
+ class WorkflowPendingStageDeliveryFailedError extends Error {
14100
+ code = "pending_stage_delivery_failed";
14101
+ runId;
14102
+ stageId;
14103
+ stageName;
14104
+ reason;
14105
+ constructor(runId, stageId, stageName, reason) {
14106
+ super(`atomic-workflows: stage "${stageName}" (${stageId}) did not start because its queued Intercom instructions could not be delivered: ${reason.message}`);
14107
+ this.name = "WorkflowPendingStageDeliveryFailedError";
14108
+ this.runId = runId;
14109
+ this.stageId = stageId;
14110
+ this.stageName = stageName;
14111
+ this.reason = reason;
14112
+ }
14113
+ }
14114
+ function isWorkflowPendingStageDeliveryFailure(error) {
14115
+ if (error instanceof WorkflowPendingStageDeliveryFailedError)
14116
+ return true;
14117
+ return error?.code === "pending_stage_delivery_failed";
14118
+ }
13993
14119
  function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName) {
13994
14120
  let resolveReady;
13995
14121
  let rejectReady;
13996
14122
  let readyPromise;
13997
14123
  let drainError;
14124
+ let terminalError;
13998
14125
  let drainPromise;
13999
14126
  const pendingReady = () => {
14000
14127
  if (readyPromise === undefined) {
@@ -14008,48 +14135,84 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
14008
14135
  return {
14009
14136
  routeCapability: workflowPendingStageRouteCapability(activeStore, runId),
14010
14137
  deliverPending(deliver) {
14011
- if (drainPromise === undefined) {
14012
- drainError = undefined;
14013
- const attempt = deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver);
14014
- const drain = attempt.then(() => resolveReady?.(), (error) => {
14015
- drainError = error;
14016
- rejectReady?.(error);
14017
- readyPromise = undefined;
14018
- resolveReady = undefined;
14019
- rejectReady = undefined;
14020
- if (drainPromise === drain)
14021
- drainPromise = undefined;
14022
- throw error;
14023
- });
14024
- drainPromise = drain;
14025
- }
14138
+ if (drainPromise !== undefined)
14139
+ return drainPromise;
14140
+ if (terminalError !== undefined)
14141
+ return Promise.resolve();
14142
+ drainError = undefined;
14143
+ const attempt = deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver);
14144
+ const drain = attempt.then(() => resolveReady?.(), (error) => {
14145
+ drainError = error;
14146
+ rejectReady?.(error);
14147
+ readyPromise = undefined;
14148
+ resolveReady = undefined;
14149
+ rejectReady = undefined;
14150
+ if (drainPromise === drain)
14151
+ drainPromise = undefined;
14152
+ throw error;
14153
+ });
14154
+ drainPromise = drain;
14026
14155
  return drainPromise;
14027
14156
  },
14028
14157
  ready() {
14029
- if (activeStore.pendingStageMessagesFor(runId, stageId).length === 0 && (stageId === stageName || activeStore.pendingStageMessagesFor(runId, stageName).length === 0)) {
14158
+ if (activeStore.pendingStageMessagesFor(runId, stageId).length === 0 && (stageId === stageName || activeStore.pendingStageMessagesFor(runId, stageName).length === 0) && stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName).length === 0) {
14030
14159
  return;
14031
14160
  }
14161
+ if (terminalError !== undefined)
14162
+ return Promise.reject(terminalError);
14032
14163
  return drainError === undefined ? pendingReady() : Promise.reject(drainError);
14164
+ },
14165
+ fail(reason) {
14166
+ if (terminalError !== undefined)
14167
+ return;
14168
+ terminalError = new WorkflowPendingStageDeliveryFailedError(runId, stageId, stageName, reason);
14169
+ if (readyPromise === undefined)
14170
+ return;
14171
+ readyPromise.catch(() => {});
14172
+ rejectReady?.(terminalError);
14033
14173
  }
14034
14174
  };
14035
14175
  }
14036
14176
  async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver) {
14177
+ const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName);
14037
14178
  const candidateIds = new Set([
14038
14179
  ...activeStore.pendingStageMessagesFor(runId, stageId),
14039
- ...activeStore.pendingStageMessagesFor(runId, stageName)
14180
+ ...activeStore.pendingStageMessagesFor(runId, stageName),
14181
+ ...stickyEntries
14040
14182
  ].map((entry) => entry.id));
14041
- const entries = (activeStore.runs().find((run2) => run2.id === runId)?.pendingStageMessages ?? []).map((entry, index) => ({ entry, index })).filter(({ entry }) => candidateIds.has(entry.id)).sort((left, right) => (left.entry.admissionOrder ?? left.index + 1) - (right.entry.admissionOrder ?? right.index + 1) || left.index - right.index).map(({ entry }) => entry);
14183
+ const runs = activeStore.runs();
14184
+ const entries = [
14185
+ ...(runs.find((run2) => run2.id === runId)?.pendingStageMessages ?? []).map((entry, index) => ({ entry, index })).filter(({ entry }) => candidateIds.has(entry.id) && entry.sticky !== true),
14186
+ ...stickyEntries.map((entry) => ({ entry, index: Number.MAX_SAFE_INTEGER }))
14187
+ ].sort((left, right) => (left.entry.admissionOrder ?? left.index + 1) - (right.entry.admissionOrder ?? right.index + 1) || left.index - right.index).map(({ entry }) => entry);
14042
14188
  const rootBackend = getDurableBackend();
14043
- const backend = durableBackendForRun(rootBackend, activeStore.runs(), runId);
14189
+ const backend = durableBackendForRun(rootBackend, runs, runId);
14044
14190
  if (backend === undefined) {
14045
14191
  throw new Error(`atomic-workflows: workflow run ${runId} has no durable owner for pending-stage delivery`);
14046
14192
  }
14047
14193
  for (const entry of entries) {
14048
- const releaseClaim = claimPendingDelivery(activeStore, runId, entry.stageKey, entry.id);
14194
+ const claimOwner = entry.sticky === true ? `${entry.runId}\x00${runId}:${stageId}` : entry.runId;
14195
+ const releaseClaim = claimPendingDelivery(activeStore, claimOwner, entry.stageKey, entry.id);
14049
14196
  if (releaseClaim === undefined)
14050
14197
  continue;
14051
14198
  try {
14052
14199
  await deliver(toPendingStageSender(entry), entry.message);
14200
+ if (entry.sticky === true) {
14201
+ const entryBackend = durableBackendForRun(rootBackend, activeStore.runs(), entry.runId);
14202
+ if (entryBackend === undefined) {
14203
+ throw new Error(`atomic-workflows: workflow run ${entry.runId} has no durable owner for sticky pending-stage delivery`);
14204
+ }
14205
+ if (!await activeStore.recordPendingStageMessageDeliveries(entry.runId, entry.id, [
14206
+ {
14207
+ runId,
14208
+ stageId,
14209
+ ...stageName === stageId ? {} : { stageName }
14210
+ }
14211
+ ], new Date().toISOString(), entryBackend)) {
14212
+ throw new Error(`atomic-workflows: pending-stage message ${entry.id} changed during delivery`);
14213
+ }
14214
+ continue;
14215
+ }
14053
14216
  if (!await activeStore.markPendingStageMessageDelivered(runId, entry.stageKey, entry.id, new Date().toISOString(), backend)) {
14054
14217
  throw new Error(`atomic-workflows: pending-stage message ${entry.id} changed during delivery`);
14055
14218
  }
@@ -14058,6 +14221,29 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
14058
14221
  }
14059
14222
  }
14060
14223
  }
14224
+ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName) {
14225
+ const runs = activeStore.runs();
14226
+ const rootRunId = durableRootRunIdForRun(runs, runId);
14227
+ if (rootRunId === undefined)
14228
+ return [];
14229
+ const rootRun = runs.find((run2) => run2.id === rootRunId);
14230
+ if (rootRun === undefined)
14231
+ return [];
14232
+ const hops = workflowBoundaryHops(runs, runId);
14233
+ if (hops === undefined)
14234
+ return [];
14235
+ return (rootRun.pendingStageMessages ?? []).filter((entry) => {
14236
+ if (entry.sticky !== true || entry.status !== "queued")
14237
+ return false;
14238
+ const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
14239
+ if (parsed === undefined || parsed.rootRunId !== rootRunId)
14240
+ return false;
14241
+ if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId)) {
14242
+ return false;
14243
+ }
14244
+ return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
14245
+ });
14246
+ }
14061
14247
  function claimPendingDelivery(store2, runId, stageKey, messageId) {
14062
14248
  let claims = pendingDeliveryClaims.get(store2);
14063
14249
  if (claims === undefined) {
@@ -14090,10 +14276,210 @@ import { createStructuredOutputCapture, runCallback as runCallback2 } from "@bas
14090
14276
 
14091
14277
  // dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts
14092
14278
  import {
14093
- convertToLlm,
14094
- shouldApplyCodexFastModeForScope
14279
+ convertToLlm
14095
14280
  } from "@bastani/atomic";
14096
14281
 
14282
+ // dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts
14283
+ function makeCandidate(id, value, level) {
14284
+ return {
14285
+ id,
14286
+ value,
14287
+ ...level !== undefined ? { reasoningLevel: level } : {}
14288
+ };
14289
+ }
14290
+ var WORKFLOW_THINKING_LEVELS = [
14291
+ "off",
14292
+ "minimal",
14293
+ "low",
14294
+ "medium",
14295
+ "high",
14296
+ "xhigh",
14297
+ "max"
14298
+ ];
14299
+ var WORKFLOW_THINKING_LEVEL_SET = new Set(WORKFLOW_THINKING_LEVELS);
14300
+ function splitReasoningSuffix(model) {
14301
+ const index = model.lastIndexOf(":");
14302
+ if (index < 0)
14303
+ return { baseModel: model };
14304
+ const suffix = model.slice(index + 1);
14305
+ if (WORKFLOW_THINKING_LEVEL_SET.has(suffix)) {
14306
+ return { baseModel: model.slice(0, index), level: suffix };
14307
+ }
14308
+ return { baseModel: model };
14309
+ }
14310
+ function candidateKey(candidate) {
14311
+ return `${candidate.id}::${candidate.reasoningLevel ?? ""}`;
14312
+ }
14313
+
14314
+ class WorkflowModelValidationError extends Error {
14315
+ failures;
14316
+ constructor(failures) {
14317
+ super(formatModelValidationError(failures));
14318
+ this.name = "WorkflowModelValidationError";
14319
+ this.failures = failures;
14320
+ }
14321
+ }
14322
+ function formatModelValidationError(failures) {
14323
+ const lines = ["workflows: model validation failed before starting workflow.", "Unavailable or ambiguous models:"];
14324
+ for (const failure2 of failures) {
14325
+ lines.push(`- ${failure2.input} (${failure2.reason})`);
14326
+ }
14327
+ return lines.join(`
14328
+ `);
14329
+ }
14330
+ function isModelObject(value) {
14331
+ return typeof value !== "string";
14332
+ }
14333
+ function workflowModelId(value) {
14334
+ if (value === undefined)
14335
+ return;
14336
+ if (typeof value === "string") {
14337
+ const trimmed = value.trim();
14338
+ return trimmed.length === 0 ? undefined : trimmed;
14339
+ }
14340
+ return `${String(value.provider)}/${value.id}`;
14341
+ }
14342
+ function normalizeInfo(info) {
14343
+ const fullId = info.fullId.trim().length > 0 ? info.fullId : `${info.provider}/${info.id}`;
14344
+ return { ...info, fullId };
14345
+ }
14346
+ function uniqueByFullId(models) {
14347
+ const seen = new Set;
14348
+ const result = [];
14349
+ for (const info of models.map(normalizeInfo)) {
14350
+ if (seen.has(info.fullId))
14351
+ continue;
14352
+ seen.add(info.fullId);
14353
+ result.push(info);
14354
+ }
14355
+ return result;
14356
+ }
14357
+ function resolveStringModel(rawInput, availableModels, preferredProvider) {
14358
+ const input = rawInput.trim();
14359
+ if (!input)
14360
+ return { input: rawInput, reason: "empty model id" };
14361
+ const { baseModel, level } = splitReasoningSuffix(input);
14362
+ const candidate = (id, value) => makeCandidate(id, value, level);
14363
+ if (availableModels === undefined) {
14364
+ return candidate(baseModel, baseModel);
14365
+ }
14366
+ const models = uniqueByFullId(availableModels);
14367
+ const explicit = models.find((model) => model.fullId === baseModel);
14368
+ if (explicit !== undefined) {
14369
+ return candidate(explicit.fullId, explicit.model ?? explicit.fullId);
14370
+ }
14371
+ if (baseModel.includes("/")) {
14372
+ return candidate(baseModel, baseModel);
14373
+ }
14374
+ const byBareId = models.filter((model) => model.id === baseModel);
14375
+ if (byBareId.length === 0) {
14376
+ return { input, reason: "not available" };
14377
+ }
14378
+ if (byBareId.length === 1) {
14379
+ const only = byBareId[0];
14380
+ return candidate(only.fullId, only.model ?? only.fullId);
14381
+ }
14382
+ const preferred = preferredProvider === undefined ? undefined : byBareId.find((model) => model.provider === preferredProvider);
14383
+ if (preferred !== undefined) {
14384
+ return candidate(preferred.fullId, preferred.model ?? preferred.fullId);
14385
+ }
14386
+ return {
14387
+ input,
14388
+ reason: `ambiguous: ${byBareId.map((model) => model.fullId).join(", ")}; specify provider/model`
14389
+ };
14390
+ }
14391
+ function resolveModelValue(value, availableModels, preferredProvider) {
14392
+ if (isModelObject(value)) {
14393
+ return { id: workflowModelId(value), value };
14394
+ }
14395
+ return resolveStringModel(value, availableModels, preferredProvider);
14396
+ }
14397
+ function isFailure(value) {
14398
+ return "reason" in value;
14399
+ }
14400
+ function buildModelCandidates(input) {
14401
+ const rawValues = [];
14402
+ if (input.primaryModel !== undefined)
14403
+ rawValues.push(input.primaryModel);
14404
+ for (const [index, fallback] of (input.fallbackModels ?? []).entries()) {
14405
+ const trimmedFallback = fallback.trim();
14406
+ const split = splitReasoningSuffix(trimmedFallback);
14407
+ const compatLevel = input.fallbackThinkingLevels?.[index];
14408
+ if (split.level === undefined && compatLevel !== undefined) {
14409
+ if (!WORKFLOW_THINKING_LEVEL_SET.has(compatLevel)) {
14410
+ throw new WorkflowModelValidationError([
14411
+ {
14412
+ input: trimmedFallback,
14413
+ reason: `invalid fallbackThinkingLevels[${index}] "${compatLevel}"; expected one of ${WORKFLOW_THINKING_LEVELS.join(", ")}`
14414
+ }
14415
+ ]);
14416
+ }
14417
+ rawValues.push(`${trimmedFallback}:${compatLevel}`);
14418
+ } else {
14419
+ rawValues.push(trimmedFallback);
14420
+ }
14421
+ }
14422
+ if (input.currentModel !== undefined)
14423
+ rawValues.push(input.currentModel);
14424
+ const failures = [];
14425
+ const seen = new Set;
14426
+ const candidates = [];
14427
+ for (const value of rawValues) {
14428
+ const resolved = resolveModelValue(value, input.availableModels, input.preferredProvider);
14429
+ if (isFailure(resolved)) {
14430
+ failures.push(resolved);
14431
+ continue;
14432
+ }
14433
+ const key2 = candidateKey(resolved);
14434
+ if (seen.has(key2))
14435
+ continue;
14436
+ seen.add(key2);
14437
+ candidates.push(resolved);
14438
+ }
14439
+ if (failures.length > 0)
14440
+ throw new WorkflowModelValidationError(failures);
14441
+ return candidates;
14442
+ }
14443
+ function catalogUnavailableWarning() {
14444
+ return "workflows: model catalog unavailable; using the current selected model for fallback validation.";
14445
+ }
14446
+ async function buildModelCandidatesFromCatalog(input) {
14447
+ const hasExplicitModel = input.primaryModel !== undefined || (input.fallbackModels?.length ?? 0) > 0;
14448
+ if (!hasExplicitModel)
14449
+ return [];
14450
+ if (input.catalog === undefined) {
14451
+ return buildModelCandidates({
14452
+ primaryModel: input.primaryModel,
14453
+ fallbackModels: input.fallbackModels,
14454
+ fallbackThinkingLevels: input.fallbackThinkingLevels
14455
+ });
14456
+ }
14457
+ try {
14458
+ const availableModels = await input.catalog.listModels();
14459
+ return buildModelCandidates({
14460
+ primaryModel: input.primaryModel,
14461
+ fallbackModels: input.fallbackModels,
14462
+ fallbackThinkingLevels: input.fallbackThinkingLevels,
14463
+ currentModel: input.catalog.currentModel,
14464
+ availableModels,
14465
+ preferredProvider: input.catalog.preferredProvider
14466
+ });
14467
+ } catch (err) {
14468
+ if (input.catalog.currentModel === undefined) {
14469
+ throw err;
14470
+ }
14471
+ input.catalog.recordWarning?.(catalogUnavailableWarning());
14472
+ return buildModelCandidates({ currentModel: input.catalog.currentModel });
14473
+ }
14474
+ }
14475
+ // dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts
14476
+ import {
14477
+ errorMessage as errorMessage2,
14478
+ isRetryableModelFailure,
14479
+ isRetryableSameModelFailure,
14480
+ modelFailureMessage,
14481
+ normalizeModelFailureSignal
14482
+ } from "@bastani/atomic";
14097
14483
  // dist/builtin/workflows/src/runs/foreground/stage-delivery-activity.ts
14098
14484
  class StageDeliveryActivity {
14099
14485
  listeners = new Set;
@@ -14356,6 +14742,15 @@ function lastAssistantTextFromMessages(messages) {
14356
14742
  }
14357
14743
  return;
14358
14744
  }
14745
+ function structuredOutputTurnDetail(messages, startIndex) {
14746
+ for (let index = messages.length - 1;index >= Math.max(startIndex, 0); index -= 1) {
14747
+ const message = messages[index];
14748
+ if (message?.role !== "assistant")
14749
+ continue;
14750
+ return extractMessageText(message).trim().length > 0 ? "The model produced assistant text but never called structured_output" : "The model produced an assistant message with empty text";
14751
+ }
14752
+ return "The model produced no assistant message after the prompt";
14753
+ }
14359
14754
  function assistantArtifactTextForToolCall(messages, toolCallId2) {
14360
14755
  for (let index = messages.length - 1;index >= 0; index -= 1) {
14361
14756
  const message = messages[index];
@@ -15077,7 +15472,7 @@ function retrySettingsManagerFromError(error) {
15077
15472
  if (manager === null || typeof manager !== "object")
15078
15473
  return;
15079
15474
  const candidate = manager;
15080
- return typeof candidate.getCodexFastModeSettings === "function" ? candidate : undefined;
15475
+ return typeof candidate.getRetrySettings === "function" ? candidate : undefined;
15081
15476
  }
15082
15477
  function retryableAgentSession(activeSession) {
15083
15478
  const session = asAgentSession(activeSession);
@@ -15126,6 +15521,7 @@ class StageSessionController {
15126
15521
  };
15127
15522
  terminatingToolCallIds = new Set;
15128
15523
  latestStructuredOutputToolErrorValue;
15524
+ structuredOutputCycleAttemptMark;
15129
15525
  unsubscribeTerminateWatcher;
15130
15526
  unresolvedContextOverflowMessage;
15131
15527
  generationSealed = false;
@@ -15175,12 +15571,48 @@ class StageSessionController {
15175
15571
  get currentPromptStartIndex() {
15176
15572
  return this.lastPromptStartIndex;
15177
15573
  }
15178
- get latestStructuredOutputToolError() {
15179
- return this.latestStructuredOutputToolErrorValue;
15180
- }
15181
15574
  resetStructuredOutputToolError() {
15182
15575
  this.latestStructuredOutputToolErrorValue = undefined;
15183
15576
  }
15577
+ beginStructuredOutputCandidateCycle() {
15578
+ this.structuredOutputCycleAttemptMark = this.modelAttempts.length;
15579
+ }
15580
+ structuredOutputFailureReason() {
15581
+ const toolError = this.latestStructuredOutputToolErrorValue;
15582
+ if (toolError !== undefined)
15583
+ return toolError;
15584
+ const messages = this.session?.messages;
15585
+ if (messages === undefined)
15586
+ return STRUCTURED_OUTPUT_MISSING_ERROR;
15587
+ return `${STRUCTURED_OUTPUT_MISSING_ERROR} ${structuredOutputTurnDetail(messages, this.lastPromptStartIndex ?? 0)}`;
15588
+ }
15589
+ async failCandidateForStructuredOutputExhaustion(error) {
15590
+ const mark = this.structuredOutputCycleAttemptMark ?? 0;
15591
+ this.structuredOutputCycleAttemptMark = undefined;
15592
+ for (let attemptIndex = mark;attemptIndex < this.modelAttempts.length; attemptIndex += 1) {
15593
+ const attempt = this.modelAttempts[attemptIndex];
15594
+ if (attempt === undefined || !attempt.success)
15595
+ continue;
15596
+ this.modelAttempts[attemptIndex] = { ...attempt, success: false, error };
15597
+ }
15598
+ const candidates = this.hasExplicitModelFallbackConfig ? await this.modelCandidates() : [];
15599
+ const index = this.activeCandidateIndex ?? 0;
15600
+ const candidate = candidates[index];
15601
+ const nextCandidate = candidates[index + 1];
15602
+ if (this.opts.signal?.aborted || candidate === undefined || nextCandidate === undefined) {
15603
+ this.modelWarnings.push(...this.pendingFallbackWarnings);
15604
+ this.pendingFallbackWarnings.length = 0;
15605
+ this.notifyModelFallbackMetaChange();
15606
+ return false;
15607
+ }
15608
+ this.pendingFallbackWarnings.push(`[fallback] ${candidateLabel(candidate)} failed: ${error}. Retrying with ${candidateLabel(nextCandidate)}.`);
15609
+ this.modelWarnings.push(...this.pendingFallbackWarnings);
15610
+ this.pendingFallbackWarnings.length = 0;
15611
+ await this.disposeCurrentSession();
15612
+ this.activeCandidateIndex = index + 1;
15613
+ this.notifyModelFallbackMetaChange();
15614
+ return true;
15615
+ }
15184
15616
  requireSession(property) {
15185
15617
  if (!this.session)
15186
15618
  unavailableSync(property);
@@ -15359,10 +15791,8 @@ class StageSessionController {
15359
15791
  currentModelFallbackMeta() {
15360
15792
  const attemptedModels = this.modelAttempts.map((attempt) => attempt.model);
15361
15793
  const model = this.selectedModel ?? workflowModelId(this.session?.model);
15362
- const fastMode = this.isWorkflowFastModeEnabled();
15363
15794
  return {
15364
15795
  ...model !== undefined ? { model } : {},
15365
- ...fastMode !== undefined ? { fastMode } : {},
15366
15796
  ...attemptedModels.length > 0 ? { attemptedModels } : {},
15367
15797
  ...this.modelAttempts.length > 0 ? { modelAttempts: [...this.modelAttempts] } : {},
15368
15798
  ...this.modelWarnings.length > 0 ? { warnings: [...this.modelWarnings] } : {}
@@ -15810,7 +16240,7 @@ class StageSessionController {
15810
16240
  const errorSettingsManager = retrySettingsManagerFromError(error);
15811
16241
  if (errorSettingsManager !== undefined)
15812
16242
  this.sessionSettingsManager = errorSettingsManager;
15813
- const decision = nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameModelFailure(error));
16243
+ const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameModelFailure(error));
15814
16244
  if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.capturedStructuredOutputForAttempt()) {
15815
16245
  throw error;
15816
16246
  }
@@ -15879,8 +16309,16 @@ class StageSessionController {
15879
16309
  const session = attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
15880
16310
  const attachedSession = session instanceof Promise ? await session : session;
15881
16311
  const pendingStageDeliveryReady = this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
15882
- if (pendingStageDeliveryReady !== undefined)
15883
- await pendingStageDeliveryReady;
16312
+ if (pendingStageDeliveryReady !== undefined) {
16313
+ try {
16314
+ await pendingStageDeliveryReady;
16315
+ } catch (error) {
16316
+ if (this.session === attachedSession)
16317
+ this.session = undefined;
16318
+ await disposeStageSession(attachedSession).catch(() => {});
16319
+ throw error;
16320
+ }
16321
+ }
15884
16322
  await this.opts.onSessionReady?.();
15885
16323
  return attachedSession;
15886
16324
  }
@@ -15894,12 +16332,12 @@ class StageSessionController {
15894
16332
  result.session.sealWorkflowStageGeneration?.();
15895
16333
  this.replacement.adopt(result.session);
15896
16334
  this.session = result.session;
16335
+ this.sessionSettingsManager = result.settingsManager ?? result.session.settingsManager;
15897
16336
  if (this.sharedModelRuntime === undefined) {
15898
16337
  const withRegistry = result.session;
15899
16338
  if (withRegistry.modelRuntime !== undefined)
15900
16339
  this.sharedModelRuntime = withRegistry.modelRuntime;
15901
16340
  }
15902
- this.sessionSettingsManager = result.settingsManager ?? result.session.settingsManager;
15903
16341
  if (this.pendingThinkingLevel !== undefined)
15904
16342
  result.session.setThinkingLevel(this.pendingThinkingLevel);
15905
16343
  for (const listener of this.pendingListeners) {
@@ -16003,6 +16441,7 @@ class StageSessionController {
16003
16441
  });
16004
16442
  this.pendingFallbackWarnings.length = 0;
16005
16443
  this.resumeCurrentSession = true;
16444
+ this.notifySuccessfulModelFallbackMeta();
16006
16445
  return true;
16007
16446
  }
16008
16447
  throw new WorkflowPromptModelFailure(terminalFailure);
@@ -16016,6 +16455,7 @@ class StageSessionController {
16016
16455
  });
16017
16456
  this.pendingFallbackWarnings.length = 0;
16018
16457
  this.resumeCurrentSession = true;
16458
+ this.notifySuccessfulModelFallbackMeta();
16019
16459
  return true;
16020
16460
  }
16021
16461
  const message = errorMessage2(err);
@@ -16047,7 +16487,8 @@ class StageSessionController {
16047
16487
  }
16048
16488
  async handleCandidateFailure(err, candidate, candidates, index) {
16049
16489
  const message = errorMessage2(err);
16050
- if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
16490
+ const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
16491
+ if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
16051
16492
  this.recordSuccessfulAttempt(candidate);
16052
16493
  return "handled";
16053
16494
  }
@@ -16059,7 +16500,7 @@ class StageSessionController {
16059
16500
  ...usage === undefined ? {} : { usage },
16060
16501
  error: message
16061
16502
  });
16062
- if (this.opts.signal?.aborted || !isRetryableModelFailure(err) || index === candidates.length - 1) {
16503
+ if (this.opts.signal?.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
16063
16504
  this.modelWarnings.push(...this.pendingFallbackWarnings);
16064
16505
  this.pendingFallbackWarnings.length = 0;
16065
16506
  this.notifyModelFallbackMetaChange();
@@ -16083,18 +16524,19 @@ class StageSessionController {
16083
16524
  });
16084
16525
  this.pendingFallbackWarnings.length = 0;
16085
16526
  this.resumeCurrentSession = true;
16527
+ this.notifySuccessfulModelFallbackMeta();
16086
16528
  }
16087
16529
  notifyModelFallbackMetaChange() {
16088
16530
  this.opts.onModelFallbackMetaChange?.(this.currentModelFallbackMeta());
16089
16531
  }
16532
+ notifySuccessfulModelFallbackMeta() {
16533
+ if (this.disposed)
16534
+ return;
16535
+ this.notifyModelFallbackMetaChange();
16536
+ }
16090
16537
  applyCandidateThinking(candidate) {
16091
16538
  this.pendingThinkingLevel = candidate === undefined ? this.effectiveStageOptions?.thinkingLevel : effectiveCandidateReasoning(candidate, this.effectiveStageOptions?.thinkingLevel);
16092
16539
  }
16093
- isWorkflowFastModeEnabled() {
16094
- const model = this.session?.model;
16095
- const settingsManager = this.sessionSettingsManager ?? this.effectiveStageOptions?.settingsManager;
16096
- return model === undefined || settingsManager === undefined ? undefined : shouldApplyCodexFastModeForScope(model, settingsManager.getCodexFastModeSettings(), "workflow");
16097
- }
16098
16540
  throwUnresolvedContextOverflowIfPresent() {
16099
16541
  const message = this.unresolvedContextOverflowMessage;
16100
16542
  this.unresolvedContextOverflowMessage = undefined;
@@ -16371,20 +16813,27 @@ function createStageContext2(opts) {
16371
16813
  return lastAssistantText;
16372
16814
  }
16373
16815
  if (structuredOutputCapture) {
16374
- let nextPrompt = promptText;
16375
- let correctiveAttempts = 0;
16376
16816
  let structuredOutputError = STRUCTURED_OUTPUT_MISSING_ERROR;
16377
16817
  while (!structuredOutputCapture.called) {
16378
- controller.resetStructuredOutputToolError();
16379
- await controller.promptWithFallback(nextPrompt, sdkOptions);
16818
+ let nextPrompt = promptText;
16819
+ let correctiveAttempts = 0;
16820
+ controller.beginStructuredOutputCandidateCycle();
16821
+ while (!structuredOutputCapture.called) {
16822
+ controller.resetStructuredOutputToolError();
16823
+ await controller.promptWithFallback(nextPrompt, sdkOptions);
16824
+ if (structuredOutputCapture.called)
16825
+ break;
16826
+ structuredOutputError = controller.structuredOutputFailureReason();
16827
+ if (correctiveAttempts >= STRUCTURED_OUTPUT_MAX_CORRECTIVE_PROMPTS)
16828
+ break;
16829
+ correctiveAttempts += 1;
16830
+ nextPrompt = formatStructuredOutputCorrectionPrompt(structuredOutputError, correctiveAttempts, hasOutputArtifact);
16831
+ }
16380
16832
  if (structuredOutputCapture.called)
16381
16833
  break;
16382
- structuredOutputError = controller.latestStructuredOutputToolError ?? STRUCTURED_OUTPUT_MISSING_ERROR;
16383
- if (correctiveAttempts >= STRUCTURED_OUTPUT_MAX_CORRECTIVE_PROMPTS) {
16834
+ if (!await controller.failCandidateForStructuredOutputExhaustion(structuredOutputError)) {
16384
16835
  throw new Error(structuredOutputError);
16385
16836
  }
16386
- correctiveAttempts += 1;
16387
- nextPrompt = formatStructuredOutputCorrectionPrompt(structuredOutputError, correctiveAttempts, hasOutputArtifact);
16388
16837
  }
16389
16838
  const sessionMessages = controller.currentSession?.messages;
16390
16839
  const executionSnapshot = structuredOutputExecutionCapture?.snapshot;
@@ -16610,9 +17059,9 @@ function createStageSessionHeartbeat(checkpoint, intervalMs = STAGE_SESSION_HEAR
16610
17059
 
16611
17060
  // dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts
16612
17061
  function createWorkflowStageFactory(input) {
16613
- return (name, options, stageFailFastScope) => {
17062
+ return (name, options, stageFailFastScope, prepareLiveOptions) => {
16614
17063
  input.exit.throwIfWorkflowExitSelected();
16615
- options = stageOptionsWithGitWorktree(stageOptionsWithInputDefaults(options, input.inputRuntimeDefaults), input.workflowInvocationCwd, input.gitWorktreeSetupCache);
17064
+ options = stageOptionsWithInputDefaults(options, input.inputRuntimeDefaults);
16616
17065
  const stageId = options?.durableStageId ?? crypto.randomUUID();
16617
17066
  const provisionalParentIds = input.tracker.onSpawn(stageId, name);
16618
17067
  const scopedParentIds = options?.durableParentIds ?? (input.opts.continuation === undefined ? stageFailFastScope?.parentIds : undefined);
@@ -16634,6 +17083,10 @@ function createWorkflowStageFactory(input) {
16634
17083
  const replaySource = replayDecision.kind === "replay" ? replayDecision.source : undefined;
16635
17084
  const executeReplaySource = replayDecision.kind === "execute" ? replayDecision.source : undefined;
16636
17085
  const shouldReplay = replaySource !== undefined;
17086
+ if (!shouldReplay) {
17087
+ input.assertLiveWorkAllowed?.();
17088
+ options = stageOptionsWithGitWorktree(prepareLiveOptions?.() ?? options, input.workflowInvocationCwd, input.gitWorktreeSetupCache);
17089
+ }
16637
17090
  const replayStageOptions = executeReplaySource?.sessionFile === undefined ? options : {
16638
17091
  ...options ?? {},
16639
17092
  context: options?.context ?? "fork",
@@ -16682,12 +17135,6 @@ function createWorkflowStageFactory(input) {
16682
17135
  const applyModelFallbackMeta = (meta2) => {
16683
17136
  if (meta2.model !== undefined)
16684
17137
  stageSnapshot.model = meta2.model;
16685
- if (meta2.fastMode !== undefined) {
16686
- if (meta2.fastMode)
16687
- stageSnapshot.fastMode = true;
16688
- else
16689
- delete stageSnapshot.fastMode;
16690
- }
16691
17138
  if (meta2.attemptedModels !== undefined)
16692
17139
  stageSnapshot.attemptedModels = meta2.attemptedModels;
16693
17140
  if (meta2.modelAttempts !== undefined)
@@ -17011,6 +17458,7 @@ class EngineRuntime {
17011
17458
  rootBudget;
17012
17459
  gitWorktreeSetupCache;
17013
17460
  worktreeSymlinkDirectories;
17461
+ assertLiveWorkAllowed;
17014
17462
  terminalArtifactCollectors = new Map;
17015
17463
  spawnAgentStage;
17016
17464
  spawnWorkflowBoundary;
@@ -17031,6 +17479,7 @@ class EngineRuntime {
17031
17479
  this.rootBudget = input.rootBudget;
17032
17480
  this.gitWorktreeSetupCache = input.gitWorktreeSetupCache;
17033
17481
  this.worktreeSymlinkDirectories = input.worktreeSymlinkDirectories;
17482
+ this.assertLiveWorkAllowed = input.assertLiveWorkAllowed;
17034
17483
  this.spawnAgentStage = createWorkflowStageFactory({
17035
17484
  runId: input.runId,
17036
17485
  workflowIntercomGroup: this.workflowIntercomGroup,
@@ -17049,6 +17498,7 @@ class EngineRuntime {
17049
17498
  budget: input.budget,
17050
17499
  exit: input.exit,
17051
17500
  classifyExecutorFailure: input.classifyExecutorFailure,
17501
+ assertLiveWorkAllowed: input.assertLiveWorkAllowed,
17052
17502
  createMcpScope: (stageId, options) => this.createMcpScope(stageId, options),
17053
17503
  takeTerminalArtifacts: (replayKey) => this.takeTerminalArtifacts(replayKey)
17054
17504
  });
@@ -17071,7 +17521,10 @@ class EngineRuntime {
17071
17521
  boundary: this.spawnWorkflowBoundary(name, opts.replayKey, opts.identity)
17072
17522
  };
17073
17523
  }
17074
- return { kind: "agent", context: this.spawnAgentStage(name, opts.options, opts.failFastScope) };
17524
+ return {
17525
+ kind: "agent",
17526
+ context: this.spawnAgentStage(name, opts.options, opts.failFastScope, opts.prepareLiveOptions)
17527
+ };
17075
17528
  }
17076
17529
  registerTerminalArtifactCollector(replayKey, collect) {
17077
17530
  this.terminalArtifactCollectors.set(replayKey, collect);
@@ -17201,6 +17654,9 @@ async function run(def, inputs, opts = {}) {
17201
17654
  const continuedBudgetState = opts.continuation?.source.budgetState ?? priorRun?.budgetState ?? (durableAccounting === undefined ? undefined : { accounting: durableAccounting });
17202
17655
  const sameBudget = budgetSnapshot !== undefined && continuedBudget?.warnAtPercent === budgetSnapshot.warnAtPercent && ["maxDurationMs", "maxTokens", "maxCost"].every((field2) => (continuedBudget?.[field2] ?? 0) === (budgetSnapshot[field2] ?? 0));
17203
17656
  const continuationBudgetState = continuedBudgetState === undefined || !sameBudget && continuedBudgetState.accounting === undefined ? undefined : sameBudget ? continuedBudgetState : { accounting: continuedBudgetState.accounting };
17657
+ const continuationSourceRunId = opts.continuation?.source.id;
17658
+ const persistedPossibleStages = coercePossibleStages(opts.possibleStages) ?? (continuationSourceRunId !== undefined ? coercePossibleStages(rootBackend.getWorkflow(continuationSourceRunId)?.possibleStages) : undefined);
17659
+ const runPossibleStages = persistedPossibleStages ?? coercePossibleStages(rootBackend.getWorkflow(runId)?.possibleStages) ?? [];
17204
17660
  const runSnapshot = {
17205
17661
  id: runId,
17206
17662
  name: def.name,
@@ -17211,6 +17667,7 @@ async function run(def, inputs, opts = {}) {
17211
17667
  pendingStageMessages: [
17212
17668
  ...pendingStageMessagesForDurableRun(rootBackend, runId, opts.parentRun?.rootRunId ?? runId)
17213
17669
  ],
17670
+ ...opts.parentRun === undefined ? { possibleStages: runPossibleStages } : {},
17214
17671
  startedAt: Date.now(),
17215
17672
  ...opts.parentRun !== undefined ? {
17216
17673
  parentRunId: opts.parentRun.runId,
@@ -17324,7 +17781,8 @@ async function run(def, inputs, opts = {}) {
17324
17781
  activeStore,
17325
17782
  opts,
17326
17783
  classifyExecutorFailure,
17327
- drainWorkflowExitCleanups: exit.drainWorkflowExitCleanups
17784
+ drainWorkflowExitCleanups: exit.drainWorkflowExitCleanups,
17785
+ assertSuccessfulCompletion: () => assertFrontierConsumed()
17328
17786
  });
17329
17787
  const checkpointIdGenerator = createCheckpointIdGenerator();
17330
17788
  const stageReplayKeyGenerator = createStageReplayKeyGenerator(runId);
@@ -17421,6 +17879,7 @@ async function run(def, inputs, opts = {}) {
17421
17879
  worktreeSymlinkDirectories: opts.config?.worktree?.symlinkDirectories,
17422
17880
  exit,
17423
17881
  classifyExecutorFailure,
17882
+ assertLiveWorkAllowed: () => assertFrontierConsumed(),
17424
17883
  rootBudget,
17425
17884
  budget
17426
17885
  });
@@ -17460,9 +17919,10 @@ async function run(def, inputs, opts = {}) {
17460
17919
  createdAt: runSnapshot.startedAt,
17461
17920
  hasPersistence: opts.persistence !== undefined,
17462
17921
  isChildRun: opts.parentRun !== undefined,
17463
- continuationSourceId: opts.continuation?.source.id
17922
+ continuationSourceId: opts.continuation?.source.id,
17923
+ ...persistedPossibleStages === undefined ? {} : { possibleStages: persistedPossibleStages }
17464
17924
  });
17465
- const { tool, admittedTools, abandonInFlightAsCancelled, observedQuitCancellation } = createTrackedToolPrimitive({
17925
+ const { tool, admittedTools, assertFrontierConsumed, abandonInFlightAsCancelled, observedQuitCancellation } = createTrackedToolPrimitive({
17466
17926
  workflowId: runId,
17467
17927
  ...opts.continuation === undefined ? {} : { checkpointSourceWorkflowId: opts.continuation.source.id },
17468
17928
  backend: durableBackend,
@@ -17473,6 +17933,7 @@ async function run(def, inputs, opts = {}) {
17473
17933
  tracker,
17474
17934
  run: runSnapshot,
17475
17935
  sourceToContinuationNodeIds,
17936
+ resumeToolNode: opts.continuation?.source.toolNodes?.find((node) => node.id === opts.continuation?.resumeFromToolNodeId),
17476
17937
  toolControls,
17477
17938
  toolAdmission,
17478
17939
  budget
@@ -17656,6 +18117,8 @@ async function run(def, inputs, opts = {}) {
17656
18117
  assertWorkflowCreatedExecution(runSnapshot);
17657
18118
  await durableBackend.flush(runId);
17658
18119
  const returned = classifyReturnedRunStatus(result, runSnapshot);
18120
+ if (returned.status === "completed")
18121
+ assertFrontierConsumed();
17659
18122
  const recorded = activeStore.recordRunEnd(runId, returned.status, result, returned.error, returned.metadata);
17660
18123
  appendRunEndWhenRecorded(opts.persistence, recorded, {
17661
18124
  runId,
@@ -17717,7 +18180,7 @@ async function run(def, inputs, opts = {}) {
17717
18180
  stages: runSnapshot.stages,
17718
18181
  classifyFailure: classifyExecutorFailure
17719
18182
  }), runSnapshot.stages.length));
17720
- const failedToolNodeId = selectedMetadata2.failedStageId === undefined && selectedMetadata2.failureKind !== "cancelled" && selectedMetadata2.failureDisposition !== "terminal_killed" ? catchTerminalEvent?.kind === "failure" && Object.is(catchTerminalEvent.error, err) ? catchTerminalEvent.nodeId ?? observedAdmittedToolFailure?.nodeId : observedAdmittedToolFailure?.nodeId : undefined;
18183
+ const failedToolNodeId = selectedMetadata2.failedStageId === undefined && selectedMetadata2.failureDisposition !== "terminal_killed" ? catchTerminalEvent?.kind === "failure" && Object.is(catchTerminalEvent.error, err) ? catchTerminalEvent.nodeId ?? observedAdmittedToolFailure?.nodeId : observedAdmittedToolFailure?.nodeId : undefined;
17721
18184
  const metadata = failedToolNodeId === undefined ? selectedMetadata2 : { ...selectedMetadata2, failedToolNodeId };
17722
18185
  if (metadata.failureDisposition === "terminal_killed") {
17723
18186
  for (const failedStageId of metadata.failedStageIds)