@bastani/atomic 0.9.42-alpha.1 → 0.9.43-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +19 -0
  3. package/dist/builtin/intercom/index.bundle.mjs +20 -12
  4. package/dist/builtin/intercom/package.json +1 -1
  5. package/dist/builtin/mcp/package.json +1 -1
  6. package/dist/builtin/subagents/package.json +1 -1
  7. package/dist/builtin/web-access/package.json +1 -1
  8. package/dist/builtin/workflows/CHANGELOG.md +31 -0
  9. package/dist/builtin/workflows/package.json +1 -1
  10. package/dist/builtin/workflows/src/authoring.d.ts +2 -0
  11. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +17 -1
  12. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +5 -0
  13. package/dist/builtin/workflows/src/extension/index.bundle.mjs +363 -90
  14. package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +444 -180
  15. package/dist/builtin/workflows/src/index.js +334 -69
  16. package/dist/builtin/workflows/src/local-worker-entry.mjs +444 -180
  17. package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +10 -0
  18. package/dist/builtin/workflows/src/workers/public-options.d.ts +2 -0
  19. package/dist/core/settings-schema.d.ts +2 -0
  20. package/dist/core/settings-schema.d.ts.map +1 -1
  21. package/dist/core/settings-schema.js +10 -0
  22. package/dist/core/settings-schema.js.map +1 -1
  23. package/docs/settings.md +4 -0
  24. package/docs/workflows/api-reference.md +18 -3
  25. package/docs/workflows/operations.md +11 -1
  26. package/npm-shrinkwrap.json +32 -32
  27. package/package.json +3 -3
  28. package/schemas/settings.schema.json +12 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,75 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.43-alpha.1] - 2026-10-24
