@bastani/atomic 0.9.40 → 0.9.41-alpha.2

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 (323) hide show
  1. package/CHANGELOG.md +75 -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 +2 -2
  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 +3 -3
  16. package/dist/builtin/subagents/src/extension/index.bundle.mjs +99 -19
  17. package/dist/builtin/web-access/package.json +2 -2
  18. package/dist/builtin/workflows/CHANGELOG.md +33 -0
  19. package/dist/builtin/workflows/README.md +2 -0
  20. package/dist/builtin/workflows/builtin/adversarial-verification.js +2 -2
  21. package/dist/builtin/workflows/builtin/{chunk-qjqn389g.js → chunk-2jfst7e4.js} +72 -10
  22. package/dist/builtin/workflows/builtin/{chunk-4bwtzyjq.js → chunk-49kkbdpr.js} +1 -1
  23. package/dist/builtin/workflows/builtin/{chunk-qdd897wm.js → chunk-apagcs4r.js} +1 -1
  24. package/dist/builtin/workflows/builtin/{chunk-454hz1qt.js → chunk-dcxscfnb.js} +1 -1
  25. package/dist/builtin/workflows/builtin/{chunk-bjva9j5k.js → chunk-hx8v4p97.js} +1 -1
  26. package/dist/builtin/workflows/builtin/{chunk-85mx6wcf.js → chunk-k5q3t7je.js} +1 -1
  27. package/dist/builtin/workflows/builtin/{chunk-8kkv04hz.js → chunk-n2gkzkty.js} +1 -1
  28. package/dist/builtin/workflows/builtin/{chunk-y45tkftg.js → chunk-txbc93t6.js} +1 -1
  29. package/dist/builtin/workflows/builtin/{chunk-x0vvjyzg.js → chunk-w4xp1w1f.js} +1 -1
  30. package/dist/builtin/workflows/builtin/{chunk-5eh0brtd.js → chunk-z3pajrfs.js} +1 -1
  31. package/dist/builtin/workflows/builtin/classify-and-act.js +2 -2
  32. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +2 -2
  33. package/dist/builtin/workflows/builtin/generate-and-filter.js +2 -2
  34. package/dist/builtin/workflows/builtin/goal.js +2 -2
  35. package/dist/builtin/workflows/builtin/index.js +10 -10
  36. package/dist/builtin/workflows/builtin/loop-until-done.js +2 -2
  37. package/dist/builtin/workflows/builtin/open-claude-design.js +2 -2
  38. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  39. package/dist/builtin/workflows/builtin/tournament.js +2 -2
  40. package/dist/builtin/workflows/package.json +2 -2
  41. package/dist/builtin/workflows/src/authoring.d.ts +1 -1
  42. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +16 -0
  43. package/dist/builtin/workflows/src/durable/journal/legacy-journal-tables.d.ts +9 -0
  44. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +6 -0
  45. package/dist/builtin/workflows/src/extension/index.bundle.mjs +950 -116
  46. package/dist/builtin/workflows/src/index.js +806 -131
  47. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +17 -1
  48. package/dist/cli/credential-print.d.ts.map +1 -1
  49. package/dist/cli/credential-print.js +1 -1
  50. package/dist/cli/credential-print.js.map +1 -1
  51. package/dist/config.d.ts +1 -0
  52. package/dist/config.d.ts.map +1 -1
  53. package/dist/config.js +1 -0
  54. package/dist/config.js.map +1 -1
  55. package/dist/core/agent-session-extension-bindings.d.ts +2 -1
  56. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  57. package/dist/core/agent-session-extension-bindings.js +33 -18
  58. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  59. package/dist/core/agent-session-methods.d.ts +2 -1
  60. package/dist/core/agent-session-methods.d.ts.map +1 -1
  61. package/dist/core/agent-session-methods.js.map +1 -1
  62. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  63. package/dist/core/agent-session-prompt.js +114 -21
  64. package/dist/core/agent-session-prompt.js.map +1 -1
  65. package/dist/core/agent-session-runtime.d.ts +1 -1
  66. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  67. package/dist/core/agent-session-runtime.js +6 -0
  68. package/dist/core/agent-session-runtime.js.map +1 -1
  69. package/dist/core/agent-session-state.d.ts +19 -1
  70. package/dist/core/agent-session-state.d.ts.map +1 -1
  71. package/dist/core/agent-session-state.js +41 -6
  72. package/dist/core/agent-session-state.js.map +1 -1
  73. package/dist/core/auth-storage-backends.d.ts +3 -1
  74. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  75. package/dist/core/auth-storage-backends.js +79 -12
  76. package/dist/core/auth-storage-backends.js.map +1 -1
  77. package/dist/core/client-identity.d.ts +8 -0
  78. package/dist/core/client-identity.d.ts.map +1 -0
  79. package/dist/core/client-identity.js +16 -0
  80. package/dist/core/client-identity.js.map +1 -0
  81. package/dist/core/compaction/planner-outcome.d.ts.map +1 -1
  82. package/dist/core/compaction/planner-outcome.js +2 -1
  83. package/dist/core/compaction/planner-outcome.js.map +1 -1
  84. package/dist/core/execution-model-router.d.ts +18 -0
  85. package/dist/core/execution-model-router.d.ts.map +1 -1
  86. package/dist/core/execution-model-router.js +14 -8
  87. package/dist/core/execution-model-router.js.map +1 -1
  88. package/dist/core/extension-oauth-refresh-rejection.d.ts +12 -0
  89. package/dist/core/extension-oauth-refresh-rejection.d.ts.map +1 -0
  90. package/dist/core/extension-oauth-refresh-rejection.js +70 -0
  91. package/dist/core/extension-oauth-refresh-rejection.js.map +1 -0
  92. package/dist/core/extension-startup-failure.d.ts +30 -0
  93. package/dist/core/extension-startup-failure.d.ts.map +1 -0
  94. package/dist/core/extension-startup-failure.js +62 -0
  95. package/dist/core/extension-startup-failure.js.map +1 -0
  96. package/dist/core/extensions/context-types.d.ts +2 -0
  97. package/dist/core/extensions/context-types.d.ts.map +1 -1
  98. package/dist/core/extensions/context-types.js.map +1 -1
  99. package/dist/core/extensions/provider-types.d.ts +2 -0
  100. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  101. package/dist/core/extensions/provider-types.js.map +1 -1
  102. package/dist/core/extensions/runner-context.d.ts +1 -0
  103. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  104. package/dist/core/extensions/runner-context.js +8 -0
  105. package/dist/core/extensions/runner-context.js.map +1 -1
  106. package/dist/core/extensions/runner.d.ts +1 -0
  107. package/dist/core/extensions/runner.d.ts.map +1 -1
  108. package/dist/core/extensions/runner.js +3 -0
  109. package/dist/core/extensions/runner.js.map +1 -1
  110. package/dist/core/extensions/runtime-types.d.ts +1 -0
  111. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  112. package/dist/core/extensions/runtime-types.js.map +1 -1
  113. package/dist/core/extensions/workflow-run-control-hub.d.ts +1 -0
  114. package/dist/core/extensions/workflow-run-control-hub.d.ts.map +1 -1
  115. package/dist/core/extensions/workflow-run-control-hub.js +3 -0
  116. package/dist/core/extensions/workflow-run-control-hub.js.map +1 -1
  117. package/dist/core/extensions/workflow-run-control.d.ts +8 -0
  118. package/dist/core/extensions/workflow-run-control.d.ts.map +1 -1
  119. package/dist/core/extensions/workflow-run-control.js.map +1 -1
  120. package/dist/core/model-config.d.ts +28 -0
  121. package/dist/core/model-config.d.ts.map +1 -1
  122. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  123. package/dist/core/model-fallback-failures.js +12 -0
  124. package/dist/core/model-fallback-failures.js.map +1 -1
  125. package/dist/core/model-resolver-defaults.js +1 -1
  126. package/dist/core/model-resolver-defaults.js.map +1 -1
  127. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  128. package/dist/core/model-runtime-streaming.js +9 -3
  129. package/dist/core/model-runtime-streaming.js.map +1 -1
  130. package/dist/core/model-runtime.d.ts +5 -0
  131. package/dist/core/model-runtime.d.ts.map +1 -1
  132. package/dist/core/model-runtime.js +6 -0
  133. package/dist/core/model-runtime.js.map +1 -1
  134. package/dist/core/provider-composer-internal.d.ts +8 -6
  135. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  136. package/dist/core/provider-composer-internal.js +21 -8
  137. package/dist/core/provider-composer-internal.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +12 -4
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/storage/session/sql-session-store.d.ts +35 -0
  142. package/dist/core/storage/session/sql-session-store.d.ts.map +1 -1
  143. package/dist/core/storage/session/sql-session-store.js +158 -42
  144. package/dist/core/storage/session/sql-session-store.js.map +1 -1
  145. package/dist/core/structured-output/deadline.d.ts +40 -0
  146. package/dist/core/structured-output/deadline.d.ts.map +1 -0
  147. package/dist/core/structured-output/deadline.js +110 -0
  148. package/dist/core/structured-output/deadline.js.map +1 -0
  149. package/dist/core/structured-output/index.d.ts.map +1 -1
  150. package/dist/core/structured-output/index.js +103 -47
  151. package/dist/core/structured-output/index.js.map +1 -1
  152. package/dist/core/structured-output/rejection-detail.d.ts +9 -0
  153. package/dist/core/structured-output/rejection-detail.d.ts.map +1 -0
  154. package/dist/core/structured-output/rejection-detail.js +129 -0
  155. package/dist/core/structured-output/rejection-detail.js.map +1 -0
  156. package/dist/core/structured-output/types.d.ts +8 -1
  157. package/dist/core/structured-output/types.d.ts.map +1 -1
  158. package/dist/core/structured-output/types.js.map +1 -1
  159. package/dist/core/tasks/completion.d.ts +7 -1
  160. package/dist/core/tasks/completion.d.ts.map +1 -1
  161. package/dist/core/tasks/completion.js +28 -6
  162. package/dist/core/tasks/completion.js.map +1 -1
  163. package/dist/core/tasks/contracts.d.ts +6 -1
  164. package/dist/core/tasks/contracts.d.ts.map +1 -1
  165. package/dist/core/tasks/contracts.js.map +1 -1
  166. package/dist/core/tasks/pause.d.ts +2 -1
  167. package/dist/core/tasks/pause.d.ts.map +1 -1
  168. package/dist/core/tasks/pause.js +3 -2
  169. package/dist/core/tasks/pause.js.map +1 -1
  170. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  171. package/dist/core/tools/bash-pty-native.js +10 -5
  172. package/dist/core/tools/bash-pty-native.js.map +1 -1
  173. package/dist/core/tools/bash.d.ts.map +1 -1
  174. package/dist/core/tools/bash.js +16 -32
  175. package/dist/core/tools/bash.js.map +1 -1
  176. package/dist/core/tools/grep.js +1 -1
  177. package/dist/core/tools/grep.js.map +1 -1
  178. package/dist/core/tools/kill.d.ts.map +1 -1
  179. package/dist/core/tools/kill.js +17 -3
  180. package/dist/core/tools/kill.js.map +1 -1
  181. package/dist/core/tools/shell-task-render.d.ts +55 -0
  182. package/dist/core/tools/shell-task-render.d.ts.map +1 -0
  183. package/dist/core/tools/shell-task-render.js +123 -0
  184. package/dist/core/tools/shell-task-render.js.map +1 -0
  185. package/dist/core/tools/shell-task-status.d.ts +52 -0
  186. package/dist/core/tools/shell-task-status.d.ts.map +1 -0
  187. package/dist/core/tools/shell-task-status.js +184 -0
  188. package/dist/core/tools/shell-task-status.js.map +1 -0
  189. package/dist/core/tools/structured-output.d.ts +5 -0
  190. package/dist/core/tools/structured-output.d.ts.map +1 -1
  191. package/dist/core/tools/structured-output.js +3 -0
  192. package/dist/core/tools/structured-output.js.map +1 -1
  193. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  194. package/dist/extensions/codemode/execute.js +134 -57
  195. package/dist/extensions/codemode/execute.js.map +1 -1
  196. package/dist/extensions/mcp/config.d.ts.map +1 -1
  197. package/dist/extensions/mcp/config.js +3 -2
  198. package/dist/extensions/mcp/config.js.map +1 -1
  199. package/dist/index-extensions.d.ts +1 -0
  200. package/dist/index-extensions.d.ts.map +1 -1
  201. package/dist/index-extensions.js +3 -0
  202. package/dist/index-extensions.js.map +1 -1
  203. package/dist/index.d.ts +3 -1
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js +3 -1
  206. package/dist/index.js.map +1 -1
  207. package/dist/main.d.ts.map +1 -1
  208. package/dist/main.js +19 -6
  209. package/dist/main.js.map +1 -1
  210. package/dist/modes/interactive/components/task-row.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/task-row.js +11 -1
  212. package/dist/modes/interactive/components/task-row.js.map +1 -1
  213. package/dist/modes/interactive/interactive-auth-routing.js +12 -10
  214. package/dist/modes/interactive/interactive-auth-routing.js.map +1 -1
  215. package/dist/modes/interactive/interactive-extension-custom-ui.js +20 -30
  216. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  217. package/dist/modes/interactive/interactive-extension-dialogs.js +23 -96
  218. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  219. package/dist/modes/interactive/interactive-extension-runtime.js +7 -8
  220. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  221. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  222. package/dist/modes/interactive/interactive-input-handling.js +27 -4
  223. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  224. package/dist/modes/interactive/interactive-mode-base.d.ts +20 -10
  225. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  226. package/dist/modes/interactive/interactive-mode-base.js +40 -5
  227. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  228. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  229. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  230. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  231. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  232. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -4
  233. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  234. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  235. package/dist/modes/interactive/interactive-mode-types.d.ts +4 -1
  236. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
  238. package/dist/modes/interactive/interactive-prompt-restore.d.ts +3 -0
  239. package/dist/modes/interactive/interactive-prompt-restore.d.ts.map +1 -1
  240. package/dist/modes/interactive/interactive-prompt-restore.js +9 -1
  241. package/dist/modes/interactive/interactive-prompt-restore.js.map +1 -1
  242. package/dist/modes/interactive/interactive-prompt-turn.js +30 -2
  243. package/dist/modes/interactive/interactive-prompt-turn.js.map +1 -1
  244. package/dist/modes/interactive/interactive-queueing.js +43 -8
  245. package/dist/modes/interactive/interactive-queueing.js.map +1 -1
  246. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-startup.js +12 -3
  248. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  249. package/dist/modes/interactive/theme/color-utils.d.ts +6 -1
  250. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  251. package/dist/modes/interactive/theme/color-utils.js +39 -17
  252. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  253. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  254. package/dist/modes/interactive/theme/theme-class.js +2 -2
  255. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  256. package/dist/modes/interactive/theme/theme-tokens.d.ts +6 -0
  257. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -1
  258. package/dist/modes/interactive/theme/theme-tokens.js +7 -3
  259. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -1
  260. package/dist/modes/interactive-engine/isolated-auth.d.ts +3 -0
  261. package/dist/modes/interactive-engine/isolated-auth.d.ts.map +1 -1
  262. package/dist/modes/interactive-engine/isolated-auth.js +13 -1
  263. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  264. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  265. package/dist/modes/interactive-engine/isolated-runtime.js +11 -2
  266. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  267. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +8 -0
  268. package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
  269. package/dist/modes/interactive-engine/remote-model-catalog.js +54 -0
  270. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  271. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  272. package/dist/modes/rpc/rpc-command-handler.js +4 -13
  273. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  274. package/dist/modes/rpc/rpc-model-catalog.d.ts +9 -0
  275. package/dist/modes/rpc/rpc-model-catalog.d.ts.map +1 -0
  276. package/dist/modes/rpc/rpc-model-catalog.js +19 -0
  277. package/dist/modes/rpc/rpc-model-catalog.js.map +1 -0
  278. package/dist/modes/rpc/rpc-provider-auth.d.ts.map +1 -1
  279. package/dist/modes/rpc/rpc-provider-auth.js +2 -6
  280. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  281. package/dist/modes/rpc/rpc-types.d.ts +6 -0
  282. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  283. package/dist/modes/rpc/rpc-types.js.map +1 -1
  284. package/dist/utils/changelog.d.ts +6 -0
  285. package/dist/utils/changelog.d.ts.map +1 -1
  286. package/dist/utils/changelog.js +11 -0
  287. package/dist/utils/changelog.js.map +1 -1
  288. package/dist/utils/clipboard.d.ts.map +1 -1
  289. package/dist/utils/clipboard.js +4 -0
  290. package/dist/utils/clipboard.js.map +1 -1
  291. package/dist/utils/tools-manager.d.ts.map +1 -1
  292. package/dist/utils/tools-manager.js +3 -2
  293. package/dist/utils/tools-manager.js.map +1 -1
  294. package/docs/background-tasks.md +5 -3
  295. package/docs/codemode.md +2 -2
  296. package/docs/custom-provider/oauth.md +42 -1
  297. package/docs/custom-provider/registration.md +2 -0
  298. package/docs/environment-variables.md +1 -0
  299. package/docs/extensions/api-reference.md +3 -4
  300. package/docs/extensions/authoring.md +1 -1
  301. package/docs/extensions/events.md +1 -1
  302. package/docs/models-configuration.md +9 -0
  303. package/docs/models.md +3 -1
  304. package/docs/providers.md +4 -4
  305. package/docs/rpc/protocol.md +4 -2
  306. package/docs/sdk/reference.md +2 -0
  307. package/docs/sdk/structured-decisions.md +7 -5
  308. package/docs/sdk.md +5 -2
  309. package/docs/settings.md +4 -2
  310. package/docs/subagents/reference.md +1 -1
  311. package/docs/subagents.md +15 -1
  312. package/docs/themes/reference.md +3 -1
  313. package/docs/usage.md +3 -1
  314. package/docs/workflows/api-reference.md +28 -0
  315. package/docs/workflows/authoring.md +1 -1
  316. package/docs/workflows/operations.md +2 -2
  317. package/npm-shrinkwrap.json +67 -54
  318. package/package.json +6 -6
  319. package/schemas/models.schema.json +21 -0
  320. package/dist/core/provider-attribution.d.ts +0 -4
  321. package/dist/core/provider-attribution.d.ts.map +0 -1
  322. package/dist/core/provider-attribution.js +0 -87
  323. package/dist/core/provider-attribution.js.map +0 -1
