@bastani/atomic 0.9.40 → 0.9.41-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/intercom/CHANGELOG.md +12 -0
  4. package/dist/builtin/intercom/README.md +1 -1
  5. package/dist/builtin/intercom/broker/broker.ts +24 -21
  6. package/dist/builtin/intercom/broker/client.ts +97 -6
  7. package/dist/builtin/intercom/broker/list-reply.ts +53 -0
  8. package/dist/builtin/intercom/index.bundle.mjs +278 -46
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/recoverable-disconnect.ts +27 -1
  11. package/dist/builtin/intercom/types.ts +8 -1
  12. package/dist/builtin/mcp/package.json +1 -1
  13. package/dist/builtin/subagents/CHANGELOG.md +14 -0
  14. package/dist/builtin/subagents/README.md +14 -0
  15. package/dist/builtin/subagents/package.json +1 -1
  16. package/dist/builtin/subagents/src/extension/index.bundle.mjs +99 -19
  17. package/dist/builtin/web-access/package.json +1 -1
  18. package/dist/builtin/workflows/CHANGELOG.md +25 -0
  19. package/dist/builtin/workflows/README.md +2 -0
  20. package/dist/builtin/workflows/package.json +1 -1
  21. package/dist/builtin/workflows/src/authoring.d.ts +1 -1
  22. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +16 -0
  23. package/dist/builtin/workflows/src/durable/journal/legacy-journal-tables.d.ts +9 -0
  24. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +6 -0
  25. package/dist/builtin/workflows/src/extension/index.bundle.mjs +441 -90
  26. package/dist/builtin/workflows/src/index.js +226 -34
  27. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +17 -1
  28. package/dist/cli/credential-print.d.ts.map +1 -1
  29. package/dist/cli/credential-print.js +1 -1
  30. package/dist/cli/credential-print.js.map +1 -1
  31. package/dist/config.d.ts +1 -0
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +1 -0
  34. package/dist/config.js.map +1 -1
  35. package/dist/core/agent-session-extension-bindings.d.ts +2 -1
  36. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  37. package/dist/core/agent-session-extension-bindings.js +33 -18
  38. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  39. package/dist/core/agent-session-methods.d.ts +2 -1
  40. package/dist/core/agent-session-methods.d.ts.map +1 -1
  41. package/dist/core/agent-session-methods.js.map +1 -1
  42. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  43. package/dist/core/agent-session-prompt.js +114 -21
  44. package/dist/core/agent-session-prompt.js.map +1 -1
  45. package/dist/core/agent-session-runtime.d.ts +1 -1
  46. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  47. package/dist/core/agent-session-runtime.js +6 -0
  48. package/dist/core/agent-session-runtime.js.map +1 -1
  49. package/dist/core/agent-session-state.d.ts +19 -1
  50. package/dist/core/agent-session-state.d.ts.map +1 -1
  51. package/dist/core/agent-session-state.js +41 -6
  52. package/dist/core/agent-session-state.js.map +1 -1
  53. package/dist/core/auth-storage-backends.d.ts +3 -1
  54. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  55. package/dist/core/auth-storage-backends.js +79 -12
  56. package/dist/core/auth-storage-backends.js.map +1 -1
  57. package/dist/core/client-identity.d.ts +8 -0
  58. package/dist/core/client-identity.d.ts.map +1 -0
  59. package/dist/core/client-identity.js +16 -0
  60. package/dist/core/client-identity.js.map +1 -0
  61. package/dist/core/compaction/planner-outcome.d.ts.map +1 -1
  62. package/dist/core/compaction/planner-outcome.js +2 -1
  63. package/dist/core/compaction/planner-outcome.js.map +1 -1
  64. package/dist/core/execution-model-router.d.ts +18 -0
  65. package/dist/core/execution-model-router.d.ts.map +1 -1
  66. package/dist/core/execution-model-router.js +14 -8
  67. package/dist/core/execution-model-router.js.map +1 -1
  68. package/dist/core/extension-oauth-refresh-rejection.d.ts +12 -0
  69. package/dist/core/extension-oauth-refresh-rejection.d.ts.map +1 -0
  70. package/dist/core/extension-oauth-refresh-rejection.js +70 -0
  71. package/dist/core/extension-oauth-refresh-rejection.js.map +1 -0
  72. package/dist/core/extension-startup-failure.d.ts +30 -0
  73. package/dist/core/extension-startup-failure.d.ts.map +1 -0
  74. package/dist/core/extension-startup-failure.js +62 -0
  75. package/dist/core/extension-startup-failure.js.map +1 -0
  76. package/dist/core/extensions/context-types.d.ts +2 -0
  77. package/dist/core/extensions/context-types.d.ts.map +1 -1
  78. package/dist/core/extensions/context-types.js.map +1 -1
  79. package/dist/core/extensions/provider-types.d.ts +2 -0
  80. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  81. package/dist/core/extensions/provider-types.js.map +1 -1
  82. package/dist/core/extensions/runner-context.d.ts +1 -0
  83. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  84. package/dist/core/extensions/runner-context.js +8 -0
  85. package/dist/core/extensions/runner-context.js.map +1 -1
  86. package/dist/core/extensions/runner.d.ts +1 -0
  87. package/dist/core/extensions/runner.d.ts.map +1 -1
  88. package/dist/core/extensions/runner.js +3 -0
  89. package/dist/core/extensions/runner.js.map +1 -1
  90. package/dist/core/extensions/runtime-types.d.ts +1 -0
  91. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  92. package/dist/core/extensions/runtime-types.js.map +1 -1
  93. package/dist/core/extensions/workflow-run-control-hub.d.ts +1 -0
  94. package/dist/core/extensions/workflow-run-control-hub.d.ts.map +1 -1
  95. package/dist/core/extensions/workflow-run-control-hub.js +3 -0
  96. package/dist/core/extensions/workflow-run-control-hub.js.map +1 -1
  97. package/dist/core/extensions/workflow-run-control.d.ts +8 -0
  98. package/dist/core/extensions/workflow-run-control.d.ts.map +1 -1
  99. package/dist/core/extensions/workflow-run-control.js.map +1 -1
  100. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  101. package/dist/core/model-fallback-failures.js +12 -0
  102. package/dist/core/model-fallback-failures.js.map +1 -1
  103. package/dist/core/model-resolver-defaults.js +1 -1
  104. package/dist/core/model-resolver-defaults.js.map +1 -1
  105. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  106. package/dist/core/model-runtime-streaming.js +9 -3
  107. package/dist/core/model-runtime-streaming.js.map +1 -1
  108. package/dist/core/model-runtime.d.ts +5 -0
  109. package/dist/core/model-runtime.d.ts.map +1 -1
  110. package/dist/core/model-runtime.js +6 -0
  111. package/dist/core/model-runtime.js.map +1 -1
  112. package/dist/core/provider-composer-internal.d.ts +6 -5
  113. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  114. package/dist/core/provider-composer-internal.js +13 -2
  115. package/dist/core/provider-composer-internal.js.map +1 -1
  116. package/dist/core/sdk.d.ts.map +1 -1
  117. package/dist/core/sdk.js +12 -4
  118. package/dist/core/sdk.js.map +1 -1
  119. package/dist/core/storage/session/sql-session-store.d.ts +35 -0
  120. package/dist/core/storage/session/sql-session-store.d.ts.map +1 -1
  121. package/dist/core/storage/session/sql-session-store.js +158 -42
  122. package/dist/core/storage/session/sql-session-store.js.map +1 -1
  123. package/dist/core/structured-output/deadline.d.ts +40 -0
  124. package/dist/core/structured-output/deadline.d.ts.map +1 -0
  125. package/dist/core/structured-output/deadline.js +110 -0
  126. package/dist/core/structured-output/deadline.js.map +1 -0
  127. package/dist/core/structured-output/index.d.ts.map +1 -1
  128. package/dist/core/structured-output/index.js +103 -47
  129. package/dist/core/structured-output/index.js.map +1 -1
  130. package/dist/core/structured-output/rejection-detail.d.ts +9 -0
  131. package/dist/core/structured-output/rejection-detail.d.ts.map +1 -0
  132. package/dist/core/structured-output/rejection-detail.js +129 -0
  133. package/dist/core/structured-output/rejection-detail.js.map +1 -0
  134. package/dist/core/structured-output/types.d.ts +8 -1
  135. package/dist/core/structured-output/types.d.ts.map +1 -1
  136. package/dist/core/structured-output/types.js.map +1 -1
  137. package/dist/core/tasks/completion.d.ts +7 -1
  138. package/dist/core/tasks/completion.d.ts.map +1 -1
  139. package/dist/core/tasks/completion.js +28 -6
  140. package/dist/core/tasks/completion.js.map +1 -1
  141. package/dist/core/tasks/contracts.d.ts +6 -1
  142. package/dist/core/tasks/contracts.d.ts.map +1 -1
  143. package/dist/core/tasks/contracts.js.map +1 -1
  144. package/dist/core/tasks/pause.d.ts +2 -1
  145. package/dist/core/tasks/pause.d.ts.map +1 -1
  146. package/dist/core/tasks/pause.js +3 -2
  147. package/dist/core/tasks/pause.js.map +1 -1
  148. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  149. package/dist/core/tools/bash-pty-native.js +10 -5
  150. package/dist/core/tools/bash-pty-native.js.map +1 -1
  151. package/dist/core/tools/bash.d.ts.map +1 -1
  152. package/dist/core/tools/bash.js +16 -32
  153. package/dist/core/tools/bash.js.map +1 -1
  154. package/dist/core/tools/kill.d.ts.map +1 -1
  155. package/dist/core/tools/kill.js +17 -3
  156. package/dist/core/tools/kill.js.map +1 -1
  157. package/dist/core/tools/shell-task-render.d.ts +55 -0
  158. package/dist/core/tools/shell-task-render.d.ts.map +1 -0
  159. package/dist/core/tools/shell-task-render.js +123 -0
  160. package/dist/core/tools/shell-task-render.js.map +1 -0
  161. package/dist/core/tools/shell-task-status.d.ts +52 -0
  162. package/dist/core/tools/shell-task-status.d.ts.map +1 -0
  163. package/dist/core/tools/shell-task-status.js +184 -0
  164. package/dist/core/tools/shell-task-status.js.map +1 -0
  165. package/dist/core/tools/structured-output.d.ts +5 -0
  166. package/dist/core/tools/structured-output.d.ts.map +1 -1
  167. package/dist/core/tools/structured-output.js +3 -0
  168. package/dist/core/tools/structured-output.js.map +1 -1
  169. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  170. package/dist/extensions/codemode/execute.js +134 -57
  171. package/dist/extensions/codemode/execute.js.map +1 -1
  172. package/dist/extensions/mcp/config.d.ts.map +1 -1
  173. package/dist/extensions/mcp/config.js +3 -2
  174. package/dist/extensions/mcp/config.js.map +1 -1
  175. package/dist/index-extensions.d.ts +1 -0
  176. package/dist/index-extensions.d.ts.map +1 -1
  177. package/dist/index-extensions.js +3 -0
  178. package/dist/index-extensions.js.map +1 -1
  179. package/dist/index.d.ts +3 -1
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +3 -1
  182. package/dist/index.js.map +1 -1
  183. package/dist/main.d.ts.map +1 -1
  184. package/dist/main.js +19 -6
  185. package/dist/main.js.map +1 -1
  186. package/dist/modes/interactive/components/task-row.d.ts.map +1 -1
  187. package/dist/modes/interactive/components/task-row.js +11 -1
  188. package/dist/modes/interactive/components/task-row.js.map +1 -1
  189. package/dist/modes/interactive/interactive-auth-routing.js +12 -10
  190. package/dist/modes/interactive/interactive-auth-routing.js.map +1 -1
  191. package/dist/modes/interactive/interactive-extension-custom-ui.js +20 -30
  192. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  193. package/dist/modes/interactive/interactive-extension-dialogs.js +23 -96
  194. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  195. package/dist/modes/interactive/interactive-extension-runtime.js +7 -8
  196. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  197. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  198. package/dist/modes/interactive/interactive-input-handling.js +27 -4
  199. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  200. package/dist/modes/interactive/interactive-mode-base.d.ts +20 -10
  201. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  202. package/dist/modes/interactive/interactive-mode-base.js +40 -5
  203. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  204. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  205. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  206. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  207. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  208. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -4
  209. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  210. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  211. package/dist/modes/interactive/interactive-mode-types.d.ts +4 -1
  212. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  213. package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
  214. package/dist/modes/interactive/interactive-prompt-restore.d.ts +3 -0
  215. package/dist/modes/interactive/interactive-prompt-restore.d.ts.map +1 -1
  216. package/dist/modes/interactive/interactive-prompt-restore.js +9 -1
  217. package/dist/modes/interactive/interactive-prompt-restore.js.map +1 -1
  218. package/dist/modes/interactive/interactive-prompt-turn.js +30 -2
  219. package/dist/modes/interactive/interactive-prompt-turn.js.map +1 -1
  220. package/dist/modes/interactive/interactive-queueing.js +43 -8
  221. package/dist/modes/interactive/interactive-queueing.js.map +1 -1
  222. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  223. package/dist/modes/interactive/interactive-startup.js +12 -3
  224. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  225. package/dist/modes/interactive/theme/color-utils.d.ts +6 -1
  226. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  227. package/dist/modes/interactive/theme/color-utils.js +39 -17
  228. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  229. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  230. package/dist/modes/interactive/theme/theme-class.js +2 -2
  231. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  232. package/dist/modes/interactive/theme/theme-tokens.d.ts +6 -0
  233. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -1
  234. package/dist/modes/interactive/theme/theme-tokens.js +7 -3
  235. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -1
  236. package/dist/modes/interactive-engine/isolated-auth.d.ts +3 -0
  237. package/dist/modes/interactive-engine/isolated-auth.d.ts.map +1 -1
  238. package/dist/modes/interactive-engine/isolated-auth.js +13 -1
  239. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  240. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  241. package/dist/modes/interactive-engine/isolated-runtime.js +11 -2
  242. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  243. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +8 -0
  244. package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
  245. package/dist/modes/interactive-engine/remote-model-catalog.js +54 -0
  246. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  247. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  248. package/dist/modes/rpc/rpc-command-handler.js +4 -13
  249. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  250. package/dist/modes/rpc/rpc-model-catalog.d.ts +9 -0
  251. package/dist/modes/rpc/rpc-model-catalog.d.ts.map +1 -0
  252. package/dist/modes/rpc/rpc-model-catalog.js +19 -0
  253. package/dist/modes/rpc/rpc-model-catalog.js.map +1 -0
  254. package/dist/modes/rpc/rpc-provider-auth.d.ts.map +1 -1
  255. package/dist/modes/rpc/rpc-provider-auth.js +2 -6
  256. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  257. package/dist/modes/rpc/rpc-types.d.ts +6 -0
  258. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  259. package/dist/modes/rpc/rpc-types.js.map +1 -1
  260. package/dist/utils/changelog.d.ts +6 -0
  261. package/dist/utils/changelog.d.ts.map +1 -1
  262. package/dist/utils/changelog.js +11 -0
  263. package/dist/utils/changelog.js.map +1 -1
  264. package/dist/utils/clipboard.d.ts.map +1 -1
  265. package/dist/utils/clipboard.js +4 -0
  266. package/dist/utils/clipboard.js.map +1 -1
  267. package/dist/utils/tools-manager.d.ts.map +1 -1
  268. package/dist/utils/tools-manager.js +3 -2
  269. package/dist/utils/tools-manager.js.map +1 -1
  270. package/docs/background-tasks.md +5 -3
  271. package/docs/codemode.md +2 -2
  272. package/docs/custom-provider/oauth.md +42 -1
  273. package/docs/custom-provider/registration.md +2 -0
  274. package/docs/environment-variables.md +1 -0
  275. package/docs/extensions/api-reference.md +3 -4
  276. package/docs/extensions/authoring.md +1 -1
  277. package/docs/extensions/events.md +1 -1
  278. package/docs/providers.md +3 -3
  279. package/docs/rpc/protocol.md +4 -2
  280. package/docs/sdk/reference.md +2 -0
  281. package/docs/sdk/structured-decisions.md +7 -5
  282. package/docs/sdk.md +5 -2
  283. package/docs/settings.md +4 -2
  284. package/docs/subagents/reference.md +1 -1
  285. package/docs/subagents.md +15 -1
  286. package/docs/themes/reference.md +3 -1
  287. package/docs/usage.md +3 -1
  288. package/docs/workflows/api-reference.md +28 -0
  289. package/docs/workflows/operations.md +2 -2
  290. package/npm-shrinkwrap.json +32 -32
  291. package/package.json +3 -3
  292. package/dist/core/provider-attribution.d.ts +0 -4
  293. package/dist/core/provider-attribution.d.ts.map +0 -1
  294. package/dist/core/provider-attribution.js +0 -87
  295. package/dist/core/provider-attribution.js.map +0 -1
