@bastani/atomic 0.9.57 → 0.9.58-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.
- package/CHANGELOG.md +52 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +12 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +39 -5
- package/dist/builtin/web-access/CHANGELOG.md +12 -0
- package/dist/builtin/web-access/index.bundle.mjs +2 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +42 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +885 -228
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +933 -175
- package/dist/builtin/workflows/src/index.js +630 -162
- package/dist/builtin/workflows/src/local-worker-entry.mjs +933 -175
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +1 -1
- package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +13 -0
- package/dist/builtin/workflows/src/workers/public-options.d.ts +10 -0
- package/dist/core/agent-session-persistent-custom-messages.d.ts +5 -0
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +16 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +20 -0
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +4 -0
- package/dist/core/settings-defaults.d.ts.map +1 -1
- package/dist/core/settings-defaults.js +4 -0
- package/dist/core/settings-defaults.js.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts +2 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.js +6 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -1
- package/dist/core/settings-schema.d.ts +9 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +11 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/tasks/agent-adapter.d.ts +10 -1
- package/dist/core/tasks/agent-adapter.d.ts.map +1 -1
- package/dist/core/tasks/agent-adapter.js +20 -0
- package/dist/core/tasks/agent-adapter.js.map +1 -1
- package/dist/core/tasks/contracts.d.ts +6 -0
- package/dist/core/tasks/contracts.d.ts.map +1 -1
- package/dist/core/tasks/contracts.js.map +1 -1
- package/dist/core/tasks/heartbeat-notice.d.ts +64 -0
- package/dist/core/tasks/heartbeat-notice.d.ts.map +1 -0
- package/dist/core/tasks/heartbeat-notice.js +98 -0
- package/dist/core/tasks/heartbeat-notice.js.map +1 -0
- package/dist/core/tasks/heartbeat.d.ts +75 -0
- package/dist/core/tasks/heartbeat.d.ts.map +1 -0
- package/dist/core/tasks/heartbeat.js +440 -0
- package/dist/core/tasks/heartbeat.js.map +1 -0
- package/dist/core/tasks/supervisor.d.ts +2 -0
- package/dist/core/tasks/supervisor.d.ts.map +1 -1
- package/dist/core/tasks/supervisor.js +32 -4
- package/dist/core/tasks/supervisor.js.map +1 -1
- package/dist/core/tasks/task-view-source.d.ts +72 -0
- package/dist/core/tasks/task-view-source.d.ts.map +1 -0
- package/dist/core/tasks/task-view-source.js +155 -0
- package/dist/core/tasks/task-view-source.js.map +1 -0
- package/dist/core/tools/bash-pty-native.d.ts +2 -0
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
- package/dist/core/tools/bash-pty-native.js +1 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -1
- package/dist/core/tools/bash.d.ts +3 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +20 -2
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/powershell.d.ts +16 -8
- package/dist/core/tools/powershell.d.ts.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +7 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +3 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +4 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.d.ts +11 -0
- package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +2 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +15 -8
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +12 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/task-detail.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-detail.js +5 -0
- package/dist/modes/interactive/components/task-detail.js.map +1 -1
- package/dist/modes/interactive/components/task-heartbeat-message.d.ts +14 -0
- package/dist/modes/interactive/components/task-heartbeat-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/task-heartbeat-message.js +76 -0
- package/dist/modes/interactive/components/task-heartbeat-message.js.map +1 -0
- package/dist/modes/interactive/components/task-inspector.d.ts +6 -3
- package/dist/modes/interactive/components/task-inspector.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-inspector.js +53 -100
- package/dist/modes/interactive/components/task-inspector.js.map +1 -1
- package/dist/modes/interactive/skill-command-autocomplete.d.ts +22 -2
- package/dist/modes/interactive/skill-command-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/skill-command-autocomplete.js +28 -9
- package/dist/modes/interactive/skill-command-autocomplete.js.map +1 -1
- package/docs/background-tasks.md +65 -1
- package/docs/settings.md +12 -0
- package/docs/subagents.md +2 -0
- package/docs/tools.md +2 -1
- package/docs/workflows/operations.md +5 -3
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +24 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.58] - 2026-11-01
|
|
6
|
+
|
|
7
|
+
Task heartbeats, stage chats that work on local workers, and a local worker pool that holds up under load.
|
|
8
|
+
|
|
9
|
+
- **Task heartbeats:** a background shell or subagent that keeps running now reports to its chat every 15 minutes, so the model catches stuck or runaway tasks without you stepping in. Change the cadence per call with `heartbeatMs` or for every task with the `tasks.heartbeatMs` setting, and see each task's cadence in `/tasks` ([#4141](https://github.com/bastani-inc/atomic/pull/4141))
|
|
10
|
+
- **Stage chats on local workers:** a stage whose session has not started reads as queued instead of running, and opens once it has. Its chat completes `/skill:` commands, runs `/compact` and `!` commands, and `/tasks` lists, opens and stops the stage's agents and shells, as in an in-process stage chat ([#4137](https://github.com/bastani-inc/atomic/pull/4137), [#4139](https://github.com/bastani-inc/atomic/pull/4139), [#4140](https://github.com/bastani-inc/atomic/pull/4140))
|
|
11
|
+
- **A local worker pool that holds up under load:** reloading workflows or starting other runs no longer fails a running root's children with `Stale lease for run <id>`, a busy machine no longer fails stages on delivery or lease errors, `/workflow pause` pauses a root's stages even while its own steps run, and an overloaded machine starts stages one at a time, tunable with `workflows.localWorkers.maxLoadPerCpu` ([#4138](https://github.com/bastani-inc/atomic/pull/4138), [#4145](https://github.com/bastani-inc/atomic/pull/4145), [#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
12
|
+
- **Resuming pooled runs:** a root that runs children on local workers resumes from a new process, including one paused or failed by 0.9.57, and runs again the children that failed on a pool fault instead of replaying the failure ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
13
|
+
- **Stopped tasks finish:** a shell stopped with `kill`, from `/tasks` or with Esc no longer stays "stopping" in the Tasks indicator forever; it ends as failed with the resource that could not be cleaned up ([#4142](https://github.com/bastani-inc/atomic/pull/4142))
|
|
14
|
+
- **Quieter PDF fetches:** pdf.js font warnings such as `Warning: TT: undefined function: 32` no longer print over the terminal UI when a PDF is fetched ([#4136](https://github.com/bastani-inc/atomic/pull/4136))
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `createSessionSkillAutocompleteProvider` also completes from a `SessionCommandCatalog`, the plain-data skill command list of a session that runs in another process (captured there with `getSessionCommandCatalog`), and shows a pending catalog's loading notice instead of an unavailable warning.
|
|
19
|
+
- `TaskInspector` and `ChatSessionHost` read tasks through a `TaskViewSource` (`ownerTaskViewSource(store)` for a session's own task store), so a host can show `/tasks` for a session that runs in another process through the new `getTaskSource` option.
|
|
20
|
+
- Added task heartbeats: a background shell or subagent that keeps running sends its chat a periodic `♥ Task heartbeat` notice, every 15 minutes by default like workflow heartbeats, so the model can catch runaway shells, stale subagents and hung tool calls without you stepping in. Each notice gives the task's elapsed time and when it last produced output or activity, a shell's last output lines, and a subagent's current tool call and turn, tool-call and token counts, then asks the model to let a progressing task run or to inspect, steer or stop one that is stuck, never relaunching a duplicate. Only running tasks heartbeat; tasks due together share one notice, a chat never has more than one unread heartbeat, and missed intervals are not replayed. Set `heartbeatMs` on a `bash` or `powershell` call (or `subagent`) to change one task's cadence, `0` to turn it off, or `tasks.heartbeatMs` in settings to change the default; `/tasks` shows each running task's cadence. Workflow stages on local workers heartbeat into their own stage chat the same way. See [Task heartbeats](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/docs/background-tasks.md#task-heartbeats).
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Workflow roots that run children on local workers (`workflows.localWorkers`) keep their children running when the session is busy. Reloading workflows and starting other runs in the same session could delay the root's lease renewal past the pool's 90-second window, after which every running child, and every child started later, failed with `Stale lease for run <id>` while the root kept running. The pool now waits for the late renewal, each run renews its lease independently, and a renewal that briefly fails is retried. Roots that never run a pooled `ctx.workflow` child no longer start an idle pool coordinator process. ([#4138](https://github.com/bastani-inc/atomic/pull/4138))
|
|
25
|
+
- A stopped shell no longer stays **stopping** in the Tasks indicator below the prompt forever (for example `Tasks 3 local agents running · 3 stopping · /tasks`). When a shell stopped with `kill`, from `/tasks`, by Esc on a foreground command, or by its timeout left a process outside its process group holding its output open (a daemon or a `setsid` or detached child), Atomic killed the command's process group but could not confirm cleanup, and the task never reached a final state. It now ends within a few seconds as failed with `CleanupUnconfirmed: Stop requested (<cause>); cleanup unconfirmed: <resource>`, and the indicator counts only tasks that are still stopping. A stopped subagent whose cleanup fails also ends instead of staying stopping. ([#4142](https://github.com/bastani-inc/atomic/pull/4142))
|
|
26
|
+
- Workflow stages on local workers (`workflows.localWorkers`) survive a heavily loaded machine. A slow startup delivery of queued Intercom messages no longer fails stages with `Worker exited before delivery acknowledgement`, a work lease that ran out only because renewals were processed late no longer fails or replays children (`Stale work lease`, `Stale resource admission attempt`), and a pool fault that reaches a running child replays it instead of failing its stage. Stages that do fail on a pool fault are recorded with that fault as a recoverable failure, and resume runs them again. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
27
|
+
- `/workflow pause` pauses a root's stages on local workers even while the root's own steps run, instead of reporting `No active stages to pause`, and pause or resume no longer fails with `Worker control acknowledgement unresolved` on a busy machine; the result says how many stages have not confirmed the pause yet. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
28
|
+
- Resuming a workflow root that runs children on local workers, including one paused or failed by 0.9.57, runs again the children an earlier process failed on a fault of the pool itself instead of replaying their failure, and a paused root with durable progress says it can be resumed from a new process. ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
29
|
+
- On an overloaded machine, stages of workflow children on local workers start one at a time, at most one every 5 seconds, instead of all at once while earlier ones are still starting. Tune or turn off with `workflows.localWorkers.maxLoadPerCpu` (default `3`, `0` off). ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
30
|
+
|
|
31
|
+
## [0.9.58-alpha.1] - 2026-11-01
|
|
32
|
+
|
|
33
|
+
Task heartbeats, stage chats that work on local workers, and a local worker pool that holds up under load.
|
|
34
|
+
|
|
35
|
+
- **Task heartbeats:** a background shell or subagent that keeps running now reports to its chat every 15 minutes, so the model catches stuck or runaway tasks without you stepping in. Change the cadence per call with `heartbeatMs` or for every task with the `tasks.heartbeatMs` setting, and see each task's cadence in `/tasks` ([#4141](https://github.com/bastani-inc/atomic/pull/4141))
|
|
36
|
+
- **Stage chats on local workers:** a stage whose session has not started reads as queued instead of running, and opens once it has. Its chat completes `/skill:` commands, runs `/compact` and `!` commands, and `/tasks` lists, opens and stops the stage's agents and shells, as in an in-process stage chat ([#4137](https://github.com/bastani-inc/atomic/pull/4137), [#4139](https://github.com/bastani-inc/atomic/pull/4139), [#4140](https://github.com/bastani-inc/atomic/pull/4140))
|
|
37
|
+
- **A local worker pool that holds up under load:** reloading workflows or starting other runs no longer fails a running root's children with `Stale lease for run <id>`, a busy machine no longer fails stages on delivery or lease errors, `/workflow pause` pauses a root's stages even while its own steps run, and an overloaded machine starts stages one at a time, tunable with `workflows.localWorkers.maxLoadPerCpu` ([#4138](https://github.com/bastani-inc/atomic/pull/4138), [#4145](https://github.com/bastani-inc/atomic/pull/4145), [#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
38
|
+
- **Resuming pooled runs:** a root that runs children on local workers resumes from a new process, including one paused or failed by 0.9.57, and runs again the children that failed on a pool fault instead of replaying the failure ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
39
|
+
- **Stopped tasks finish:** a shell stopped with `kill`, from `/tasks` or with Esc no longer stays "stopping" in the Tasks indicator forever; it ends as failed with the resource that could not be cleaned up ([#4142](https://github.com/bastani-inc/atomic/pull/4142))
|
|
40
|
+
- **Quieter PDF fetches:** pdf.js font warnings such as `Warning: TT: undefined function: 32` no longer print over the terminal UI when a PDF is fetched ([#4136](https://github.com/bastani-inc/atomic/pull/4136))
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- `createSessionSkillAutocompleteProvider` also completes from a `SessionCommandCatalog`, the plain-data skill command list of a session that runs in another process (captured there with `getSessionCommandCatalog`), and shows a pending catalog's loading notice instead of an unavailable warning.
|
|
45
|
+
- `TaskInspector` and `ChatSessionHost` read tasks through a `TaskViewSource` (`ownerTaskViewSource(store)` for a session's own task store), so a host can show `/tasks` for a session that runs in another process through the new `getTaskSource` option.
|
|
46
|
+
- Added task heartbeats: a background shell or subagent that keeps running sends its chat a periodic `♥ Task heartbeat` notice, every 15 minutes by default like workflow heartbeats, so the model can catch runaway shells, stale subagents and hung tool calls without you stepping in. Each notice gives the task's elapsed time and when it last produced output or activity, a shell's last output lines, and a subagent's current tool call and turn, tool-call and token counts, then asks the model to let a progressing task run or to inspect, steer or stop one that is stuck, never relaunching a duplicate. Only running tasks heartbeat; tasks due together share one notice, a chat never has more than one unread heartbeat, and missed intervals are not replayed. Set `heartbeatMs` on a `bash` or `powershell` call (or `subagent`) to change one task's cadence, `0` to turn it off, or `tasks.heartbeatMs` in settings to change the default; `/tasks` shows each running task's cadence. Workflow stages on local workers heartbeat into their own stage chat the same way. See [Task heartbeats](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/docs/background-tasks.md#task-heartbeats).
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Workflow roots that run children on local workers (`workflows.localWorkers`) keep their children running when the session is busy. Reloading workflows and starting other runs in the same session could delay the root's lease renewal past the pool's 90-second window, after which every running child, and every child started later, failed with `Stale lease for run <id>` while the root kept running. The pool now waits for the late renewal, each run renews its lease independently, and a renewal that briefly fails is retried. Roots that never run a pooled `ctx.workflow` child no longer start an idle pool coordinator process. ([#4138](https://github.com/bastani-inc/atomic/pull/4138))
|
|
51
|
+
- A stopped shell no longer stays **stopping** in the Tasks indicator below the prompt forever (for example `Tasks 3 local agents running · 3 stopping · /tasks`). When a shell stopped with `kill`, from `/tasks`, by Esc on a foreground command, or by its timeout left a process outside its process group holding its output open (a daemon or a `setsid` or detached child), Atomic killed the command's process group but could not confirm cleanup, and the task never reached a final state. It now ends within a few seconds as failed with `CleanupUnconfirmed: Stop requested (<cause>); cleanup unconfirmed: <resource>`, and the indicator counts only tasks that are still stopping. A stopped subagent whose cleanup fails also ends instead of staying stopping. ([#4142](https://github.com/bastani-inc/atomic/pull/4142))
|
|
52
|
+
- Workflow stages on local workers (`workflows.localWorkers`) survive a heavily loaded machine. A slow startup delivery of queued Intercom messages no longer fails stages with `Worker exited before delivery acknowledgement`, a work lease that ran out only because renewals were processed late no longer fails or replays children (`Stale work lease`, `Stale resource admission attempt`), and a pool fault that reaches a running child replays it instead of failing its stage. Stages that do fail on a pool fault are recorded with that fault as a recoverable failure, and resume runs them again. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
53
|
+
- `/workflow pause` pauses a root's stages on local workers even while the root's own steps run, instead of reporting `No active stages to pause`, and pause or resume no longer fails with `Worker control acknowledgement unresolved` on a busy machine; the result says how many stages have not confirmed the pause yet. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
54
|
+
- Resuming a workflow root that runs children on local workers, including one paused or failed by 0.9.57, runs again the children an earlier process failed on a fault of the pool itself instead of replaying their failure, and a paused root with durable progress says it can be resumed from a new process. ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
55
|
+
- On an overloaded machine, stages of workflow children on local workers start one at a time, at most one every 5 seconds, instead of all at once while earlier ones are still starting. Tune or turn off with `workflows.localWorkers.maxLoadPerCpu` (default `3`, `0` off). ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
56
|
+
|
|
5
57
|
## [0.9.57] - 2026-10-31
|
|
6
58
|
|
|
7
59
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.58-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": [
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.58] - 2026-11-01
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Running subagents now send the parent periodic task heartbeats (every 15 minutes by default) with their current tool call, time since their last activity, and turn, tool-call and token counts. Set `heartbeatMs` on a `subagent` call, or on a `tasks` entry, to change a child's cadence; `0` turns it off.
|
|
10
|
+
|
|
11
|
+
## [0.9.58-alpha.1] - 2026-11-01
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Running subagents now send the parent periodic task heartbeats (every 15 minutes by default) with their current tool call, time since their last activity, and turn, tool-call and token counts. Set `heartbeatMs` on a `subagent` call, or on a `tasks` entry, to change a child's cadence; `0` turns it off.
|
|
16
|
+
|
|
5
17
|
## [0.9.57] - 2026-10-31
|
|
6
18
|
|
|
7
19
|
Desktop computer use moves from Cua Driver to agent-desktop.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/subagents",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.58-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": [
|
|
@@ -10820,6 +10820,7 @@ ${launch.message}` : input.task,
|
|
|
10820
10820
|
},
|
|
10821
10821
|
wait: { kind: "background" },
|
|
10822
10822
|
runtime: input.runtime,
|
|
10823
|
+
...input.heartbeatMs === undefined ? {} : { heartbeatMs: input.heartbeatMs },
|
|
10823
10824
|
onTerminal: launch.onTerminal,
|
|
10824
10825
|
...input.schedule ? { schedule: input.schedule } : {},
|
|
10825
10826
|
...input.outputText ? { outputText: input.outputText } : {},
|
|
@@ -10834,7 +10835,8 @@ ${launch.message}` : input.task,
|
|
|
10834
10835
|
agent: input.agent,
|
|
10835
10836
|
task: input.intentTask ?? input.task,
|
|
10836
10837
|
cwd: input.options.cwd ?? input.cwd,
|
|
10837
|
-
...input.options.modelRoute ? { routerSelection: input.options.modelRoute.routerSelection } : {}
|
|
10838
|
+
...input.options.modelRoute ? { routerSelection: input.options.modelRoute.routerSelection } : {},
|
|
10839
|
+
...input.heartbeatMs === undefined ? {} : { heartbeatMs: input.heartbeatMs }
|
|
10838
10840
|
}, input.operation ?? `${input.options.runId}:${input.options.index ?? 0}`, (context) => {
|
|
10839
10841
|
dispatched = true;
|
|
10840
10842
|
queuedChildren.delete(context.ref.taskId);
|
|
@@ -11182,6 +11184,7 @@ async function runForegroundParallelTasks(input) {
|
|
|
11182
11184
|
options: runOptions,
|
|
11183
11185
|
runtime: input.runtime,
|
|
11184
11186
|
wait: input.wait,
|
|
11187
|
+
...(task.heartbeatMs ?? input.heartbeatMs) === undefined ? {} : { heartbeatMs: task.heartbeatMs ?? input.heartbeatMs },
|
|
11185
11188
|
schedule,
|
|
11186
11189
|
onTerminal: (child) => {
|
|
11187
11190
|
terminalChild = child;
|
|
@@ -15334,6 +15337,9 @@ async function recordReportedGoneSubagentChildren(pi, outcomes) {
|
|
|
15334
15337
|
}
|
|
15335
15338
|
}
|
|
15336
15339
|
|
|
15340
|
+
// dist/builtin/subagents/src/runs/foreground/subagent-executor.ts
|
|
15341
|
+
import { validateTaskHeartbeatMs } from "@bastani/atomic";
|
|
15342
|
+
|
|
15337
15343
|
// dist/builtin/subagents/src/agents/agent-management.ts
|
|
15338
15344
|
import * as fs15 from "node:fs";
|
|
15339
15345
|
import * as path16 from "node:path";
|
|
@@ -16257,7 +16263,8 @@ function topLevelSingleTask(item) {
|
|
|
16257
16263
|
...item.params.modelConstraints !== undefined ? { modelConstraints: item.params.modelConstraints } : {},
|
|
16258
16264
|
...item.params.taskNeeds !== undefined ? { taskNeeds: item.params.taskNeeds } : {},
|
|
16259
16265
|
...item.params.skill !== undefined ? { skill: item.params.skill } : {},
|
|
16260
|
-
...item.params.group !== undefined ? { group: item.params.group } : {}
|
|
16266
|
+
...item.params.group !== undefined ? { group: item.params.group } : {},
|
|
16267
|
+
...item.params.heartbeatMs !== undefined ? { heartbeatMs: item.params.heartbeatMs } : {}
|
|
16261
16268
|
};
|
|
16262
16269
|
}
|
|
16263
16270
|
function existingParallelTask(item, task) {
|
|
@@ -16266,7 +16273,8 @@ function existingParallelTask(item, task) {
|
|
|
16266
16273
|
...task,
|
|
16267
16274
|
cwd: originatingTaskCwd(callCwd, task.cwd),
|
|
16268
16275
|
[BURST_TASK_DISCOVERY_CWD]: callCwd,
|
|
16269
|
-
...task.group === undefined && item.params.group !== undefined ? { group: item.params.group } : {}
|
|
16276
|
+
...task.group === undefined && item.params.group !== undefined ? { group: item.params.group } : {},
|
|
16277
|
+
...task.heartbeatMs === undefined && item.params.heartbeatMs !== undefined ? { heartbeatMs: item.params.heartbeatMs } : {}
|
|
16270
16278
|
};
|
|
16271
16279
|
}
|
|
16272
16280
|
function mergeBurst(items) {
|
|
@@ -16992,6 +17000,7 @@ async function runParallelPath(data, deps) {
|
|
|
16992
17000
|
const detachedNotificationScope = { orchestrationContext: ctx.orchestrationContext };
|
|
16993
17001
|
const results = await runForegroundParallelTasks({
|
|
16994
17002
|
wait: params.wait,
|
|
17003
|
+
...params.heartbeatMs === undefined ? {} : { heartbeatMs: params.heartbeatMs },
|
|
16995
17004
|
schedule: params[BURST_EXECUTION_SCHEDULE],
|
|
16996
17005
|
onDetachedExit: (index, result) => {
|
|
16997
17006
|
if (workflowStageAcceptsDetachedNotification(detachedNotificationScope)) {
|
|
@@ -17340,6 +17349,7 @@ async function runSinglePath(data, deps) {
|
|
|
17340
17349
|
intentTask: handoffTaskContext,
|
|
17341
17350
|
options: runOptions,
|
|
17342
17351
|
wait: params.wait,
|
|
17352
|
+
...params.heartbeatMs === undefined ? {} : { heartbeatMs: params.heartbeatMs },
|
|
17343
17353
|
schedule: params[BURST_EXECUTION_SCHEDULE],
|
|
17344
17354
|
runtime: deps.runtime,
|
|
17345
17355
|
recordChild: createSubagentChildRecordSink(deps.pi, ctx),
|
|
@@ -17926,6 +17936,22 @@ function inferExecutionMode(params) {
|
|
|
17926
17936
|
return "parallel";
|
|
17927
17937
|
return "single";
|
|
17928
17938
|
}
|
|
17939
|
+
function invalidHeartbeatResult(params) {
|
|
17940
|
+
try {
|
|
17941
|
+
if (params.heartbeatMs !== undefined)
|
|
17942
|
+
validateTaskHeartbeatMs(params.heartbeatMs);
|
|
17943
|
+
for (const [index, task] of (params.tasks ?? []).entries())
|
|
17944
|
+
if (task.heartbeatMs !== undefined)
|
|
17945
|
+
validateTaskHeartbeatMs(task.heartbeatMs, `tasks[${index}].heartbeatMs`);
|
|
17946
|
+
return;
|
|
17947
|
+
} catch (error) {
|
|
17948
|
+
return {
|
|
17949
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
|
|
17950
|
+
isError: true,
|
|
17951
|
+
details: { mode: inferExecutionMode(params), results: [] }
|
|
17952
|
+
};
|
|
17953
|
+
}
|
|
17954
|
+
}
|
|
17929
17955
|
function duplicateSubagentCallResult(params) {
|
|
17930
17956
|
return {
|
|
17931
17957
|
content: [
|
|
@@ -17999,7 +18025,7 @@ function createSubagentExecutor(rawDeps) {
|
|
|
17999
18025
|
duplicateResult: duplicateSubagentCallResult
|
|
18000
18026
|
});
|
|
18001
18027
|
return {
|
|
18002
|
-
execute: (id, params, signal, onUpdate, ctx) => params.action ? execute(id, params, signal, onUpdate, ctx) : executeWithBurstCollection(id, params, signal, onUpdate, ctx)
|
|
18028
|
+
execute: async (id, params, signal, onUpdate, ctx) => params.action ? execute(id, params, signal, onUpdate, ctx) : invalidHeartbeatResult(params) ?? executeWithBurstCollection(id, params, signal, onUpdate, ctx)
|
|
18003
18029
|
};
|
|
18004
18030
|
}
|
|
18005
18031
|
|
|
@@ -19709,6 +19735,12 @@ var MaxOutputSchema = Type.Object({
|
|
|
19709
19735
|
bytes: Type.Optional(Type.Number()),
|
|
19710
19736
|
lines: Type.Optional(Type.Number())
|
|
19711
19737
|
}, { additionalProperties: false });
|
|
19738
|
+
function heartbeatSchema(scope) {
|
|
19739
|
+
return Type.Number({
|
|
19740
|
+
minimum: 0,
|
|
19741
|
+
description: `Heartbeat cadence in ms for ${scope} while it runs (default 15 min; 0 disables; min 60000).`
|
|
19742
|
+
});
|
|
19743
|
+
}
|
|
19712
19744
|
var GroupSchema = Type.Union([Type.String(), Type.Boolean()], {
|
|
19713
19745
|
description: "Intercom group for spawned children. A named string joins that group; boolean `true` or the trimmed, case-insensitive string sentinel `true`/`auto` auto-generates one shared UUID group per parallel set. The names `true` and `auto` are reserved; use a different literal group name. Defaults to the current session/stage's group. Only applied when the child has intercom access; contact_supervisor still reaches the supervisor across groups."
|
|
19714
19746
|
});
|
|
@@ -19727,7 +19759,8 @@ var TaskItem = Type.Object({
|
|
|
19727
19759
|
modelConstraints: Type.Optional(ModelConstraintsSchema),
|
|
19728
19760
|
taskNeeds: Type.Optional(TaskNeedsSchema),
|
|
19729
19761
|
skill: Type.Optional(SkillOverride),
|
|
19730
|
-
group: Type.Optional(GroupSchema)
|
|
19762
|
+
group: Type.Optional(GroupSchema),
|
|
19763
|
+
heartbeatMs: Type.Optional(heartbeatSchema("this task"))
|
|
19731
19764
|
});
|
|
19732
19765
|
var ControlOverrides = Type.Object({
|
|
19733
19766
|
enabled: Type.Optional(Type.Boolean({ description: "Enable/disable subagent control attention tracking for this run" })),
|
|
@@ -19764,6 +19797,7 @@ var SubagentParams = Type.Object({
|
|
|
19764
19797
|
budgetMs: Type.Optional(Type.Number({ description: "Foreground wait budget in milliseconds (kind='foreground' only)." }))
|
|
19765
19798
|
}, { additionalProperties: false })),
|
|
19766
19799
|
budgetMs: Type.Optional(Type.Number({ description: "Foreground wait budget in milliseconds." })),
|
|
19800
|
+
heartbeatMs: Type.Optional(heartbeatSchema("each child; a task's own wins")),
|
|
19767
19801
|
agent: Type.Optional(Type.String({ description: "Agent name (SINGLE mode) or target for management get/update/delete" })),
|
|
19768
19802
|
task: Type.Optional(Type.String({ description: "Task (SINGLE mode, optional for self-contained agents)" })),
|
|
19769
19803
|
action: Type.Optional(Type.String({
|
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.58] - 2026-11-01
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- PDF text extraction no longer prints pdf.js font warnings such as `Warning: TT: undefined function: 32` over the interactive terminal UI when fetching PDFs with unusual embedded fonts. Extraction errors are still reported.
|
|
12
|
+
|
|
13
|
+
## [0.9.58-alpha.1] - 2026-11-01
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- PDF text extraction no longer prints pdf.js font warnings such as `Warning: TT: undefined function: 32` over the interactive terminal UI when fetching PDFs with unusual embedded fonts. Extraction errors are still reported.
|
|
18
|
+
|
|
7
19
|
## [0.9.52] - 2026-10-29
|
|
8
20
|
|
|
9
21
|
### Fixed
|
|
@@ -72560,7 +72560,7 @@ async function extractPDFToMarkdown(buffer, url, options = {}) {
|
|
|
72560
72560
|
filename
|
|
72561
72561
|
} = options;
|
|
72562
72562
|
const safeMaxPages = Number.isFinite(maxPages) ? Math.max(1, Math.floor(maxPages)) : DEFAULT_MAX_PAGES;
|
|
72563
|
-
const pdf = await getDocumentProxy(new Uint8Array(buffer));
|
|
72563
|
+
const pdf = await getDocumentProxy(new Uint8Array(buffer), { verbosity: PDF_JS_VERBOSITY_ERRORS });
|
|
72564
72564
|
const metadata = await pdf.getMetadata();
|
|
72565
72565
|
const metadataInfo = metadata.info && typeof metadata.info === "object" ? metadata.info : null;
|
|
72566
72566
|
const metaTitle = typeof metadataInfo?.Title === "string" ? metadataInfo.Title : undefined;
|
|
@@ -72650,7 +72650,7 @@ function isPDF(url, contentType) {
|
|
|
72650
72650
|
return false;
|
|
72651
72651
|
}
|
|
72652
72652
|
}
|
|
72653
|
-
var DEFAULT_MAX_PAGES = 100, DEFAULT_OUTPUT_DIR;
|
|
72653
|
+
var DEFAULT_MAX_PAGES = 100, PDF_JS_VERBOSITY_ERRORS = 0, DEFAULT_OUTPUT_DIR;
|
|
72654
72654
|
var init_pdf_extract = __esm(() => {
|
|
72655
72655
|
init_dist();
|
|
72656
72656
|
DEFAULT_OUTPUT_DIR = join4(homedir4(), "Downloads");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.58-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,48 @@ 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.58] - 2026-11-01
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `workflows.localWorkers.maxLoadPerCpu` (SDK `localWorkers.maxLoadPerCpu`): while the machine's load per CPU is above it, the stages of pooled children start one at a time, at most one every 5 seconds in the order they asked, instead of all at once while earlier ones are still starting. Running stages and their subagents and tool processes are not held. Default `3`; `0` turns it off. It is not saved with the root. ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- A message sent to a stage on a local worker (`workflows.localWorkers`) while its session was still starting no longer fails the stage with "generation closed before the stage finished; its tool calls were refused" when the stage has `fallbackModels`.
|
|
18
|
+
- The chat of a stage on a local worker completes `/skill:` commands with that stage's skills, as an in-process stage chat does, instead of warning "Skill discovery unavailable: this stage host does not expose its session command metadata." While the stage's session is still starting, it says its skills are loading.
|
|
19
|
+
- In the chat of a stage on a local worker, `/compact` compacts that stage's session and a `!` command runs on the worker in the stage's working directory, with its output streaming into the chat and Escape stopping it even while the pool is paused, as in the chat of an in-process stage. After `/compact` the open chat shows the compacted transcript. Before, `/compact` was sent to the model as plain text and a `!` command failed with "no live agent session on this stage". `/tasks` there lists the stage's agents and shells on its worker with their live status, opens their output and transcripts, sends them input and stops them, and the chat's task footer counts them, as in the chat of an in-process stage. An agent task's reply shows while it streams, tasks can be inspected and stopped while the pool is paused, and a stop that cannot reach the worker says so. Before, `/tasks` showed an empty list.
|
|
20
|
+
- A stage on a local worker reads as queued, with what it is doing (`creating session 32s`), on its graph node, in the graph header, the stage list, `/workflow status` and the `workflow` tool's stage list until its session has started, instead of reading as running. Its chat says it is starting on its local worker instead of showing a blank transcript, streams the stage as soon as the session starts, and opens the live view by itself when the worker cannot serve one yet. A message sent meanwhile waits for the session instead of failing with "The connection to stage … was lost" and "1 message not delivered".
|
|
21
|
+
- A root that runs children on local workers (`workflows.localWorkers`) no longer fails all of them with `Stale lease for run <id>` when its own process renews the root's lease late. A busy session, such as one that reloads its workflows and starts several other runs with in-process agent stages, could push the root's renewal past the pool's 90-second window. The pool treated that late renewal as a lost lease: it failed every running child, and every child the root started afterwards failed at once, while the root itself kept running. The pool now waits for the renewal and its workers keep their children; only a lease that was released or taken over by another holder ends them. Each run also renews its lease on its own, so a busy or blocked run no longer delays another run's renewal, and a renewal that fails without losing the lease, such as one that meets a briefly locked database, is retried on the next heartbeat instead of giving up the run. ([#4138](https://github.com/bastani-inc/atomic/pull/4138))
|
|
22
|
+
- With `workflows.localWorkers` configured, a root starts its pool's coordinator process when it runs its first pooled `ctx.workflow` child, or when it resumes a pool that already ran. A root that only runs `ctx.task` stages and `ctx.tool` steps no longer starts one, so launching such runs no longer leaves an idle coordinator process for each of them. ([#4138](https://github.com/bastani-inc/atomic/pull/4138))
|
|
23
|
+
- Stages on local workers (`workflows.localWorkers`) no longer fail with `Worker exited before delivery acknowledgement` while their worker is still running. On a busy machine a stage's startup delivery of queued Intercom messages could make no progress for a minute; the root then ended the worker's delivery request while the delivery kept going, and the next message reached a closed connection, failing the stage at `preparing message delivery` with an unknown, terminal failure. The delivery now keeps its connection to the worker until it finishes, and the stage still starts after a minute without progress, as an in-process stage does. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
24
|
+
- A worker whose work lease ran out only because the machine was too busy to process its renewal in time keeps its child. Its next journal write, usage report or completion is no longer refused with `Stale work lease`, which ended the child's attempt and could fail the child as `killed`; a session it starts no longer fails with `Stale resource admission attempt`, and waits for the renewal instead. Only an attempt that recovery handed to another worker is refused. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
25
|
+
- A fault of the pool itself that reaches a running pooled child, such as a journal write the database refused, replays the child from its last checkpoint (up to the usual three attempts) instead of failing its stage. A stage that does fail on a pool fault is classified with that fault as its failure code (`worker_lost`, `stale_work_lease`, …), recoverable and retryable, instead of `unknown`, and resume runs it again. A child whose attempt was fenced is no longer completed with the aborted run's result. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
26
|
+
- A stage on a local worker that ended keeps the worker lease it ended under: its worker's later lease renewals for the child's other stages no longer show it as renewed after it ended. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
27
|
+
- `/workflow pause <run>` and the `workflow` tool's `pause` pause a root's stages on local workers even while the root's own `ctx.tool` steps or in-process stages run, instead of reporting `No active stages to pause`. Pause, `pause --all` and resume no longer fail with `Worker control acknowledgement unresolved` when workers confirm slowly on a busy machine: the pause is recorded at once, workers pause their stages as they next check in, and the result says how many stages have not confirmed yet. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
28
|
+
- Resuming a root that runs children on local workers runs again the children an earlier process failed on a fault of the pool itself (a stage that lost its worker's delivery or lease on a busy machine, recorded as `Worker exited before delivery acknowledgement`, `Stale work lease` or `Stale resource admission attempt`), instead of replaying their failure. This includes runs paused or failed by 0.9.57. Pausing a root whose children have durable progress now says it can be resumed from a new process once this one exits, instead of `Resume with /workflow resume on this live process … Cross-process resume requires durable checkpoint or pending prompt progress`. ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
29
|
+
|
|
30
|
+
## [0.9.58-alpha.1] - 2026-11-01
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- `workflows.localWorkers.maxLoadPerCpu` (SDK `localWorkers.maxLoadPerCpu`): while the machine's load per CPU is above it, the stages of pooled children start one at a time, at most one every 5 seconds in the order they asked, instead of all at once while earlier ones are still starting. Running stages and their subagents and tool processes are not held. Default `3`; `0` turns it off. It is not saved with the root. ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- A message sent to a stage on a local worker (`workflows.localWorkers`) while its session was still starting no longer fails the stage with "generation closed before the stage finished; its tool calls were refused" when the stage has `fallbackModels`.
|
|
39
|
+
- The chat of a stage on a local worker completes `/skill:` commands with that stage's skills, as an in-process stage chat does, instead of warning "Skill discovery unavailable: this stage host does not expose its session command metadata." While the stage's session is still starting, it says its skills are loading.
|
|
40
|
+
- In the chat of a stage on a local worker, `/compact` compacts that stage's session and a `!` command runs on the worker in the stage's working directory, with its output streaming into the chat and Escape stopping it even while the pool is paused, as in the chat of an in-process stage. After `/compact` the open chat shows the compacted transcript. Before, `/compact` was sent to the model as plain text and a `!` command failed with "no live agent session on this stage". `/tasks` there lists the stage's agents and shells on its worker with their live status, opens their output and transcripts, sends them input and stops them, and the chat's task footer counts them, as in the chat of an in-process stage. An agent task's reply shows while it streams, tasks can be inspected and stopped while the pool is paused, and a stop that cannot reach the worker says so. Before, `/tasks` showed an empty list.
|
|
41
|
+
- A stage on a local worker reads as queued, with what it is doing (`creating session 32s`), on its graph node, in the graph header, the stage list, `/workflow status` and the `workflow` tool's stage list until its session has started, instead of reading as running. Its chat says it is starting on its local worker instead of showing a blank transcript, streams the stage as soon as the session starts, and opens the live view by itself when the worker cannot serve one yet. A message sent meanwhile waits for the session instead of failing with "The connection to stage … was lost" and "1 message not delivered".
|
|
42
|
+
- A root that runs children on local workers (`workflows.localWorkers`) no longer fails all of them with `Stale lease for run <id>` when its own process renews the root's lease late. A busy session, such as one that reloads its workflows and starts several other runs with in-process agent stages, could push the root's renewal past the pool's 90-second window. The pool treated that late renewal as a lost lease: it failed every running child, and every child the root started afterwards failed at once, while the root itself kept running. The pool now waits for the renewal and its workers keep their children; only a lease that was released or taken over by another holder ends them. Each run also renews its lease on its own, so a busy or blocked run no longer delays another run's renewal, and a renewal that fails without losing the lease, such as one that meets a briefly locked database, is retried on the next heartbeat instead of giving up the run. ([#4138](https://github.com/bastani-inc/atomic/pull/4138))
|
|
43
|
+
- With `workflows.localWorkers` configured, a root starts its pool's coordinator process when it runs its first pooled `ctx.workflow` child, or when it resumes a pool that already ran. A root that only runs `ctx.task` stages and `ctx.tool` steps no longer starts one, so launching such runs no longer leaves an idle coordinator process for each of them. ([#4138](https://github.com/bastani-inc/atomic/pull/4138))
|
|
44
|
+
- Stages on local workers (`workflows.localWorkers`) no longer fail with `Worker exited before delivery acknowledgement` while their worker is still running. On a busy machine a stage's startup delivery of queued Intercom messages could make no progress for a minute; the root then ended the worker's delivery request while the delivery kept going, and the next message reached a closed connection, failing the stage at `preparing message delivery` with an unknown, terminal failure. The delivery now keeps its connection to the worker until it finishes, and the stage still starts after a minute without progress, as an in-process stage does. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
45
|
+
- A worker whose work lease ran out only because the machine was too busy to process its renewal in time keeps its child. Its next journal write, usage report or completion is no longer refused with `Stale work lease`, which ended the child's attempt and could fail the child as `killed`; a session it starts no longer fails with `Stale resource admission attempt`, and waits for the renewal instead. Only an attempt that recovery handed to another worker is refused. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
46
|
+
- A fault of the pool itself that reaches a running pooled child, such as a journal write the database refused, replays the child from its last checkpoint (up to the usual three attempts) instead of failing its stage. A stage that does fail on a pool fault is classified with that fault as its failure code (`worker_lost`, `stale_work_lease`, …), recoverable and retryable, instead of `unknown`, and resume runs it again. A child whose attempt was fenced is no longer completed with the aborted run's result. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
47
|
+
- A stage on a local worker that ended keeps the worker lease it ended under: its worker's later lease renewals for the child's other stages no longer show it as renewed after it ended. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
48
|
+
- `/workflow pause <run>` and the `workflow` tool's `pause` pause a root's stages on local workers even while the root's own `ctx.tool` steps or in-process stages run, instead of reporting `No active stages to pause`. Pause, `pause --all` and resume no longer fail with `Worker control acknowledgement unresolved` when workers confirm slowly on a busy machine: the pause is recorded at once, workers pause their stages as they next check in, and the result says how many stages have not confirmed yet. ([#4145](https://github.com/bastani-inc/atomic/pull/4145))
|
|
49
|
+
- Resuming a root that runs children on local workers runs again the children an earlier process failed on a fault of the pool itself (a stage that lost its worker's delivery or lease on a busy machine, recorded as `Worker exited before delivery acknowledgement`, `Stale work lease` or `Stale resource admission attempt`), instead of replaying their failure. This includes runs paused or failed by 0.9.57. Pausing a root whose children have durable progress now says it can be resumed from a new process once this one exits, instead of `Resume with /workflow resume on this live process … Cross-process resume requires durable checkpoint or pending prompt progress`. ([#4146](https://github.com/bastani-inc/atomic/pull/4146))
|
|
50
|
+
|
|
9
51
|
## [0.9.57] - 2026-10-31
|
|
10
52
|
|
|
11
53
|
### Changed
|