package/docs/codemode.md CHANGED
@@ -18,7 +18,7 @@ A script may start with an options line. It must be the first line; an options l
18
18
  ```
19
19
 
20
20
  - `max_output_tokens` (default 10000) limits the output. Longer output keeps its start and end, and the full text is written to a temp file whose path is included in the result.
21
- - `timeout_ms` is a hard deadline for the whole script. It is unset by default. Image generation can take minutes, so do not set a short deadline for scripts that generate images.
21
+ - `timeout_ms` is a hard deadline for the whole script, including any wait for a free worker. It is unset by default. Image generation can take minutes, so do not set a short deadline for scripts that generate images.
22
22
 
23
23
  The result starts with `Script completed` or `Script failed`, the wall time, and the output. Text and image items appear in order. When output has multiple text items (from `text()` or `return`), each starts with a `==> text N/M <==` line. Console calls follow the other output in one `<console_output>` block, with one line per call. A failed script keeps its partial output, followed by `Script error:` and the error. Tool calls are real: calls made before a failure are not undone. Calls still running when the script ends are cancelled, and unawaited promises are discarded.
24
24
 
@@ -236,6 +236,6 @@ Extensions call classifiers and image models through `ctx.modelRegistry.classify
236
236
 
237
237
  - A script's VM has 256 MB of memory. Running out throws `InternalError: out of memory`; filter or aggregate large data instead of accumulating it.
238
238
  - Stopping a script or reaching its deadline ends the call promptly. In the standalone `atomic` binary (Bun), a built-in that does not check for interruption, such as a long string search, can keep computing in its worker until it returns.
239
- - At most two codemode workers may be alive across all sessions in one Atomic process. A cancelled worker occupies its slot until it exits. At capacity, new scripts fail immediately with `Codemode worker limit reached` without starting another worker; retry after an existing worker exits.
239
+ - At most two codemode workers may be alive across all sessions in one Atomic process; `ATOMIC_CODEMODE_MAX_WORKERS` changes the limit. A cancelled worker occupies its slot until it exits. At capacity, new scripts wait for a free worker in arrival order. A script that gets no worker within 60 seconds, or before its `timeout_ms`, fails without running.
240
240
  - A script that waits on a promise that can never settle (no tool call pending) fails immediately, since there are no timers.
241
241
  - Scripts cannot start other `codemode` scripts.