6
+
7
+ Local workflow worker pools now survive slow, busy, and crashed workers, and large workflow journals open without running out of memory.
8
+
9
+ - **Pools that recover instead of failing:** a worker that dies mid-run is replaced and its child replays from the last checkpoint instead of crashing the root with `EPIPE`, a resumed root releases children leased to workers that died with the host, and unconfirmed worker exits are retried rather than failing every waiting child ([#3891](https://github.com/bastani-inc/atomic/pull/3891), [#3893](https://github.com/bastani-inc/atomic/pull/3893), [#3895](https://github.com/bastani-inc/atomic/pull/3895))
10
+ - **Leases that follow worker liveness:** a busy root no longer fences healthy workers with `Stale work lease`, and the new `workflows.localWorkers.leaseMs` setting controls how long an unresponsive worker keeps its child (30000 ms by default) ([#3894](https://github.com/bastani-inc/atomic/pull/3894))
11
+ - **Retry decisions you can make in code:** `WorkflowInfrastructureError` and `isRetryableWorkflowError` tell retryable pool and runtime faults apart from failures of a child's own logic ([#3895](https://github.com/bastani-inc/atomic/pull/3895))
12
+ - **Faster startup on long journals:** workers become ready without reading the whole journal, the readiness timeout is configurable with `workflows.localWorkers.startupTimeoutMs`, and sessions, `/workflow status`, and the `/workflow resume` picker read each run's latest state instead of every event, so large journals no longer exhaust the heap ([#3891](https://github.com/bastani-inc/atomic/pull/3891), [#3896](https://github.com/bastani-inc/atomic/pull/3896))
13
+ - **Easier worker diagnosis:** each worker's standard error is kept under `worker-logs/` next to the journal, and startup and retry-limit errors name the log file and show the end of its output ([#3891](https://github.com/bastani-inc/atomic/pull/3891))
14
+
15
+ ### Added
16
+
17
+ - Added `WorkflowInfrastructureError` and `isRetryableWorkflowError` to `@bastani/atomic/workflows`, so workflows can tell local worker pool and runtime faults (which are safe to retry) from failures of a child workflow's own logic ([#3889](https://github.com/bastani-inc/atomic/issues/3889))
18
+ - Added the `workflows.localWorkers.leaseMs` setting: how long, in milliseconds, a local workflow worker that is still running but has stopped responding keeps its child before the child is replayed on another worker (30000 by default, at least 2000) ([#3888](https://github.com/bastani-inc/atomic/issues/3888))
19
+
20
+ ### Fixed
21
+
22
+ - Local workflow worker pools no longer fail with `Local worker startup timed out` when workers are slow to become ready, for example on a workflow journal with a long history. The readiness timeout is now configurable with the `workflows.localWorkers.startupTimeoutMs` setting (30000 ms by default) ([#3887](https://github.com/bastani-inc/atomic/issues/3887))
23
+
24
+ ## [0.9.42] - 2026-10-23
25
+
26
+ Sessions, workflow runs, and Intercom can now share one libSQL / Turso database across machines, and provider rate limits are respected across every request in a process.
27
+
28
+ - **Shared storage across machines:** install `@bastani/atomic-storage-libsql`, join a machine with `atomic storage join <url> --token-file <path>`, and check the result with `atomic storage status`. Atomic packages can ship their own storage adapters, and `createSqliteDatabase()` applies the facade rules when you write one ([#3856](https://github.com/bastani-inc/atomic/issues/3856), [#3857](https://github.com/bastani-inc/atomic/issues/3857))
29
+ - **Intercom you can inspect and restart:** `atomic intercom status` and `atomic intercom restart` show and refresh the broker's storage selection and multi-node routing, and a broker that stops answering is replaced after about a minute instead of hanging every session ([#3857](https://github.com/bastani-inc/atomic/issues/3857), [#3862](https://github.com/bastani-inc/atomic/issues/3862))
30
+ - **Rate limits handled across requests:** `configureProviderRequestBudget()` sets process-wide request budgets, 429 cooldowns are shared between model requests, and workflow model chains wait for the earliest eligible account instead of exhausting it ([#3864](https://github.com/bastani-inc/atomic/issues/3864))
31
+ - **Admission limits and local workflow pools:** SDK hosts can share session and command limits with `resourceAdmission`, and workflows can run child subtrees in local worker processes ([#3869](https://github.com/bastani-inc/atomic/issues/3869))
32
+ - **More responsive sessions and workflows:** Ctrl+C and queue clearing act without waiting for a busy engine, workflow stages reload resources four at a time, and standalone `run()` gives stages Intercom without an interactive host ([#3861](https://github.com/bastani-inc/atomic/issues/3861), [#3863](https://github.com/bastani-inc/atomic/issues/3863), [#3865](https://github.com/bastani-inc/atomic/issues/3865))
33
+ - **Login, export, and search fixes:** device-code `/login` waits for Enter before opening the browser, HTML exports show billed costs and the session's own system prompt, and `/resume` search ranks name matches first ([pi #9282](https://github.com/earendil-works/pi/issues/9282), [pi #9980](https://github.com/earendil-works/pi/issues/9980), [pi #11261](https://github.com/earendil-works/pi/issues/11261), [pi #11220](https://github.com/earendil-works/pi/issues/11220))
34
+ - **Security updates:** the standalone binaries embed Bun 1.4.4 with its upstream security fixes, and the bundled `ip-address` dependency no longer stalls on a long crafted IPv6 string ([GHSA-rxp7-6hxx-x8q5](https://github.com/advisories/GHSA-rxp7-6hxx-x8q5))
35
+
36
+ ### Added
37
+
38
+ - Markdown transformers registered with `pi.registerMarkdownTransformer()` now receive `messageId` and `timestamp` in their context when a message is rendered from the saved session, so an extension can tie its output to a session entry. Both are `undefined` for live messages. See [registerMarkdownTransformer](docs/extensions/api-reference.md#pi-registermarkdowntransformer-transformer)
39
+ - Added `configureProviderRequestBudget(provider, { maxRequests, intervalMs })` for process-wide rolling request budgets shared across SDK model runtimes. Model requests also share provider cooldowns after 429 responses. Separate configured provider IDs remain independent ([#3864](https://github.com/bastani-inc/atomic/issues/3864)).
40
+ - Storage adapter modules can import `@bastani/atomic/storage` and `@bastani/atomic` without an installed or linked copy of Atomic. They get the running Atomic's own modules, as extensions do, so Atomic recognizes the storage errors they throw ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
41
+ - `createSqliteDatabase()` in `@bastani/atomic/storage` turns a SQLite-compatible driver's calls into a `SqliteDatabase` that applies the facade rules for you: call-order queueing, transaction handle lifetime, NUL rejection, integer and blob normalization, and typed errors with credentials redacted. `redactSecrets()` builds the credential redactor. The libSQL/Turso example in [Storage](docs/storage.md#bring-your-own-driver) now uses it and is a complete adapter ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
42
+ - Atomic packages can provide storage adapters with a `storageAdapters` manifest entry, and `storage.adapter` can name one by package (`<package>` or `<package>/<name>`), so `atomic install npm:<adapter-package>` installs the adapter together with its driver. See [Adapters from Atomic packages](docs/storage.md#adapters-from-atomic-packages) ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
43
+ - `@bastani/atomic-storage-libsql` is a first-party libSQL / Turso storage adapter package. Install it with `atomic install npm:@bastani/atomic-storage-libsql` and select it with `"storage": { "adapter": "@bastani/atomic-storage-libsql" }` to share sessions, workflow runs, and Intercom routing across machines. See [Turso and libSQL](docs/storage.md#turso-and-libsql) ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
44
+ - `atomic storage status` shows, for sessions, workflow runs, and Intercom, the selected storage and where the selection comes from (environment variable, project or global settings, or default), the outranked selections, whether the adapter loads, and whether the database answers a `SELECT 1`, without creating anything. It also shows whether the running Intercom broker uses the current selection, its multi-node routing state, and the brokers live in the shared database. `--json` prints the same report. See [Checking the selected storage](docs/storage.md#checking-the-selected-storage) ([#3856](https://github.com/bastani-inc/atomic/issues/3856), [#3857](https://github.com/bastani-inc/atomic/issues/3857))
45
+ - `atomic storage join <url> --token-file <path>` joins this machine to a shared libSQL / Turso database in one step: it checks the token and the connection, stores the trimmed token in the agent directory with mode 600, writes only the global `storage` setting, creates no tables, and lists the environment variables and settings that override the new selection. It refuses a URL that carries the token itself, so a credential never reaches settings or output. When `@bastani/atomic-storage-libsql` is not installed, it prints the install command. See [Joining a machine to a shared database](docs/storage.md#joining-a-machine-to-a-shared-database) ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
46
+ - `atomic intercom restart` replaces the running Intercom broker so it reads a changed storage selection; connected sessions reconnect to the new broker. `atomic intercom status` shows the broker, whether it uses the current selection, and its multi-node routing state ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
47
+ - Interactive and print sessions warn at startup when the shared `storage` selection names an adapter that the running Atomic cannot load, naming the adapter and the cause, instead of Intercom multi-node routing staying off silently ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
48
+ - SDK hosts can share admission limits through `resourceAdmission` and `withResourceAdmission()`. Session and managed-command permits remain held until cleanup, including background commands. Delegated sessions inherit the same service and request immediate admission or rejection rather than waiting on a permit held by their parent. See [Shared resource admission](docs/sdk.md#shared-resource-admission) ([#3869](https://github.com/bastani-inc/atomic/issues/3869)).
49
+
50
+ ### Changed
51
+
52
+ - The standalone `atomic` binaries are now built with Bun 1.4.4, which includes upstream security fixes in the embedded runtime
53
+ - Device-code `/login` flows (Kimi Code, GitHub Copilot, Meta, and extension providers) no longer open the browser on their own. Press Enter to open the verification URL and copy the code, or log in manually. Providers can turn off either action with `openBrowserOnConfirm: false` or `copyCodeOnConfirm: false`. See [Provider OAuth](docs/custom-provider/oauth.md#oauth-support) ([pi #9282](https://github.com/earendil-works/pi/issues/9282))
54
+ - A `{ "file": ... }` storage secret now drops one trailing line ending (`\n` or `\r\n`), so a token saved with `turso db tokens create <db> > token` works without trimming it first. Other whitespace is still kept ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
55
+
56
+ ### Fixed
57
+
58
+ - HTML session exports now show the recorded total cost of each response, such as OpenRouter's billed cost, instead of the sum of its catalog-estimated components. Sessions recorded before totals were stored still use the component sum ([pi #9980](https://github.com/earendil-works/pi/issues/9980))
59
+ - On macOS, cancelling a running bash command no longer lets the next command in a `a; b` sequence start while the shell is being killed: the process group is stopped before it is killed ([pi #11252](https://github.com/earendil-works/pi/issues/11252))
60
+ - HTML session exports, including `atomic --export`, now show the system prompt and available tools from the session's first system message, and later system messages as named prompt-section and tool updates. Sessions without system entries still show the prompt and tools from the agent state ([pi #11261](https://github.com/earendil-works/pi/issues/11261))
61
+ - HTML session exports of very long sessions no longer fail to render the session tree with a call-stack overflow ([pi #11225](https://github.com/earendil-works/pi/issues/11225))
62
+ - `pi.exec()` now reports why a command could not be started (for example `ENOENT` for a missing executable) in `stderr` instead of returning an empty `stderr` with exit code 1 ([pi #11085](https://github.com/earendil-works/pi/issues/11085))
63
+ - `/resume` search matches the session name, summary, id, messages and working directory separately. A name match ranks first, then text found in the id, summary, messages or directory, then characters scattered through the name, summary or directory. Matches deep in a long transcript are no longer ranked last, and scattered characters in session ids or message text no longer produce noise matches ([pi #11220](https://github.com/earendil-works/pi/issues/11220))
64
+ - Updated the bundled `ip-address` dependency to 10.7.4, which fixes a quadratic-time zone-identifier match in IPv6 address parsing that a single long string could use to stall the process ([GHSA-rxp7-6hxx-x8q5](https://github.com/advisories/GHSA-rxp7-6hxx-x8q5))
65
+ - Provider request-budget waits no longer consume OpenAI, Anthropic, Mistral, or explicit Codex SSE HTTP timeouts, and successive Anthropic federation-authenticated requests keep reusing their cached token. Cancelling a queued model request reports an aborted result without dispatching it ([#3864](https://github.com/bastani-inc/atomic/issues/3864)).
66
+ - Cancelling or clearing queued messages no longer waits for a busy interactive engine to finish draining its output before acting. Cancelled prompts and shell commands waiting to start do not run later when output resumes. If queue clearing or cancellation of chat, shell commands, compaction, or retries stalls or fails, Ctrl+C can still replace the engine even while it continues sending heartbeats, including controls sent while a replacement initializes; an earlier failed queue pause no longer prevents an abort from being sent ([#3865](https://github.com/bastani-inc/atomic/issues/3865))
67
+ - The standalone binary's Intercom broker now runs multi-node routing with a shared `storage` selection and loads storage adapters, as the npm installation does ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
68
+ - `atomic storage join` keeps previous credentials intact when saving settings fails, rejects relative `file:` URLs that would select different databases from different directories, and rejects credentials embedded in `file:` URLs before printing or saving them. New joins use separate private token files, preserving existing sessions' credentials. A successful join no longer reports failure when malformed project settings prevent the final override report: it warns that storage was saved and asks you to fix the settings before running status ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
69
+ - `atomic storage status` reports settings load failures, opens local SQLite files (including adapter `file:` URLs) read-only without creating missing databases or changing journal mode, and bounds connection cleanup even when a query stalls ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
70
+ - `createSqliteDatabase()` preserves callback and rollback failures when transaction cleanup also fails ([#3856](https://github.com/bastani-inc/atomic/issues/3856))
71
+ - Package-name storage adapters now honor packages listed in legacy global settings, while explicit agent directories remain isolated ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
72
+ - On macOS, pausing a managed command no longer causes it to be reported as completed and terminated ([#3869](https://github.com/bastani-inc/atomic/issues/3869)).
73
+
5
74
  ## [0.9.42-alpha.1] - 2026-10-23
6
75
 
7
76
  Sessions, workflow runs, and Intercom can now share one libSQL / Turso database across machines, and provider rate limits are respected across every request in a process.
@@ -4,6 +4,25 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.43-alpha.1] - 2026-10-24
8
+
9
+ ### Fixed
10
+
11
+ - Fixed `Intercom event relay failed (atomic:workflow-pending-stage-route): Intercom runtime no longer active` appearing in the session after a local workflow worker died and its child was replayed. Route updates that arrive while a run's previous route connection is still closing or opening, as they do when the run's route is replaced, no longer race each other: the newest route is registered over one connection and an update the replacement made obsolete ends quietly. A route connection abandoned because the session itself shut down is still reported ([#3887](https://github.com/bastani-inc/atomic/issues/3887))
12
+
13
+ ## [0.9.42] - 2026-10-23
14
+
15
+ ### Added
16
+
17
+ - `intercom({ action: "status" })` reports the broker's multi-node routing state, for example `Multi-node routing: on (adapter @bastani/atomic-storage-libsql, prefix none), 1 peer broker live (build-host)`, or why it is off or unavailable ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
18
+ - The broker writes a positive line to `broker.log` when it starts: `Intercom multi-node routing is on (adapter <adapter>, prefix <prefix>)`, or `Intercom multi-node routing is off: <reason>`, also for an absent, in-memory, or domain-only selection, so a log without errors is no longer ambiguous ([#3856](https://github.com/bastani-inc/atomic/issues/3856), [#3857](https://github.com/bastani-inc/atomic/issues/3857))
19
+ - The broker answers status and shutdown requests from `atomic storage status`, `atomic intercom status`, and `atomic intercom restart`: its storage selection, sessions, multi-node state, and the other brokers live in the shared database. A restart lets connected sessions reconnect to a broker that reads the current storage selection, without closing them ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
20
+
21
+ ### Fixed
22
+
23
+ - Fixed Intercom remaining stuck on a broker that accepts connections but stops answering. New brokers monitor their own request handling and terminate after about a minute of failed health checks so clients can start one replacement. Timed-out client requests also check connection health before entering reconnect recovery, without restarting a responsive broker. Identical in-flight sends keep sharing one result through the health check. A bounded previous broker log and the latest watchdog diagnosis survive replacement ([#3862](https://github.com/bastani-inc/atomic/issues/3862)).
24
+ - Restarting an older broker on Windows no longer mistakes a lingering named pipe for a restarted broker after its process has exited ([#3857](https://github.com/bastani-inc/atomic/issues/3857))
25
+
7
26
  ## [0.9.42-alpha.1] - 2026-10-23
8
27
 
9
28
  ### Added
@@ -8151,23 +8151,30 @@ function piIntercomExtension(pi, testOverrides = {}) {
8151
8151
  pi.events.emit(PENDING_STAGE_ROUTE_REVOKED_EVENT, { runId, capability: state.route.capability });
8152
8152
  });
8153
8153
  }
8154
+ async function retirePendingStageRouteClient(state) {
8155
+ try {
8156
+ await state.promise;
8157
+ } catch {}
8158
+ if (state.client) {
8159
+ try {
8160
+ await state.client.disconnect();
8161
+ } catch {}
8162
+ }
8163
+ }
8164
+ function supersededPendingStageRouteError(context, generation) {
8165
+ return getLiveContext(context, generation) ? new IntercomClientDisconnectedError : new Error("Intercom runtime no longer active");
8166
+ }
8154
8167
  async function ensurePendingStageRouteClient(runId, route, options = {}) {
8155
8168
  const contextAtStart = getLiveContext();
8156
8169
  const generationAtStart = runtimeGeneration;
8157
8170
  if (!contextAtStart)
8158
8171
  throw new Error("Intercom runtime not initialized");
8159
8172
  let existing = pendingStageRouteClients.get(runId);
8173
+ let retired;
8160
8174
  if (existing && !samePendingStageRoute(existing.route, route)) {
8161
8175
  pendingStageRouteClients.delete(runId);
8162
8176
  endPendingStageRouteBackoff(existing, new IntercomClientDisconnectedError);
8163
- try {
8164
- await existing.promise;
8165
- } catch {}
8166
- if (existing.client) {
8167
- try {
8168
- await existing.client.disconnect();
8169
- } catch {}
8170
- }
8177
+ retired = retirePendingStageRouteClient(existing);
8171
8178
  existing = undefined;
8172
8179
  }
8173
8180
  const state = existing ?? {
@@ -8191,9 +8198,9 @@ function piIntercomExtension(pi, testOverrides = {}) {
8191
8198
  }
8192
8199
  if (state.reconnectTimer !== null && options.bypassBackoff !== true)
8193
8200
  return state.retryWaiters.join();
8194
- const promise = routeClientConnectGate.run(async () => {
8201
+ const connect = () => routeClientConnectGate.run(async () => {
8195
8202
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
8196
- throw new Error("Intercom runtime no longer active");
8203
+ throw supersededPendingStageRouteError(contextAtStart, generationAtStart);
8197
8204
  }
8198
8205
  await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
8199
8206
  const routeReturnAddress = `${currentSessionId}:pending-stage-route:${runId}`;
@@ -8205,16 +8212,17 @@ function piIntercomExtension(pi, testOverrides = {}) {
8205
8212
  await nextClient.connect({ ...buildRegistration(), recipientPurpose: "control", name: undefined, groups: [normalizeGroup(route.group)], group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
8206
8213
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
8207
8214
  await nextClient.disconnect();
8208
- throw new Error("Intercom runtime no longer active");
8215
+ throw supersededPendingStageRouteError(contextAtStart, generationAtStart);
8209
8216
  }
8210
8217
  await nextClient.registerPendingStageRouteAcknowledged(runId, normalizeGroup(route.group), route.capability, route.stages, route.possibleStages, route.parent, route.dormant === true);
8211
8218
  if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
8212
8219
  await nextClient.disconnect();
8213
- throw new Error("Intercom runtime no longer active");
8220
+ throw supersededPendingStageRouteError(contextAtStart, generationAtStart);
8214
8221
  }
8215
8222
  state.reconnectAttempt = 0;
8216
8223
  endPendingStageRouteBackoff(state);
8217
8224
  });
8225
+ const promise = retired === undefined ? connect() : retired.then(connect);
8218
8226
  state.promise = promise;
8219
8227
  try {
8220
8228
  await promise;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.42-alpha.1",
3
+ "version": "0.9.43-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.42-alpha.1",
3
+ "version": "0.9.43-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic's pi-compatible MCP integration for server connections, OAuth, tools, resources, and terminal management.",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.42-alpha.1",
3
+ "version": "0.9.43-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.42-alpha.1",
3
+ "version": "0.9.43-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,37 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.43-alpha.1] - 2026-10-24
10
+
11
+ ### Added
12
+
13
+ - `ctx.workflow(child)` now throws a `WorkflowInfrastructureError` with `retryable: true` and a fault `code` when the local worker pool cannot run a child because of a fault in the pool or its runtime (for example `Local worker retry limit`, `Local worker cleanup was not confirmed`, `Stale work lease`, `Intercom runtime no longer active` or `Storage unavailable`), and `isRetryableWorkflowError(error)` recognizes it anywhere in an error's `cause` chain. Failures of a child's own logic keep throwing a plain `Error` ([#3889](https://github.com/bastani-inc/atomic/issues/3889))
14
+
15
+ ### Changed
16
+
17
+ - Local worker leases now follow worker liveness. A worker that is still running and responding keeps its child even when the root is too busy to process its heartbeats in time, so a slow root no longer fences healthy workers with `Stale work lease`. A worker that has stopped responding is fenced after `localWorkers.leaseMs` milliseconds, which defaults to 30000 instead of the previous fixed 5000 ([#3888](https://github.com/bastani-inc/atomic/issues/3888))
18
+
19
+ ### Fixed
20
+
21
+ - A local workflow worker that dies while the root still owes it replies no longer crashes the root with `Error: write EPIPE`. The root fences that worker's attempt and replays the child from its last committed checkpoint on a replacement worker ([#3887](https://github.com/bastani-inc/atomic/issues/3887))
22
+ - Each local worker's standard error is now kept in `worker-logs/<root run ID>/<worker ID>.log` in the workflow journal's directory, and the `Local worker exited before readiness`, `Local worker startup timed out` and `Local worker retry limit` errors name that file and include the end of the worker's output. Logs of workers that are still running when the pool shuts down normally are removed ([#3887](https://github.com/bastani-inc/atomic/issues/3887))
23
+ - Local worker pools no longer fail with `Local worker startup timed out` on a workflow journal with a long history. Workers no longer read every run in the journal before reporting ready, the pool starts running children once one worker is ready and fails only when none starts, and the readiness timeout can be raised with `localWorkers.startupTimeoutMs` (30000 ms by default). Once running, workers bring their view of the root up to date by reading only the journal events added since their last read, instead of re-reading the root's whole history after every checkpoint and claim. The timeout is not saved with the root, so it can change between resumes ([#3887](https://github.com/bastani-inc/atomic/issues/3887))
24
+ - Resuming a pooled root after its host process crashed no longer leaves children leased to workers that died with it. The resumed root releases those attempts as soon as it starts its new pool, and their children are replayed from their last committed checkpoints on the new workers ([#3890](https://github.com/bastani-inc/atomic/issues/3890))
25
+ - Opening or resuming a session with a large workflow journal no longer shows a blank screen and then crashes with `JavaScript heap out of memory`. Sessions, `/workflow status` and the `/workflow resume` picker now read each run's latest state instead of every event in the journal, and load a run's full history only when that run is resumed, recovered, inspected or opened ([#3892](https://github.com/bastani-inc/atomic/issues/3892))
26
+ - A local worker whose process exit cannot be confirmed during lease recovery no longer fails every child waiting on the pool with `Local worker cleanup was not confirmed`. The pool keeps the attempt fenced and retries recovery until the worker exits ([#3889](https://github.com/bastani-inc/atomic/issues/3889))
27
+
28
+ ## [0.9.42] - 2026-10-23
29
+
30
+ ### Added
31
+
32
+ - Local workflow pools can be enabled per run through SDK options or workflow settings, with root and optional user-wide admission limits. A root stays local while registered child workflow subtrees run in local worker processes; unsupported process containment and incompatible worker definitions fail closed ([#3869](https://github.com/bastani-inc/atomic/issues/3869)).
33
+
34
+ ### Fixed
35
+
36
+ - Workflow model chains now share provider-account cooldowns after rate limits, honor `Retry-After`, and wait for the earliest eligible account instead of exhausting a cooling chain. Retries remain bounded, including retries within each session; waits can be paused or cancelled, and workflow status and task results report provider counts and cooldown deadlines. Retrying a follow-up on the same model preserves its conversation history. Follow-ups keep each model's retry allowance across account switches and can return to an earlier account when its cooldown expires ([#3864](https://github.com/bastani-inc/atomic/issues/3864)).
37
+ - Workflow stages now reload resources up to four at a time per Atomic process instead of one at a time, so a slow reload no longer blocks every other stage at startup. Cancelling a stage waiting for a reload slot removes it from the queue immediately; an active reload retains its slot until it finishes ([#3861](https://github.com/bastani-inc/atomic/issues/3861)).
38
+ - Standalone `run()` now owns Intercom routes for eligible workflow stages until the run settles, so stages can use Intercom without an interactive workflow host. An installed SDK reuses an Intercom owner the extension bundle already registered for the store instead of starting a second one. When a route-update acknowledgement times out, the update retries without disconnecting a healthy owner ([#3863](https://github.com/bastani-inc/atomic/issues/3863))
39
+
9
40
  ## [0.9.42-alpha.1] - 2026-10-23
10
41
 
11
42
  ### Added
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.42-alpha.1",
3
+ "version": "0.9.43-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -36,6 +36,8 @@ export type RunOpts = Omit<AuthoringContract.RunOpts, "registry"> & {
36
36
  export declare const INTERACTIVE_WORKFLOW_POLICY: WorkflowExecutionPolicy;
37
37
  export declare const NON_INTERACTIVE_WORKFLOW_POLICY: WorkflowExecutionPolicy;
38
38
  export declare function run<TInputs extends WorkflowInputValues, TOutputs extends WorkflowOutputValues, TRunInputs extends WorkflowInputValues = TInputs>(definition: WorkflowDefinition<TInputs, TOutputs, TRunInputs>, inputs: Readonly<NoInfer<WorkflowRunInputArgument<TRunInputs>>>, opts?: RunOpts): Promise<RunResult<TOutputs>>;
39
+ export type { WorkflowInfrastructureFault } from "./shared/workflow-infrastructure-error.js";
40
+ export { isRetryableWorkflowError, WorkflowInfrastructureError } from "./shared/workflow-infrastructure-error.js";
39
41
  export declare function loadWorkerWorkflow(path: string, exportName?: string): Promise<AnyWorkflowDefinition>;
40
42
  export type { LocalWorkerOptions, WorkflowAdmissionOptions } from "./workers/public-options.js";
41
43
  /**
@@ -1,17 +1,33 @@
1
1
  import type { SqliteExecutor } from "@bastani/atomic/storage";
2
- import type { RunJournal } from "./types.js";
2
+ import { type JournalEntry, type RunJournal } from "./types.js";
3
3
  export declare const JOURNAL_READ_PAGE_SIZE = 256;
4
+ /** Event types the durable backend folds without replacing the run's handle; every other event carries it. */
5
+ export declare const NON_SNAPSHOT_EVENT_TYPES: readonly ["CheckpointRecorded", "MessageSettled", "MessageDelivered"];
4
6
  /** A run's latest event. A run whose history was deleted and recorded again ends with a different event. */
5
7
  export interface RunVersion {
6
8
  readonly seq: number;
7
9
  readonly at: number;
8
10
  }
11
+ /**
12
+ * A run's latest snapshot event (one carrying the run's handle) and the checkpoints recorded after it: enough to
13
+ * list the run in a catalog without reading its history.
14
+ */
15
+ export interface RunSnapshotTail {
16
+ /** The run's latest event of any type. */
17
+ readonly version: RunVersion;
18
+ readonly snapshot: JournalEntry;
19
+ readonly laterCheckpoints: number;
20
+ /** `completedAt` of the last of `laterCheckpoints`. */
21
+ readonly lastCheckpointAt?: number;
22
+ }
9
23
  /** Lets a durable backend re-read only the runs that changed; kept off the public journal shape. */
10
24
  export interface RunJournalVersions {
11
25
  /** Moves whenever any connection, in this process or another, commits a change to the journal's store. */
12
26
  changeToken(): Promise<string>;
13
27
  /** Every listed run with its latest event; a run with no events has version `{ seq: 0, at: 0 }`. */
14
28
  runVersions(): Promise<ReadonlyMap<string, RunVersion>>;
29
+ /** Undefined for a run with no snapshot event. */
30
+ snapshotTail(runId: string): Promise<RunSnapshotTail | undefined>;
15
31
  }
16
32
  export declare function registerRunJournalVersions(journal: RunJournal, versions: RunJournalVersions): void;
17
33
  /** Change tracking for a journal that registered it; other journals are re-read in full. */
@@ -29,6 +29,11 @@ export declare class SqlRunJournal implements RunJournal {
29
29
  */
30
30
  private changeToken;
31
31
  private runVersions;
32
+ /**
33
+ * The latest snapshot event is found by walking the run's `(run_id, seq)` key back from its last event, so
34
+ * only the events after it are visited and only its payload is read.
35
+ */
36
+ private snapshotTail;
32
37
  private requireRun;
33
38
  /** Whether this run exists only in the legacy tables, whose events are then read in place. */
34
39
  private isUnconvertedLegacyRun;