@bastani/atomic 0.9.43-alpha.1 → 0.9.44-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 +45 -0
- package/dist/builtin/intercom/CHANGELOG.md +18 -0
- package/dist/builtin/intercom/broker/broker.ts +31 -7
- package/dist/builtin/intercom/broker/client.ts +65 -0
- package/dist/builtin/intercom/index.bundle.mjs +227 -95
- package/dist/builtin/intercom/live-route-refusal.ts +20 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/skills/intercom/SKILL.md +10 -6
- package/dist/builtin/intercom/types.ts +20 -1
- package/dist/builtin/mcp/CHANGELOG.md +7 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +9 -0
- package/dist/builtin/subagents/README.md +8 -8
- package/dist/builtin/subagents/agents/worker.md +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
- package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +21 -2
- package/dist/builtin/subagents/skills/cua-driver/LINUX.md +2 -2
- package/dist/builtin/subagents/skills/cua-driver/MACOS.md +342 -10
- package/dist/builtin/subagents/skills/cua-driver/README.md +4 -3
- package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +3 -1
- package/dist/builtin/subagents/skills/cua-driver/SKILL.md +7 -4
- package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +6 -5
- package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +15 -0
- package/dist/builtin/subagents/skills/herdr/SKILL.md +22 -10
- package/dist/builtin/subagents/skills/subagent/SKILL.md +8 -5
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +6 -6
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +33 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/builtin/{chunk-frqxd4d1.js → chunk-k8d7ehjx.js} +22 -0
- package/dist/builtin/workflows/builtin/{chunk-3s95f7ry.js → chunk-qxpymnaf.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-edhf30ef.js → chunk-zjecnjxx.js} +1 -1
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1750 -598
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +1786 -600
- package/dist/builtin/workflows/src/index.js +1802 -650
- package/dist/builtin/workflows/src/local-worker-entry.mjs +1786 -600
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +11 -2
- package/dist/core/exec.js.map +1 -1
- package/dist/core/package-manager-resolver.d.ts.map +1 -1
- package/dist/core/package-manager-resolver.js +25 -14
- package/dist/core/package-manager-resolver.js.map +1 -1
- package/dist/core/package-manager-types.d.ts +8 -0
- package/dist/core/package-manager-types.d.ts.map +1 -1
- package/dist/core/package-manager-types.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader-extension-warnings.d.ts +4 -1
- package/dist/core/resource-loader-extension-warnings.d.ts.map +1 -1
- package/dist/core/resource-loader-extension-warnings.js +15 -0
- package/dist/core/resource-loader-extension-warnings.js.map +1 -1
- package/dist/core/resource-loader-package-resources.d.ts.map +1 -1
- package/dist/core/resource-loader-package-resources.js +1 -0
- package/dist/core/resource-loader-package-resources.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +5 -3
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/extensions/mcp/client/oauth/flow.d.ts.map +1 -1
- package/dist/extensions/mcp/client/oauth/flow.js +4 -1
- package/dist/extensions/mcp/client/oauth/flow.js.map +1 -1
- package/dist/extensions/mcp/client/oauth/types.d.ts +1 -0
- package/dist/extensions/mcp/client/oauth/types.d.ts.map +1 -1
- package/dist/extensions/mcp/client/oauth/types.js +8 -4
- package/dist/extensions/mcp/client/oauth/types.js.map +1 -1
- package/dist/extensions/mcp/client/transports/streamable-http.d.ts.map +1 -1
- package/dist/extensions/mcp/client/transports/streamable-http.js +2 -1
- package/dist/extensions/mcp/client/transports/streamable-http.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +20 -10
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +4 -2
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +6 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +11 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/model-search.d.ts +10 -0
- package/dist/modes/interactive/model-search.d.ts.map +1 -1
- package/dist/modes/interactive/model-search.js +21 -0
- package/dist/modes/interactive/model-search.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +5 -0
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +30 -35
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/computer-use.md +5 -5
- package/docs/custom-provider/streaming.md +9 -14
- package/docs/environment-variables.md +1 -0
- package/docs/intercom.md +5 -1
- package/docs/packages.md +2 -0
- package/docs/settings.md +2 -2
- package/docs/skills.md +2 -2
- package/docs/subagents.md +38 -9
- package/docs/workflows/api-reference.md +1 -1
- package/docs/workflows/authoring.md +1 -1
- package/docs/workflows/operations.md +8 -6
- package/docs/workflows/reliable-design.md +23 -5
- package/examples/extensions/custom-provider-anthropic/index.ts +31 -31
- package/examples/extensions/todo.ts +7 -0
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
package/docs/subagents.md
CHANGED
|
@@ -108,9 +108,38 @@ Completed, failed, interrupted, and cancelled noninteractive children cannot ans
|
|
|
108
108
|
|
|
109
109
|
### Peer coordination
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
Peer-to-peer (swarm) coordination is the default. There are no limits on communication between agents; it is encouraged whenever you need to. The supervisor is not a message relay: relaying adds latency, loses detail, and fills the supervisor's context, while children that talk directly converge faster. Children launched in one parallel set, or with the same explicit `group`, share an Intercom group, and children launched by a workflow stage inherit that stage's invocation group. A child can run `intercom({ action: "list" })` to see live siblings and use ordinary `send` or `ask` with them directly: a locator hands file paths to the analyzer, two writers agree who owns which files or who runs the shared test suite, a debugger reuses a sibling's verified reproduction, or one reviewer challenges another's finding with evidence before each returns its own verdict. `contact_supervisor` stays reserved for supervisor decisions, and ordinary Intercom group restrictions still apply.
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
Children coordinate spontaneously: they discover peers with `list`, broadcast findings, claim shared files or expensive steps, ask and answer each other, hand work along a chain, and debate as much as is useful, then each returns its own complete result rather than deferring to a sibling. Explicit user approval gates and authorization for destructive or external actions still apply. Peer asks and one blocking supervisor request can wait concurrently in the same child; mutual asks work as long as both children process inbound work. The `intercom` skill (`/skill:intercom`) has copy-paste peer patterns.
|
|
114
|
+
|
|
115
|
+
For example, three reviewers launched as one parallel set work as a swarm, and the parent reads their three final results:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const peerRules =
|
|
119
|
+
"Your siblings review the same diff. Run intercom list to find them, share every confirmed finding, " +
|
|
120
|
+
"ask them whatever you need, and debate disagreements with evidence. Then return your own structured verdict.";
|
|
121
|
+
|
|
122
|
+
subagent({
|
|
123
|
+
tasks: [
|
|
124
|
+
{ agent: "reviewer", task: `Review correctness of the auth changes. ${peerRules}` },
|
|
125
|
+
{ agent: "reviewer", task: `Review security of the auth changes. ${peerRules}` },
|
|
126
|
+
{ agent: "reviewer", task: `Review test coverage of the auth changes. ${peerRules}` },
|
|
127
|
+
],
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Scaling a swarm
|
|
132
|
+
|
|
133
|
+
Swarm size scales with the task. For very complex work, or when you ask for heavy parallelism, the agent can run hundreds or thousands of agents. They organize themselves into teams and coordinate peer-to-peer, like an organization, and useful behavior emerges from their exchanges rather than from one central plan.
|
|
134
|
+
|
|
135
|
+
These are the limits that apply:
|
|
136
|
+
|
|
137
|
+
- **Children per parallel set.** One set holds up to `parallel.maxTasks` children (default 1000, no hard cap). `parallel.concurrency` and `parallel.runningCapacity` (each default 1000) bound how many run at once per parent. For more than 1000, raise all three, as shown in [Context and execution modes](#context-and-execution-modes).
|
|
138
|
+
- **Nesting.** Subagent delegation is one level deep and cannot be configured: a child cannot call `subagent`. To nest teams, start them from workflow stages. Each stage can launch its own parallel set, and `ctx.workflow(...)` nests child workflows up to the workflow `maxDepth` (default 3, configurable).
|
|
139
|
+
- **Workflow fan-out.** `ctx.parallel(...)` has no task-count limit. The workflow `defaultConcurrency` setting (default 1000) or a per-call `concurrency` bounds how many stages run at once. Set `workflows.localWorkers` to run first-level child workflows in a pool of worker processes. See [Workflow configuration](/workflows/operations#workflow-configuration) and [Local workflow workers](/workflows/operations#local-workflow-workers).
|
|
140
|
+
- **Teams.** Intercom groups have no member limit. Give each team its own `group` so its members coordinate internally. Team members reach their lead with `contact_supervisor`, the lead steers them, and the leads, as stages of one workflow, talk to each other in the invocation group.
|
|
141
|
+
|
|
142
|
+
For example, 20 parallel workflow stages that each launch 50 children form a swarm of 1,000 agents. The workflow and subagent defaults already run them all at once: up to 1000 stages and 1000 running children per parent. Lower `defaultConcurrency` or a per-call `concurrency` to run fewer stages at a time. Beyond these settings, the practical ceiling is your provider rate limits, machine memory, and any workflow admission limits you set.
|
|
114
143
|
|
|
115
144
|
### Single-child handoff
|
|
116
145
|
|
|
@@ -289,18 +318,18 @@ Fresh children inherit the invoking session's SDK configuration, resource-discov
|
|
|
289
318
|
|
|
290
319
|
Top-level parallel calls apply these settings from `~/.atomic/agent/extensions/subagent/config.json` after expanding each task's optional `count`:
|
|
291
320
|
|
|
292
|
-
- `parallel.maxTasks` defaults to
|
|
293
|
-
- `parallel.concurrency` defaults to
|
|
294
|
-
- `parallel.runningCapacity` defaults to
|
|
321
|
+
- `parallel.maxTasks` defaults to 1000 and limits the number of tasks in a parallel set. There is no hard upper cap; raise or lower it as needed.
|
|
322
|
+
- `parallel.concurrency` defaults to 1000 and limits how many children are dispatched at once. Per-call `concurrency` takes precedence.
|
|
323
|
+
- `parallel.runningCapacity` defaults to 1000 and limits simultaneously running child turns per parent.
|
|
295
324
|
|
|
296
|
-
To run
|
|
325
|
+
To run more than 1000 children at once, raise concurrency and running capacity as well as the task limit:
|
|
297
326
|
|
|
298
327
|
```json
|
|
299
328
|
{
|
|
300
329
|
"parallel": {
|
|
301
|
-
"maxTasks":
|
|
302
|
-
"concurrency":
|
|
303
|
-
"runningCapacity":
|
|
330
|
+
"maxTasks": 2000,
|
|
331
|
+
"concurrency": 2000,
|
|
332
|
+
"runningCapacity": 2000
|
|
304
333
|
}
|
|
305
334
|
}
|
|
306
335
|
```
|
|
@@ -802,7 +802,7 @@ readonly concurrency?: number;
|
|
|
802
802
|
readonly failFast?: boolean;
|
|
803
803
|
```
|
|
804
804
|
|
|
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 `
|
|
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 `1000`; explicit configuration and per-call concurrency remain honored. Parallel execution is fail-fast unless `failFast` is explicitly `false`.
|
|
806
806
|
|
|
807
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
808
|
|
|
@@ -1000,7 +1000,7 @@ A child exposes only outputs declared in `outputs` and returned from `run` or su
|
|
|
1000
1000
|
|
|
1001
1001
|
Missing required outputs, schema type mismatches, and non-JSON-serializable returned values fail normal child completion before the parent continues; child `ctx.exit({ outputs })` allows missing required outputs but still validates every provided key and sets `child.exited === true` so parent code must handle the partial shape.
|
|
1002
1002
|
|
|
1003
|
-
Pass only imported workflow definitions to `ctx.workflow(...)`, not registry names or paths. Missing modules or invalid exports fail discovery. Nested children count against `maxDepth`, default `
|
|
1003
|
+
Pass only imported workflow definitions to `ctx.workflow(...)`, not registry names or paths. Missing modules or invalid exports fail discovery. Nested children count against `maxDepth`, default `3` total workflow levels.
|
|
1004
1004
|
|
|
1005
1005
|
A missing, empty, or invalid child graph retains a boundary summary rather than displaying unrelated nodes. Failed or skipped boundaries also retain summaries. Use `stageName` for a concise custom boundary label.
|
|
1006
1006
|
|
|
@@ -814,8 +814,8 @@ Example config:
|
|
|
814
814
|
"team": { "path": "./workflows/team.ts" },
|
|
815
815
|
"shared": { "path": "/shared/team/workflows" }
|
|
816
816
|
},
|
|
817
|
-
"defaultConcurrency":
|
|
818
|
-
"maxDepth":
|
|
817
|
+
"defaultConcurrency": 1000,
|
|
818
|
+
"maxDepth": 3,
|
|
819
819
|
"budget": { "maxDurationMs": 0, "maxTokens": 0, "maxCost": 0, "warnAtPercent": 80 },
|
|
820
820
|
"persistRuns": true,
|
|
821
821
|
"statusFile": false,
|
|
@@ -834,8 +834,8 @@ Runtime config defaults:
|
|
|
834
834
|
|
|
835
835
|
| Key | Default | Purpose |
|
|
836
836
|
|-----|---------|---------|
|
|
837
|
-
| `defaultConcurrency` | `
|
|
838
|
-
| `maxDepth` | `
|
|
837
|
+
| `defaultConcurrency` | `1000` | Default stage concurrency and concurrency for authored `ctx.parallel(...)` execution |
|
|
838
|
+
| `maxDepth` | `3` | Maximum workflow nesting depth |
|
|
839
839
|
| `budget` | `{ maxDurationMs: 0, maxTokens: 0, maxCost: 0, warnAtPercent: 80 }` | Default per-run budget declaration; `0` disables a dimension; warnings default to `80` percent |
|
|
840
840
|
| `persistRuns` | `true` | Persist run metadata for status/resume/history |
|
|
841
841
|
| `statusFile` | `false` | Write a derived status file; defaults under `.atomic/workflows/status.json` when enabled |
|
|
@@ -873,7 +873,7 @@ Local workers are opt-in. With no `localWorkers` setting or `RunOpts.localWorker
|
|
|
873
873
|
}
|
|
874
874
|
```
|
|
875
875
|
|
|
876
|
-
The root workflow remains in its original process and owns the run graph, run controls
|
|
876
|
+
The root workflow remains in its original process and owns the run graph, run controls and the root's journal writes. It can be an inline closure. The pool adds one coordinator process per root, and the worker processes run under it: the coordinator handles worker messages and heartbeats, pool journal writes, and the Intercom routes of pooled children, so a busy pool does not slow down the interactive TUI. Only an entire first-level `ctx.workflow(child)` subtree can move to a local worker. Nested workflows stay on that worker. Independent stage placement is not supported. Register every worker-eligible child definition by its module path and export name. The worker loads the module again in its own process, so the definition must be importable rather than a closure. Missing or incompatible definitions fail the run; Atomic does not fall back to local execution.
|
|
877
877
|
|
|
878
878
|
Worker definitions are loaded in the SDK with `loadWorkerWorkflow(absolutePath, exportName)`, then passed to `ctx.workflow(...)`. The SDK also accepts `RunOpts.localWorkers`; the settings form applies to CLI launches. Paths in worker settings resolve against the invocation working directory. `RunOpts.localWorkers` paths resolve against `cwd` (or the current working directory when omitted). On resume, Atomic checks the saved worker options (`count` and `definitions`) and definition entry-module digests. A changed definition or worker configuration is refused. The digest covers the entry file, not its imported dependency graph.
|
|
879
879
|
|
|
@@ -887,10 +887,12 @@ The root's existing `/workflow status`, `/workflow stages`, steering, pause, qui
|
|
|
887
887
|
|
|
888
888
|
Each worker process must report that it is ready within `localWorkers.startupTimeoutMs` milliseconds, 30000 by default. When a pool starts, it runs children as soon as one worker is ready. A worker that exits or times out during that startup is left out of the pool, and the run fails only when no worker starts. A replacement worker that cannot start fails the run. `startupTimeoutMs` is not saved with the root, so you can change it before resuming.
|
|
889
889
|
|
|
890
|
-
A worker that exits is detected immediately, and its child is replayed from its last committed checkpoint on a replacement worker. A worker that is still running keeps its child as long as it keeps responding, even when the
|
|
890
|
+
A worker that exits is detected immediately, and its child is replayed from its last committed checkpoint on a replacement worker. A worker that is still running keeps its child as long as it keeps responding, even when the pool is briefly too busy to process its heartbeats. Only a running worker that has not responded for `localWorkers.leaseMs` milliseconds (30000 by default) is stopped and its child replayed. When a root is resumed after its process crashed, children that were held by the crashed process's workers are replayed on the new workers right away.
|
|
891
891
|
|
|
892
892
|
A worker that exits or is killed while it runs a child does not stop the root. The root fences that worker's attempt and replays the child from its last committed checkpoint on a replacement worker, up to three attempts per child.
|
|
893
893
|
|
|
894
|
+
If the root process exits, even when it is killed, the pool's coordinator and workers exit with it. Resume the root to continue its children. If the coordinator process itself dies, its workers exit with it, and each pooled child the root is waiting on fails with the retryable `worker_lost` fault and the message `Local worker pool coordinator exited (…)`.
|
|
895
|
+
|
|
894
896
|
Each worker writes its standard error to `worker-logs/<root run ID>/<worker ID>.log` in the directory that holds the workflow journal. With the default journal, that is `~/.atomic/workflows/worker-logs/`. Characters in the root run ID that are unsafe in a file name are percent-encoded. The errors `Local worker exited before readiness`, `Local worker startup timed out after … ms`, and `Local worker retry limit` name the log file and include the end of the worker's output. Atomic keeps the logs of workers that fail. It deletes the logs of workers that are still running when the pool shuts down normally.
|
|
895
897
|
|
|
896
898
|
### Worker resource limits
|
|
@@ -1325,14 +1325,32 @@ Constructive quorum relies on existing Intercom mechanics: every workflow invoca
|
|
|
1325
1325
|
|
|
1326
1326
|
#### Peer coordination between stages
|
|
1327
1327
|
|
|
1328
|
-
Quorum is one instance of a general capability: stages in the same invocation are peers, not only targets for the supervisor to steer. A live stage can `intercom({ action: "list" })` its siblings and `send`/`ask` them directly to debate a finding with evidence, hand off file paths and reproductions, claim shared files or an expensive suite or build, or learn what a sibling already verified. A `send` to a known pending sibling queues until that stage starts, and an `ask` to a completed sibling that retains a valid conversation reopens it for a post-mortem turn. Delegated subagents inside a stage inherit the same group, so a stage's children can talk to each other and to sibling stages. Named subgroups (`group: "name"` or `group: true`) isolate their members from sibling subgroups while the invocation context keeps directional control over them.
|
|
1328
|
+
Quorum is one instance of a general capability, and peer-to-peer (swarm) exchange is the default. There are no limits on communication between agents; it is encouraged whenever you need to. The supervisor is not a message relay: relaying adds latency, loses detail, and fills its context, while stages that exchange evidence directly converge faster. Stages in the same invocation are peers, not only targets for the supervisor to steer. A live stage can `intercom({ action: "list" })` its siblings and `send`/`ask` them directly to debate a finding with evidence, hand off file paths and reproductions, claim shared files or an expensive suite or build, or learn what a sibling already verified. A `send` to a known pending sibling queues until that stage starts, and an `ask` to a completed sibling that retains a valid conversation reopens it for a post-mortem turn. Delegated subagents inside a stage inherit the same group, so a stage's children can talk to each other and to sibling stages. Named subgroups (`group: "name"` or `group: true`) isolate their members from sibling subgroups while the invocation context keeps directional control over them.
|
|
1329
1329
|
|
|
1330
|
-
|
|
1330
|
+
How stages work as a swarm:
|
|
1331
1331
|
|
|
1332
|
-
- Stages
|
|
1333
|
-
- Bound it: one evidence round, one ownership claim per shared step, one ask per fact. An unbounded conversation between parallel stages burns budget and blurs who decided what.
|
|
1332
|
+
- Stages coordinate spontaneously. They discover peers with `list` and broadcast findings, claim shared files or an expensive step, ask and answer each other, hand work along a chain, and debate for as long as it is useful.
|
|
1334
1333
|
- Keep every stage's output its own. A peer's claim is evidence to inspect, not a verdict to copy; each stage still returns its own structured result to the reducer or downstream stage.
|
|
1335
|
-
- Peer messages are activity inside already-running stages, not graph edges. They never replace `previous`, artifacts, or declared outputs for durable handoffs
|
|
1334
|
+
- Peer messages are activity inside already-running stages, not graph edges. They never replace `previous`, artifacts, or declared outputs for durable handoffs. Explicit user approval gates and authorization for destructive or external actions still apply.
|
|
1335
|
+
|
|
1336
|
+
A minimal swarm: three parallel investigators share findings directly, and the workflow collects each stage's own result.
|
|
1337
|
+
|
|
1338
|
+
```typescript
|
|
1339
|
+
const swarm = [
|
|
1340
|
+
"Your sibling stages investigate other angles of the same failure.",
|
|
1341
|
+
"Run intercom list to find them and talk to them as much as you need: share findings,",
|
|
1342
|
+
"claim any shared suite before running it, ask instead of guessing, and debate disagreements.",
|
|
1343
|
+
"Then return your own findings.",
|
|
1344
|
+
].join("\n");
|
|
1345
|
+
|
|
1346
|
+
const results = await ctx.parallel([
|
|
1347
|
+
{ name: "logs", prompt: `Trace the timeout through the service logs.\n${swarm}` },
|
|
1348
|
+
{ name: "code", prompt: `Trace the timeout through the retry code.\n${swarm}` },
|
|
1349
|
+
{ name: "repro", prompt: `Build a minimal reproduction of the timeout.\n${swarm}` },
|
|
1350
|
+
]);
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
Swarm size scales with the task. For very complex work, or when the user asks for heavy parallelism, fan out to hundreds or thousands of agents: wide `ctx.parallel(...)` stages, a subagent parallel set inside each stage, and child workflows via `ctx.workflow(...)` (optionally on `workflows.localWorkers`). Give each team a named subgroup so its members coordinate internally while the team leads, as sibling stages, coordinate in the invocation group. Up to 1000 stages run at once by default; lower `defaultConcurrency` or pass `concurrency` to run fewer; `maxDepth` (default 3) bounds child-workflow nesting, and subagent children cannot delegate further. See [Scaling a swarm](/subagents#scaling-a-swarm) for every limit.
|
|
1336
1354
|
|
|
1337
1355
|
#### Pattern diagrams
|
|
1338
1356
|
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
type TextContent,
|
|
20
20
|
type ThinkingContent,
|
|
21
21
|
type Tool,
|
|
22
|
-
|
|
22
|
+
ToolCallArgumentsStream,
|
|
23
23
|
type ToolResultMessage,
|
|
24
24
|
type TranscriptContext,
|
|
25
25
|
} from "@bastani/pi-ai/compat";
|
|
@@ -378,8 +378,11 @@ function streamCustomAnthropic(
|
|
|
378
378
|
}
|
|
379
379
|
const anthropicStream = client.messages.stream({ ...params }, { signal: options?.signal });
|
|
380
380
|
stream.push({ type: "start", partial: output });
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
|
|
382
|
+
// Stream state per Anthropic block index, kept off the content blocks so it never reaches partial messages.
|
|
383
|
+
// ToolCallArgumentsStream reads each argument delta once and shows the arguments parsed so far.
|
|
384
|
+
const openBlocks = new Map<number, { contentIndex: number; arguments?: ToolCallArgumentsStream }>();
|
|
385
|
+
|
|
383
386
|
for await (const event of anthropicStream) {
|
|
384
387
|
if (event.type === "message_start") {
|
|
385
388
|
output.usage.input = event.message.usage.input_tokens || 0;
|
|
@@ -391,15 +394,12 @@ function streamCustomAnthropic(
|
|
|
391
394
|
calculateCost(model, output.usage);
|
|
392
395
|
} else if (event.type === "content_block_start") {
|
|
393
396
|
if (event.content_block.type === "text") {
|
|
394
|
-
output.content.push({ type: "text", text: ""
|
|
397
|
+
output.content.push({ type: "text", text: "" });
|
|
398
|
+
openBlocks.set(event.index, { contentIndex: output.content.length - 1 });
|
|
395
399
|
stream.push({ type: "text_start", contentIndex: output.content.length - 1, partial: output });
|
|
396
400
|
} else if (event.content_block.type === "thinking") {
|
|
397
|
-
output.content.push({
|
|
398
|
-
|
|
399
|
-
thinking: "",
|
|
400
|
-
thinkingSignature: "",
|
|
401
|
-
index: event.index,
|
|
402
|
-
} as any);
|
|
401
|
+
output.content.push({ type: "thinking", thinking: "", thinkingSignature: "" });
|
|
402
|
+
openBlocks.set(event.index, { contentIndex: output.content.length - 1 });
|
|
403
403
|
stream.push({ type: "thinking_start", contentIndex: output.content.length - 1, partial: output });
|
|
404
404
|
} else if (event.content_block.type === "tool_use") {
|
|
405
405
|
output.content.push({
|
|
@@ -409,15 +409,19 @@ function streamCustomAnthropic(
|
|
|
409
409
|
? fromClaudeCodeName(event.content_block.name, context.tools)
|
|
410
410
|
: event.content_block.name,
|
|
411
411
|
arguments: {},
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
412
|
+
});
|
|
413
|
+
openBlocks.set(event.index, {
|
|
414
|
+
contentIndex: output.content.length - 1,
|
|
415
|
+
arguments: new ToolCallArgumentsStream(),
|
|
416
|
+
});
|
|
415
417
|
stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
|
|
416
418
|
}
|
|
417
419
|
} else if (event.type === "content_block_delta") {
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
420
|
+
const open = openBlocks.get(event.index);
|
|
421
|
+
if (!open) continue;
|
|
422
|
+
const index = open.contentIndex;
|
|
423
|
+
const block = output.content[index]!;
|
|
424
|
+
|
|
421
425
|
if (event.delta.type === "text_delta" && block.type === "text") {
|
|
422
426
|
block.text += event.delta.text;
|
|
423
427
|
stream.push({ type: "text_delta", contentIndex: index, delta: event.delta.text, partial: output });
|
|
@@ -429,11 +433,8 @@ function streamCustomAnthropic(
|
|
|
429
433
|
delta: event.delta.thinking,
|
|
430
434
|
partial: output,
|
|
431
435
|
});
|
|
432
|
-
} else if (event.delta.type === "input_json_delta" && block.type === "toolCall") {
|
|
433
|
-
|
|
434
|
-
try {
|
|
435
|
-
block.arguments = JSON.parse((block as any).partialJson);
|
|
436
|
-
} catch {}
|
|
436
|
+
} else if (event.delta.type === "input_json_delta" && block.type === "toolCall" && open.arguments) {
|
|
437
|
+
block.arguments = open.arguments.append(event.delta.partial_json);
|
|
437
438
|
stream.push({
|
|
438
439
|
type: "toolcall_delta",
|
|
439
440
|
contentIndex: index,
|
|
@@ -444,19 +445,19 @@ function streamCustomAnthropic(
|
|
|
444
445
|
block.thinkingSignature = (block.thinkingSignature || "") + (event.delta as any).signature;
|
|
445
446
|
}
|
|
446
447
|
} else if (event.type === "content_block_stop") {
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
448
|
+
const open = openBlocks.get(event.index);
|
|
449
|
+
if (!open) continue;
|
|
450
|
+
openBlocks.delete(event.index);
|
|
451
|
+
const index = open.contentIndex;
|
|
452
|
+
const block = output.content[index]!;
|
|
453
|
+
|
|
451
454
|
if (block.type === "text") {
|
|
452
455
|
stream.push({ type: "text_end", contentIndex: index, content: block.text, partial: output });
|
|
453
456
|
} else if (block.type === "thinking") {
|
|
454
457
|
stream.push({ type: "thinking_end", contentIndex: index, content: block.thinking, partial: output });
|
|
455
|
-
} else if (block.type === "toolCall") {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
} catch {}
|
|
459
|
-
delete (block as any).partialJson;
|
|
458
|
+
} else if (block.type === "toolCall" && open.arguments) {
|
|
459
|
+
// One full parse of the complete text; malformed arguments are reported in `argumentsError`.
|
|
460
|
+
Object.assign(block, open.arguments.finish());
|
|
460
461
|
stream.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: output });
|
|
461
462
|
}
|
|
462
463
|
} else if (event.type === "message_delta") {
|
|
@@ -478,7 +479,6 @@ function streamCustomAnthropic(
|
|
|
478
479
|
stream.push({ type: "done", reason: output.stopReason as "stop" | "length" | "toolUse", message: output });
|
|
479
480
|
stream.end();
|
|
480
481
|
} catch (error) {
|
|
481
|
-
for (const block of output.content) delete (block as any).index;
|
|
482
482
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
483
483
|
output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
484
484
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
@@ -275,6 +275,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
275
275
|
|
|
276
276
|
case "clear":
|
|
277
277
|
return new Text(theme.fg("success", "✓ ") + theme.fg("muted", "Cleared all todos"), 0, 0);
|
|
278
|
+
|
|
279
|
+
default:
|
|
280
|
+
return new Text(
|
|
281
|
+
result.content[0]?.type === "text" ? theme.fg("error", result.content[0].text) : "",
|
|
282
|
+
0,
|
|
283
|
+
0,
|
|
284
|
+
);
|
|
278
285
|
}
|
|
279
286
|
},
|
|
280
287
|
});
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/atomic",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.44-alpha.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bastani/atomic",
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.44-alpha.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@bastani/atomic-natives": "0.9.
|
|
13
|
-
"@bastani/pi-ai": "0.9.
|
|
12
|
+
"@bastani/atomic-natives": "0.9.44-alpha.1",
|
|
13
|
+
"@bastani/pi-ai": "0.9.44-alpha.1",
|
|
14
14
|
"@earendil-works/pi-agent-core": "1.4.0",
|
|
15
15
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
16
16
|
"@earendil-works/pi-tui": "1.4.0",
|
|
@@ -427,18 +427,18 @@
|
|
|
427
427
|
}
|
|
428
428
|
},
|
|
429
429
|
"node_modules/@bastani/atomic-natives": {
|
|
430
|
-
"version": "0.9.
|
|
431
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.
|
|
430
|
+
"version": "0.9.44-alpha.1",
|
|
431
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.44-alpha.1.tgz",
|
|
432
432
|
"license": "MIT",
|
|
433
433
|
"optionalDependencies": {
|
|
434
|
-
"@bastani/atomic-natives-darwin-arm64": "0.9.
|
|
435
|
-
"@bastani/atomic-natives-darwin-x64": "0.9.
|
|
436
|
-
"@bastani/atomic-natives-linux-arm64-gnu": "0.9.
|
|
437
|
-
"@bastani/atomic-natives-linux-arm64-musl": "0.9.
|
|
438
|
-
"@bastani/atomic-natives-linux-x64-gnu": "0.9.
|
|
439
|
-
"@bastani/atomic-natives-linux-x64-musl": "0.9.
|
|
440
|
-
"@bastani/atomic-natives-win32-arm64-msvc": "0.9.
|
|
441
|
-
"@bastani/atomic-natives-win32-x64-msvc": "0.9.
|
|
434
|
+
"@bastani/atomic-natives-darwin-arm64": "0.9.44-alpha.1",
|
|
435
|
+
"@bastani/atomic-natives-darwin-x64": "0.9.44-alpha.1",
|
|
436
|
+
"@bastani/atomic-natives-linux-arm64-gnu": "0.9.44-alpha.1",
|
|
437
|
+
"@bastani/atomic-natives-linux-arm64-musl": "0.9.44-alpha.1",
|
|
438
|
+
"@bastani/atomic-natives-linux-x64-gnu": "0.9.44-alpha.1",
|
|
439
|
+
"@bastani/atomic-natives-linux-x64-musl": "0.9.44-alpha.1",
|
|
440
|
+
"@bastani/atomic-natives-win32-arm64-msvc": "0.9.44-alpha.1",
|
|
441
|
+
"@bastani/atomic-natives-win32-x64-msvc": "0.9.44-alpha.1"
|
|
442
442
|
},
|
|
443
443
|
"engines": {
|
|
444
444
|
"bun": ">=1.4.2",
|
|
@@ -446,8 +446,8 @@
|
|
|
446
446
|
}
|
|
447
447
|
},
|
|
448
448
|
"node_modules/@bastani/atomic-natives-darwin-arm64": {
|
|
449
|
-
"version": "0.9.
|
|
450
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.
|
|
449
|
+
"version": "0.9.44-alpha.1",
|
|
450
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.44-alpha.1.tgz",
|
|
451
451
|
"license": "MIT",
|
|
452
452
|
"os": [
|
|
453
453
|
"darwin"
|
|
@@ -458,8 +458,8 @@
|
|
|
458
458
|
"optional": true
|
|
459
459
|
},
|
|
460
460
|
"node_modules/@bastani/atomic-natives-darwin-x64": {
|
|
461
|
-
"version": "0.9.
|
|
462
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.
|
|
461
|
+
"version": "0.9.44-alpha.1",
|
|
462
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.44-alpha.1.tgz",
|
|
463
463
|
"license": "MIT",
|
|
464
464
|
"os": [
|
|
465
465
|
"darwin"
|
|
@@ -470,8 +470,8 @@
|
|
|
470
470
|
"optional": true
|
|
471
471
|
},
|
|
472
472
|
"node_modules/@bastani/atomic-natives-linux-arm64-gnu": {
|
|
473
|
-
"version": "0.9.
|
|
474
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.
|
|
473
|
+
"version": "0.9.44-alpha.1",
|
|
474
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.44-alpha.1.tgz",
|
|
475
475
|
"license": "MIT",
|
|
476
476
|
"os": [
|
|
477
477
|
"linux"
|
|
@@ -485,8 +485,8 @@
|
|
|
485
485
|
"optional": true
|
|
486
486
|
},
|
|
487
487
|
"node_modules/@bastani/atomic-natives-linux-arm64-musl": {
|
|
488
|
-
"version": "0.9.
|
|
489
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.
|
|
488
|
+
"version": "0.9.44-alpha.1",
|
|
489
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.44-alpha.1.tgz",
|
|
490
490
|
"license": "MIT",
|
|
491
491
|
"os": [
|
|
492
492
|
"linux"
|
|
@@ -500,8 +500,8 @@
|
|
|
500
500
|
"optional": true
|
|
501
501
|
},
|
|
502
502
|
"node_modules/@bastani/atomic-natives-linux-x64-gnu": {
|
|
503
|
-
"version": "0.9.
|
|
504
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.
|
|
503
|
+
"version": "0.9.44-alpha.1",
|
|
504
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.44-alpha.1.tgz",
|
|
505
505
|
"license": "MIT",
|
|
506
506
|
"os": [
|
|
507
507
|
"linux"
|
|
@@ -515,8 +515,8 @@
|
|
|
515
515
|
"optional": true
|
|
516
516
|
},
|
|
517
517
|
"node_modules/@bastani/atomic-natives-linux-x64-musl": {
|
|
518
|
-
"version": "0.9.
|
|
519
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.
|
|
518
|
+
"version": "0.9.44-alpha.1",
|
|
519
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.44-alpha.1.tgz",
|
|
520
520
|
"license": "MIT",
|
|
521
521
|
"os": [
|
|
522
522
|
"linux"
|
|
@@ -530,8 +530,8 @@
|
|
|
530
530
|
"optional": true
|
|
531
531
|
},
|
|
532
532
|
"node_modules/@bastani/atomic-natives-win32-arm64-msvc": {
|
|
533
|
-
"version": "0.9.
|
|
534
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.
|
|
533
|
+
"version": "0.9.44-alpha.1",
|
|
534
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.44-alpha.1.tgz",
|
|
535
535
|
"license": "MIT",
|
|
536
536
|
"os": [
|
|
537
537
|
"win32"
|
|
@@ -542,8 +542,8 @@
|
|
|
542
542
|
"optional": true
|
|
543
543
|
},
|
|
544
544
|
"node_modules/@bastani/atomic-natives-win32-x64-msvc": {
|
|
545
|
-
"version": "0.9.
|
|
546
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.
|
|
545
|
+
"version": "0.9.44-alpha.1",
|
|
546
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.44-alpha.1.tgz",
|
|
547
547
|
"license": "MIT",
|
|
548
548
|
"os": [
|
|
549
549
|
"win32"
|
|
@@ -554,8 +554,8 @@
|
|
|
554
554
|
"optional": true
|
|
555
555
|
},
|
|
556
556
|
"node_modules/@bastani/pi-ai": {
|
|
557
|
-
"version": "0.9.
|
|
558
|
-
"resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.
|
|
557
|
+
"version": "0.9.44-alpha.1",
|
|
558
|
+
"resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.44-alpha.1.tgz",
|
|
559
559
|
"license": "MIT",
|
|
560
560
|
"dependencies": {
|
|
561
561
|
"@anthropic-ai/sdk": "0.129.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/atomic",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.44-alpha.1",
|
|
4
4
|
"description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"atomicConfig": {
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"prepublishOnly": "bun run clean && bun run build && bun run shrinkwrap"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@bastani/atomic-natives": "0.9.
|
|
93
|
-
"@bastani/pi-ai": "0.9.
|
|
92
|
+
"@bastani/atomic-natives": "0.9.44-alpha.1",
|
|
93
|
+
"@bastani/pi-ai": "0.9.44-alpha.1",
|
|
94
94
|
"@earendil-works/pi-agent-core": "1.4.0",
|
|
95
95
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
96
96
|
"@earendil-works/pi-tui": "1.4.0",
|