@@ -18,6 +18,10 @@
18
18
  * reconnect, or the previous attempt's session is still being torn down), the
19
19
  * same bounded retry that recovers a lost socket clears it (#3163). A refusal
20
20
  * whose code repeats identically on retry is not recoverable.
21
+ *
22
+ * A broker that accepts the socket but does not answer a registration in time is
23
+ * saturated, not gone. Its timeout is recoverable for the same reason, and a
24
+ * background relay that sees it keeps quiet unless the outage persists.
21
25
  */
22
26
 
23
27
  import { IntercomLiveRouteRefusedError } from "./live-route-refusal.js";
@@ -47,8 +51,18 @@ export class IntercomClientDisconnectedError extends Error implements Recoverabl
47
51
  }
48
52
  }
49
53
 
54
+ /** Raised when the broker accepted the socket but did not answer a registration within its bound. */
55
+ export class IntercomBrokerTimeoutError extends Error implements RecoverableDisconnectMarker {
56
+ readonly intercomRecoverableDisconnect = true;
57
+
58
+ constructor(message: string, options?: ErrorOptions) {
59
+ super(message, options);
60
+ this.name = "IntercomBrokerTimeoutError";
61
+ }
62
+ }
63
+
50
64
  /**
51
- * True for an `IntercomClientDisconnectedError` or a transient
65
+ * True for an `IntercomClientDisconnectedError`, an `IntercomBrokerTimeoutError`, or a transient
52
66
  * `IntercomLiveRouteRefusedError`, directly or as a bounded `cause` ancestor.
53
67
  */