@@ -73,7 +73,7 @@ await pi.registerProvider("corporate-ai", {
73
73
 
74
74
  After registration, users can authenticate via `/login corporate-ai`.
75
75
 
76
- Existing extension OAuth definitions keep their `login`, `refreshToken`, `getApiKey`, and optional `modifyModels` methods. OAuth refresh is serialized so concurrent requests do not overwrite each other's credentials.
76
+ Existing extension OAuth definitions keep their `login`, `refreshToken`, `getApiKey`, and optional `modifyModels` methods. OAuth refresh is serialized so concurrent requests do not overwrite each other's credentials. Atomic never aborts the `signal` passed to `refreshToken` on a timeout, because the provider may already have rotated the refresh token; a late result is saved, and a normal exit waits up to three seconds for it. Do not add your own timeout or abort to the token request.
77
77
 
78
78
  OAuth callbacks run in the engine in isolated interactive mode. Use the provided callbacks for user interaction rather than relying on terminal-process state.
79
79
 
@@ -85,6 +85,47 @@ Successful login persists credentials before refreshing the catalog. Logout remo
85
85
 
86
86
  Intentional cancellation is quiet, including native `AbortError`, an aborted signal or its exact reason, nested abort causes, and the legacy exact `Login cancelled` error. Provider denial, timeout, network/protocol errors, malformed responses, token exchange failures, and storage failures remain visible. Catalog-refresh failures are reported by `/model` while cached models remain selectable; they do not turn a persisted login into a failed transaction.
87
87
 
88
+ ## Rejected logins
89
+
90
+ When the provider rejects the stored refresh token, for example because the user revoked access or the login expired, throw `OAuthRefreshRejectedError` from `refreshToken`:
91
+
92
+ ```typescript
93
+ import { OAuthRefreshRejectedError } from "@bastani/atomic";
94
+
95
+ async refreshToken(credentials, signal) {
96
+ const response = await fetch("https://sso.corp.com/token", { method: "POST", body: refreshBody(credentials), signal });
97
+ if (!response.ok) {
98
+ const body = await response.json().catch(() => ({}));
99
+ if (response.status === 401 || body.error === "invalid_grant") {
100
+ throw new OAuthRefreshRejectedError(
101
+ `Corporate AI token refresh failed (${response.status})`,
102
+ { status: response.status, code: body.error, description: body.error_description },
103
+ [credentials.refresh, credentials.access],
104
+ );
105
+ }
106
+ throw new Error(`Token refresh failed (${response.status})`);
107
+ }
108
+ // ...
109
+ }
110
+ ```
111
+
112
+ Atomic then handles the refresh as it does for a built-in provider. It first uses a newer login that another session saved, if there is one. Otherwise the request fails with:
113
+
114
+ ```
115
+ OAuth refresh failed for corporate-ai: invalid_grant (Refresh token expired). The provider rejected the stored login; run /login corporate-ai to sign in again.
116
+ ```
117
+
118
+ The message shows only the provider ID, the error code (or `HTTP <status>` when there is none), and the description. Pass the stored tokens as the third argument: a description that contains one of them, contains a URL, or is too long is left out. Never put tokens or request bodies in the code or description.
119
+
120
+ Atomic also treats these errors from `refreshToken` as a rejected login, including when they are the `cause` of the error you throw. The rejected-login codes are the ones the built-in providers use: `invalid_grant`, `refresh_token_expired`, `refresh_token_reused`, and `refresh_token_invalidated`.
121
+
122
+ - an error whose `error` or `code` property is a rejected-login code, such as openid-client's response errors; an `error_description` property supplies the description
123
+ - an error whose `body`, `data`, `response.data`, or `response.body` holds an OAuth error response with a rejected-login code in `error`, `error.code`, or `code`, as an object or JSON text, as HTTP clients such as axios attach it; `error_description` or `error.message` supplies the description
124
+ - an error whose `status`, `statusCode`, `response.status`, or `response.statusCode` is 401, as HTTP clients such as axios and got report it
125
+ - an error message that contains a rejected-login code, alone or in an OAuth error response, as the built-in providers report it
126
+
127
+ Other failures are reported as `OAuth refresh failed for <provider>: <message>` without asking the user to sign in again, because a retry may succeed. These include a 5xx status, a network error, and other OAuth error codes such as `invalid_client`, `invalid_request`, or `server_error`.
128
+
88
129
  ## Dynamic model catalog refresh
89
130
 
90
131
  Providers whose catalogs change at runtime can add `refreshModels`. Atomic calls it during the model picker's bounded asynchronous refresh, independently of authentication completion:
@@ -102,6 +102,8 @@ await pi.registerProvider("my-llm", {
102
102
 
103
103
  When `models` is provided, it **replaces** all existing chat, image, and classifier models for that provider. A missing `type` means chat; image and classifier models need `type: "image"` or `type: "classifier"` and implementations in the `images` or `classifiers` maps keyed by each model's `api`. See the [mixed-operation provider example](/custom-provider#quick-reference).
104
104
 
105
+ A provider registered this way is listed in `/login` like a built-in provider: `/login my-llm` prompts for an API key and saves it to `auth.json`, and the selector shows whether the provider is configured (for example `✓ env: MY_LLM_API_KEY`). `/model` lists its models once it is configured. When `$MY_LLM_API_KEY` is unset and no key is stored, using one of its models reports `No API key found for my-llm` with the `/login` hint, as for a built-in provider. This also holds in interactive sessions, where extensions run in the engine process.
106
+
105
107
  ## Unregister Provider
106
108
 
107
109
  Use `pi.unregisterProvider(name)` to remove a provider that was previously registered via `pi.registerProvider(name, ...)`:
@@ -20,6 +20,7 @@ Atomic accepts environment variables for configuration, provider credentials, an
20
20
  | `ATOMIC_SESSIONS_STORAGE` | None | JSON session-only storage selection, in the same form as `sessions.storage`. Conflicts with a non-empty `ATOMIC_CODING_AGENT_SESSION_DIR` |
21
21
  | `ATOMIC_WORKFLOWS_JOURNAL` | None | JSON workflow-run-only storage selection, in the same form as `workflows.journal`. Conflicts with a non-empty `ATOMIC_WORKFLOW_JOURNAL_PATH` |
22
22
  | `ATOMIC_HEAP_MB` | `PI_HEAP_MB` | Heap size in MiB for the Atomic process that runs agents when Atomic runs on Node (npm installs): the interactive engine, or a headless run (`-p`, `--mode json`, `--mode rpc`), which restarts itself once with the larger heap. By default it gets half of system memory when that is more than Node's default limit, because every in-process subagent and workflow stage shares that heap. `0` keeps Node's default. A `--max-old-space-size` in `NODE_OPTIONS` or on Atomic's own command line takes precedence. The standalone binary does not use this value |
23
+ | `ATOMIC_CODEMODE_MAX_WORKERS` | `PI_CODEMODE_MAX_WORKERS` | Maximum codemode workers alive at once across all sessions in the process; default `2`. Each worker's script may use up to 256 MB. Raise it when one process runs several sessions, such as in-process subagents. Further scripts wait for a free worker. See [Codemode](/codemode) |
23
24
 
24
25
  `VISUAL` and `EDITOR` select the Ctrl+G external editor when `externalEditor` is unset.
25
26
 
@@ -986,9 +986,8 @@ await pi.registerProvider("corporate-ai", {
986
986
  return { refresh: code, access: code, expires: Date.now() + 3600000 };
987
987
  },
988
988
  async refreshToken(credentials, signal) {
989
- // Forward the rotation timeout signal, not the caller's cancellation signal.
990
- signal.throwIfAborted();
991
- return credentials;
989
+ // Pass `signal` through, but add no timeout or abort of your own (see below).
990
+ return refreshCorporateToken(credentials.refresh, { signal });
992
991
  },
993
992
  getApiKey(credentials) {
994
993
  return credentials.access;
@@ -1016,7 +1015,7 @@ await pi.registerProvider("local-server", {
1016
1015
  });
1017
1016
  ```
1018
1017
 
1019
- OAuth `refreshToken` receives a 60-second rotation timeout signal. Forward it to your network request. Cancelling a request or model refresh stops that caller's wait, but an already started token rotation continues so Atomic can persist the updated credentials. Return the rotated credentials promptly and do not discard them because the initiating caller cancelled.
1018
+ OAuth `refreshToken` receives a signal that Atomic does not abort on a timeout: once the token request is sent, the provider may already have rotated the refresh token, and only its response carries the replacement. The caller stops waiting after 60 seconds, but the exchange keeps running and Atomic saves its result when it arrives. When Atomic exits normally, it waits up to three seconds for an exchange still in flight. Cancelling a request or model refresh likewise stops only that caller's wait. Do not add your own timeout or abort to the token request, and do not send the same refresh token again after the provider may have received it. Return the rotated credentials, even when the caller that started the refresh has stopped waiting.
1020
1019
 
1021
1020
  **Config options:**
1022
1021
  - `name` - Display name for the provider in UI such as `/login`.
@@ -315,7 +315,7 @@ pi.registerTool({
315
315
 
316
316
  Return `terminate: true` from `execute()` to skip the automatic follow-up model call only when every finalized result in the tool batch also terminates.
317
317
 
318
- For a schema-backed decision, use `createStructuredOutputTool({ schema, name })`. Atomic does not register `structured_output` in normal sessions by default. The calling model supplies `instructions`, nonempty named `state`, and optional `model` and `fallbackModels`. The tool resolves those exact IDs through the session model registry, infers a value matching `schema`, and returns that value as terminating JSON. It does not treat the calling model's arguments as the result. Omit `model` to use the current session chat model; explicit fallbacks run next, and the current chat model is the terminal fallback. A registered classifier runs only for a finite Choice schema. An incompatible schema skips that classifier. Provider errors, including refusals, advance to the next model. Plain-text responses without the required result are repaired up to three times before advancing. Cancellation stops the call. Include a custom name such as `final_decision` in any explicit tool allowlist.
318
+ For a schema-backed decision, use `createStructuredOutputTool({ schema, name })`. Atomic does not register `structured_output` in normal sessions by default. The calling model supplies `instructions`, nonempty named `state`, and optional `model` and `fallbackModels`. The tool resolves those exact IDs through the session model registry, infers a value matching `schema`, and returns that value as terminating JSON. It does not treat the calling model's arguments as the result. Omit `model` to use the current session chat model; explicit fallbacks run next, and the current chat model is the terminal fallback. A registered classifier runs only for a finite Choice schema. An incompatible schema skips that classifier. Provider errors, including refusals, advance to the next model. Plain-text responses without the required result are repaired up to three times before advancing. Cancellation stops the call. Each call also has a wall-clock deadline covering every repair attempt, retry, and fallback; it defaults to the session's `httpIdleTimeoutMs` setting, and `createStructuredOutputTool({ timeoutMs })` overrides it. Include a custom name such as `final_decision` in any explicit tool allowlist.
319
319
 
320
320
  ```typescript
321
321
  // Correct: throw to signal an error
@@ -536,7 +536,7 @@ Rules: keep a system message at index 0 (providers read the prompt and initial t
536
536
 
537
537
  #### before_provider_headers
538
538
 
539
- Fires after outgoing HTTP headers are assembled. Mutate `event.headers` to add, override, or remove headers. The event also identifies the provider and model.
539
+ Fires after outgoing HTTP headers are assembled. Mutate `event.headers` to add, override, or remove headers. The event also identifies the provider and model. Atomic's default `User-Agent` and provider attribution headers (OpenRouter, NVIDIA NIM, OpenCode) are added after this event, so handlers do not see them; headers you set here or in `models.json` take precedence over them. For OpenCode models the `x-opencode-session` header is already present, so a handler can read, replace, or remove it.
540
540
 
541
541
  When Atomic retries a request with credentials saved by another process after a credential rejection, this event fires again for the retry.
542
542
 
@@ -199,6 +199,15 @@ Also applies to `azure-openai-responses` and `openai-codex-responses`.
199
199
  |---|---|---|---|
200
200
  | `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system messages after the conversation has started. When false, later system messages are folded into the leading system message. |
201
201
 
202
+ ### `typesafe-system-one`
203
+
204
+ Also applies to `cloudflare-workers-ai-system-one`.
205
+
206
+ | Field | Type | Default | Description |
207
+ |---|---|---|---|
208
+ | `imageInput` | `"assets" \| "images" \| "state-image-urls"` | | How the service takes classifier images. "assets" sends TypeSafe's assets map (PNG and JPEG) and references the images from the state, as TypeSafe and Jev on Workers AI expect. "images" sends Clef's images list of data URLs (PNG, JPEG, and WebP, at most four), as Clef on Workers AI expects. "state-image-urls" places image_url parts before the state, as OpenRouter expects; OpenRouter drops assets without an error. Auto-detected from the provider, baseUrl, and model ID. Classifier models read it from the provider-level compat; models and modelOverrides entries apply to chat models only. |
209
+ | `sendImageOptInHeader` | boolean | | Whether requests with images send the TypeSafe-Danger-Zone-Images: true header, which TypeSafe's own API requires for its experimental image input. Defaults to true for the typesafe-system-one API unless the model is detected as OpenRouter. |
210
+
202
211
  ### Atomic compatibility aliases
203
212
 
204
213
  | Field | Type | Default | Description |
package/docs/models.md CHANGED
@@ -31,7 +31,9 @@ OpenAI's GPT-6 Luna Decisions classifier is `openai-decisions/gpt-6-luna`. It us
31
31
 
32
32
  GPT-6 Luna accepts up to 128 image blocks through `images`, alongside the JSON state. Other classifiers reject images unless their catalog input and API support them. Refused answers produce an error result. The endpoint rejects inputs above 922K tokens; very large inputs, currently above roughly 600K tokens, can hit its gateway time limit. These 504 responses are not retried, so reduce the input before trying again.
33
33
 
34
- TypeSafe Jev and Cloudflare Clef classifiers are also available through their providers. The direct TypeSafe classifiers, `typesafe/jev-latest` and `typesafe/jev-1.14.0`, accept up to 262K tokens and PNG or JPEG images through `images`; see [TypeSafe Jev](/providers#typesafe-jev). [Local llama.cpp models](/llama-cpp#classification) support native decision models and a next-token-probability fallback for chat models.
34
+ TypeSafe Jev and Cloudflare Clef classifiers are also available through their providers. The direct TypeSafe classifiers, `typesafe/jev-latest` and `typesafe/jev-1.14.0`, accept up to 262K tokens and PNG or JPEG images through `images`; see [TypeSafe Jev](/providers#typesafe-jev). On Workers AI, Jev (`typesafe/jev`, `typesafe/jev-1.14.0`) takes PNG and JPEG images, and Clef, Clef Flash, and Clef Omni take PNG, JPEG, and WebP images, at most four per request. OpenRouter's Jev and Clef models accept images when their catalog entry lists image input. Jev from `vercel-ai-gateway` and `opencode` takes text only. [Local llama.cpp models](/llama-cpp#classification) support native decision models and a next-token-probability fallback for chat models.
35
+
36
+ Each System One service takes images in its own request format, which the model's `compat.imageInput` selects. Built-in models set it, so overriding a provider's `baseUrl` keeps it. A custom provider that proxies another service's classifiers sets `imageInput` and `sendImageOptInHeader` in its provider-level `compat` in `models.json`; see [System One compatibility](/models-configuration#typesafe-system-one). OpenRouter in particular answers requests in TypeSafe's format without an error but drops the images, so a proxy that reaches OpenRouter needs `"imageInput": "state-image-urls"` and `"sendImageOptInHeader": false`.
35
37
 
36
38
  ## Table of Contents
37
39
 
package/docs/providers.md CHANGED
@@ -51,9 +51,9 @@ Type `/logout ` to autocomplete providers with stored credentials, or use `/logo
51
51
 
52
52
  Atomic refreshes a stored OAuth token when fewer than **five minutes** of validity remain, so a long turn does not start with a token about to expire. Tokens outside this window are untouched.
53
53
 
54
- Concurrent sessions sharing `auth.json`, including workflow stages and subagents, coordinate token refresh rather than rotating the same credential independently.
54
+ Concurrent sessions sharing `auth.json`, including workflow stages and subagents, coordinate token refresh rather than rotating the same credential independently. This holds when a session is slow or briefly unresponsive under heavy load. If a refresh reports a timeout, the token exchange keeps running and its result is saved when it arrives. Retry the request instead of signing in again. When Atomic exits normally (quitting an interactive session, `SIGTERM`, the end of an `atomic -p` run, or an `atomic auth` command), it waits up to three seconds for a token exchange still in flight and saves its result. If Atomic is killed or crashes during a token refresh, the provider may already have rotated the token; run `/login <provider>` to sign in again.
55
55
 
56
- Running sessions pick up changes to `auth.json` made by another Atomic window, `atomic auth`, or another process's token refresh without restarting. This applies to extension-provided OAuth too. Refresh runs automatically through the shared credential store; a failed refresh is reported as an OAuth error rather than starting a new login flow. Sign in again with `/login <provider>` if the provider has revoked access.
56
+ Running sessions pick up changes to `auth.json` made by another Atomic window, `atomic auth`, or another process's token refresh without restarting. This applies to extension-provided OAuth too. Refresh runs automatically through the shared credential store; a failed refresh is reported as an OAuth error rather than starting a new login flow. If the provider rejects the stored login as revoked or expired (for example `invalid_grant`, OpenAI's `refresh_token_expired` or `refresh_token_reused`, or HTTP 401), Atomic first uses a newer login that another session saved. When there is none, the error names the provider and tells you to run `/login <provider>`, because the provider has revoked or expired that login.
57
57
 
58
58
  If a chat request is rejected with HTTP 401 or an invalid/revoked-token error before any response content arrives, Atomic rereads credentials and retries once only if the effective credential changed. It does not repeatedly retry the same rejected token or replay a partially delivered response. Explicit request credentials and runtime API-key overrides still take precedence over the auth file.
59
59
 
@@ -618,7 +618,7 @@ atomic --provider cloudflare-workers-ai --model "@cf/moonshotai/kimi-k2.6"
618
618
 
619
619
  Atomic automatically sets `x-session-affinity` for [prefix caching](https://developers.cloudflare.com/workers-ai/features/prompt-caching/) discounts.
620
620
 
621
- Workers AI also lists Cloudflare's Clef (`@cf/cloudflare/clef`) and Clef Flash (`@cf/cloudflare/clef-flash`) as classifiers. They use the same `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID`. Name the exact ID in `routerModel`, `structured_output`, or `generateStructuredOutput()`; like other classifiers they do not appear in `/model` or work with `--model`. See [Structured decisions](/sdk/structured-decisions).
621
+ Workers AI also lists Cloudflare's Clef (`@cf/cloudflare/clef`), Clef Flash (`@cf/cloudflare/clef-flash`), and Clef Omni (`@cf/cloudflare/clef-omni`) and TypeSafe's Jev (`typesafe/jev`, `typesafe/jev-1.14.0`) as classifiers. They use the same `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID`. Name the exact ID in `routerModel`, `structured_output`, or `generateStructuredOutput()`; like other classifiers they do not appear in `/model` or work with `--model`. All of them accept images in `images`: Clef takes up to four PNG, JPEG, or WebP images, and Jev takes PNG or JPEG images. See [Structured decisions](/sdk/structured-decisions).
622
622
 
623
623
  ### Google Vertex AI
624
624
 
@@ -648,7 +648,7 @@ Atomic also registers `vercel-ai-gateway/typesafe-ai/jev`, `opencode/jev-1.13`,
648
648
 
649
649
  An explicit `routerModel` other than `auto` selects that exact registered chat or classifier model for workflow-stage and subagent `model: "auto"` routing. An unset or `auto` router uses the current chat model. General `generateStructuredOutput()` calls and the `structured_output` tool select their own model: an optional exact `model`, then `fallbackModels`, then the current chat model. Those calls resolve the ID through the current model registry and use the generic classify operation for a registered classifier, including `typesafe/jev-latest`. They do not inherit `routerModel`. A catalog entry does not prove that classify is available or entitled. User-issued `/workflow` commands launch directly.
650
650
 
651
- Routers send one classify request for a registered classifier and can repair a malformed chat answer up to three times after the initial attempt, without a structured-decision deadline. Cancel the request to stop waiting; independent provider and enclosing tool-request limits still apply. A `structured_output` or `generateStructuredOutput()` classifier candidate is skipped, not repaired into a free-form value, when the schema is not a finite Choice. Missing credentials, an unavailable provider, an unsupported classify operation, a provider size rejection, a refusal, and a malformed classifier answer switch routing to the current chat model and advance a general structured-output chain. Cancellation does not. See [structured decision limits](/sdk/structured-decisions#provider-behavior-and-limits).
651
+ Routers send one classify request for a registered classifier and can repair a malformed chat answer up to three times after the initial attempt, all within one structured-decision deadline taken from [`httpIdleTimeoutMs`](/settings#http). Cancel the request to stop sooner; independent provider and enclosing tool-request limits still apply. A `structured_output` or `generateStructuredOutput()` classifier candidate is skipped, not repaired into a free-form value, when the schema is not a finite Choice. Missing credentials, an unavailable provider, an unsupported classify operation, a provider size rejection, a refusal, and a malformed classifier answer switch routing to the current chat model and advance a general structured-output chain. Cancellation does not. See [structured decision limits](/sdk/structured-decisions#provider-behavior-and-limits).
652
652
 
653
653
  HTTP 401 means check the key saved through `/login typesafe` or `TYPESAFE_API_KEY`, 422 means check the question/state contract, and 429 or 529 means wait before retrying explicitly. Configured credentials do not verify access or quota. See [TypeSafe's API](https://docs.typesafe.ai/api.md) and [Choice reference](https://docs.typesafe.ai/primitives/choice.md).
654
654
 
@@ -65,7 +65,7 @@ The `images` field is optional. Each image uses `ImageContent` format: `{"type":
65
65
 
66
66
  #### steer
67
67
 
68
- Queue a steering message while the agent is running. It is delivered after the current assistant turn finishes executing its tool calls, before the next LLM call. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
68
+ Queue a steering message while the agent is running. It is delivered after the current assistant turn finishes executing its tool calls, before the next LLM call. If no run is active when it arrives and the session already has messages, Atomic starts a turn to deliver it, so a `prompt` sent while that turn runs needs `streamingBehavior`. On a session with no messages yet, or after a run was stopped with `abort`, it stays queued until the next `prompt`. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
69
69
 
70
70
  ```json
71
71
  {"type": "steer", "message": "Stop and do this instead"}
@@ -89,7 +89,7 @@ See [set_steering_mode](#set_steering_mode) for controlling how steering message
89
89
 
90
90
  #### follow_up
91
91
 
92
- Queue a follow-up message to be processed after the agent finishes. Delivered only when agent has no more tool calls or steering messages. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
92
+ Queue a follow-up message to be processed after the agent finishes. Delivered only when agent has no more tool calls or steering messages. If no run is active when it arrives and the session already has messages, Atomic starts a turn to deliver it, so a `prompt` sent while that turn runs needs `streamingBehavior`. On a session with no messages yet, or after a run was stopped with `abort`, it stays queued until the next `prompt`. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
93
93
 
94
94
  ```json
95
95
  {"type": "follow_up", "message": "After you're done, also do this"}
@@ -317,6 +317,8 @@ Response contains an array of full [Model](#model) objects:
317
317
  }
318
318
  ```
319
319
 
320
+ `data` also carries `scopedModels`, `oauthProviders`, `customAuthProviders`, and `providerAuthStatuses`. `customAuthProviders` lists extension-registered providers (`{ id, name }`) that accept an API key through `login_provider`. `providerAuthStatuses` lists the authentication status of extension-registered providers (`{ provider, status }`, where `status` is `{ configured, source?, label? }`) when it does not come from a credential stored in `auth.json`, for example an environment variable. `refresh_models` responses carry the same fields.
321
+
320
322
  The subprocess protocol returns full `Model` objects. The exported TypeScript `RpcClient.getAvailableModels()` keeps its smaller backward-compatible `ModelInfo` shape (`provider`, `id`, `contextWindow`, `reasoning`) and adds optional `compat`. When present, `compat` exposes constrained-sampling capability claims including `supportsStrictTools`, `supportsStrictMode`, canonical `supportsOpenAIGrammarTools`, and Atomic's synchronized `supportsGrammarTools` alias. Treat absence as unknown/unsupported; do not infer enforcement from the provider name.
321
323
 
322
324
  ```typescript
@@ -378,6 +378,8 @@ The calling model does not supply the decision fields. It calls `structured_outp
378
378
 
379
379
  The tool infers the result through the session model registry. A successful call returns the schema-validated value as pretty-printed JSON, stores that value in `details`, and sets `terminate: true`. It does not capture the calling model's arguments as the decision. A classifier is used only when the registered schema is a finite Choice; otherwise that candidate is skipped and the next fallback, then the current chat model, is tried. A classifier failure such as missing credentials, an unavailable provider, an unsupported classify operation, a refusal, or a malformed answer advances the same chain. A chat provider refusal advances immediately when reported as an error; plain text without a result gets up to three repairs before advancing. Cancellation stops the call. Saved `/login` credentials are used through the session model registry; a listed model does not prove live access.
380
380
 
381
+ Each call must finish within a wall-clock deadline that covers every repair attempt, retry, and model fallback. It defaults to the session's [`httpIdleTimeoutMs`](/settings#http) setting; pass `timeoutMs` (a positive integer in milliseconds) to `createStructuredOutputTool()` to change it. The calling model cannot. See [Structured decisions](/sdk/structured-decisions#cancellation-and-failures).
382
+
381
383
  A custom tool name still works. Include that name in any explicit `tools` allowlist:
382
384
 
383
385
  ```typescript
@@ -18,7 +18,7 @@ Pass an optional exact `provider/model` string, not a model object and not `auto
18
18
  - Omit `model` to use the current stage or chat model as the primary.
19
19
  - After the primary and every explicit fallback, Atomic tries the current chat model if it has not already been tried.
20
20
 
21
- Image-generation models, model patterns, reasoning suffixes, and surrounding whitespace are rejected. Atomic validates every model ID before sending the first request, so a mistyped fallback fails the call even if the primary model would have succeeded. A classifier is never an execution `auto` candidate. A catalog entry does not prove that the provider can classify, that credentials work, or that quota remains. Setting `routerModel` does not change this selection.
21
+ Image-generation models, model patterns, reasoning suffixes, surrounding whitespace, and IDs the registry does not list cannot be used. Atomic skips such an ID, records it with its error in `modelAttempts`, and still tries the remaining candidates, including the current chat model, so a mistyped `model` or fallback does not fail the call. The call fails with the first ID's error only when no candidate resolves. A classifier is never an execution `auto` candidate. A catalog entry does not prove that the provider can classify, that credentials work, or that quota remains. Setting `routerModel` does not change this selection.
22
22
 
23
23
  A classifier can answer a finite Choice. Literal unions, enums, booleans, and flat objects whose required fields all use those types are Choice-compatible. Free-form text, unconstrained numbers, arrays, optional fields, and nested objects are not. Atomic compiles compatible schemas into generic choice questions and skips an incompatible classifier, recording the skip. A request whose entire chain is incompatible fails without inventing a decoder.
24
24
 
@@ -51,13 +51,13 @@ console.log(result.value.category, result.model);
51
51
 
52
52
  The returned `value` is the schema-validated decision, not the request arguments. `model` names the candidate that produced it. `modelAttempts` records skips and failed candidates when a chain was used. This decision API does not expose classifier billing usage: its classifier-produced `usage` is not a classifier bill. The lower-level classifier operation may report usage and cost separately. Chat usage is reported when a chat candidate supplies the accepted result. A valid shape is not proof that the judgment is correct. Validate current policy again before any later action.
53
53
 
54
- The `structured_output` tool takes the same decision inputs from the calling model: required `instructions` and nonempty named `state`, plus optional `model` and `fallbackModels`. The registered schema is fixed by `createStructuredOutputTool({ schema })`. The tool resolves those IDs through the session registry and returns the inferred value. Omitting `model` uses the current stage or session chat model. See [Structured output final results](/sdk/reference#structured-output-final-results).
54
+ The `structured_output` tool takes the same decision inputs from the calling model: required `instructions` and nonempty named `state`, plus optional `model` and `fallbackModels`. The registered schema is fixed by `createStructuredOutputTool({ schema })`. The tool resolves those IDs through the session registry and returns the inferred value. Omitting `model` uses the current stage or session chat model. The calling model cannot set a deadline; the tool's own [`timeoutMs`](#cancellation-and-failures) option does. See [Structured output final results](/sdk/reference#structured-output-final-results).
55
55
 
56
56
  ## Select the router
57
57
 
58
58
  For workflow stages and subagents with `model: "auto"`, `routerModel` selects the decision provider: an explicit exact registered chat or classifier ID uses that model, while an unset or `auto` value uses the current chat model. Saved classifier credentials do not change this selection. An invalid explicit router selection fails instead of falling back. Set it through [/settings](/settings#routermodel); extensions can read the current value with `ctx.getRouterModel()`.
59
59
 
60
- Chat routing gets an initial attempt plus up to three corrective retries for malformed or schema-invalid output. A failed explicit classifier routing attempt switches to the current chat model immediately when one exists, including missing credentials, an unsupported classify operation, a provider size or context rejection, and a refusal. Cancellation does not fall back. The result includes `fallback: { from, to, reason }` when that hop is used. Transient provider retries follow the selected provider's operation and the request's retry settings. General `generateStructuredOutput()` advances its own `fallbackModels` chain; it does not read `routerModel`.
60
+ Chat routing gets an initial attempt plus up to three corrective retries for malformed or schema-invalid output, all within one [decision deadline](#cancellation-and-failures). A failed explicit classifier routing attempt switches to the current chat model immediately when one exists, including missing credentials, an unsupported classify operation, a provider size or context rejection, and a refusal. Cancellation does not fall back. The result includes `fallback: { from, to, reason }` when that hop is used. Transient provider retries follow the selected provider's operation and the request's retry settings. General `generateStructuredOutput()` advances its own `fallbackModels` chain; it does not read `routerModel`.
61
61
 
62
62
  For [workflow-stage](/workflows/operations#automatic-stage-models) and [subagent](/subagents/reference#automatic-model-selection) `model: "auto"`, a complete routing-inference failure runs the stage or child on the current chat model with a recorded warning instead of failing, provided that model is available and satisfies every routing constraint.
63
63
 
@@ -87,9 +87,11 @@ Classifier response bodies are limited by the provider operation. Atomic validat
87
87
 
88
88
  ## Cancellation and failures
89
89
 
90
- Structured decisions have no built-in wall-clock timeout. Slow authentication, inference, repairs, and chat fallback can finish without the former 30-second cutoff. Pass an `AbortSignal` to cancel; SDK callers that need their own deadline can supply `signal: AbortSignal.timeout(milliseconds)`. Cancellation rejects the whole call immediately, even if a provider ignores its signal. Output has no fixed token cap: a chat decision may use the selected model's full output limit. Pass a positive integer `maxTokens` only when you want a smaller bound.
90
+ One wall-clock deadline covers the whole call: every repair attempt, transport retry, and model-candidate fallback together, not each generation alone. `timeoutMs` sets it as a positive integer number of milliseconds. Without it, the `structured_output` tool uses the session's [`httpIdleTimeoutMs`](/settings#http) setting and every other call uses that setting's default of 10 minutes. A disabled idle timeout (`0` or `"disabled"`) leaves only the largest timer delay, about 24.8 days. Raise the deadline for slow, reasoning-heavy models or large `state`.
91
91
 
92
- The `timeoutMs` request option and `DEFAULT_STRUCTURED_OUTPUT_TIMEOUT_MS` export have been removed. Remove these from existing integrations and use `signal` for caller-owned cancellation. Provider transport, credential-preparation and enclosing tool-request limits remain independent; removing the decision timeout does not disable them.
92
+ When the deadline passes, Atomic stops the in-flight generation, which also ends a provider that ignores its signal, and rejects the call with `Structured output decision exceeded its <n>ms deadline; no decision was accepted.` That failure is final: it does not start another repair or advance to a fallback model. Unlike cancellation, it names the deadline. The message ends with how each attempt finished and how long it took, such as `Attempts: 1) stopReason=stop 25m02s; 2) still generating 4m58s.`. The error for exhausted repairs ends the same way, so a slow wedge reads differently from several failed generations. Provider transport, credential-preparation and enclosing tool-request limits remain independent of this deadline.
93
+
94
+ Pass an `AbortSignal` to cancel sooner, for example `signal: AbortSignal.timeout(milliseconds)`. Cancellation rejects the whole call immediately, even if a provider ignores its signal. Output has no fixed token cap: a chat decision may use the selected model's full output limit. Pass a positive integer `maxTokens` only when you want a smaller bound.
93
95
 
94
96
  No result is returned for missing state, invalid configuration, unrepaired malformed output or an unrecovered provider failure. Keep action admission after the awaited result and check cancellation again at that boundary. Neither API runs recursive agents or provider probes.
95
97
 
package/docs/sdk.md CHANGED
@@ -310,6 +310,7 @@ interface SessionWorkflows {
310
310
  pause(target: { all: true }): Promise<WorkflowRunControlOutcome>;
311
311
  quit(target: string | { all: true }): Promise<WorkflowRunControlOutcome>;
312
312
  resume(runId: string, options?: { stageId?: string; message?: string }): Promise<WorkflowRunControlOutcome>;
313
+ waitForSettled(runId: string): Promise<void>;
313
314
  observe(observer: WorkflowActivityObserver): WorkflowActivitySubscription;
314
315
  }
315
316
  ```
@@ -324,6 +325,8 @@ A run with a live foreign lease remains read-only, even while a long-running too
324
325
 
325
326
  Disposing an owning session with `await session.dispose()` stops its in-flight runs at their last checkpoint and records their release in the journal. Another authorized SDK session with the same `cwd` and journal can then call `resume(runId)`. The adopting session becomes the owner, and completed checkpoints replay without rerunning their callbacks.
326
327
 
328
+ A run reports `completed`, `failed` or `killed` to `workflow_lifecycle` and `session.workflows` as soon as it ends, and then records that ending in the journal. With a remote journal this takes a few round trips. `await session.dispose()` waits up to 10 seconds for runs in that window before it closes the journal. If the journal still cannot record an ending, `dispose()` rejects with `ShutdownFailed` and names the run, rather than leaving the journal showing it as `running`. To wait without disposing, for example before another process reads the journal, call `await session.workflows.waitForSettled(runId)`. It resolves once the ending is in the journal and the run's lease is released, resolves at once for a run this session is not executing, and rejects with `WorkflowRunStorageError` when the journal could not record the ending. It has no timeout of its own, so race it against your own deadline.
329
+
327
330
  Workflow resume is project-scoped. SDK and workflow-tool resume calls for a run from a different `cwd` return an actionable error without changing it. To continue in a different project, use `/workflow resume <id>` interactively and confirm the fork into the current directory. The fork receives a new run ID and copies saved progress; the original run is left untouched. To keep the original ID, create the successor session with the original `cwd`.
328
331
 
329
332
  ```ts
@@ -542,7 +545,7 @@ Shared loaders, event buses, settings, and `SessionManager` instances do not sha
542
545
 
543
546
  #### Session replacement and deferred cleanup
544
547
 
545
- `await runtime.dispose()` refuses new replacements and waits for pending factories, startup, and cleanup. No successor is published after closure. Host callbacks must settle independently of disposal. Call `runtime.dispose({ fromSignal: true })` when the host is shutting down because of `SIGTERM` or `SIGHUP`, so `session_shutdown` handlers receive `fromSignal: true` and can tell it from an explicit quit.
548
+ `await runtime.dispose()` refuses new replacements and waits for pending factories, startup, and cleanup. It also waits up to three seconds, counted from the start of disposal, for an OAuth token exchange still in flight, so a token the provider already rotated is saved before your host exits. No successor is published after closure. Host callbacks must settle independently of disposal. Call `runtime.dispose({ fromSignal: true })` when the host is shutting down because of `SIGTERM` or `SIGHUP`, so `session_shutdown` handlers receive `fromSignal: true` and can tell it from an explicit quit.
546
549
 
547
550
  An extension command may await `ctx.newSession()`, `ctx.fork()`, `ctx.switchSession()`, or `session.reload()`. Its old generation remains owned until the command continuation finishes, and final disposal waits for that cleanup. Do not await disposal inside the continuation it must drain. Concurrent replacements are supported, and deferred cleanup failures remain visible.
548
551
 
@@ -689,7 +692,7 @@ await session.steer("New instruction");
689
692
  await session.followUp("After you're done, also do this");
690
693
  ```
691
694
 
692
- Both `steer()` and `followUp()` expand file-based prompt templates but error on extension commands (extension commands cannot be queued). They return `"queued"` if the input was queued (including after an extension transformed it), or `"handled"` if an extension consumed it.
695
+ If the session is idle and already has messages when either is called, it starts a turn to deliver the message instead of leaving it queued. On a session with no messages yet, or after a run was stopped with `abort()`, the message stays queued until the next `prompt()`. A `prompt()` call made while that turn runs must pass `streamingBehavior`, or it fails with "Agent is already processing". Both `steer()` and `followUp()` expand file-based prompt templates but error on extension commands (extension commands cannot be queued). They return `"queued"` if the input was queued (including after an extension transformed it), or `"handled"` if an extension consumed it.
693
696
 
694
697
  `pauseQueuedMessages()` synchronously holds existing raw steering/follow-up entries before an abort boundary. Later context-bearing arrivals also stay queued without starting a provider turn. These include trigger-turn custom messages, batches, interrupts, `sendUserMessage()`, and ordinary `prompt()` calls.
695
698
 
package/docs/settings.md CHANGED
@@ -86,7 +86,7 @@ Use `/settings` → **Router model** to change the effective selection. If the p
86
86
 
87
87
  An explicit ID other than `auto` is resolved through the current model registry: a registered classifier first, otherwise a chat model. Built-in gateway classifiers include `vercel-ai-gateway/typesafe-ai/jev`, `opencode/jev-1.13`, and `opencode/jev-1.13-free`; authenticate their provider before choosing them. An invalid explicit ID, image-generation model, non-string value, or surrounding whitespace fails the decision instead of silently changing providers. An explicit empty project value overrides a global selection and restores the current chat model.
88
88
 
89
- A failed explicit classifier routing attempt switches to the current chat model when one exists. That includes missing credentials, an unavailable classify operation, a provider size or context rejection, a refusal, and a malformed answer. Transient retries follow the provider operation and retry settings. Chat routing gets an initial attempt plus three corrective retries for invalid output, using the same context. Routing has no built-in wall-clock deadline; cancel the request to stop waiting. Independent provider, credential-preparation, and enclosing tool-request limits still apply. The fallback can incur chat-provider charges. Cancellation does not trigger fallback.
89
+ A failed explicit classifier routing attempt switches to the current chat model when one exists. That includes missing credentials, an unavailable classify operation, a provider size or context rejection, a refusal, and a malformed answer. Transient retries follow the provider operation and retry settings. Chat routing gets an initial attempt plus three corrective retries for invalid output, using the same context. Each routing inference must finish within a wall-clock deadline taken from [`httpIdleTimeoutMs`](#http), 10 minutes by default, covering its corrective retries and any chat fallback; otherwise routing fails like any other total inference failure. Cancel the request to stop sooner. Independent provider, credential-preparation, and enclosing tool-request limits still apply. The fallback can incur chat-provider charges. Cancellation does not trigger fallback.
90
90
 
91
91
  A classifier `routerModel` such as Jev only chooses between the shortlisted models and never receives the task; a chat model (`routerModel` when it is one, otherwise the current chat model) reads the task to answer the routing questions. If the selected classifier rejects the request, routing switches to the current chat model.
92
92
 
@@ -205,7 +205,7 @@ See [Providers](/providers#fast-models) for which providers publish fast variant
205
205
  | `fullscreenWheelScrollLines` | `"auto"` or number | `"auto"` | Lines per mouse-wheel tick in fullscreen views. `"auto"` uses terminal-aware scrolling; numeric values are clamped to 1–100. Settable from `/settings` |
206
206
  | `quietStartup` | boolean or `"header"` | `false` | `true` hides the startup header. `"header"` keeps the startup header but hides the model scope line |
207
207
  | `defaultProjectTrust` | string | `"ask"` | Fallback project trust behavior: `"ask"`, `"always"`, or `"never"`. Global setting only |
208
- | `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
208
+ | `collapseChangelog` | boolean | `false` | Show a one-line update notice after updates instead of the What's New highlights; `/changelog` shows the full changelog |
209
209
  | `enableInstallTelemetry` | boolean | `true` | Send a version-adoption ping on the first interactive launch with fresh settings, and on the first interactive launch after an update whose version has changelog entries. This does not control update checks |
210
210
  | `firstRunOnboardingStartedVersion` | string | - | Managed onboarding state; leave unchanged |
211
211
  | `onboardedVersion` | string | - | Managed onboarding completion state; leave unchanged |
@@ -374,6 +374,8 @@ When a provider requests a retry delay longer than `retry.provider.maxRetryDelay
374
374
 
375
375
  Atomic applies this timeout to the global HTTP dispatcher used by `fetch` and provider SDK HTTP clients. The default is 600,000 ms (10 minutes), which keeps slow long-context requests working while reclaiming stale idle connections. Atomic does not impose a separate fixed connect-phase timeout; connection failures surface through the provider and agent retry/error paths.
376
376
 
377
+ The same value is the default wall-clock limit for one [structured decision](/sdk/structured-decisions#cancellation-and-failures): a `structured_output` call, a `generateStructuredOutput()` call, or one automatic model-selection inference. The limit covers every repair attempt, retry, and fallback together, so a model that streams for a long time cannot hold a workflow stage past it. A disabled idle timeout leaves those calls effectively unbounded. Schema-backed workflow stages can set their own limit with [`schemaTimeoutMs`](/workflows/api-reference#schematimeoutms).
378
+
377
379
  The `/settings` picker offers these presets:
378
380
 
379
381
  | Label | Value |
@@ -51,7 +51,7 @@ The shared [`routerModel`](/settings#routermodel) setting chooses the model maki
51
51
 
52
52
  Saved classifier credentials do not change this order. Neither routing nor child fallback changes the parent chat model or the `structured_output` tool.
53
53
 
54
- Routing has no built-in wall-clock deadline. Slow decisions can finish; cancel the request to stop waiting. Independent provider and credential-preparation limits still apply. Chat routing gets an initial attempt plus three corrective retries for malformed or schema-invalid answers. A classifier routing failure switches to the current chat model instead of repeating the classifier request. A valid answer stops repairs.
54
+ Each routing inference has a wall-clock deadline taken from the [`httpIdleTimeoutMs`](/settings#http) setting, 10 minutes by default, covering its corrective retries and any chat fallback. A slower decision fails like any other routing-inference failure. Cancel the request to stop sooner. Independent provider and credential-preparation limits still apply. Chat routing gets an initial attempt plus three corrective retries for malformed or schema-invalid answers. A classifier routing failure switches to the current chat model instead of repeating the classifier request. A valid answer stops repairs.
55
55
 
56
56
  The result records a primary `{ model, effort }`, up to two ordered `fallbacks`, each with its own model and effort, and `candidates`, every model the router could choose from after the routing settings, constraints, and the task's image and long-context needs. Atomic ranks three distinct eligible provider/model IDs, or all available IDs when fewer than three qualify. It selects each rank from the remaining models, excluding all efforts of earlier choices. A supported `"off"` is distinct from `null`, which means no configurable reasoning. The catalog reflects configured authentication, not proof of valid credentials, quota, or entitlement.
57
57
 
package/docs/subagents.md CHANGED
@@ -218,6 +218,8 @@ subagent({ action: "resume", id: "<child-id>", message: "Focus on the failing te
218
218
 
219
219
  - **`pause`** stops the child's current turn and holds its queued steering and follow-ups in place; `resume` delivers them once, in order, before its own `message`. Intercom messages sent to a paused child wait until you resume it, as long as the same Atomic process keeps running.
220
220
  - **`quit`** stops the child gracefully, including a child that is already paused, by you or with its workflow stage. A quit child stays resumable while the session or workflow stage that launched it can still resume it; once that workflow stage closes for good, the child becomes terminal like every other child of the stage.
221
+ - A paused or quit child is **paused · awaiting resume**, as a quit workflow run is. The `pause` or `quit` result and the parent's completion notice say so and name the exact call, `subagent({ action: "resume", id: "<child-id>" })`. The notice reads, for example, `Subagent worker quit · paused, awaiting resume: …` with `Stop reason: quit` (or `pause`); it never says the execution has ended. A child its workflow stage's pause stopped gets the same notice with `Stop reason: pause`. Only children cancelled for good get the `This execution has ended` notice.
222
+ - `subagent({ action: "status", id: "<child-id>" })` (or its task id) reports a paused or quit child as `<agent> (<child-id>, <intercom-name>) quit · paused · awaiting resume` with its resume call, and `subagent({ action: "status" })` lists every such child under **Awaiting resume**. Both read the session's child records, so a quit child stays listed after Atomic restarts. It is not relaunched when the session reopens; it waits for `resume`.
221
223
  - A parallel child still waiting for a free slot behind its concurrency limit can be paused or quit too, by id or with `all: true`. It then does not start when a slot frees; `resume` starts it on its original task, with `message`, if given, added after the task. This also works after Atomic restarts: the child starts as a new launch under the same child id, Intercom name, and group, with its original agent, task, working directory or worktree, model, thinking level, and skills. A child that inherited your model and thinking level keeps the ones you had when you launched it, even if you have switched since; if that model is no longer available, resume reports the child as gone instead of starting it on your current model. A child launched with `context: "fork"` starts on the copy of your conversation it was launched with; if that copy no longer exists, resume reports the child as gone instead of starting it without your conversation. A child that was still waiting for a slot when Atomic exited starts the same way when its session reopens.
222
224
  - A resumed child of a parallel run, queued or not, waits for a free slot under that run's concurrency limit, as its original launch did. A paused or quit child holds no slot.
223
225
  - **`resume`** continues the child from its own saved session, under the same child id, Intercom name, and group, with fresh supervisor authorization. For a paused, quit, or interrupted child, `message` is delivered once as its next prompt, and after replying the child continues where it left off. For a completed or failed child, `message` is one fresh prompt in the same session, with nothing queued after it. Without `message`, the child is asked to continue where it left off, or to stop if its task is finished; this works for completed and failed children too. `all: true` is not accepted for `resume`.
@@ -244,7 +246,7 @@ Each background subagent launch card shows the child's latest state, including a
244
246
 
245
247
  Hosts with an owner task store expose `/tasks` and `/tasks <id>` for background agents and shells, including their retained terminal results. Foreground-only work is excluded. Enter opens detail; arrows select an explicit action. Cancel asks for confirmation of the selected task. Terminal tasks retain transcript inspection but omit foreground, cancellation, and stdin actions. Escape returns from detail or stdin before returning to the composer.
246
248
 
247
- Cancelling a subagent from `/tasks` stops it for good: its row shows **Killed (non-resumable)** and `resume` refuses it. To stop a child and keep it resumable, use `subagent({ action: "quit", id })` or `pause` instead.
249
+ Cancelling a subagent from `/tasks` stops it for good: its row shows **Killed (non-resumable)** and `resume` refuses it. A paused or quit subagent's row shows **Paused · awaiting resume** (`‖`) instead of **Stopped**. To stop a child and keep it resumable, use `subagent({ action: "quit", id })` or `pause` instead.
248
250
 
249
251
  `/tasks` appears in slash-command autocomplete. The inspector groups agents and shells with counts, status symbols, and a highlighted selection. Task descriptions lead; the selected row shows secondary activity and tool counts. The header and footer remain visible in ordinary terminal sizes, with a compact fallback for short terminals.
250
252
 
@@ -305,6 +307,18 @@ To run up to 100 children at once, raise both concurrency and running capacity a
305
307
 
306
308
  Running capacity is selected when a parent's first child is created. Restart Atomic after changing this setting to apply the new capacity.
307
309
 
310
+ `resumeInFlight` controls what happens when a session starts or is resumed to subagents you paused or quit that are still awaiting resume (the same values as the [workflow setting](/workflows/operations)):
311
+
312
+ ```json
313
+ { "resumeInFlight": "ask" }
314
+ ```
315
+
316
+ - `"never"` (the default) leaves them listed under **Awaiting resume** in `subagent({ action: "status" })` until you resume them.
317
+ - `"ask"` shows one confirmation that lists each subagent by name and id, such as "2 interrupted subagent(s) can resume from their own sessions: ... Resume now?". Choosing No leaves them awaiting resume. Without an interactive UI it behaves like `"never"`.
318
+ - `"auto"` resumes them, each continuing from its own session, and its result reaches the session that launched it.
319
+
320
+ Starting Atomic and resuming a session (`/resume`) recover children; `/reload`, `/new`, and forking do not. Only subagents launched by the session being started or resumed are affected; subagents owned by a workflow stage are never resumed this way. Any other value is reported when the config loads and treated as `"never"`.
321
+
308
322
  When one assistant response emits several sibling execution-mode `subagent` tool calls, Atomic collects that synchronous burst before starting a child and runs it as one indexed parallel set. Each original tool call still receives one result containing only the children it requested, and its live result, progress, control, and artifact updates are projected to that same route without sibling data. The TUI redraws the shared run as one aggregate parallel widget rather than retaining one widget per original call. A single call keeps its original SINGLE or PARALLEL mode, calls awaited in sequence remain separate runs, and management actions bypass collection. An execution call that arrives after a child has started still receives the existing in-progress rejection. Prefer one explicit `{ tasks: [...] }` call when planning parallel work; burst collection handles sibling calls emitted by a model.
309
323
 
310
324
  For a collected burst, each call contributes its top-level `agent` task first and then its `tasks` entries in array order. Atomic preserves duplicates, expands `count` in place, and applies `parallel.maxTasks` after flattening and expansion. Each call-level `cwd` selects that call's agent-discovery scope and child base directory. A task-level `cwd` stays relative to that call base and changes only that child's execution directory, not agent discovery. This per-origin discovery rule applies only to collected sibling calls; an ordinary explicit `{ tasks: [...] }` call keeps one discovery scope from its top-level `cwd`. Per-call and per-task `group` values also stay with their originating children. Shared run options must match across every sibling call: `concurrency`, `worktree`, `context`, `share`, `control`, `sessionDir`, `maxOutput`, `artifacts`, `includeProgress`, and `agentScope`. A mismatch rejects the whole burst before any child launches and names the incompatible field.
@@ -171,7 +171,9 @@ Five formats are supported:
171
171
 
172
172
  ### Terminal Compatibility
173
173
 
174
- Atomic uses 24-bit RGB colors. Most modern terminals support this (iTerm2, Kitty, WezTerm, Windows Terminal, VS Code). For older terminals with only 256-color support, Atomic falls back to the nearest approximation.
174
+ Atomic uses 24-bit RGB colors. Most modern terminals support this (iTerm2, Kitty, WezTerm, Windows Terminal, VS Code). For older terminals with only 256-color support, Atomic falls back to the nearest palette color, which turns a slightly tinted background into a gray.
175
+
176
+ The tool status backgrounds `toolPendingBg`, `toolSuccessBg`, and `toolErrorBg` keep their hue instead: each uses the nearest palette color whose strongest RGB channel is the same, so a green-tinted success background stays green. Give these three tokens different strongest channels (for example blue, green, and red tints) to keep them distinguishable in 256-color terminals, or set a palette index directly.
175
177
 
176
178
  Check truecolor support:
177
179
 
package/docs/usage.md CHANGED
@@ -86,7 +86,7 @@ Type `/` in the editor to open command completion. Extensions can register custo
86
86
  | `/share` | Upload as private GitHub gist with shareable HTML link |
87
87
  | `/reload` | Reload keybindings, extensions, skills, prompts, and context files |
88
88
  | `/hotkeys` | Show all keyboard shortcuts |
89
- | `/changelog` | Display version history |
89
+ | `/changelog` | Display the full version history |
90
90
  | `/exit` | Exit Atomic |
91
91
  | `/quit` | Quit Atomic |
92
92
 
@@ -102,6 +102,8 @@ You can submit messages while the agent is still working:
102
102
 
103
103
  Each queue preserves submission order, and steering messages take priority over follow-ups. Messages submitted during compaction keep their queue type and join that queue when compaction finishes or is cancelled, even if the agent is still working.
104
104
 
105
+ Messages you submit while Atomic is still preparing a prompt, while it waits to retry a failed request, or while extensions finish handling the end of a run are queued the same way. They show as queued at once and join the run at its next turn boundary, in the order you submitted them. If the agent refuses one, Atomic returns the text to the editor, or keeps it queued, and shows the error.
106
+
105
107
  If the first message sent after compaction fails, it stays queued with the messages after it, in the order you typed them, and Atomic shows the error. Anything you submit next is queued behind them, and your next submission sends them again in order. **ALT+Up** retrieves them to the editor in that same order.
106
108
 
107
109
  Both interrupts hold a queued message only while it is still waiting in the queue. A message the agent has already picked up is written into the transcript, and an interrupt that cancels its reply before any output appears no longer strands it: Atomic answers it instead of returning it to the editor. A reply that had already started printing is left as-is and is not restarted. Sending a message while that recovered reply is still streaming is safe — it is delivered as soon as the reply finishes.
@@ -575,6 +575,8 @@ A same-candidate retry resumes the existing turn when the transcript ends in a m
575
575
 
576
576
  Request/context incompatibility also advances it, including HTTP 400/413/422 bad, unprocessable, or payload-too-large requests; unsupported tools or parameters; context-length or context-window overflow; and `too large`, `invalid_request`, or `bad_request` errors.
577
577
 
578
+ If an extension fails to start a stage session, the stage error and its model attempts name each failing extension and its own error, for example `Extension startup failed: <extension path>: Broker failed to start within timeout`. A load-dependent failure, such as a timeout or a refused or closed local connection, uses the same-candidate retry budget from `settings.retry` and then advances to the next candidate, so the stage keeps its fallbacks and a fail-fast `parallel()` group keeps its siblings running. Any other extension startup error fails the stage at once, because every candidate would load the same extension; fix the extension named in the error and resume the run.
579
+
578
580
  If extension initialization fails and its session cannot be cleaned up, the stage stops without trying another model. Later prompts or attachment attempts on that stage also fail. Inspect both the initialization and cleanup errors and resolve the extension failure before starting a new run; changing fallback models does not fix a cleanup failure.
579
581
 
580
582
  A context overflow that the stage session's compaction has already failed to resolve is terminal for its candidate: it skips the same-candidate retry, because re-sending an identical request cannot fit a context compaction could not shrink, and advances straight to the next candidate.
@@ -646,6 +648,14 @@ A schema-backed `StageContext` supports one `prompt()` call, so create another s
646
648
 
647
649
  With both `schema` and `output`, ordinary text from the successful `structured_output` message goes to the artifact. The inferred tool result is the typed value. Corrective attempts and later turns cannot replace that pair. If the successful message has no ordinary text, the artifact uses the most recent earlier assistant text without a `structured_output` call, or stays empty with a warning. The pattern builtins save their inter-stage decisions as JSON separately.
648
650
 
651
+ ### `schemaTimeoutMs`
652
+
653
+ ```typescript
654
+ readonly schemaTimeoutMs?: number;
655
+ ```
656
+
657
+ Sets the wall-clock limit, in milliseconds, for each `structured_output` decision of a schema-backed item. The limit covers the whole decision, every repair attempt, transport retry, and model fallback together, not each generation alone. It must be a positive integer; anything else fails when the stage is set up. Without it, the limit follows the [`httpIdleTimeoutMs`](/settings#http) setting, 10 minutes by default. A decision that overruns stops its in-flight generation and fails with `Structured output decision exceeded its <n>ms deadline; no decision was accepted.` followed by how each attempt ended and how long it took. The stage then handles that error like any other failed `structured_output` call: the model receives the text unchanged, the corrective follow-ups and `fallbackModels` apply as usual, and a stage that runs out of both fails with that error rather than a structured-output contract error. Raise the limit for slow, reasoning-heavy models or a large `state`; the calling model cannot change it. `schemaTimeoutMs` has no effect without `schema`.
658
+
649
659
  ### `output` / `outputMode`
650
660
 
651
661
  ```typescript
@@ -794,6 +804,24 @@ readonly failFast?: boolean;
794
804
 
795
805
  `WorkflowParallelOptions` uses `concurrency` to bound active tasks in an authored `ctx.parallel(...)`. When omitted, the runtime uses the workflow's `defaultConcurrency` setting, which defaults to `3`; explicit configuration and per-call concurrency remain honored. Parallel execution is fail-fast unless `failFast` is explicitly `false`.
796
806
 
807
+ With `failFast: false`, every step settles before the call rejects. When any step failed, the rejection is usually an `AggregateError` whose `errors` hold the step failures and whose `partialResults` holds one entry per step, in step order: the task result for each step that completed, and `undefined` for a step that failed or did not run. Two rejections are not wrapped and have no `partialResults`: a workflow exit, and a `WorkflowBudgetExceededError` when every failed step exhausted a budget. Check for `partialResults` and rethrow anything else unchanged:
808
+
809
+ ```typescript
810
+ import type { WorkflowParallelFailure } from "@bastani/atomic/workflows";
811
+
812
+ function isParallelFailure(error: unknown): error is WorkflowParallelFailure {
813
+ return error instanceof AggregateError && Array.isArray((error as Partial<WorkflowParallelFailure>).partialResults);
814
+ }
815
+
816
+ try {
817
+ return await ctx.parallel(steps, { failFast: false });
818
+ } catch (error) {
819
+ if (!isParallelFailure(error)) throw error;
820
+ const completed = error.partialResults.filter((result) => result !== undefined);
821
+ // Use `completed`, then rethrow or handle the failures in `error.errors`.
822
+ }
823
+ ```
824
+
797
825
  For a dynamic parallel step array that cannot be scanned, set `possibleStageNames: ["review-*"]` in the call's options. Supply a literal array covering every possible step name; `*` matches a varying name component. This metadata only controls advance stage discovery, not execution or concurrency. Named helpers can forward `options.possibleStageNames` directly to their parallel calls when every direct caller supplies a literal array, including through named relative imports. Use plain data properties in those caller options; options methods/getters, mutation, and side-effecting parameter defaults are not supported for discovery. Opaque forwarding and unannotated dynamic calls still produce discovery warnings.
798
826
 
799
827
  ### Stage prompt options (`StagePromptOptions`)
@@ -253,7 +253,7 @@ Discovery cannot prove every dynamic path acyclic. Validate your branches and re
253
253
  - **Schema-backed gates** - Prefer schema-backed workflow stages (`ctx.stage(..., { schema })`, `ctx.chain` items, or `ctx.parallel` items) for review/gate decisions whenever the workflow must evaluate model output; a schema-enabled item receives the structured-output tool automatically. See [Evaluation and Quality Gates](/workflows/reliable-design#evaluation-and-quality-gates).
254
254
  - **Stages are model stages** - Treat atomic workflow units as language model stages, not deterministic tools.
255
255
  - **Small deterministic-gate stages** - When deterministic gates are needed, create small dedicated stages that instruct a model to run a specific tool or perform a specific check. This keeps gates adaptive to the current codebase while preserving explicit workflow structure.
256
- - **Checkpoint workflow-owned side effects** - Prefer `ctx.tool(name, args, fn)` for filesystem writes, network mutations, external API actions, and other side effects orchestrated directly by the workflow definition. Atomic durably caches a completed call's serializable result, so resume returns that result without rerunning `fn`. Keep pure computation and side-effect-free transformations as ordinary TypeScript. Do not wrap agent-stage internals or every function call indiscriminately. Do not retain `ctx.tool` for detached work after the workflow executor returns: terminal admission is closed first, and a later call rejects before its callback, retries, graph node, or checkpoint can begin.
256
+ - **Checkpoint workflow-owned side effects** - Prefer `ctx.tool(name, args, fn)` for filesystem writes, network mutations, external API actions, and other side effects orchestrated directly by the workflow definition. Atomic durably caches a completed call's serializable result, so resume returns that result without rerunning `fn`. Keep pure computation and side-effect-free transformations as ordinary TypeScript. Do not wrap agent-stage internals or every function call indiscriminately. Do not retain `ctx.tool` for detached work after the workflow executor returns: terminal admission is closed first, and a later call rejects before its callback, retries, graph node, or checkpoint can begin. When workflow code leaves a rejection unhandled, for example a rolling pool that keeps `branch.finally(...)` as a separate promise, or a `ctx.task(...)`, `ctx.ui.confirm(...)` or `ctx.stage(...).prompt(...)` promise that is never awaited, Atomic fails that run with the error instead of ending the whole process, and `ctx.exit()` called inside such a branch ends the run as exited, as it does anywhere else. When you stop a run with `/workflow quit` or a kill, a branch that keeps running and then calls `ctx` does not end the process either, and the run keeps the status the stop gave it. Once the run has ended, an error from a `ctx` call and the reason a stopped run was stopped with are ignored, and so is an error thrown by your own workflow code for the next 30 seconds, so the remaining branches of a failing pool cannot end the process; a later error from your own code ends it. When Atomic runs on Bun (the standalone binary) and two runs of the same workflow file overlap, it cannot tell which of them an error thrown by your own code belongs to, so that error ends the process instead of failing a run that may be healthy. Await or catch the promises you start so the failure surfaces where you can handle it.
257
257
 
258
258
  ### Context engineering guidance
259
259
 
@@ -8,7 +8,7 @@ For stages authored with `model: "auto"`, Atomic ranks up to three distinct elig
8
8
 
9
9
  Model selection uses the actual stage prompt, stage name, hard constraints, eligible model catalog, and compact dated evaluation records, not full human guides. Stage system and appended system prompts are not sent to the model router. Put requirements that should influence model selection in the stage prompt; the execution session still receives its configured system prompts.
10
10
 
11
- Malformed or schema-invalid chat routing answers receive up to three corrective retries after the initial attempt. A classifier routing failure, including a provider size or context rejection, switches to the current chat model instead of repeating the classifier request. Transient provider failures (connection errors, HTTP 408, 429 and 5xx) are retried up to three times with backoff. Model selection has no built-in wall-clock deadline; cancellation and independent provider limits still apply. An unset or `auto` router uses the current chat model; an explicit `routerModel` selects a registered classifier or chat model. Saved classifier credentials do not select the router. If routing inference fails completely, the stage runs on the current chat model instead of failing, with a recorded warning, but only when that model is available and satisfies every routing constraint (such as `allowedModels` and effort, cost, context and input limits). Otherwise the stage fails. An empty eligible catalog, stale decisions, credential-bearing routing context and cancellation still prevent stage execution without fallback. Choose router and chat providers permitted to receive the stage task and reference context.
11
+ Malformed or schema-invalid chat routing answers receive up to three corrective retries after the initial attempt. A classifier routing failure, including a provider size or context rejection, switches to the current chat model instead of repeating the classifier request. Transient provider failures (connection errors, HTTP 408, 429 and 5xx) are retried up to three times with backoff. A stage waits at most five minutes for model selection, counting any wait for a routing slot: Atomic runs at most eight routing inferences at once across all stages, so a burst of stages queues instead of overloading the router provider. When the wait ends, selection counts as a complete routing failure, as described below. A stage that fails this way reports the `model-resolution` startup phase, and a later prompt on the same stage selects a model again. Cancellation and independent provider limits still apply. An unset or `auto` router uses the current chat model; an explicit `routerModel` selects a registered classifier or chat model. Saved classifier credentials do not select the router. If routing inference fails completely, the stage runs on the current chat model instead of failing, with a recorded warning, but only when that model is available and satisfies every routing constraint (such as `allowedModels` and effort, cost, context and input limits). Otherwise the stage fails. An empty eligible catalog, stale decisions, credential-bearing routing context and cancellation still prevent stage execution without fallback. Choose router and chat providers permitted to receive the stage task and reference context.
12
12
 
13
13
  Replay reuses recorded results without routing. Resume of a saved auto stage retains its verified selection and revalidates it against the current catalog and restrictions before fresh session admission, without a hidden new decision. If it is no longer eligible, resume fails rather than choosing another model. See [authoring automatic stages](/workflows/authoring#automatic-stage-model-selection).
14
14
 
@@ -70,7 +70,7 @@ Status, run detail, dispatch confirmation, and run-picker cards wrap full IDs on
70
70
 
71
71
  An `AWAITING INPUT` banner has two identity rows: `?` with the full run id, then the workflow name and optional metadata. The question and options appear below it in the normal prompt UI.
72
72
 
73
- The `/workflow connect` run picker shows five runs at a time; use the arrow keys or mouse wheel to scroll through additional retained runs.
73
+ The `/workflow connect` run picker shows five runs at a time; use the arrow keys or mouse wheel to scroll through additional retained runs. Active runs come first, with runs waiting for input or blocked at the top, then running and paused runs, followed by ended runs (failed, cancelled, then completed); the newest run comes first within each group, and `/workflow status` lists runs in the same order.
74
74
 
75
75
  The rendered card shape at the 80-column breakpoint is:
76
76