@bastani/atomic 0.9.12 → 0.9.13-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 +20 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +5 -12
- package/dist/builtin/intercom/broker/client.ts +11 -2
- package/dist/builtin/intercom/contact-supervisor-tool.ts +13 -3
- package/dist/builtin/intercom/index-heavy.ts +13 -3
- package/dist/builtin/intercom/index.ts +43 -19
- package/dist/builtin/intercom/intercom-utils.ts +15 -29
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/source-ownership.ts +9 -12
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/README.md +3 -1
- package/dist/builtin/mcp/index.ts +10 -16
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/startup-warmup.ts +20 -8
- package/dist/builtin/subagents/CHANGELOG.md +30 -0
- package/dist/builtin/subagents/README.md +22 -30
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/doctor.ts +1 -1
- package/dist/builtin/subagents/src/extension/fanout-child.ts +76 -56
- package/dist/builtin/subagents/src/extension/index.ts +23 -32
- package/dist/builtin/subagents/src/extension/startup-maintenance.ts +25 -44
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +7 -7
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +166 -434
- package/dist/builtin/subagents/src/runs/background/notify.ts +29 -8
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -281
- package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +11 -75
- package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +457 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +119 -246
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +18 -9
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +4 -4
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +1 -646
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -7
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +5 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +7 -8
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +14 -5
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +158 -93
- package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +179 -0
- package/dist/builtin/subagents/src/runs/inprocess/background.ts +89 -0
- package/dist/builtin/subagents/src/runs/inprocess/child-policy.ts +27 -0
- package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +55 -0
- package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +106 -0
- package/dist/builtin/subagents/src/runs/inprocess/index.ts +50 -0
- package/dist/builtin/subagents/src/runs/inprocess/nested-routing.ts +218 -0
- package/dist/builtin/subagents/src/runs/{shared/subagent-prompt-runtime.ts → inprocess/prompt-behavior.ts} +37 -75
- package/dist/builtin/subagents/src/runs/inprocess/runner.ts +1138 -0
- package/dist/builtin/subagents/src/runs/{shared/nested-events.ts → inprocess/runtime-support/nested-api.ts} +13 -7
- package/dist/builtin/subagents/src/runs/{shared/nested-events-control.ts → inprocess/runtime-support/nested-control.ts} +18 -17
- package/dist/builtin/subagents/src/runs/{shared/nested-events-core.ts → inprocess/runtime-support/nested-core.ts} +14 -61
- package/dist/builtin/subagents/src/runs/{shared/nested-events-projection.ts → inprocess/runtime-support/nested-projection.ts} +4 -10
- package/dist/builtin/subagents/src/runs/{shared/nested-events-registry.ts → inprocess/runtime-support/nested-registry.ts} +19 -4
- package/dist/builtin/subagents/src/runs/{shared/nested-render.ts → inprocess/runtime-support/nested-rendering.ts} +3 -3
- package/dist/builtin/subagents/src/runs/{shared/nested-events-sanitize.ts → inprocess/runtime-support/nested-sanitize.ts} +3 -3
- package/dist/builtin/subagents/src/runs/inprocess.ts +1 -0
- package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +10 -4
- package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +0 -1
- package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +15 -492
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +13 -11
- package/dist/builtin/subagents/src/runs/shared/run-history.ts +3 -5
- package/dist/builtin/subagents/src/runs/shared/single-output.ts +4 -4
- package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +5 -5
- package/dist/builtin/subagents/src/shared/types-async.ts +0 -1
- package/dist/builtin/subagents/src/shared/types-config.ts +18 -0
- package/dist/builtin/subagents/src/shared/types-results.ts +9 -2
- package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +2 -3
- package/dist/builtin/subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-chain-graph.ts +10 -4
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +12 -11
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +49 -12
- package/dist/builtin/subagents/src/tui/render-result.ts +46 -17
- package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +8 -5
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -8
- package/dist/builtin/subagents/src/tui/render-widget.ts +0 -24
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +25 -0
- package/dist/builtin/workflows/README.md +13 -3
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +7 -0
- package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
- package/dist/builtin/workflows/src/durable/types.ts +5 -0
- package/dist/builtin/workflows/src/engine/run.ts +17 -1
- package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
- package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
- package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
- package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
- package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
- package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
- package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
- package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
- package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
- package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
- package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
- package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
- package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
- package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
- package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
- package/dist/builtin/workflows/src/shared/timing.ts +10 -0
- package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
- package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
- package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
- package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
- package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
- package/dist/builtin/workflows/src/tui/widget.ts +16 -46
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +54 -11
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +49 -14
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +13 -0
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-models.js +12 -1
- package/dist/core/agent-session-models.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +4 -0
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-retry.d.ts +21 -4
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +232 -106
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/agent-session-state.d.ts.map +1 -1
- package/dist/core/agent-session-state.js +2 -1
- package/dist/core/agent-session-state.js.map +1 -1
- package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
- package/dist/core/agent-session-tool-hooks.js +12 -0
- package/dist/core/agent-session-tool-hooks.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +1 -1
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +3 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +25 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts +2 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +4 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/model-fallback-failures.d.ts +30 -0
- package/dist/core/model-fallback-failures.d.ts.map +1 -0
- package/dist/core/model-fallback-failures.js +610 -0
- package/dist/core/model-fallback-failures.js.map +1 -0
- package/dist/core/retry-policy.d.ts +30 -0
- package/dist/core/retry-policy.d.ts.map +1 -0
- package/dist/core/retry-policy.js +25 -0
- package/dist/core/retry-policy.js.map +1 -0
- package/dist/core/sdk-types.d.ts +8 -2
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +6 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +2 -0
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +7 -0
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/docs/intercom.md +5 -10
- package/docs/settings.md +7 -1
- package/docs/subagents.md +19 -19
- package/docs/workflows.md +21 -5
- package/examples/extensions/gondolin/package-lock.json +3 -3
- package/npm-shrinkwrap.json +29 -29
- package/package.json +2 -2
- package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
- package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
- package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
- package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
- package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
- package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
- package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
- package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
- package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
- package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
- package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
- package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
- package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
- package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
- package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
- package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
- package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
- package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
- package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
- package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
- package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
- package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
- package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
- package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
- package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
- package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
- package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
- package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
- package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
- package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
- package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
- package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
- package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
- package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
- package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
- package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
- /package/dist/builtin/subagents/src/runs/{shared/nested-path.ts → inprocess/runtime-support/nested-paths.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.13-alpha.1] - 2026-08-05
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `CreateAgentSessionOptions` and `ExtensionContext` now carry an immutable typed subagent child capability policy for in-process tool registration ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
10
|
+
- `CreateAgentSessionOptions` now supports construction-time system-prompt and inherited-context transforms, allowing in-process child sessions to apply typed policy without extension injection ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Typed child policy now includes MCP direct-tool selection and admission-issued Intercom identity/capability, allowing in-process extensions to consume child policy without inheritable environment state ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
15
|
+
- Bundled subagent launches now use in-process `AgentSession` children with typed admission, canonical identities, and live async continuation; `async: true` work is owned by the parent process and does not survive parent exit ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Workflow runs awaiting human input now use the blue `?` indicator in the BACKGROUND panel, `/workflow connect` picker, and `/workflow status` listing, including prompts raised by hidden nested workflow children; the indicator returns to the run's current state when the prompt resolves.
|
|
20
|
+
- Fixed main-chat model fallback to classify provider failures consistently with workflows, advance rejected credentials and incompatible or unavailable models to the next candidate, and restore the user-selected model at the next turn without overriding an explicit `/model` choice. A failure that requesting the same model again cannot repair now takes that model out of the chain for the rest of the turn at every reasoning level, so a fallback entry differing only by its `:low`/`:high` suffix is skipped instead of retrying the same dead credential; transient rate-limit and transport failures keep those reasoning variants ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
|
|
21
|
+
- Fixed a context overflow that compaction cannot resolve to advance the configured `fallbackModels` chain instead of ending the turn, so a larger-context candidate can answer. Compaction still runs first, and a compactable overflow spends no fallback candidate ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
|
|
22
|
+
- Fixed a reasoning-level change during a model fallback stranding the session on the fallback model. Changing reasoning effort is not a model choice, so it no longer cancels the pending restore; the next turn returns to the user-selected primary and keeps the reasoning level that was chosen. Only an explicit `/model` selection or model cycle cancels the restore ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
|
|
23
|
+
- Fixed gRPC `ResourceExhausted` provider errors, seen from providers such as NVIDIA NIM, bypassing the same-model auto-retry budget. They are now retried like other transient provider failures, matching upstream pi-ai, and still advance a configured fallback chain when the retries are exhausted ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
|
|
24
|
+
|
|
5
25
|
## [0.9.12] - 2026-08-04
|
|
6
26
|
|
|
7
27
|
Cumulative release of the `0.9.12-alpha.1` prerelease. The summary below covers the user-visible outcome of that work; the per-change detail remains in the prerelease section below.
|
|
@@ -4,6 +4,12 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.13-alpha.1] - 2026-08-05
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- In-process child identities and supervisor capabilities now arrive through typed admission policy and are captured on each `IntercomClient` at connect time instead of being read from environment for every message. Descendants cannot inherit a parent's supervisor grant through process environment; legacy Atomic/Pi bridge metadata remains available for older hosts ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
12
|
+
|
|
7
13
|
## [0.9.12] - 2026-08-04
|
|
8
14
|
|
|
9
15
|
### Fixed
|
|
@@ -20,7 +20,7 @@ Sometimes you're running multiple Atomic/pi sessions — one researching, one ex
|
|
|
20
20
|
|
|
21
21
|
Unlike pi-messenger (a shared chat room for multi-agent swarms), intercom is for targeted 1:1 communication where you pick the recipient.
|
|
22
22
|
|
|
23
|
-
Intercom also integrates with delegated subagents:
|
|
23
|
+
Intercom also integrates with delegated subagents: in-process children receive a typed admission-issued identity for `contact_supervisor`, including their canonical run/agent/index metadata and any supervisor capability. The child identity is bound to its `IntercomClient` when it connects, so each message uses the same client-owned source and a descendant cannot inherit a parent's capability through process environment. Atomic-prefixed bridge environment variables and legacy `PI_*` metadata remain compatible for older integrations only. Use `reason: "need_decision"` for blocking clarification, `reason: "interview_request"` for multiple structured supervisor answers, and `reason: "progress_update"` for meaningful plan-changing updates. Normal sessions only see the regular `intercom` tool.
|
|
24
24
|
|
|
25
25
|
## In One Minute
|
|
26
26
|
|
|
@@ -227,20 +227,13 @@ The planner typically uses `send`. If you prefer manual approval for outgoing no
|
|
|
227
227
|
|
|
228
228
|
## Workflow: Subagent-to-Supervisor Escalation
|
|
229
229
|
|
|
230
|
-
This workflow
|
|
230
|
+
This workflow uses Atomic's in-process subagent admission. When the runtime admits a delegated child with supervisor coordination, the child session gets a subagent-only `contact_supervisor` tool in addition to the regular `intercom` tool. Normal sessions never see `contact_supervisor`.
|
|
231
231
|
|
|
232
232
|
### When the Tool Appears
|
|
233
233
|
|
|
234
|
-
`contact_supervisor`
|
|
234
|
+
`contact_supervisor` is registered from the typed admission record. The record binds the supervisor target, canonical child identity, child index, session name, and broker-issued capability to the child session; these values are not inherited from environment variables. If the parent does not grant supervisor coordination, the session falls back to the regular `intercom` tool.
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
- `PI_SUBAGENT_RUN_ID` — the run identifier
|
|
238
|
-
- `PI_SUBAGENT_CHILD_AGENT` — the agent type
|
|
239
|
-
- `PI_SUBAGENT_CHILD_INDEX` — the child index within the run
|
|
240
|
-
|
|
241
|
-
Atomic's bundled subagent bridge additionally supplies internal `ATOMIC_SUBAGENT_SUPERVISOR_CAPABILITY` and `ATOMIC_SUBAGENT_SUPERVISOR_SESSION_ID` values issued by the broker. They are not user-configurable authentication flags: the broker accepts the capability only for the child scope and supervisor session that requested it, and the parent restores the same secret if the broker reconnects. Legacy `PI_*` aliases remain readable where applicable.
|
|
242
|
-
|
|
243
|
-
If any are missing, the session falls back to the regular `intercom` tool.
|
|
236
|
+
The child identity remains stable across foreground continuation, `async: true`, interruption, and cold resume. Intercom detach uses the same in-process continuation as async work, so the jobs widget and terminal envelope retain one canonical path.
|
|
244
237
|
|
|
245
238
|
### Three Reasons
|
|
246
239
|
|
|
@@ -254,7 +247,7 @@ Do not use `contact_supervisor` for routine completion handoffs. Return the fina
|
|
|
254
247
|
|
|
255
248
|
Cross-group delivery uses a dedicated broker protocol. Ordinary raw `send` frames always remain group-isolated and are rejected if they include a forged `channel: "supervisor"` marker. A child can cross groups only after its broker-issued capability has bound its registered socket to the exact supervisor. The broker adds the `supervisor` channel marker to validated inbound traffic so parent relays can distinguish it. Replies cross back only when `replyTo` matches a recorded supervisor message in the exact reverse direction; fabricated thread IDs do not bypass isolation.
|
|
256
249
|
|
|
257
|
-
During a foreground subagent run, Atomic probes for an exact live foreground owner before delivery. The matching child reserves the request, accepts a generation-scoped detach commit, and acknowledges it before asks, sends, decisions, interviews, and progress updates enter the parent's model-visible steering queue. A busy workflow stage first reserves the message in its AgentSession generation boundary, then waits inside that admission for the same detach handshake before model-visible queue insertion. This prevents terminal stage close from overtaking the handshake while still preventing the active subagent tool from blocking the child request that would release it; unclaimed traffic and a still-current receiver whose owner disappears before commit fall back to ordinary queue insertion. One accepted commit releases foreground supervision for every active member of a parallel group while retaining each
|
|
250
|
+
During a foreground subagent run, Atomic probes for an exact live foreground owner before delivery. The matching child reserves the request, accepts a generation-scoped detach commit, and acknowledges it before asks, sends, decisions, interviews, and progress updates enter the parent's model-visible steering queue. A busy workflow stage first reserves the message in its AgentSession generation boundary, then waits inside that admission for the same detach handshake before model-visible queue insertion. This prevents terminal stage close from overtaking the handshake while still preventing the active subagent tool from blocking the child request that would release it; unclaimed traffic and a still-current receiver whose owner disappears before commit fall back to ordinary queue insertion. One accepted commit releases foreground supervision for every active member of a parallel group while retaining each in-process session and eventual result. Blocking calls remain alive until the parent sends the exact threaded reply; fire-and-forget calls create no reply waiter. Background and unmatched traffic for ordinary sessions keeps queued-until-idle behavior, and generation cancellation/replacement invalidates stale handshakes.
|
|
258
251
|
|
|
259
252
|
### Example: Blocked Subagent Asks for Guidance
|
|
260
253
|
|
|
@@ -38,6 +38,8 @@ export class IntercomClient extends EventEmitter {
|
|
|
38
38
|
private socket: net.Socket | null = null;
|
|
39
39
|
private _sessionId: string | null = null;
|
|
40
40
|
private _supervisorSessionId: string | null = null;
|
|
41
|
+
/** Source identity is captured once at connect, never read from env per message. */
|
|
42
|
+
private _messageSource: Message["source"] | undefined;
|
|
41
43
|
private pendingSends = new PendingSendRegistry();
|
|
42
44
|
private pendingLists = new Map<string, { resolve: (sessions: SessionInfo[]) => void; reject: (e: Error) => void }>();
|
|
43
45
|
private pendingSupervisorAuthorizations = new Map<string, {
|
|
@@ -85,10 +87,16 @@ export class IntercomClient extends EventEmitter {
|
|
|
85
87
|
return socket;
|
|
86
88
|
}
|
|
87
89
|
|
|
88
|
-
connect(
|
|
90
|
+
connect(
|
|
91
|
+
session: Omit<SessionInfo, "id">,
|
|
92
|
+
supervisor?: SupervisorRegistration,
|
|
93
|
+
supervisorOwnerToken?: string,
|
|
94
|
+
messageSource?: Message["source"],
|
|
95
|
+
): Promise<void> {
|
|
89
96
|
if (this.socket) {
|
|
90
97
|
return Promise.reject(new Error("Already connected"));
|
|
91
98
|
}
|
|
99
|
+
this._messageSource = messageSource ?? readSubagentMessageSource();
|
|
92
100
|
|
|
93
101
|
return new Promise((resolve, reject) => {
|
|
94
102
|
const socket = net.connect(BROKER_SOCKET);
|
|
@@ -141,6 +149,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
141
149
|
}
|
|
142
150
|
this._sessionId = null;
|
|
143
151
|
this._supervisorSessionId = null;
|
|
152
|
+
this._messageSource = undefined;
|
|
144
153
|
this.disconnectError = null;
|
|
145
154
|
if (connectionEstablished && !wasDisconnecting) {
|
|
146
155
|
this.emit("disconnected", disconnectError);
|
|
@@ -463,7 +472,7 @@ export class IntercomClient extends EventEmitter {
|
|
|
463
472
|
replyTo: options.replyTo,
|
|
464
473
|
expectsReply: options.expectsReply,
|
|
465
474
|
replyError: options.replyError,
|
|
466
|
-
source:
|
|
475
|
+
source: this._messageSource,
|
|
467
476
|
content: { text: options.text, attachments: options.attachments },
|
|
468
477
|
};
|
|
469
478
|
try {
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "./intercom-utils.js";
|
|
20
20
|
|
|
21
21
|
interface ContactSupervisorDeps {
|
|
22
|
-
childOrchestratorMetadata: ChildOrchestratorMetadata | null;
|
|
22
|
+
childOrchestratorMetadata: ChildOrchestratorMetadata | null | (() => ChildOrchestratorMetadata | null);
|
|
23
23
|
ensureConnected(reason: "tool"): Promise<IntercomClient>;
|
|
24
24
|
syncPresenceIdentity(sessionId: string): void;
|
|
25
25
|
resolveSessionTarget(activeClient: IntercomClient, nameOrId: string): Promise<string | null>;
|
|
@@ -35,7 +35,10 @@ interface ContactSupervisorDeps {
|
|
|
35
35
|
|
|
36
36
|
export function registerContactSupervisorTool(pi: ExtensionAPI, deps: ContactSupervisorDeps): void {
|
|
37
37
|
const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget, beginReplyWait, hasReplyWaiter } = deps;
|
|
38
|
-
|
|
38
|
+
const getMetadata = typeof childOrchestratorMetadata === "function"
|
|
39
|
+
? childOrchestratorMetadata
|
|
40
|
+
: () => childOrchestratorMetadata;
|
|
41
|
+
if (childOrchestratorMetadata !== null) {
|
|
39
42
|
pi.registerTool({
|
|
40
43
|
name: "contact_supervisor",
|
|
41
44
|
label: "Contact Supervisor",
|
|
@@ -116,7 +119,14 @@ export function registerContactSupervisorTool(pi: ExtensionAPI, deps: ContactSup
|
|
|
116
119
|
};
|
|
117
120
|
}
|
|
118
121
|
|
|
119
|
-
const metadata =
|
|
122
|
+
const metadata = getMetadata();
|
|
123
|
+
if (!metadata) {
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: "Supervisor contact is unavailable for this session" }],
|
|
126
|
+
isError: true,
|
|
127
|
+
details: { error: true },
|
|
128
|
+
};
|
|
129
|
+
}
|
|
120
130
|
let sendTo: string;
|
|
121
131
|
if (connectedClient.supervisorSessionId || metadata.supervisor) {
|
|
122
132
|
sendTo = connectedClient.supervisorSessionId ?? metadata.supervisor!.supervisorSessionId;
|
|
@@ -15,6 +15,7 @@ import { registerSubagentRelay } from "./subagent-relay.js";
|
|
|
15
15
|
import { ForegroundDetachHandoff, handleForegroundInboundDelivery } from "./foreground-detach-handoff.js";
|
|
16
16
|
import { routeIncomingReply } from "./reply-routing.js";
|
|
17
17
|
import { INBOUND_FLUSH_DELAY_MS, INBOUND_IDLE_RETRY_MS, buildPresenceIdentity, formatAttachments, readChildOrchestratorMetadata, toError } from "./intercom-utils.js";
|
|
18
|
+
import { readSubagentMessageSource } from "./source-ownership.js";
|
|
18
19
|
import { buildIncomingCustomMessage, createIncomingMessageSender } from "./incoming-message-delivery.js";
|
|
19
20
|
import { InboundIdleQueue } from "./inbound-idle-queue.js";
|
|
20
21
|
import { registerTerminalOrderingBarrier } from "./terminal-ordering-barrier.js";
|
|
@@ -46,8 +47,13 @@ export default function piIntercomExtension(pi: ExtensionAPI, testOverrides: Int
|
|
|
46
47
|
};
|
|
47
48
|
let client: IntercomClient | null = null;
|
|
48
49
|
const config: IntercomConfig = loadConfig();
|
|
49
|
-
const
|
|
50
|
+
const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
|
|
50
51
|
let runtimeContext: ExtensionContext | null = null;
|
|
52
|
+
function currentChildOrchestratorMetadata() {
|
|
53
|
+
return runtimeContext?.subagentPolicy !== undefined
|
|
54
|
+
? readChildOrchestratorMetadata(runtimeContext.subagentPolicy)
|
|
55
|
+
: legacyChildOrchestratorMetadata;
|
|
56
|
+
}
|
|
51
57
|
let currentSessionId: string | null = null;
|
|
52
58
|
let currentModel = "unknown";
|
|
53
59
|
let sessionStartedAt: number | null = null;
|
|
@@ -389,8 +395,12 @@ export default function piIntercomExtension(pi: ExtensionAPI, testOverrides: Int
|
|
|
389
395
|
attachClientHandlers(nextClient);
|
|
390
396
|
try {
|
|
391
397
|
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
|
|
398
|
+
const childMetadata = currentChildOrchestratorMetadata();
|
|
392
399
|
await nextClient.connect(
|
|
393
|
-
buildRegistration(),
|
|
400
|
+
buildRegistration(),
|
|
401
|
+
childMetadata?.supervisor,
|
|
402
|
+
supervisorAuthorizations.ownerToken,
|
|
403
|
+
readSubagentMessageSource(runtimeContext?.subagentPolicy),
|
|
394
404
|
);
|
|
395
405
|
await supervisorAuthorizations.restore(nextClient);
|
|
396
406
|
if (!getLiveContext(contextAtStart, generationAtStart)) {
|
|
@@ -470,7 +480,7 @@ export default function piIntercomExtension(pi: ExtensionAPI, testOverrides: Int
|
|
|
470
480
|
});
|
|
471
481
|
|
|
472
482
|
registerContactSupervisorTool(pi, {
|
|
473
|
-
childOrchestratorMetadata,
|
|
483
|
+
childOrchestratorMetadata: currentChildOrchestratorMetadata,
|
|
474
484
|
ensureConnected,
|
|
475
485
|
syncPresenceIdentity,
|
|
476
486
|
resolveSessionTarget: resolveSessionTargetId,
|
|
@@ -92,10 +92,10 @@ function renderHeavyToolResult(loadedHeavy: CapturedHeavy | null, name: string,
|
|
|
92
92
|
return renderIntercomToolResult(name, args);
|
|
93
93
|
}
|
|
94
94
|
export default function intercom(pi: ExtensionAPI, options: LightweightIntercomOptions = {}) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
const inheritedDelegatedSessionName = readSubagentEnv("INTERCOM_SESSION_NAME");
|
|
96
|
+
let heavyAttempt: HeavyAttempt | null = null;
|
|
97
|
+
let loadedHeavy: IntercomHeavyHandle | null = null;
|
|
98
|
+
let sessionSnapshot: SessionSnapshot | null = null;
|
|
99
99
|
let lifecycleGeneration = 0;
|
|
100
100
|
let nextLeaseId = 1;
|
|
101
101
|
let activeLease = createLifecycleLease<ShutdownSnapshot>(nextLeaseId++);
|
|
@@ -229,21 +229,45 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
|
|
|
229
229
|
);
|
|
230
230
|
return promise;
|
|
231
231
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
232
|
+
let typedContactSupervisorRegistered = hasSubagentIntercomEnv();
|
|
233
|
+
const registerTypedContactSupervisor = (): void => {
|
|
234
|
+
if (typedContactSupervisorRegistered) return;
|
|
235
|
+
typedContactSupervisorRegistered = true;
|
|
236
|
+
pi.registerTool({
|
|
237
|
+
name: "contact_supervisor",
|
|
238
|
+
label: "Contact Supervisor",
|
|
239
|
+
description: "Subagent-only tool for contacting the supervisor agent that delegated this task.",
|
|
240
|
+
promptSnippet: "Subagent-only: contact the supervisor for decisions, interviews, or meaningful updates.",
|
|
241
|
+
parameters: Type.Object({
|
|
242
|
+
reason: Type.String({ enum: ["need_decision", "progress_update", "interview_request"] }),
|
|
243
|
+
message: Type.Optional(Type.String()),
|
|
244
|
+
interview: Type.Optional(Type.Unknown()),
|
|
245
|
+
}),
|
|
246
|
+
execute: (...args) => executeHeavyTool(loadHeavy, "contact_supervisor", args),
|
|
247
|
+
renderResult: (...args) => renderHeavyToolResult(loadedHeavy?.heavy ?? null, "contact_supervisor", args),
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
pi.on("session_start", async (event, ctx) => {
|
|
251
|
+
const typedIdentity = ctx.subagentPolicy?.intercom;
|
|
252
|
+
if (typedIdentity) {
|
|
253
|
+
if (typedIdentity.sessionName && typeof pi.setSessionName === "function") pi.setSessionName(typedIdentity.sessionName);
|
|
254
|
+
registerTypedContactSupervisor();
|
|
255
|
+
} else if (inheritedDelegatedSessionName && typeof pi.setSessionName === "function") {
|
|
256
|
+
pi.setSessionName(inheritedDelegatedSessionName);
|
|
257
|
+
}
|
|
258
|
+
if (activeLease.retired) activeLease = createLifecycleLease<ShutdownSnapshot>(nextLeaseId++, activeLease.cleanupBarrier);
|
|
259
|
+
const lease = activeLease;
|
|
260
|
+
await waitForPriorCleanup(lease);
|
|
261
|
+
if (sessionSnapshot) {
|
|
262
|
+
activeLifecycle.turnStart = null;
|
|
263
|
+
activeLifecycle.agentStart = null;
|
|
264
|
+
activeLifecycle.activeTools.clear();
|
|
265
|
+
activeLifecycle.modelSelect = null;
|
|
266
|
+
}
|
|
267
|
+
const generation = ++lifecycleGeneration;
|
|
268
|
+
sessionSnapshot = { event, ctx, generation, lease };
|
|
269
|
+
if (loadedHeavy) await ensureSessionStartReplayed(loadedHeavy.heavy, lease);
|
|
270
|
+
});
|
|
247
271
|
pi.on("session_shutdown", async (event, ctx) => {
|
|
248
272
|
const lease = activeLease;
|
|
249
273
|
const generation = ++lifecycleGeneration;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { APP_NAME, getEnvValue } from "@bastani/atomic";
|
|
1
|
+
import { type ExtensionAPI, type SubagentChildPolicy } from "@bastani/atomic";
|
|
3
2
|
import type { Attachment, Message, SessionInfo, SupervisorRegistration } from "./types.js";
|
|
4
3
|
import { DEFAULT_GROUP, normalizeGroup } from "./group.js";
|
|
5
4
|
|
|
@@ -12,14 +11,6 @@ export const SUBAGENT_SUPERVISOR_AUTHORIZATION_EVENT = "subagent:supervisor-auth
|
|
|
12
11
|
export const INBOUND_FLUSH_DELAY_MS = 200;
|
|
13
12
|
export const INBOUND_IDLE_RETRY_MS = 500;
|
|
14
13
|
export const DEFAULT_UNNAMED_SESSION_ALIAS_PREFIX = "subagent-chat";
|
|
15
|
-
const ENV_PREFIX = APP_NAME.toUpperCase();
|
|
16
|
-
const SUBAGENT_ORCHESTRATOR_TARGET_ENV = `${ENV_PREFIX}_SUBAGENT_ORCHESTRATOR_TARGET`;
|
|
17
|
-
const SUBAGENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_RUN_ID`;
|
|
18
|
-
const SUBAGENT_CHILD_AGENT_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_AGENT`;
|
|
19
|
-
const SUBAGENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_INDEX`;
|
|
20
|
-
const SUBAGENT_INTERCOM_SESSION_NAME_ENV = `${ENV_PREFIX}_SUBAGENT_INTERCOM_SESSION_NAME`;
|
|
21
|
-
const SUBAGENT_SUPERVISOR_CAPABILITY_ENV = `${ENV_PREFIX}_SUBAGENT_SUPERVISOR_CAPABILITY`;
|
|
22
|
-
const SUBAGENT_SUPERVISOR_SESSION_ID_ENV = `${ENV_PREFIX}_SUBAGENT_SUPERVISOR_SESSION_ID`;
|
|
23
14
|
|
|
24
15
|
export interface ChildOrchestratorMetadata {
|
|
25
16
|
orchestratorTarget: string;
|
|
@@ -76,28 +67,23 @@ export function formatAttachments(attachments: Attachment[]): string {
|
|
|
76
67
|
}
|
|
77
68
|
return text;
|
|
78
69
|
}
|
|
79
|
-
export function
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const agent = getEnvValue(SUBAGENT_CHILD_AGENT_ENV)?.trim();
|
|
83
|
-
const index = getEnvValue(SUBAGENT_CHILD_INDEX_ENV)?.trim();
|
|
84
|
-
if (!orchestratorTarget || !runId || !agent || !index) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
const sessionName = getEnvValue(SUBAGENT_INTERCOM_SESSION_NAME_ENV)?.trim();
|
|
88
|
-
const capability = getEnvValue(SUBAGENT_SUPERVISOR_CAPABILITY_ENV)?.trim();
|
|
89
|
-
const supervisorSessionId = getEnvValue(SUBAGENT_SUPERVISOR_SESSION_ID_ENV)?.trim();
|
|
70
|
+
export function childOrchestratorMetadataFromPolicy(policy?: SubagentChildPolicy): ChildOrchestratorMetadata | null {
|
|
71
|
+
const identity = policy?.intercom;
|
|
72
|
+
if (!identity) return null;
|
|
90
73
|
return {
|
|
91
|
-
orchestratorTarget,
|
|
92
|
-
runId,
|
|
93
|
-
agent,
|
|
94
|
-
index,
|
|
95
|
-
...(sessionName ? { sessionName } : {}),
|
|
96
|
-
...(
|
|
97
|
-
? { supervisor: { capability, supervisorSessionId } }
|
|
98
|
-
: {}),
|
|
74
|
+
orchestratorTarget: identity.orchestratorTarget,
|
|
75
|
+
runId: identity.runId,
|
|
76
|
+
agent: identity.agent,
|
|
77
|
+
index: String(identity.index),
|
|
78
|
+
...(identity.sessionName ? { sessionName: identity.sessionName } : {}),
|
|
79
|
+
...(identity.supervisor ? { supervisor: identity.supervisor } : {}),
|
|
99
80
|
};
|
|
100
81
|
}
|
|
82
|
+
|
|
83
|
+
/** Resolve metadata only from the admission-issued typed child identity. */
|
|
84
|
+
export function readChildOrchestratorMetadata(policy?: SubagentChildPolicy): ChildOrchestratorMetadata | null {
|
|
85
|
+
return childOrchestratorMetadataFromPolicy(policy);
|
|
86
|
+
}
|
|
101
87
|
export function formatChildOrchestratorMessage(kind: "ask" | "update" | "interview", metadata: ChildOrchestratorMetadata, message: string): string {
|
|
102
88
|
const heading = kind === "ask"
|
|
103
89
|
? "Subagent needs a supervisor decision."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type SubagentChildPolicy } from "@bastani/atomic";
|
|
2
2
|
import type { Message } from "./types.js";
|
|
3
3
|
|
|
4
|
-
const ENV_PREFIX = APP_NAME.toUpperCase();
|
|
5
|
-
const SUBAGENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_RUN_ID`;
|
|
6
|
-
const SUBAGENT_CHILD_AGENT_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_AGENT`;
|
|
7
|
-
const SUBAGENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_INDEX`;
|
|
8
|
-
|
|
9
4
|
export function buildSubagentMessageSource(
|
|
10
5
|
runIdValue: string | undefined,
|
|
11
6
|
agentValue: string | undefined,
|
|
@@ -25,10 +20,12 @@ export function buildSubagentMessageSource(
|
|
|
25
20
|
};
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
export function readSubagentMessageSource(): Message["source"] | undefined {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
export function readSubagentMessageSource(policy?: SubagentChildPolicy): Message["source"] | undefined {
|
|
24
|
+
const identity = policy?.intercom;
|
|
25
|
+
if (!identity) return undefined;
|
|
26
|
+
return {
|
|
27
|
+
subagentRunId: identity.runId,
|
|
28
|
+
subagentAgent: identity.agent,
|
|
29
|
+
subagentIndex: identity.index,
|
|
30
|
+
};
|
|
34
31
|
}
|
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.13-alpha.1] - 2026-08-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- In-process subagents now receive MCP direct-tool selection through typed admission policy. Omitted selection preserves MCP configuration defaults, a list selects exact server/tool entries, and an empty list disables direct tools; the process-era environment bridge has been removed ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
15
|
+
|
|
10
16
|
## [0.9.12] - 2026-08-04
|
|
11
17
|
|
|
12
18
|
### Fixed
|
|
@@ -240,7 +240,9 @@ To exclude specific tools while still using `directTools: true`, add `excludeToo
|
|
|
240
240
|
|
|
241
241
|
Each direct tool costs ~150-300 tokens in the system prompt (name + description + schema). Good for targeted sets of 5-20 tools. For servers with 75+ tools, stick with the proxy or pick specific tools with a `string[]`.
|
|
242
242
|
|
|
243
|
-
Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup when the cache is warm. On the first session after adding `directTools` to a new server, or when a child/subagent selects tools
|
|
243
|
+
Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup when the cache is warm. On the first session after adding `directTools` to a new server, or when a child/subagent selects tools, the cache may not exist yet — tools fall back to proxy-only while the selected/configured direct-tool servers populate in the background, then the extension refreshes tool registration so the warmed direct tools become available in the current session. To force it immediately: `/mcp reconnect <server>`.
|
|
244
|
+
|
|
245
|
+
In-process subagents receive direct-tool selection through the typed admission policy rather than an environment bridge. An omitted `mcpDirectTools` field preserves the session's MCP configuration defaults, a list selects exactly those server/tool names, and an empty list explicitly disables direct tools. The legacy environment override is removed; parent sessions should use MCP configuration instead.
|
|
244
246
|
|
|
245
247
|
When you change direct-tool toggles in `/mcp` or write new config through `/mcp setup`, the extension triggers Pi's normal reload flow automatically. That refreshes extensions, prompts, skills, and MCP tool registration in one shot, so newly configured direct tools can appear without a manual restart.
|
|
246
248
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentToolUpdateCallback, ExtensionAPI, ExtensionContext, ToolInfo } from "@bastani/atomic";
|
|
1
|
+
import type { AgentToolUpdateCallback, ExtensionAPI, ExtensionContext, SubagentChildPolicy, ToolInfo } from "@bastani/atomic";
|
|
2
2
|
import type { McpExtensionState } from "./state.js";
|
|
3
3
|
import type { McpConfig } from "./types.ts";
|
|
4
4
|
import type { MetadataCache } from "./metadata-cache.js";
|
|
@@ -55,22 +55,15 @@ export default function mcpAdapter(pi: ExtensionAPI) {
|
|
|
55
55
|
async function registerDirectToolsFromConfig(
|
|
56
56
|
config: McpConfig,
|
|
57
57
|
cache: MetadataCache | null,
|
|
58
|
+
subagentPolicy?: SubagentChildPolicy,
|
|
58
59
|
): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
|
|
59
60
|
const [{ resolveDirectTools, createDirectToolExecutor, getMissingConfiguredDirectToolServers }, { truncateAtWord }] = await Promise.all([
|
|
60
61
|
import("./direct-tools.ts"),
|
|
61
62
|
import("./utils.js"),
|
|
62
63
|
]);
|
|
63
64
|
const prefix = config.settings?.toolPrefix ?? "server";
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const directSpecs = envRaw === "__none__"
|
|
67
|
-
? []
|
|
68
|
-
: resolveDirectTools(
|
|
69
|
-
config,
|
|
70
|
-
cache,
|
|
71
|
-
prefix,
|
|
72
|
-
envDirectTools,
|
|
73
|
-
);
|
|
65
|
+
const directTools = subagentPolicy?.mcpDirectTools;
|
|
66
|
+
const directSpecs = resolveDirectTools(config, cache, prefix, directTools === undefined ? undefined : [...directTools]);
|
|
74
67
|
for (const spec of directSpecs) {
|
|
75
68
|
if (registeredDirectToolNames.has(spec.prefixedName)) continue;
|
|
76
69
|
registeredDirectToolNames.add(spec.prefixedName);
|
|
@@ -92,13 +85,13 @@ export default function mcpAdapter(pi: ExtensionAPI) {
|
|
|
92
85
|
refreshTools?.();
|
|
93
86
|
return {
|
|
94
87
|
directToolCount: directSpecs.length,
|
|
95
|
-
missingConfiguredDirectToolServers: getMissingConfiguredDirectToolServers(config, cache,
|
|
88
|
+
missingConfiguredDirectToolServers: getMissingConfiguredDirectToolServers(config, cache, directTools),
|
|
96
89
|
};
|
|
97
90
|
}
|
|
98
91
|
|
|
99
|
-
async function registerDirectTools(nextState: McpExtensionState): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
|
|
92
|
+
async function registerDirectTools(nextState: McpExtensionState, subagentPolicy?: SubagentChildPolicy): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
|
|
100
93
|
const { loadMetadataCache } = await import("./metadata-cache.js");
|
|
101
|
-
return registerDirectToolsFromConfig(nextState.config, loadMetadataCache());
|
|
94
|
+
return registerDirectToolsFromConfig(nextState.config, loadMetadataCache(), subagentPolicy);
|
|
102
95
|
}
|
|
103
96
|
|
|
104
97
|
async function shutdownOAuthFlow(reason: string): Promise<void> {
|
|
@@ -196,7 +189,7 @@ export default function mcpAdapter(pi: ExtensionAPI) {
|
|
|
196
189
|
throw new Error(`${STALE_INITIALIZATION_PREFIX} after startup`);
|
|
197
190
|
}
|
|
198
191
|
|
|
199
|
-
const directToolState = await registerDirectTools(initializedState);
|
|
192
|
+
const directToolState = await registerDirectTools(initializedState, session.ctx.subagentPolicy);
|
|
200
193
|
if (!isCurrentSession(session) || initPromise !== expectedPromise.current) {
|
|
201
194
|
throw new Error(`${STALE_INITIALIZATION_PREFIX} after tool registration`);
|
|
202
195
|
}
|
|
@@ -211,10 +204,11 @@ export default function mcpAdapter(pi: ExtensionAPI) {
|
|
|
211
204
|
updateStatusBar(initializedState);
|
|
212
205
|
let cancelWarmup: (() => void) | null = null;
|
|
213
206
|
const warmup = scheduleMcpStartupWarmup(initializedState, {
|
|
207
|
+
subagentPolicy: session.ctx.subagentPolicy,
|
|
214
208
|
shouldContinue: () => isCurrentSession(session) && state === initializedState,
|
|
215
209
|
onDirectToolsChanged: async () => {
|
|
216
210
|
if (!isCurrentSession(session) || state !== initializedState) return;
|
|
217
|
-
await registerDirectTools(initializedState);
|
|
211
|
+
await registerDirectTools(initializedState, session.ctx.subagentPolicy);
|
|
218
212
|
},
|
|
219
213
|
onSettled: () => {
|
|
220
214
|
if (isCurrentSession(session) && state === initializedState && startupWarmupCancel === cancelWarmup) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
|
|
6
6
|
"contributors": [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SubagentChildPolicy } from "@bastani/atomic";
|
|
1
2
|
import type { McpExtensionState } from "./state.js";
|
|
2
3
|
import { getMissingConfiguredDirectToolServers } from "./direct-tools.ts";
|
|
3
4
|
import { loadMetadataCache } from "./metadata-cache.js";
|
|
@@ -7,9 +8,11 @@ import { logger } from "./logger.ts";
|
|
|
7
8
|
import { updateMetadataCache, updateStatusBar } from "./init.js";
|
|
8
9
|
|
|
9
10
|
export interface McpStartupWarmupOptions {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/** Typed child selection issued during in-process admission. */
|
|
12
|
+
subagentPolicy?: SubagentChildPolicy;
|
|
13
|
+
shouldContinue?: () => boolean;
|
|
14
|
+
onDirectToolsChanged?: () => void | Promise<void>;
|
|
15
|
+
onSettled?: () => void;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export interface McpStartupWarmupHandle {
|
|
@@ -17,6 +20,17 @@ export interface McpStartupWarmupHandle {
|
|
|
17
20
|
cancel(): void;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
export interface McpDirectToolsSelection {
|
|
24
|
+
readonly disabled: boolean;
|
|
25
|
+
readonly tools?: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Resolve direct-tool selection exclusively from typed admission policy. */
|
|
29
|
+
export function resolveMcpDirectToolsSelection(subagentPolicy?: SubagentChildPolicy): McpDirectToolsSelection {
|
|
30
|
+
const tools = subagentPolicy?.mcpDirectTools;
|
|
31
|
+
return { disabled: tools !== undefined && tools.length === 0, ...(tools === undefined ? {} : { tools: [...tools] }) };
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
function deferToMacrotask(): Promise<void> {
|
|
21
35
|
return new Promise((resolve) => setImmediate(resolve));
|
|
22
36
|
}
|
|
@@ -31,12 +45,10 @@ export function scheduleMcpStartupWarmup(
|
|
|
31
45
|
const promise = (async () => {
|
|
32
46
|
await deferToMacrotask();
|
|
33
47
|
if (!shouldContinue()) return;
|
|
48
|
+
const selection = resolveMcpDirectToolsSelection(options.subagentPolicy);
|
|
49
|
+
if (selection.disabled) return;
|
|
34
50
|
|
|
35
|
-
const
|
|
36
|
-
if (envDirect === "__none__") return;
|
|
37
|
-
|
|
38
|
-
const envDirectTools = envDirect?.split(",").map((item) => item.trim()).filter(Boolean);
|
|
39
|
-
const missingCacheServers = getMissingConfiguredDirectToolServers(state.config, loadMetadataCache(), envDirectTools)
|
|
51
|
+
const missingCacheServers = getMissingConfiguredDirectToolServers(state.config, loadMetadataCache(), selection.tools)
|
|
40
52
|
.filter((name) => state.manager.getConnection(name)?.status !== "connected");
|
|
41
53
|
if (missingCacheServers.length === 0) return;
|
|
42
54
|
|
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.13-alpha.1] - 2026-08-05
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- `async: true` no longer survives parent exit. Async subagents now run as in-process children of the parent session on the same foreground executor, so quitting Atomic ends any in-flight async run. The child's canonical identity and its session file persist on disk and can be reloaded on a later start, but the running work does not continue in the background across a restart. The detached runner process that previously provided parent-exit survival has been deleted ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
10
|
+
- Removed the `ATOMIC_SUBAGENT_*` process-era environment bridge variables consumed by the deleted spawn path and the synthesized numeric child-result exit-code protocol (`0/1/-1/-2/143`). Child identity, policy, supervisor capability, and terminal outcomes now cross typed admission; results use required `status` (`ok | error | skipped | interrupted | continued`) plus `cause` and `stats` ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added the in-process subagent control-plane doors and `InProcessChildRunner` foundation backed by the Rust N-API registry, typed statuses, session statistics, and bounded result envelopes ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Nested in-process children now route live `interrupt` and cold `resume` actions directly through the Rust control plane. Nested event and control records use an in-memory host route while retaining the validated file shape for cold-start compatibility; session JSONL is flushed before forced interruption, and the former 200 ms nested-control polling loop is replaced by event-driven delivery ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
19
|
+
- In-process children now advance through their model-fallback ladder via the SDK session's `fallbackModels` — the exact classification, same-model retry, and candidate-advancement behavior main chat and workflow stages converged on ([#2170](https://github.com/bastani-inc/atomic/issues/2170)) — instead of a subagents-local walk. Pre-spawn auth filtering still builds the ladder, and results report the effective `model`, `attemptedModels`, and skipped pre-spawn attempts ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
20
|
+
- Foreground subagent attempts now enter through the in-process session runner, expose typed terminal status and `SessionStats`, and record typed run-history statuses; the foreground process-attempt implementation was removed ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
21
|
+
- In-process admission now resolves child management and fanout capabilities as a typed policy carried into the session and tool executor; restricted children cannot create, update, or delete agent definitions, and fanout authorization cannot be widened by a descendant ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
22
|
+
- `async: true` chain and parallel runs now execute on the same in-process foreground executor as their synchronous counterparts, un-awaited, instead of a separately serialized detached runner. Chain `{previous}` substitution, chain output bindings, dynamic fanout, worktree setup and cleanup, structured-output schemas, skills resolution, progress files, fail-fast, and per-step model-candidate ladders are now served by one implementation for both modes ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
23
|
+
- Child prompt behavior now enters in-process `AgentSession` construction through typed admission policy: boundary instructions, project-context and inherited-skill filtering, orchestration-skill removal, and parent-only message filtering no longer depend on the process-era extension injection path ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
24
|
+
- Child MCP direct-tool selection and Intercom identity/capability now cross the in-process admission boundary as typed policy; omitted MCP selection preserves defaults, empty selection disables direct tools, and supervisor grants are never inherited through environment ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Fixed in-process parallel siblings colliding on the same canonical identity and terminal artifact path, and fixed async completions omitting their persisted result envelope from the parent notification ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
29
|
+
- Fixed model-failure classification sharing so subagent fallback decisions stay aligned with main chat and workflow candidates for auth, unavailable-model, request-incompatible, quota, and transport failures ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
33
|
+
- Removed every remaining OS child-process code path from subagent execution, satisfying the spec's zero-process goal: the detached jiti async runner and its twelve `subagent-runner*` modules, the `async-execution-*` spawn layer, the async event journal, the idle/wall attempt watchdog, the stdout drain grace, the CLI spawn resolver, the environment-bridge builder, and the post-exit stdio guard ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
|
|
34
|
+
|
|
5
35
|
## [0.9.12] - 2026-08-04
|
|
6
36
|
|
|
7
37
|
### Fixed
|