54
68
  export function isRecoverableIntercomDisconnect(error: unknown): boolean {
@@ -56,8 +70,20 @@ export function isRecoverableIntercomDisconnect(error: unknown): boolean {
56
70
  for (let depth = 0; depth <= MAX_CAUSE_DEPTH; depth += 1) {
57
71
  if (!(current instanceof Error)) return false;
58
72
  if (current instanceof IntercomClientDisconnectedError) return true;
73
+ if (current instanceof IntercomBrokerTimeoutError) return true;
59
74
  if (current instanceof IntercomLiveRouteRefusedError) return current.transient;
60
75
  current = current.cause;
61
76
  }
62
77
  return false;
63
78
  }
79
+
80
+ /** True for an `IntercomBrokerTimeoutError`, directly or as a bounded `cause` ancestor. */
81
+ export function isIntercomBrokerTimeout(error: unknown): boolean {
82
+ let current: unknown = error;
83
+ for (let depth = 0; depth <= MAX_CAUSE_DEPTH; depth += 1) {
84
+ if (!(current instanceof Error)) return false;
85
+ if (current instanceof IntercomBrokerTimeoutError) return true;
86
+ current = current.cause;
87
+ }
88
+ return false;
89
+ }
@@ -70,6 +70,8 @@ export interface SessionDirectory {
70
70
  readonly sessions: SessionInfo[];
71
71
  readonly workflowStages: WorkflowStageRosterEntry[];
72
72
  readonly workflowFutureStages: WorkflowFutureStageRosterEntry[];
73
+ /** The peeked workflow invocation group exists but is visible only to its members. */
74
+ readonly restricted?: true;
73
75
  }
74
76
 
75
77
  export interface WorkflowStageRosterAnnouncement {
@@ -186,6 +188,8 @@ export type ClientMessage =
186
188
  | { type: "pending_stage_notification_result"; requestId: string; delivered: boolean }
187
189
  | {
188
190
  type: "register_pending_stage_route";
191
+ /** When present, the broker answers with `pending_stage_route_registered` once the route is applied. */
192
+ requestId?: string;
189
193
  runId: string;
190
194
  group: string;
191
195
  capability: string;
@@ -230,10 +234,12 @@ export type BrokerMessage =
230
234
  supervisorSessionId?: string;
231
235
  /** #3761: echoed only to a client that advertised it; that client may now send `received`. */
232
236
  acknowledgesReceipt?: true;
237
+ /** This broker acknowledges a `register_pending_stage_route` that carries a `requestId`; absent on older brokers. */
238
+ acknowledgesPendingStageRoutes?: true;
233
239
  }
234
240
  | { type: "registration_failed"; reason: string; code?: LiveWorkflowStageRouteRefusalCode }
235
241
  | { type: "question_target"; messageId: string; attemptId: string; sessionId: string }
236
- | { type: "sessions"; requestId: string; sessions: SessionInfo[]; workflowStages?: WorkflowStageRosterEntry[]; workflowFutureStages?: WorkflowFutureStageRosterEntry[] }
242
+ | { type: "sessions"; requestId: string; sessions: SessionInfo[]; workflowStages?: WorkflowStageRosterEntry[]; workflowFutureStages?: WorkflowFutureStageRosterEntry[]; restricted?: true }
237
243
  | { type: "groups"; requestId: string; groups: GroupSummary[] }
238
244
  | { type: "membership_ack"; requestId: string; groups: string[] }
239
245
  | { type: "supervisor_authorized"; requestId: string; capability: string; supervisorSessionId: string; childName: string }
@@ -251,6 +257,7 @@ export type BrokerMessage =
251
257
  live?: boolean;
252
258
  }
253
259
  | { type: "live_workflow_stage_route_registered"; requestId: string }
260
+ | { type: "pending_stage_route_registered"; requestId: string }
254
261
  /** A dormant route's run was resumed by another process, which now owns the run's routes (#3760). */
255
262
  | { type: "pending_stage_route_revoked"; runId: string }
256
263
  | { type: "presence_update"; session: SessionInfo }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.40",
3
+ "version": "0.9.41-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic's pi-compatible MCP integration for server connections, OAuth, tools, resources, and terminal management.",
6
6
  "contributors": [
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.41-alpha.1] - 2026-10-21
6
+
7
+ ### Added
8
+
9
+ - Added a `resumeInFlight` subagent setting (`"never"`, `"ask"`, or `"auto"`, default `"never"`) for recovery of paused and quit subagents that are awaiting resume. `ask` confirms once, listing each subagent, and `auto` resumes each from its own session, with its completion reaching the session that launched it; `never` leaves them for a manual `resume`. It applies when Atomic starts or a session is resumed, to that session's own subagents, never to workflow-stage children, and an invalid value is reported and treated as `never` ([#3827](https://github.com/bastani-inc/atomic/issues/3827)).
10
+
11
+ ### Changed
12
+
13
+ - Quitting a subagent now behaves like quitting a workflow. The `quit` and `pause` results say the child is paused · awaiting resume and name `{ action: "resume", id: "<child-id>" }`; the parent's completion notice says the same, with the typed `quit` or `pause` stop reason instead of `parent-handoff` and without "This execution has ended". `{ action: "status", id }` reports a paused or quit child as paused · awaiting resume with its resume call, and `{ action: "status" }` lists every such child, including after Atomic restarts. Launch cards of such children show `‖ Paused · awaiting resume` (or `‖ Quit · paused · awaiting resume`) instead of `(resumable)`.
14
+
15
+ ### Fixed
16
+
17
+ - A subagent with `model: "auto"` no longer waits indefinitely on a slow routing model. Each routing inference now stops after the `httpIdleTimeoutMs` deadline (10 minutes by default), and the subagent runs on the current chat model when it satisfies the routing constraints ([#3806](https://github.com/bastani-inc/atomic/issues/3806))
18
+
5
19
  ## [0.9.40] - 2026-10-20
6
20
 
7
21
  ### Breaking Changes
@@ -620,6 +620,20 @@ Subagent configuration controls discovery, parallel limits, session storage, con
620
620
 
621
621
  Running capacity is selected when a parent's first child is created. Restart Atomic after changing this setting to apply the new capacity.
622
622
 
623
+ ### `resumeInFlight`
624
+
625
+ ```json
626
+ { "resumeInFlight": "ask" }
627
+ ```
628
+
629
+ Recovery of paused and quit subagents that are awaiting resume when a session starts or is resumed, using the same values as the workflow setting of that name:
630
+
631
+ - `never` (default): leave them listed under "Awaiting resume" for a manual `resume`.
632
+ - `ask`: confirm once, listing each subagent by name and id. No leaves them awaiting resume; without a UI it behaves like `never`.
633
+ - `auto`: resume each from its own session. Its result reaches the session that launched it.
634
+
635
+ Starting Atomic and resuming a session recover children; a reload, new session, or fork does not. Only children launched by the session being started or resumed are affected; workflow-stage children are never resumed this way. Any other value is reported and treated as `never`.
636
+
623
637
  ### `defaultSessionDir`
624
638
 
625
639
  ```json
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.40",
3
+ "version": "0.9.41-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -8467,6 +8467,7 @@ var SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom";
8467
8467
  var SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
8468
8468
  var SUBAGENT_TERMINAL_ORDERING_BARRIER_EVENT = "subagent:terminal-ordering-barrier";
8469
8469
  var SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery";
8470
+ var RESUME_IN_FLIGHT_MODES = ["ask", "auto", "never"];
8470
8471
  // dist/builtin/subagents/src/shared/types-depth.ts
8471
8472
  function isWorkflowStageOrchestrationContext(ctx) {
8472
8473
  return ctx.orchestrationContext?.kind === "workflow-stage";
@@ -10558,7 +10559,11 @@ function retainedTaskOutput(ownerId, taskId) {
10558
10559
 
10559
10560
  // dist/builtin/subagents/src/runs/foreground/task-execution.ts
10560
10561
  function subagentTaskResultLabel(result) {
10561
- return result.kind === "cancelled" && result.cause === "user" ? "killed (non-resumable)" : result.kind;
10562
+ if (result.kind === "cancelled" && result.cause === "user")
10563
+ return "killed (non-resumable)";
10564
+ if (result.kind === "cancelled" && (result.cause === "pause" || result.cause === "quit"))
10565
+ return "paused · awaiting resume";
10566
+ return result.kind;
10562
10567
  }
10563
10568
  function subagentTaskResponseText(response) {
10564
10569
  const outcomes = response.kind === "parallel" ? response.slots.map((slot) => slot.outcome) : [response];
@@ -10887,7 +10892,7 @@ ${launch.message}` : input.task,
10887
10892
  });
10888
10893
  const stopped = takeSubagentChildStop(context.ref.taskId);
10889
10894
  const stoppedByControl = stopped !== undefined && child.status === "interrupted";
10890
- const stoppedByStagePause = !stoppedByControl && child.status === "interrupted" && context.signal.aborted && context.signal.reason === "parent-handoff";
10895
+ const stoppedByStagePause = !stoppedByControl && child.status === "interrupted" && context.signal.aborted && context.signal.reason === "pause";
10891
10896
  const endedForGood = ownerClosed() && input.recordChild?.ownerEndedForGood?.() === true;
10892
10897
  if (stopped !== undefined && !stoppedByControl)
10893
10898
  unparkRunWorktree(runId, index);
@@ -10921,7 +10926,7 @@ ${launch.message}` : input.task,
10921
10926
  if (child.interrupted)
10922
10927
  return {
10923
10928
  kind: "cancelled",
10924
- cause: stoppedByControl || stoppedByStagePause || input.options.interruptSignal?.aborted ? "parent-handoff" : "owner-close",
10929
+ cause: stoppedByControl ? stopped === "quit" ? "quit" : "pause" : stoppedByStagePause ? "pause" : input.options.interruptSignal?.aborted ? "parent-handoff" : "owner-close",
10925
10930
  output
10926
10931
  };
10927
10932
  return child.status === "ok" ? { kind: "completed", output } : {
@@ -17474,7 +17479,7 @@ async function stopHostChild(deps, host, record, status) {
17474
17479
  const taskId = record.taskId;
17475
17480
  requestSubagentChildStop(taskId, status);
17476
17481
  parkRunWorktree(record.runId, record.index);
17477
- const cancelled = await host.cancelTask(taskId, "parent-handoff");
17482
+ const cancelled = await host.cancelTask(taskId, status === "quit" ? "quit" : "pause");
17478
17483
  if (!cancelled.ok) {
17479
17484
  unparkRunWorktree(record.runId, record.index);
17480
17485
  return cancelled.error.message;
@@ -17550,7 +17555,7 @@ async function stopChildren(deps, ctx, request) {
17550
17555
  continue;
17551
17556
  }
17552
17557
  children.push(childDetails(record, status));
17553
- lines.push(action === "pause" ? `Paused ${label(record)}. Its queued messages are held until resume; resume it with { action: "resume", id: "${record.childId}", message? }.` : `Quit ${label(record)}. It stays resumable with { action: "resume", id: "${record.childId}", message? }.`);
17558
+ lines.push(action === "pause" ? `Paused ${label(record)} · awaiting resume. Its queued messages are held until resume; resume it with { action: "resume", id: "${record.childId}", message? }.` : `Quit ${label(record)}: paused · awaiting resume, as a quit workflow run is. It stays resumable with { action: "resume", id: "${record.childId}", message? }.`);
17554
17559
  continue;
17555
17560
  }
17556
17561
  const stopped = stoppedAs(record);
@@ -17559,7 +17564,7 @@ async function stopChildren(deps, ctx, request) {
17559
17564
  releasePausedChildHold(key);
17560
17565
  await recordSubagentChildStatus(deps.pi, record, "quit");
17561
17566
  children.push(childDetails(record, "quit"));
17562
- lines.push(`Quit paused ${label(record)}. It stays resumable.`);
17567
+ lines.push(`Quit paused ${label(record)}: paused · awaiting resume. It stays resumable with { action: "resume", id: "${record.childId}", message? }.`);
17563
17568
  continue;
17564
17569
  }
17565
17570
  children.push(childDetails(record, stopped));
@@ -17605,6 +17610,18 @@ async function resumeChild(deps, ctx, request) {
17605
17610
  ...message ? { message } : {}
17606
17611
  });
17607
17612
  }
17613
+ function awaitingResumeLine(record) {
17614
+ const how = record.terminalStatus === "quit" ? "quit · paused · awaiting resume" : record.terminalStatus === SUBAGENT_CHILD_STAGE_PAUSED_STATUS ? "paused with its workflow stage · awaiting resume" : "paused · awaiting resume";
17615
+ return `${label(record)} ${how}. Resume it with { action: "resume", id: "${record.childId}", message? }.`;
17616
+ }
17617
+ function subagentChildrenAwaitingResume(ctx, id) {
17618
+ const records = ownedRecords(ctx);
17619
+ if (id?.trim()) {
17620
+ const resolved = resolveRecord(records, id);
17621
+ return typeof resolved === "object" && stoppedAs(resolved) ? [awaitingResumeLine(resolved)] : [];
17622
+ }
17623
+ return [...records.values()].filter((record) => stoppedAs(record)).map(awaitingResumeLine);
17624
+ }
17608
17625
  function controlSubagentChildren(deps, ctx, request) {
17609
17626
  if (request.all && request.id)
17610
17627
  return Promise.resolve(errorResult(request.action, "Pass either id or all: true, not both."));
@@ -17612,6 +17629,42 @@ function controlSubagentChildren(deps, ctx, request) {
17612
17629
  return Promise.resolve(errorResult(request.action, `${request.action} needs the id of a child, or all: true.`));
17613
17630
  return request.action === "resume" ? resumeChild(deps, ctx, request) : stopChildren(deps, ctx, { ...request, action: request.action });
17614
17631
  }
17632
+ async function resumeAwaitingSubagentChildren(deps, ctx, mode, isCurrent) {
17633
+ if (mode === "never" || ctx.isPresentationOnly === true)
17634
+ return;
17635
+ if (isSubagentChildSession(ctx) || isWorkflowStageOrchestrationContext(ctx))
17636
+ return;
17637
+ if (mode === "ask" && (ctx.hasUI === false || typeof ctx.ui?.confirm !== "function"))
17638
+ return;
17639
+ const notify = (message, type) => {
17640
+ try {
17641
+ ctx.ui?.notify?.(message, type);
17642
+ } catch {
17643
+ return;
17644
+ }
17645
+ };
17646
+ try {
17647
+ const awaiting = [...ownedRecords(ctx).values()].filter((record) => record.owner.kind === "session" && stoppedAs(record));
17648
+ if (awaiting.length === 0)
17649
+ return;
17650
+ if (mode === "ask" && !await ctx.ui.confirm("Resume interrupted subagents?", `${awaiting.length} interrupted subagent(s) can resume from their own sessions:
17651
+ ${awaiting.map((record) => `- ${label(record)}`).join(`
17652
+ `)}
17653
+ Resume now? Choose No to leave them awaiting resume; resume one later with subagent({ action: "resume", id }).`))
17654
+ return;
17655
+ for (const record of awaiting) {
17656
+ if (!isCurrent())
17657
+ return;
17658
+ const result = await controlSubagentChildren(deps, ctx, { action: "resume", id: record.childId });
17659
+ notify(result.content.map((part) => part.type === "text" ? part.text : "").join(`
17660
+ `), result.isError ? "warning" : "info");
17661
+ }
17662
+ } catch (error) {
17663
+ if (!isCurrent())
17664
+ return;
17665
+ notify(`Subagent startup resume failed: ${String(error)}. Use subagent({ action: "resume", id }) to retry.`, "warning");
17666
+ }
17667
+ }
17615
17668
 
17616
17669
  // dist/builtin/subagents/src/runs/foreground/subagent-executor.ts
17617
17670
  var MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete"]);
@@ -17693,6 +17746,7 @@ async function handleManagementRequest(input) {
17693
17746
  });
17694
17747
  }
17695
17748
  const targetTaskId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
17749
+ const awaitingResume = action === "status" ? subagentChildrenAwaitingResume(ctx, targetTaskId) : [];
17696
17750
  if (action === "status" && ctx.getAgentTaskHost && targetTaskId) {
17697
17751
  const host = ctx.getAgentTaskHost();
17698
17752
  const taskId = targetTaskId;
@@ -17706,7 +17760,9 @@ async function handleManagementRequest(input) {
17706
17760
  content: [
17707
17761
  {
17708
17762
  type: "text",
17709
- text: `${records.some((task) => task.execution.kind === "settled" && subagentTaskResultLabel(task.execution.result) === "killed (non-resumable)") ? `Killed. This child cannot be resumed. Underlying host records:
17763
+ text: `${awaitingResume.length > 0 ? `${awaitingResume.join(`
17764
+ `)}
17765
+ ` : ""}${records.some((task) => task.execution.kind === "settled" && subagentTaskResultLabel(task.execution.result) === "killed (non-resumable)") ? `Killed. This child cannot be resumed. Underlying host records:
17710
17766
  ` : ""}${JSON.stringify(records)}${settledOutput}`
17711
17767
  }
17712
17768
  ],
@@ -17720,14 +17776,28 @@ async function handleManagementRequest(input) {
17720
17776
  };
17721
17777
  }
17722
17778
  }
17779
+ if (targetTaskId && awaitingResume.length > 0)
17780
+ return {
17781
+ content: [{ type: "text", text: awaitingResume.join(`
17782
+ `) }],
17783
+ details: { mode: "management", results: [] }
17784
+ };
17723
17785
  if (action === "status") {
17724
17786
  const targetRunId = paramsWithResolvedCwd.id ?? paramsWithResolvedCwd.runId;
17725
- const inProcess = inspectInProcessChildStatus(targetRunId);
17726
- if (inProcess)
17727
- return inProcess;
17728
17787
  const foreground = getForegroundControl(deps.state, targetRunId);
17729
- if (foreground)
17730
- return foregroundStatusResult(foreground);
17788
+ const live = inspectInProcessChildStatus(targetRunId) ?? (foreground ? foregroundStatusResult(foreground) : undefined);
17789
+ if (awaitingResume.length > 0) {
17790
+ const liveText = live?.content.map((part) => part.type === "text" ? part.text : "").join(`
17791
+ `);
17792
+ const text = [liveText, `Awaiting resume:
17793
+ ${awaitingResume.join(`
17794
+ `)}`].filter(Boolean).join(`
17795
+
17796
+ `);
17797
+ return { details: live?.details ?? { mode: "management", results: [] }, content: [{ type: "text", text }] };
17798
+ }
17799
+ if (live)
17800
+ return live;
17731
17801
  return {
17732
17802
  content: [
17733
17803
  {
@@ -19371,11 +19441,19 @@ function renderSubagentResult(result, options, theme) {
19371
19441
  // dist/builtin/subagents/src/extension/config.ts
19372
19442
  import * as fs19 from "node:fs";
19373
19443
  import { getAgentConfigPaths as getAgentConfigPaths5 } from "@bastani/atomic";
19444
+ function withoutInvalidResumeInFlight(config, configPath) {
19445
+ const value = config.resumeInFlight;
19446
+ if (value === undefined || RESUME_IN_FLIGHT_MODES.some((mode) => mode === value))
19447
+ return config;
19448
+ console.error(`Invalid subagent config '${configPath}': "resumeInFlight" must be "ask", "auto", or "never", got ${JSON.stringify(value)}`);
19449
+ const { resumeInFlight: _ignored, ...rest } = config;
19450
+ return rest;
19451
+ }
19374
19452
  function loadConfig() {
19375
19453
  for (const configPath of getAgentConfigPaths5("extensions", "subagent", "config.json")) {
19376
19454
  try {
19377
19455
  if (fs19.existsSync(configPath)) {
19378
- return JSON.parse(fs19.readFileSync(configPath, "utf-8"));
19456
+ return withoutInvalidResumeInFlight(JSON.parse(fs19.readFileSync(configPath, "utf-8")), configPath);
19379
19457
  }
19380
19458
  } catch (error) {
19381
19459
  console.error(`Failed to load subagent config from '${configPath}':`, error);
@@ -19664,9 +19742,9 @@ MANAGEMENT (use action field, omit agent/task/tasks):
19664
19742
  • { action: "update", agent: "code-analysis.custom-agent", config: { package: "analysis", ... } } - merge
19665
19743
  • { action: "delete", agent: "code-analysis.custom-agent" }
19666
19744
  CONTROL:
19667
- • { action: "status", id: "..." } - inspect an in-process run by id or prefix
19745
+ • { action: "status", id: "..." } - inspect an in-process run by id or prefix; a paused or quit child shows as paused · awaiting resume with its resume call, and { action: "status" } lists every such child
19668
19746
  • { action: "pause", id: "..." } / { action: "pause", all: true } - stop a running child and hold its queued messages until resume; it stays resumable
19669
- • { action: "quit", id: "..." } / { action: "quit", all: true } - stop a child gracefully (including a paused one); it stays resumable
19747
+ • { action: "quit", id: "..." } / { action: "quit", all: true } - stop a child gracefully (including a paused one), as a workflow quit does: it is paused · awaiting resume, not ended, and stays resumable
19670
19748
  • { action: "resume", id: "...", message?: "..." } - continue a paused, quit, interrupted, completed or failed child from its own session under the same id and Intercom name; message is delivered once as its next prompt, otherwise it continues where it left off. Children cancelled for good (owner or batch cancellation, the removed kill action), ended with their workflow stage (quit ones included), or reported gone cannot be resumed
19671
19749
  • id accepts the child id (<runId>:<index>), its task id, its Intercom name, or the run id of a single-child run. kill and interrupt were removed: use quit`;
19672
19750
 
@@ -19686,12 +19764,12 @@ function effectiveParallelTaskCount(tasks) {
19686
19764
  var SETTLED_VIEWS = {
19687
19765
  ok: { icon: "✓", label: "Completed", color: "success" },
19688
19766
  error: { icon: "✗", label: "Failed", color: "error" },
19689
- paused: { icon: "‖", label: "Paused (resumable)", color: "warning" },
19690
- quit: { icon: "■", label: "Quit (resumable)", color: "warning" },
19767
+ paused: { icon: "‖", label: "Paused · awaiting resume", color: "warning" },
19768
+ quit: { icon: "‖", label: "Quit · paused · awaiting resume", color: "warning" },
19691
19769
  interrupted: { icon: "○", label: "Interrupted (resumable)", color: "warning" },
19692
19770
  [SUBAGENT_CHILD_STAGE_PAUSED_STATUS]: {
19693
19771
  icon: "‖",
19694
- label: "Paused with its workflow stage (resumable)",
19772
+ label: "Paused with its workflow stage · awaiting resume",
19695
19773
  color: "warning"
19696
19774
  },
19697
19775
  killed: { icon: "✗", label: "Terminal · killed", color: "error" },
@@ -19797,7 +19875,7 @@ function renderSubagentToolResult(result, options, theme, context) {
19797
19875
  ${theme.fg("muted", `│ ${displayText2(line)}`)}`).join("") : ""
19798
19876
  ].join("");
19799
19877
  }
19800
- const state = observation.kind === "yielded" ? request?.action === "wait" ? "Still running in background" : "Launched in background" : observation.result.kind === "completed" ? "Completed" : observation.result.kind === "failed" ? "Failed" : subagentTaskResultLabel(observation.result) === "killed (non-resumable)" ? "Killed (non-resumable)" : "Stopped";
19878
+ const state = observation.kind === "yielded" ? request?.action === "wait" ? "Still running in background" : "Launched in background" : observation.result.kind === "completed" ? "Completed" : observation.result.kind === "failed" ? "Failed" : subagentTaskResultLabel(observation.result) === "killed (non-resumable)" ? "Killed (non-resumable)" : subagentTaskResultLabel(observation.result) === "paused · awaiting resume" ? "Paused · awaiting resume" : "Stopped";
19801
19879
  const icon = observation.kind === "yielded" ? "∀" : observation.result.kind === "completed" ? "✓" : observation.result.kind === "failed" ? "✗" : "○";
19802
19880
  const color = observation.kind === "yielded" ? "accent" : observation.result.kind === "failed" ? "error" : observation.result.kind === "completed" ? "success" : "warning";
19803
19881
  const identity = labels[index];
@@ -20326,6 +20404,8 @@ function registerSubagentExtension(pi) {
20326
20404
  holdRunningSubagentChildren(pi.events, ctx).catch(() => {
20327
20405
  return;
20328
20406
  });
20407
+ if (opened)
20408
+ resumeAwaitingSubagentChildren(executorDeps, ctx, config.resumeInFlight ?? "never", lifecycle.isCurrent);
20329
20409
  }
20330
20410
  });
20331
20411
  pi.on("session_recovery_restore", async (_event, ctx) => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.40",
3
+ "version": "0.9.41-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.41-alpha.1] - 2026-10-21
10
+
11
+ ### Added
12
+
13
+ - Added `schemaTimeoutMs` to workflow stage, task, chain, and parallel options: the wall-clock limit in milliseconds for each `structured_output` decision of a schema-backed item, covering its repair attempts, retries, and model fallbacks together. It defaults to the `httpIdleTimeoutMs` setting ([#3806](https://github.com/bastani-inc/atomic/issues/3806))
14
+
15
+ ### Changed
16
+
17
+ - Reopening `/workflow resume` is faster: the run list is kept between opens and rereads only the runs whose journal changed since the last open, including changes made by other Atomic processes. Whether another session still owns a run is checked when you select it.
18
+ - `/workflow connect` and `/workflow status` now list runs the way `/tasks` does. Active runs come before ended ones, with runs waiting for your input or blocked first, then running, then paused; ended runs follow with failed, cancelled, then completed. Within each group the newest run comes first, where before the `/workflow connect` list showed the oldest running run first ([#3824](https://github.com/bastani-inc/atomic/issues/3824)).
19
+
20
+ ### Fixed
21
+
22
+ - A workflow stage no longer stays stuck selecting its model when many workflows run at once. A stage with `model: "auto"` now waits at most five minutes for model selection, counting any wait for one of eight routing slots shared by every stage, so a burst of stages queues instead of overloading the router provider. When the wait ends, the stage runs on the current chat model if that model satisfies every routing constraint; otherwise it fails with an error that names the stage and the `model-resolution` startup phase, and its startup status reads `failed` instead of staying active. A failed selection is no longer remembered, so the next prompt on the same stage selects a model again, without launching a replacement workflow.
23
+ - After a blocked workflow run is resumed, Intercom sends to `workflow:<rootRunId>/**`, to stage patterns, and to stages that have not started yet are accepted and delivered again instead of failing with `Workflow execution for <runId> is retired`.
24
+ - In a long-running session, starting a workflow from a turn that an Intercom message started no longer fails with `Workflow execution for <runId> is retired; startup cleanup failed: …` after an earlier workflow run in the session has ended or been quit. The session's Intercom connection is now opened outside the workflow run that first needed it. The `is retired` error now names the run whose execution actually ended, not the run being started.
25
+ - A workflow stage whose fallback session fails to start because an extension's `session_start` failed under load, for example Intercom's `Broker failed to start within timeout` or `connect ECONNREFUSED`, now retries that session with the same-model retry budget and then moves on to its next fallback model, instead of failing the stage and letting fail-fast skip its sibling stages. Any other extension startup error still fails the stage at once. The stage error, model attempts, and fallback warnings now name each failing extension and its error rather than only `Extension startup failed`.
26
+ - When a workflow stage falls back to another model and that fallback session cannot start, the stage now closes the session it was replacing. Before, that session kept its session database open after the stage failed, and on Windows the file could not be deleted until the process exited.
27
+ - Workflow stage sessions now provide `ctx.ui.theme` and the other default UI members, so extensions that read `ctx.ui.theme.fg(...)` in `session_start`, such as `examples/extensions/status-line.ts`, no longer fail stage startup with `Extension startup failed` ([#3801](https://github.com/bastani-inc/atomic/issues/3801))
28
+ - Workflow inputs now reject integer and number values outside the `minimum`/`maximum` declared in the input schema, such as `count: 0` for `Type.Integer({ minimum: 1, maximum: 8 })`, when the run is started, instead of passing them to the workflow body. The error names the input and the violated bound ([#3812](https://github.com/bastani-inc/atomic/issues/3812)).
29
+ - A `ctx.parallel(..., { failFast: false })` call that has a failing step no longer loses the results of the steps that succeeded. The `AggregateError` it rejects with now carries `partialResults`, one entry per step in step order, holding each completed step's result and `undefined` for a step that failed. The `WorkflowParallelFailure` type describes it ([#3809](https://github.com/bastani-inc/atomic/issues/3809))
30
+ - A workflow stage's corrective prompt after a rejected `structured_output` result now names the failing paths and expected types, or reports that the tool arguments were not valid JSON, instead of only saying the response does not match the decision schema ([#3802](https://github.com/bastani-inc/atomic/issues/3802))
31
+ - Disposing a session right after a workflow run reports that it ended no longer leaves the run `running` in the workflow journal, with its lease released, for readers to report as crashed. `session.dispose()` now waits up to 10 seconds for runs that have ended but are still recording their ending, before it closes the journal, and it rejects naming the run when that ending still cannot be recorded. A run whose journal rejects the write of its `completed` status now retries it once, and reports it with an error notice and a rejected `waitForSettled` when it still fails, instead of failing in silence ([#3811](https://github.com/bastani-inc/atomic/issues/3811))
32
+ - A schema-backed workflow stage no longer stays `running` for hours inside one `structured_output` call when a slow model keeps generating without calling the tool. The decision now stops after the `httpIdleTimeoutMs` deadline (10 minutes by default) or the stage's `schemaTimeoutMs`, and the error that names the deadline and each attempt's duration reaches the model and the failed stage unchanged instead of being treated as a structured-output contract failure ([#3806](https://github.com/bastani-inc/atomic/issues/3806))
33
+
9
34
  ## [0.9.40] - 2026-10-20
10
35
 
11
36
  ### Added
@@ -449,6 +449,8 @@ const decision = await ctx.stage("review-gate", { schema: Decision }).prompt(
449
449
 
450
450
  Atomic registers the canonical `structured_output` tool only for schema-enabled items and automatically adds it to explicit `tools` allowlists. The schema is used directly as the tool argument contract. A schema-backed `StageContext` supports one `prompt()` call because the final-answer tool is a single result contract; create another `ctx.stage(..., { schema })` for another structured prompt. If a turn completes without calling `structured_output`, or the tool call fails schema validation, Atomic sends up to three corrective follow-up prompts that include the exact contract/validation error before failing the item. `ctx.task`/`ctx.chain`/`ctx.parallel` results expose the captured value as `result.structured` and keep `result.text` as formatted JSON for handoffs.
451
451
 
452
+ Each `structured_output` decision has a wall-clock limit that covers its repair attempts, retries, and model fallbacks together. It defaults to the session's `httpIdleTimeoutMs` setting (10 minutes unless changed); set `schemaTimeoutMs` (a positive integer in milliseconds) beside `schema` to change it for one item. An overrun stops the in-flight generation and fails the call with `Structured output decision exceeded its <n>ms deadline; no decision was accepted.` plus how long each attempt took. That is an execution failure, not a structured-output contract failure, and the error text reaches the model unchanged.
453
+
452
454
  When an item configures both `schema` and `output`, its successful `structured_output` turn has two separate channels: all ordinary assistant text blocks from that exact message, in order, form the human-readable artifact written to `output`, while the successful tool arguments remain the typed machine-readable workflow result. Atomic never serializes those arguments into the artifact. The runner snapshots the result together with the exact successful tool-call id, so corrective attempts, another call with the same tool name, and later admitted turns cannot replace either side of the pairing. When the successful message has no ordinary text — including after a model-fallback session recreation that leaves the live session without that message — Atomic falls back to the most recent earlier assistant text that made no `structured_output` call; only when no such text exists is the artifact written empty, with the standard empty-artifact warning in the receipt. Items with `schema` but no `output` keep their existing result-text behavior.
453
455
 
454
456
  `subagent` is available as a default workflow-stage tool on the same terms as main chat: a stage is a top-level session, so it can delegate once, and the children it launches cannot delegate further. Delegation is one level deep and nothing configures it. `tools` allowlists apply to bundled extension tools as well as built-ins; if a stage sets `tools`, list every non-mandatory tool it should see. Ordinary `intercom` remains registered and active in every workflow model stage even under `noTools: "all"`, restrictive allowlists, or exclusions. Restrictions on `subagent`, `web_search`, `fetch_content`, and every other tool are unchanged. Bundled `@bastani/subagents` agent definitions are available to the `subagent` tool in workflow stages, including workflows launched from a subagent child process.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.40",
3
+ "version": "0.9.41-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -8,7 +8,7 @@ export type { RunJournalOption, RunJournalSettings } from "./durable/journal/res
8
8
  export { resolveRunJournal } from "./durable/journal/resolution.js";
9
9
  export { openSqlRunJournal, SqlRunJournal } from "./durable/journal/sqlite-run-journal.js";
10
10
  export * from "./durable/journal/types.js";
11
- export type { AgentSessionAdapter, CompleteAdapter, CompleteStageOpts, EffectiveBudget, GitWorktreeSetupOptions, GitWorktreeSetupResult, PromptAdapter, PromptOptions, ResolvedInputs, RunResult, RunStatus, StageAdapters, StageContext, StageExecutionMeta, StageMcpOptions, StageOptions, StageOutputOptions, StagePromptOptions, StageSendUserMessageOptions, StageSessionCreateOptions, StageSessionCreateResult, StageSessionEvent, StageSessionRuntime, StageSnapshot, StageStatus, StageUserMessageContent, StageUserMessageDelivery, ToolNodeSnapshot, WorkflowAction, WorkflowArtifact, WorkflowBudget, WorkflowChainOptions, WorkflowChildResult, WorkflowContextMode, WorkflowControlEvent, WorkflowCustomToolDefinition, WorkflowCustomUiComponent, WorkflowCustomUiFactory, WorkflowCustomUiKeybindings, WorkflowCustomUiOptions, WorkflowCustomUiOverlayHandle, WorkflowCustomUiOverlayOptions, WorkflowCustomUiTheme, WorkflowCustomUiTui, WorkflowDetails, WorkflowDetailsMode, WorkflowDetailsStatus, WorkflowExecutionMode, WorkflowExecutionPolicy, WorkflowExitOptions, WorkflowExitStatus, WorkflowInputBindings, WorkflowInputSchema, WorkflowInputSchemaMap, WorkflowInputValues, WorkflowIntercomSummary, WorkflowMaxOutput, WorkflowMcpPort, WorkflowModelAttempt, WorkflowModelCatalogPort, WorkflowModelFallbackFields, WorkflowModelInfo, WorkflowModelUsage, WorkflowModelValue, WorkflowOutputMode, WorkflowOutputSchema, WorkflowOutputSchemaMap, WorkflowOutputValues, WorkflowParallelOptions, WorkflowPersistencePort, WorkflowProgressSummary, WorkflowRunChildArgs, WorkflowRunChildOptions, WorkflowRunChildOptionsArgument, WorkflowRunOutput, WorkflowRuntimeConfig, WorkflowSerializableObject, WorkflowSerializablePrimitive, WorkflowSerializableValue, WorkflowSharedTaskDefaults, WorkflowTaskContext, WorkflowTaskContextInput, WorkflowTaskOptions, WorkflowTaskResult, WorkflowTaskSessionFields, WorkflowTaskSessionOptions, WorkflowTaskStep, WorkflowThinkingLevel, WorkflowToolContext, WorkflowToolError, WorkflowToolFailure, WorkflowToolOptions, WorkflowToolOutcome, WorkflowToolPrimitive, WorkflowToolReturnOptions, WorkflowToolSuccess, WorkflowToolThrowOptions, WorkflowUIAdapter, WorkflowUIContext, WorkflowWorktreeInputBinding, } from "./shared/authoring-contract.js";
11
+ export type { AgentSessionAdapter, CompleteAdapter, CompleteStageOpts, EffectiveBudget, GitWorktreeSetupOptions, GitWorktreeSetupResult, PromptAdapter, PromptOptions, ResolvedInputs, RunResult, RunStatus, StageAdapters, StageContext, StageExecutionMeta, StageMcpOptions, StageOptions, StageOutputOptions, StagePromptOptions, StageSendUserMessageOptions, StageSessionCreateOptions, StageSessionCreateResult, StageSessionEvent, StageSessionRuntime, StageSnapshot, StageStatus, StageUserMessageContent, StageUserMessageDelivery, ToolNodeSnapshot, WorkflowAction, WorkflowArtifact, WorkflowBudget, WorkflowChainOptions, WorkflowChildResult, WorkflowContextMode, WorkflowControlEvent, WorkflowCustomToolDefinition, WorkflowCustomUiComponent, WorkflowCustomUiFactory, WorkflowCustomUiKeybindings, WorkflowCustomUiOptions, WorkflowCustomUiOverlayHandle, WorkflowCustomUiOverlayOptions, WorkflowCustomUiTheme, WorkflowCustomUiTui, WorkflowDetails, WorkflowDetailsMode, WorkflowDetailsStatus, WorkflowExecutionMode, WorkflowExecutionPolicy, WorkflowExitOptions, WorkflowExitStatus, WorkflowInputBindings, WorkflowInputSchema, WorkflowInputSchemaMap, WorkflowInputValues, WorkflowIntercomSummary, WorkflowMaxOutput, WorkflowMcpPort, WorkflowModelAttempt, WorkflowModelCatalogPort, WorkflowModelFallbackFields, WorkflowModelInfo, WorkflowModelUsage, WorkflowModelValue, WorkflowOutputMode, WorkflowOutputSchema, WorkflowOutputSchemaMap, WorkflowOutputValues, WorkflowParallelFailure, WorkflowParallelOptions, WorkflowPersistencePort, WorkflowProgressSummary, WorkflowRunChildArgs, WorkflowRunChildOptions, WorkflowRunChildOptionsArgument, WorkflowRunOutput, WorkflowRuntimeConfig, WorkflowSerializableObject, WorkflowSerializablePrimitive, WorkflowSerializableValue, WorkflowSharedTaskDefaults, WorkflowTaskContext, WorkflowTaskContextInput, WorkflowTaskOptions, WorkflowTaskResult, WorkflowTaskSessionFields, WorkflowTaskSessionOptions, WorkflowTaskStep, WorkflowThinkingLevel, WorkflowToolContext, WorkflowToolError, WorkflowToolFailure, WorkflowToolOptions, WorkflowToolOutcome, WorkflowToolPrimitive, WorkflowToolReturnOptions, WorkflowToolSuccess, WorkflowToolThrowOptions, WorkflowUIAdapter, WorkflowUIContext, WorkflowWorktreeInputBinding, } from "./shared/authoring-contract.js";
12
12
  import type * as AuthoringContract from "./shared/authoring-contract.js";
13
13
  import type { AuthoredWorkflowSpec as SharedAuthoredWorkflowSpec, WorkflowInputsFromSchemas, WorkflowOutputsFromSchemas, WorkflowProvidedInputsFromSchemas } from "./shared/workflow-authoring-types.js";
14
14
  export type { WorkflowInputsFromSchemas, WorkflowOutputsFromSchemas, WorkflowProvidedInputsFromSchemas, } from "./shared/workflow-authoring-types.js";
@@ -1 +1,17 @@
1
+ import type { RunJournal } from "./types.js";
1
2
  export declare const JOURNAL_READ_PAGE_SIZE = 256;
3
+ /** A run's latest event. A run whose history was deleted and recorded again ends with a different event. */
4
+ export interface RunVersion {
5
+ readonly seq: number;
6
+ readonly at: number;
7
+ }
8
+ /** Lets a durable backend re-read only the runs that changed; kept off the public journal shape. */
9
+ export interface RunJournalVersions {
10
+ /** Moves whenever any connection, in this process or another, commits a change to the journal's store. */
11
+ changeToken(): Promise<string>;
12
+ /** Every listed run with its latest event; a run with no events has version `{ seq: 0, at: 0 }`. */
13
+ runVersions(): Promise<ReadonlyMap<string, RunVersion>>;
14
+ }
15
+ export declare function registerRunJournalVersions(journal: RunJournal, versions: RunJournalVersions): void;
16
+ /** Change tracking for a journal that registered it; other journals are re-read in full. */
17
+ export declare function runJournalVersions(journal: RunJournal): RunJournalVersions | undefined;
@@ -14,6 +14,13 @@ type LegacyEventRow = SqliteRow & {
14
14
  [c.payload]: string;
15
15
  [c.at]: number;
16
16
  };
17
+ export type RunVersionRow = SqliteRow & {
18
+ [c.runId]: string;
19
+ [c.seq]: number;
20
+ [c.at]: number;
21
+ };
22
+ /** `seq` and `at` of the latest event of `${runs}.run_id`, through the `(run_id, seq)` primary key. */
23
+ export declare function latestEventColumns(events: string, runs: string): string;
17
24
  /**
18
25
  * Runs recorded before #3682, kept in the unprefixed `meta`/`runs`/`events`/`leases` tables.
19
26
  *
@@ -32,6 +39,8 @@ export declare class LegacyJournalRuns {
32
39
  cwd?: string;
33
40
  }): Promise<LegacyRunRow[]>;
34
41
  find(executor: SqliteExecutor, runId: string): Promise<LegacyRunRow | undefined>;
42
+ /** Latest event of each pending legacy run; the legacy tables are never modified. */
43
+ versions(executor: SqliteExecutor): Promise<RunVersionRow[]>;
35
44
  /** Events of an unconverted legacy run, read in place. */
36
45
  events(executor: SqliteExecutor, runId: string, fromSeq: number, limit: number): Promise<LegacyEventRow[]>;
37
46
  eventByKey(executor: SqliteExecutor, runId: string, key: string): Promise<LegacyEventRow | undefined>;
@@ -22,6 +22,12 @@ export declare class SqlRunJournal implements RunJournal {
22
22
  listRuns(filter?: {
23
23
  cwd?: string;
24
24
  }): Promise<readonly RunSummary[]>;
25
+ /**
26
+ * `data_version` moves when another connection commits and `total_changes()` when this one writes; the
27
+ * table aggregates also catch run changes if the adapter does not serve every statement from one connection.
28
+ */
29
+ private changeToken;
30
+ private runVersions;
25
31
  private requireRun;
26
32
  /** Whether this run exists only in the legacy tables, whose events are then read in place. */
27
33
  private isUnconvertedLegacyRun;