@bastani/atomic 0.8.29-alpha.4 → 0.8.30-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 +27 -0
- package/dist/builtin/cursor/CHANGELOG.md +6 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +7 -1
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/mcp/CHANGELOG.md +7 -1
- package/dist/builtin/mcp/package.json +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +11 -0
- package/dist/builtin/subagents/README.md +10 -30
- package/dist/builtin/subagents/package.json +4 -4
- package/dist/builtin/subagents/skills/subagent/SKILL.md +5 -11
- package/dist/builtin/subagents/src/agents/agent-management.ts +0 -5
- package/dist/builtin/subagents/src/agents/agent-serializer.ts +7 -3
- package/dist/builtin/subagents/src/agents/agents.ts +4 -29
- package/dist/builtin/subagents/src/agents/chain-serializer.ts +27 -25
- package/dist/builtin/subagents/src/extension/schemas.ts +0 -75
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -29
- package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -2
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +134 -239
- package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +1 -52
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +103 -94
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +0 -10
- package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +16 -8
- package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +0 -1
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +0 -3
- package/dist/builtin/subagents/src/runs/shared/structured-output.ts +67 -2
- package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +6 -20
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +2 -6
- package/dist/builtin/subagents/src/shared/settings.ts +1 -4
- package/dist/builtin/subagents/src/shared/types.ts +1 -156
- package/dist/builtin/subagents/src/tui/render.ts +0 -1
- package/dist/builtin/web-access/CHANGELOG.md +7 -1
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +13 -0
- package/dist/builtin/workflows/README.md +2 -2
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/src/extension/index.ts +8 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +66 -10
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +70 -19
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +98 -14
- package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +0 -1
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +4 -0
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
- package/dist/builtin/workflows/src/shared/store.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -4
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +21 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +6 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +2 -0
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction.d.ts +43 -16
- package/dist/core/compaction/context-compaction.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction.js +518 -189
- package/dist/core/compaction/context-compaction.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +4 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +11 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +14 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -1
- package/dist/core/model-registry.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 +52 -18
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +20 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +89 -24
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +14 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +145 -3
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +9 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +16 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/thinking-blocks.d.ts +7 -0
- package/dist/core/thinking-blocks.d.ts.map +1 -0
- package/dist/core/thinking-blocks.js +16 -0
- package/dist/core/thinking-blocks.js.map +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +4 -0
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +30 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +87 -12
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +37 -18
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +24 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +58 -13
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/utils/child-process.d.ts +9 -4
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +42 -10
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +4 -27
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +469 -51
- package/docs/containerization.md +37 -37
- package/docs/extensions.md +23 -14
- package/docs/models.md +6 -4
- package/docs/packages.md +2 -0
- package/docs/providers.md +1 -1
- package/docs/subagents.md +11 -4
- package/docs/workflows.md +4 -2
- package/examples/extensions/README.md +2 -2
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/question.ts +39 -18
- package/examples/extensions/questionnaire.ts +49 -28
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +7 -5
- package/dist/builtin/subagents/src/runs/shared/acceptance.ts +0 -612
- package/dist/builtin/subagents/src/runs/shared/completion-guard.ts +0 -147
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Bumped the bundled upstream pi runtime libraries `@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui` from `^0.79.3` to `^0.79.4`, added `semver` as an explicit runtime dependency for package/version checks, and aligned companion extension peer ranges so Atomic inherits upstream provider/model metadata updates, agent-core fixes, the new terminal background-color query used by first-run theme detection, and shared TUI wrapping/keyboard compatibility fixes.
|
|
8
|
+
- Clarified `models.json` value-resolution docs for Atomic's intentional divergence from upstream pi v0.79.4: legacy uppercase env-var-like provider values are still migrated to explicit `$VAR` syntax on startup when the same-named environment variable is present, while new configs should use `$VAR`/`${VAR}` explicitly and non-migrated values remain literals.
|
|
9
|
+
- Changed package install/update handling to respect npm semver ranges instead of forcing ranged package specs to `latest`, preserve configured npm specs during batch updates, locate pnpm global package roots when `pnpm root -g` is unavailable, and exit immediately after package commands complete.
|
|
10
|
+
- Updated extension docs and examples for the upstream v0.79.4 API clarifications: `pi.getActiveTools()` returns active tool names while `pi.getAllTools()` returns metadata including `promptGuidelines`, long-lived resources should be opened from session-scoped hooks and cleaned up in `session_shutdown`, and question/questionnaire example UIs wrap long prompts and option descriptions without truncation.
|
|
11
|
+
- Removed the bundled subagent acceptance and no-mutation completion-gate behavior from the CLI-visible subagent extension: no acceptance field, inferred gate, acceptance-report prompt injection/parsing, completionGuard config, or acceptance/completion-guard status display remains. Migration guidance now directs users to remove stale acceptance fields from subagent calls/chains/parallel items and move validation requirements into task text; JSON chain rewrites drop legacy acceptance entries ([#1398](https://github.com/bastani-inc/atomic/issues/1398)).
|
|
12
|
+
- Replaced the verbatim context-compaction planner's fixed turn cap and mode split with a deterministic strict reduction loop driven by configurable compaction parameters: `compression_ratio` (fraction to keep, default `0.5`), `preserve_recent` (default `2`), and `query` (explicit or auto-detected). The prompt substitutes the effective ratio-derived target as a hard completion requirement, hooks receive the parameters through `event.parameters`/`preparation.parameters`/`result.parameters`, extension `ctx.compact()` can override them per run, the runtime exits only once validated deletion stats meet the target, and premature plain-text exits receive an automatic nudge to keep removing message entries/content blocks. The planner still balances early search/read exploration with quick exploitation of high-confidence low-value deletion targets, the `context_compaction_budget` progress tool reports context-window fullness and remaining reduction work while inheriting the session's current model thinking level, and legacy parsing of deletion JSON from final assistant prose has been removed so only validated tool state can drive compaction.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Fixed package commands to drain stdout/stderr before the forced post-command exit so piped `atomic list`, help, progress, and self-update fallback output is not truncated under Node while still terminating leaked extension handles.
|
|
17
|
+
- Fixed custom `models.json` providers whose `apiKey` references an unset explicit environment variable so their models are omitted from `/model`, `--list-models`, available-model RPC responses, and automatic fallback candidates until the environment variable is configured.
|
|
18
|
+
- Fixed bash/child-process output draining so late stdout/stderr arriving after process exit continues draining while active, quiet inherited pipes release promptly, endlessly noisy detached descendants are bounded by a longer active-drain cap, and the built-in `bash` tool ignores output after its result accumulator has been finalized.
|
|
19
|
+
- Fixed npm package source resolution to re-resolve and re-validate the managed install path after installing a configured semver range, preventing stale legacy global package copies from being loaded.
|
|
20
|
+
- Fixed explicit npm dist-tag package sources such as `npm:pkg@beta` and `npm:pkg@latest` so online resolution verifies installed copies against the resolved registry target before accepting them, while offline resolution keeps already-installed tag-based resources usable without attempting registry or install work.
|
|
21
|
+
- Fixed interactive shutdown ordering so SIGTERM/SIGHUP-triggered exits keep signal handlers installed until terminal cleanup and extension `session_shutdown` disposal finish, preventing terminal restoration from being skipped during signal-exit handling.
|
|
22
|
+
- Fixed first-run theme selection to query the terminal OSC 11 background color before falling back to `COLORFGBG`, persist high-confidence auto-detected dark/light themes, and wrap `/tree` help rows by semantic chunks instead of truncating keybinding hints.
|
|
23
|
+
- Fixed release publishing to generate and upload a `SHA256SUMS` asset alongside the six Atomic binary archives.
|
|
24
|
+
- Fixed workflow stages launched from workflows discovered through `atomic -e` to inherit the parent chat's custom resource-loading snapshot (extensions/tools, subagents and agent definitions, skills, prompt templates, themes, workflows, packages, and trusted borrowed project-local resources) without sharing the parent resource-loader instance.
|
|
25
|
+
- Fixed context compaction recent-entry and id-only deletion guards so `context_delete` attempts against disallowed context entries now return explicit non-terminating correction errors, exact deletion payloads with transcript text or replacement content are rejected instead of ignored, `context_grep_delete` silently ignores rejected matches while deleting allowed matches without counting rejected blocks as removals, and `context_grep_delete` keeps `maxMatches` scoped to one tool call without adding any cumulative deletion cap.
|
|
26
|
+
- Fixed bundled workflow and subagent structured-output gates to recover from missing or invalid `structured_output` final answers by issuing up to three corrective retries that echo the actual contract or schema-validation error before failing.
|
|
27
|
+
- Fixed bundled workflow failed-stage metadata so error-stage transcripts remain discoverable and follow-up messaging resumes from the failed conversation instead of resetting to an empty session.
|
|
28
|
+
- Fixed context compaction so older assistant `thinking` and `redacted_thinking` blocks can be removed like other stale blocks, while `thinking` or `redacted_thinking` blocks in the latest assistant message remain rejected by validation and paired tool-result restoration still preserves active context integrity ([#1386](https://github.com/bastani-inc/atomic/issues/1386)).
|
|
29
|
+
|
|
30
|
+
## [0.8.29] - 2026-06-15
|
|
31
|
+
|
|
5
32
|
### Added
|
|
6
33
|
|
|
7
34
|
- Added support for local `-e <dir>` extension sources to borrow project-local Atomic resources from `<dir>/.atomic`, legacy `<dir>/.pi`, and `<dir>/.agents/skills` after resolving trust for that extension source, preserving package-manager provenance and explicit-path workflow forwarding while avoiding untrusted borrowed resources ([#1354](https://github.com/bastani-inc/atomic/issues/1354)).
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Published a synchronized Atomic 0.8.30-alpha.1 prerelease; no functional Cursor provider changes were made after 0.8.29.
|
|
8
|
+
|
|
9
|
+
## [0.8.29] - 2026-06-15
|
|
10
|
+
|
|
5
11
|
### Added
|
|
6
12
|
|
|
7
13
|
- Added a prototype Rust/N-API HTTP/2 native binding and loader so the Cursor transport uses the generated `@bastani/atomic-natives` NAPI-RS package without requiring Node.js on `PATH`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/cursor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Experimental first-party Atomic extension for Cursor OAuth, model discovery, and streaming provider registration.",
|
|
6
6
|
"contributors": [
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@bastani/atomic-natives": "0.8.
|
|
43
|
+
"@bastani/atomic-natives": "0.8.30-alpha.1",
|
|
44
44
|
"@bufbuild/protobuf": "^2.0.0"
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -6,7 +6,13 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
|
|
|
6
6
|
|
|
7
7
|
### Changed
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- Aligned the intercom extension peer dependency with upstream pi TUI `^0.79.4`; no intercom extension code changes were made.
|
|
10
|
+
|
|
11
|
+
## [0.8.29] - 2026-06-15
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Published a synchronized Atomic 0.8.29 stable release with the upstream pi TUI dependency aligned to `^0.79.3`; no functional changes were made in the intercom extension.
|
|
10
16
|
|
|
11
17
|
## [0.8.28] - 2026-06-11
|
|
12
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30-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": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@bastani/atomic": "*",
|
|
42
|
-
"@earendil-works/pi-tui": "^0.79.
|
|
42
|
+
"@earendil-works/pi-tui": "^0.79.4"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
45
45
|
"@bastani/atomic": {
|
|
@@ -9,7 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
|
-
-
|
|
12
|
+
- Aligned the MCP extension peer dependencies with upstream pi AI/TUI `^0.79.4`; no MCP extension code changes were made.
|
|
13
|
+
|
|
14
|
+
## [0.8.29] - 2026-06-15
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Published a synchronized Atomic 0.8.29 stable release with upstream pi AI/TUI dependencies aligned to `^0.79.3`; no functional changes were made in the MCP extension.
|
|
13
19
|
|
|
14
20
|
## [0.8.28] - 2026-06-11
|
|
15
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30-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": [
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@bastani/atomic": "*",
|
|
35
|
-
"@earendil-works/pi-ai": "^0.79.
|
|
36
|
-
"@earendil-works/pi-tui": "^0.79.
|
|
35
|
+
"@earendil-works/pi-ai": "^0.79.4",
|
|
36
|
+
"@earendil-works/pi-tui": "^0.79.4",
|
|
37
37
|
"zod": "^3.25.0 || ^4.0.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
### Changed
|
|
6
6
|
|
|
7
|
+
- Aligned the subagents extension peer dependencies with upstream pi `^0.79.4` runtime packages (`@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui`); no subagents extension code changes were made for this metadata sync.
|
|
8
|
+
- Removed subagent acceptance gates, deterministic task-text acceptance inference, the remaining no-mutation completion guard, acceptance-report prompt injection/parsing, acceptance/completion-guard status metadata, and related tool/schema/config fields; completed child output is now preserved without acceptance or mutation-intent evaluation. Migration guidance now directs users to remove stale acceptance fields from subagent calls/chains/parallel items and move validation requirements into task text; JSON chain rewrites drop legacy acceptance entries ([#1398](https://github.com/bastani-inc/atomic/issues/1398)).
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed `outputSchema` child runs to retry the structured-output contract up to three times before failing, re-running with a corrective prompt that includes the exact missing-output or schema-validation error and validating captured `output.json` against the schema on readback.
|
|
13
|
+
|
|
14
|
+
## [0.8.29] - 2026-06-15
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
7
18
|
- Aligned the subagents extension with upstream pi `^0.79.3` runtime packages (`@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui`) so child sessions inherit the latest shared agent, provider, and TUI compatibility fixes.
|
|
8
19
|
- Changed `outputSchema` child runs to use Atomic's shared `structured_output` factory with direct schema parameters, concise two-line prompt guidance, parent-side `structuredOutput` capture from `output.json`, and auto-allowing the required tool for explicit child tool allowlists ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
9
20
|
- Removed parent-side top-level-object restrictions from child `outputSchema`; any plain JSON Schema object can be passed directly to the `structured_output` tool ([#1350](https://github.com/bastani-inc/atomic/issues/1350)).
|
|
@@ -463,7 +463,6 @@ Important fields:
|
|
|
463
463
|
| `defaultReads` | Files to read before running in chain/parallel behavior. |
|
|
464
464
|
| `defaultProgress` | Maintain `progress.md`. |
|
|
465
465
|
| `interactive` | Parsed for compatibility but not enforced in v1. |
|
|
466
|
-
| `completionGuard` | Set to `false` to intentionally opt this agent out of automatic completion-guard reminders. Use sparingly for user-authored read-only/review agents whose prompt already prevents premature completion. |
|
|
467
466
|
| `maxSubagentDepth` | Tightens nested delegation for this agent’s children. |
|
|
468
467
|
|
|
469
468
|
### Tool and extension selection
|
|
@@ -531,7 +530,7 @@ Create an implementation plan based on {outputs.context}
|
|
|
531
530
|
|
|
532
531
|
Each `.chain.md` `## agent-name` section is a step. Config lines such as `phase`, `label`, `as`, `outputSchema`, `output`, `outputMode`, `reads`, `model`, `skills`, and `progress` go immediately after the header. A blank line separates config from task text. In saved `.chain.md` files, `outputSchema` is a path to a JSON Schema file; direct tool calls and `.chain.json` files can pass the schema object inline.
|
|
533
532
|
|
|
534
|
-
When `outputSchema` is present, the child receives a schema-specific `structured_output` tool backed by Atomic's shared factory. The schema is passed directly to the tool. The child writes the tool arguments to `output.json`, and the parent
|
|
533
|
+
When `outputSchema` is present, the child receives a schema-specific `structured_output` tool backed by Atomic's shared factory. The schema is passed directly to the tool. The child writes the tool arguments to `output.json`, and the parent validates that JSON against the schema before reading it back as `structuredOutput`; Atomic no longer adds object-root restrictions, sidecar metadata, transcript-finality checks, or duplicate-call guards. If the child finishes without calling `structured_output`, or the captured JSON fails schema validation, Atomic retries up to three times with a corrective prompt that includes the exact contract/validation error and reminds the child to call `structured_output` rather than returning plain JSON.
|
|
535
534
|
|
|
536
535
|
Children without `outputSchema` do not receive `structured_output` from Atomic's default tool registry. They can still use a custom extension-provided terminating tool if you explicitly add one.
|
|
537
536
|
|
|
@@ -799,10 +798,10 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
799
798
|
| `outputMode` | `"inline" \| "file-only"` | `inline` | Return saved output inline or as a concise saved-file reference. `file-only` requires an `output` path. |
|
|
800
799
|
| `skill` | `string \| string[] \| false` | agent default | Override skills or disable all. |
|
|
801
800
|
| `model` | string | agent default | Override model. |
|
|
802
|
-
| `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`,
|
|
801
|
+
| `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. |
|
|
803
802
|
| `concurrency` | number | config or `4` | Top-level parallel concurrency. |
|
|
804
803
|
| `worktree` | boolean | false | Create isolated git worktrees for parallel tasks. |
|
|
805
|
-
| `chain` | array | - | Sequential, static parallel, and dynamic fanout chain steps. Steps and chain parallel tasks support `phase`, `label`, `as`,
|
|
804
|
+
| `chain` | array | - | Sequential, static parallel, and dynamic fanout chain steps. Steps and chain parallel tasks support `phase`, `label`, `as`, and `outputSchema` in addition to the usual execution fields. Dynamic fanout uses `expand`, one child `parallel` template, and `collect`. |
|
|
806
805
|
| `context` | `fresh \| fork` | agent default or `fresh` | `fork` creates real branched sessions from the parent leaf. Packaged `planner`, `worker`, and `oracle` default to `fork`. |
|
|
807
806
|
| `chainDir` | string | temp chain dir | Persistent directory for chain artifacts. |
|
|
808
807
|
| `clarify` | boolean | true for chains | Show TUI preview/edit flow. |
|
|
@@ -814,7 +813,6 @@ Agent definitions are not loaded into context by default. Management actions let
|
|
|
814
813
|
| `includeProgress` | boolean | false | Include full progress in result. |
|
|
815
814
|
| `share` | boolean | false | Upload session export to GitHub Gist. |
|
|
816
815
|
| `sessionDir` | string | derived | Override session log directory. |
|
|
817
|
-
| `acceptance` | string/object/false | inferred | Override the run's inferred acceptance gates. Use `"auto"`, `"attested"`, `"checked"`, `"verified"`, `"reviewed"`, or `{ level: "none", reason: "..." }`. |
|
|
818
816
|
|
|
819
817
|
`context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. It never silently downgrades to `fresh`. In multi-agent runs, if any requested agent has `defaultContext: fork` and the launch omits `context`, the whole invocation uses forked context; pass `context: "fresh"` when you intentionally want a fresh run.
|
|
820
818
|
|
|
@@ -990,35 +988,17 @@ Async runs write:
|
|
|
990
988
|
|
|
991
989
|
`status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
|
|
992
990
|
|
|
993
|
-
##
|
|
991
|
+
## Completion and output
|
|
994
992
|
|
|
995
|
-
|
|
993
|
+
Subagent runs no longer inject acceptance gate prompts, infer task policies from text, parse `acceptance-report` blocks, or reject completed children for missing acceptance evidence. Child output is preserved as returned, including any literal fenced block named `acceptance-report`. Parent sessions remain responsible for deciding whether the returned work is sufficient.
|
|
996
994
|
|
|
997
|
-
|
|
998
|
-
{
|
|
999
|
-
agent: "worker",
|
|
1000
|
-
task: "Implement the fix",
|
|
1001
|
-
acceptance: {
|
|
1002
|
-
level: "verified",
|
|
1003
|
-
criteria: ["Patch the bug without widening scope"],
|
|
1004
|
-
evidence: ["changed-files", "tests-added", "commands-run", "residual-risks", "no-staged-files"],
|
|
1005
|
-
verify: [{ id: "focused", command: "npm test", timeoutMs: 120000 }]
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
```
|
|
1009
|
-
|
|
1010
|
-
Accepted levels are `auto`, `none`, `attested`, `checked`, `verified`, and `reviewed`. `acceptance: "auto"` is the default. Read-only reviewer/scout tasks infer lightweight attestation, normal writer tasks infer checked evidence, and async/risky/dynamic writer contexts infer a reviewed gate. To disable gates, prefer `{ level: "none", reason: "..." }`.
|
|
1011
|
-
|
|
1012
|
-
Acceptance provenance is stored separately from child prose:
|
|
995
|
+
### Migration from acceptance gates
|
|
1013
996
|
|
|
1014
|
-
|
|
1015
|
-
- `attested`: child returned a structured acceptance report.
|
|
1016
|
-
- `checked`: runtime structural checks passed, such as required evidence and no staged files.
|
|
1017
|
-
- `verified`: configured runtime verification commands passed. Child-reported command success does not count.
|
|
1018
|
-
- `reviewed`: an independent reviewer result is present.
|
|
1019
|
-
- `rejected`: attestation, structural checks, verification, or review failed.
|
|
997
|
+
For existing subagent integrations and saved definitions:
|
|
1020
998
|
|
|
1021
|
-
|
|
999
|
+
- Remove `acceptance` properties from `subagent()` calls, top-level `tasks` items, `chain` steps, static parallel task items, and dynamic fanout parallel templates. The fields are no longer read; JSON chain rewrites drop legacy copies.
|
|
1000
|
+
- Remove `completionGuard: false` from agent frontmatter or custom agent definitions. The completion guard no longer exists, so the override has no effect and management rewrites strip it.
|
|
1001
|
+
- Put validation, command, evidence, review, or residual-risk requirements directly in the task text you pass to the parent or child agent.
|
|
1022
1002
|
|
|
1023
1003
|
## Live progress
|
|
1024
1004
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/subagents",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification. Fork of: https://github.com/nicobailon/pi-subagents",
|
|
6
6
|
"contributors": [
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@bastani/atomic": "*",
|
|
41
|
-
"@earendil-works/pi-agent-core": "^0.79.
|
|
42
|
-
"@earendil-works/pi-ai": "^0.79.
|
|
43
|
-
"@earendil-works/pi-tui": "^0.79.
|
|
41
|
+
"@earendil-works/pi-agent-core": "^0.79.4",
|
|
42
|
+
"@earendil-works/pi-ai": "^0.79.4",
|
|
43
|
+
"@earendil-works/pi-tui": "^0.79.4"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"@bastani/atomic": {
|
|
@@ -615,7 +615,7 @@ When you are the orchestrating agent for a new feature or non-trivial change, fa
|
|
|
615
615
|
|
|
616
616
|
Keep builtin agent defaults unless the user explicitly asks for a different model, thinking level, skills, output behavior, context mode, or other override. Do not add overrides just because you are orchestrating; the defaults encode the intended role behavior.
|
|
617
617
|
|
|
618
|
-
When the user approves launching a subagent to carry out a workflow, treat that as approval to generate a proper role-specific meta prompt for that subagent. Include the approved plan path or summary, clarified requirements, non-goals, relevant context, role boundaries, files or areas to inspect,
|
|
618
|
+
When the user approves launching a subagent to carry out a workflow, treat that as approval to generate a proper role-specific meta prompt for that subagent. Include the approved plan path or summary, clarified requirements, non-goals, relevant context, role boundaries, files or areas to inspect, completion criteria, expected output, and validation expectations. Do not pass vague instructions like "implement the change fully" or "review this" by themselves.
|
|
619
619
|
|
|
620
620
|
- `/gather-context-and-clarify` maps to: launch locator/analyzer/research specialists; synthesize findings; then use `interview` to ask every clarification question needed for shared understanding.
|
|
621
621
|
- `/parallel-review` maps to: launch fresh-context specialist reviewers with distinct review angles; synthesize the feedback before applying anything.
|
|
@@ -631,20 +631,18 @@ For feature work, use this sequence as scaffolding for parent-agent behavior:
|
|
|
631
631
|
clarify → validation contract → parallel discovery → async writer (debugger or code-simplifier) → parallel async fresh-context specialist reviewers → async fix writer → follow-up review when warranted → parent review
|
|
632
632
|
```
|
|
633
633
|
|
|
634
|
-
The validation contract defines
|
|
635
|
-
|
|
636
|
-
Use the structured `acceptance` field when the run should carry an explicit acceptance contract. If omitted, subagents infer an effective acceptance policy from role, mode, and risk. Use `level: "checked"` for ordinary writer evidence gates, `level: "verified"` when the runtime should run explicit validation commands, and `level: "reviewed"` only when an independent reviewer result is expected. Do not call a run reviewed just because the writer says it is done; reviewed means a reviewer gate returned a result. Child-reported command success is evidence, not runtime verification.
|
|
634
|
+
The validation contract defines completion before code is written: expected behavior, checks, commands or user flows to exercise, and evidence the writer should return. Keep it lightweight for small tasks, but make it explicit enough that reviewers and validators are checking the intended outcome rather than the writer’s own assumptions. Subagent runs do not carry a structured `acceptance` field, infer acceptance policies, inject acceptance-report prompts, or run acceptance gates; put any evidence requirements directly in the task text. Do not set removed acceptance config fields on `subagent()` calls, chain steps, parallel task items, or agent frontmatter; move those requirements into the assigned task text instead.
|
|
637
635
|
|
|
638
636
|
The first writer implements the approved change. The parent continues with independent inspection or validation prep while it runs, not parallel edits to the same worktree. When the async writer completes, treat its handoff as the transition into review, not as final completion, unless the user explicitly asked for writer-only work, review-only output, or to stop after implementation. Parallel specialist reviewers inspect the resulting diff from fresh context. The final fix writer applies synthesized review fixes, then the parent looks over the final diff before completing. The parent may launch these steps as an initial async chain when the workflow is already clear, or as follow-up subagent runs after each async completion. Initial chains should pass `async: true` so the main chat is unblocked; avoid `clarify: true` unless the user asked for foreground clarification. Do not stop after parallel review unless the user explicitly asked for review-only output or the review surfaced a decision that needs approval first.
|
|
639
637
|
|
|
640
638
|
For complex work, risky changes, broad refactors, or many changed lines, increase review and validation fanout rather than trusting one reviewer. Use distinct angles such as correctness/regressions (`codebase-analyzer`), failure-mode hunt (`debugger` inspect-only), pattern fit (`codebase-pattern-finder`), prior-decision conformance (`codebase-research-*`), and external-spec conformance (`codebase-online-researcher`). When reviewers find non-trivial issues or the fix writer touches many lines, run another focused review round before final validation.
|
|
641
639
|
|
|
642
|
-
For very large work, split into serial milestones instead of launching a swarm of writers. Each milestone gets one writer, a validation contract, fresh-context review, a fix pass, and parent
|
|
640
|
+
For very large work, split into serial milestones instead of launching a swarm of writers. Each milestone gets one writer, a validation contract, fresh-context review, a fix pass, and parent approval before the next milestone starts. Use parallel subagents inside a milestone for read-only context, research, and review only.
|
|
643
641
|
|
|
644
642
|
Keep orchestration authority in the parent session. Child subagents should not launch more subagents, read this skill, or run their own orchestration loops unless the parent intentionally selected an explicit fanout agent whose resolved builtin `tools` includes `subagent` for that assigned fanout. Spawned non-fanout subagents do not receive the `subagent` skill, parent-only status/control/slash messages, prior parent `subagent` tool-call/tool-result artifacts, or the `subagent` extension tool. Child context filtering also strips old hidden orchestration-instruction messages when they appear in inherited history. Every child also receives a boundary instruction that says the parent owns orchestration, the child must not propose or run subagents unless explicitly authorized for fanout, and writer children must call real edit/write tools instead of printing pseudo tool calls. Pass children concrete role-specific work instead.
|
|
645
643
|
|
|
646
|
-
1. Clarify first. This is mandatory. Gather code context with `codebase-locator`, `codebase-analyzer`, `codebase-pattern-finder`, and prior research specialists; add `codebase-online-researcher` only when external evidence matters; then ask the user clarifying questions with `interview` until scope,
|
|
647
|
-
2. Define the validation contract. State
|
|
644
|
+
1. Clarify first. This is mandatory. Gather code context with `codebase-locator`, `codebase-analyzer`, `codebase-pattern-finder`, and prior research specialists; add `codebase-online-researcher` only when external evidence matters; then ask the user clarifying questions with `interview` until scope, completion criteria, constraints, and non-goals are clear.
|
|
645
|
+
2. Define the validation contract. State completion expectations before implementation: expected behavior, checks to run, user flows to exercise, and evidence required in the writer handoff. For UI, CLI, integration, or workflow changes, include at least one validator angle that uses the product the way a user would rather than only reading code.
|
|
648
646
|
3. Plan when useful. For complex work, write a plan doc yourself and get approval before implementation. For simple work, confirm shared understanding and explicitly note why planning is skipped.
|
|
649
647
|
4. Implement with one writer. After approval, launch `debugger` (for correctness-shaped work) or `code-simplifier` (for refinement-shaped work) asynchronously with a proper meta prompt that includes clarified requirements, relevant context, plan path or summary, the validation contract, and output expectations. While it runs, prepare validation or inspect adjacent code instead of editing the same worktree.
|
|
650
648
|
5. Require a useful writer handoff. Ask the writer to report changed files, what was implemented, what was left undone, commands run with exit codes, validation evidence, surprises or new risks, decisions made inside approved scope, and decisions needing parent approval.
|
|
@@ -659,10 +657,6 @@ Example writer handoff after clarification and optional planning:
|
|
|
659
657
|
subagent({
|
|
660
658
|
agent: "debugger",
|
|
661
659
|
task: "Implement the approved fix.\n\nClarified requirements:\n- ...\n\nPlan: see ~/Documents/docs/...-plan.md\n\nValidation contract:\n- ...\n\nReturn a handoff with changed files, what was implemented, what was left undone, commands run with exit codes, validation evidence, surprises/new risks, and decisions needing parent approval.",
|
|
662
|
-
acceptance: {
|
|
663
|
-
level: "checked",
|
|
664
|
-
evidence: ["changed-files", "tests-added", "commands-run", "residual-risks", "no-staged-files"]
|
|
665
|
-
},
|
|
666
660
|
async: true
|
|
667
661
|
})
|
|
668
662
|
```
|
|
@@ -334,10 +334,6 @@ function applyAgentConfig(target: AgentConfig, cfg: Record<string, unknown>): st
|
|
|
334
334
|
target.maxSubagentDepth = cfg.maxSubagentDepth;
|
|
335
335
|
} else return "config.maxSubagentDepth must be an integer >= 0 or false when provided.";
|
|
336
336
|
}
|
|
337
|
-
if (hasKey(cfg, "completionGuard")) {
|
|
338
|
-
if (typeof cfg.completionGuard !== "boolean") return "config.completionGuard must be a boolean when provided.";
|
|
339
|
-
target.completionGuard = cfg.completionGuard;
|
|
340
|
-
}
|
|
341
337
|
return undefined;
|
|
342
338
|
}
|
|
343
339
|
|
|
@@ -413,7 +409,6 @@ function formatAgentDetail(agent: AgentConfig): string {
|
|
|
413
409
|
if (agent.defaultReads?.length) lines.push(`Reads: ${agent.defaultReads.join(", ")}`);
|
|
414
410
|
if (agent.defaultProgress) lines.push("Progress: true");
|
|
415
411
|
if (agent.maxSubagentDepth !== undefined) lines.push(`Max subagent depth: ${agent.maxSubagentDepth}`);
|
|
416
|
-
if (agent.completionGuard === false) lines.push("Completion guard: false");
|
|
417
412
|
if (agent.systemPrompt.trim()) lines.push("", "System Prompt:", agent.systemPrompt);
|
|
418
413
|
return lines.join("\n");
|
|
419
414
|
}
|
|
@@ -22,9 +22,14 @@ export const KNOWN_FIELDS = new Set([
|
|
|
22
22
|
"defaultProgress",
|
|
23
23
|
"interactive",
|
|
24
24
|
"maxSubagentDepth",
|
|
25
|
-
"completionGuard",
|
|
26
25
|
]);
|
|
27
26
|
|
|
27
|
+
const REMOVED_AGENT_FRONTMATTER_FIELDS = new Set<string>([`completion${"Guard"}`]);
|
|
28
|
+
|
|
29
|
+
export function shouldPreserveAgentExtraField(key: string): boolean {
|
|
30
|
+
return !KNOWN_FIELDS.has(key) && !REMOVED_AGENT_FRONTMATTER_FIELDS.has(key);
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
function joinComma(values: string[] | undefined): string | undefined {
|
|
29
34
|
if (!values || values.length === 0) return undefined;
|
|
30
35
|
return values.join(", ");
|
|
@@ -74,11 +79,10 @@ export function serializeAgent(config: AgentConfig): string {
|
|
|
74
79
|
if (typeof maxSubagentDepth === "number" && Number.isInteger(maxSubagentDepth) && maxSubagentDepth >= 0) {
|
|
75
80
|
lines.push(`maxSubagentDepth: ${maxSubagentDepth}`);
|
|
76
81
|
}
|
|
77
|
-
if (config.completionGuard === false) lines.push("completionGuard: false");
|
|
78
82
|
|
|
79
83
|
if (config.extraFields) {
|
|
80
84
|
for (const [key, value] of Object.entries(config.extraFields)) {
|
|
81
|
-
if (
|
|
85
|
+
if (!shouldPreserveAgentExtraField(key)) continue;
|
|
82
86
|
lines.push(`${key}: ${value}`);
|
|
83
87
|
}
|
|
84
88
|
}
|
|
@@ -7,8 +7,8 @@ import * as os from "node:os";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { CONFIG_DIR_NAME, getAgentConfigPaths, getEnvValue, getProjectConfigDirs } from "@bastani/atomic";
|
|
10
|
-
import type {
|
|
11
|
-
import {
|
|
10
|
+
import type { OutputMode } from "../shared/types.ts";
|
|
11
|
+
import { shouldPreserveAgentExtraField } from "./agent-serializer.ts";
|
|
12
12
|
import { parseChain, parseJsonChain } from "./chain-serializer.ts";
|
|
13
13
|
import { mergeAgentsForScope } from "./agent-selection.ts";
|
|
14
14
|
import { parseFrontmatter } from "./frontmatter.ts";
|
|
@@ -47,7 +47,6 @@ export interface BuiltinAgentOverrideBase {
|
|
|
47
47
|
skills?: string[];
|
|
48
48
|
tools?: string[];
|
|
49
49
|
mcpDirectTools?: string[];
|
|
50
|
-
completionGuard?: boolean;
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
interface BuiltinAgentOverrideConfig {
|
|
@@ -63,7 +62,6 @@ interface BuiltinAgentOverrideConfig {
|
|
|
63
62
|
systemPrompt?: string;
|
|
64
63
|
skills?: string[] | false;
|
|
65
64
|
tools?: string[] | false;
|
|
66
|
-
completionGuard?: boolean;
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
interface BuiltinAgentOverrideInfo {
|
|
@@ -97,7 +95,6 @@ export interface AgentConfig {
|
|
|
97
95
|
defaultProgress?: boolean;
|
|
98
96
|
interactive?: boolean;
|
|
99
97
|
maxSubagentDepth?: number;
|
|
100
|
-
completionGuard?: boolean;
|
|
101
98
|
disabled?: boolean;
|
|
102
99
|
extraFields?: Record<string, string>;
|
|
103
100
|
override?: BuiltinAgentOverrideInfo;
|
|
@@ -129,7 +126,6 @@ export interface ChainStepConfig {
|
|
|
129
126
|
concurrency?: number;
|
|
130
127
|
failFast?: boolean;
|
|
131
128
|
worktree?: boolean;
|
|
132
|
-
acceptance?: AcceptanceInput;
|
|
133
129
|
}
|
|
134
130
|
|
|
135
131
|
export interface ChainConfig {
|
|
@@ -215,7 +211,6 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
215
211
|
skills: agent.skills ? [...agent.skills] : undefined,
|
|
216
212
|
tools: agent.tools ? [...agent.tools] : undefined,
|
|
217
213
|
mcpDirectTools: agent.mcpDirectTools ? [...agent.mcpDirectTools] : undefined,
|
|
218
|
-
completionGuard: agent.completionGuard,
|
|
219
214
|
};
|
|
220
215
|
}
|
|
221
216
|
|
|
@@ -237,7 +232,6 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
|
|
|
237
232
|
...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),
|
|
238
233
|
...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),
|
|
239
234
|
...(override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {}),
|
|
240
|
-
...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),
|
|
241
235
|
};
|
|
242
236
|
}
|
|
243
237
|
|
|
@@ -383,14 +377,6 @@ function parseBuiltinOverrideEntry(
|
|
|
383
377
|
}
|
|
384
378
|
}
|
|
385
379
|
|
|
386
|
-
if ("completionGuard" in input) {
|
|
387
|
-
if (typeof input.completionGuard === "boolean") {
|
|
388
|
-
override.completionGuard = input.completionGuard;
|
|
389
|
-
} else {
|
|
390
|
-
throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'completionGuard'; expected a boolean.`);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
380
|
if ("systemPrompt" in input) {
|
|
395
381
|
if (typeof input.systemPrompt === "string") override.systemPrompt = input.systemPrompt;
|
|
396
382
|
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPrompt'; expected a string.`);
|
|
@@ -485,7 +471,6 @@ function applyBuiltinOverride(
|
|
|
485
471
|
next.tools = tools;
|
|
486
472
|
next.mcpDirectTools = mcpDirectTools;
|
|
487
473
|
}
|
|
488
|
-
if (override.completionGuard !== undefined) next.completionGuard = override.completionGuard;
|
|
489
474
|
|
|
490
475
|
return next;
|
|
491
476
|
}
|
|
@@ -525,7 +510,7 @@ function applyBuiltinOverrides(
|
|
|
525
510
|
|
|
526
511
|
export function buildBuiltinOverrideConfig(
|
|
527
512
|
base: BuiltinAgentOverrideBase,
|
|
528
|
-
draft: Pick<AgentConfig, "model" | "fallbackModels" | "fallbackThinkingLevels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools"
|
|
513
|
+
draft: Pick<AgentConfig, "model" | "fallbackModels" | "fallbackThinkingLevels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools">,
|
|
529
514
|
): BuiltinAgentOverrideConfig | undefined {
|
|
530
515
|
const override: BuiltinAgentOverrideConfig = {};
|
|
531
516
|
|
|
@@ -544,10 +529,6 @@ export function buildBuiltinOverrideConfig(
|
|
|
544
529
|
const baseTools = joinToolList(base);
|
|
545
530
|
const draftTools = joinToolList(draft);
|
|
546
531
|
if (!arraysEqual(draftTools, baseTools)) override.tools = draftTools ? [...draftTools] : false;
|
|
547
|
-
if ((draft.completionGuard !== false) !== (base.completionGuard !== false)) {
|
|
548
|
-
override.completionGuard = draft.completionGuard !== false;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
532
|
return Object.keys(override).length > 0 ? override : undefined;
|
|
552
533
|
}
|
|
553
534
|
|
|
@@ -712,15 +693,10 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
|
712
693
|
|
|
713
694
|
const extraFields: Record<string, string> = {};
|
|
714
695
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
715
|
-
if (
|
|
696
|
+
if (shouldPreserveAgentExtraField(key)) extraFields[key] = value;
|
|
716
697
|
}
|
|
717
698
|
|
|
718
699
|
const parsedMaxSubagentDepth = Number(frontmatter.maxSubagentDepth);
|
|
719
|
-
const completionGuard = frontmatter.completionGuard === "false"
|
|
720
|
-
? false
|
|
721
|
-
: frontmatter.completionGuard === "true"
|
|
722
|
-
? true
|
|
723
|
-
: undefined;
|
|
724
700
|
|
|
725
701
|
agents.push({
|
|
726
702
|
name: runtimeName,
|
|
@@ -750,7 +726,6 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
|
750
726
|
Number.isInteger(parsedMaxSubagentDepth) && parsedMaxSubagentDepth >= 0
|
|
751
727
|
? parsedMaxSubagentDepth
|
|
752
728
|
: undefined,
|
|
753
|
-
completionGuard,
|
|
754
729
|
extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,
|
|
755
730
|
});
|
|
756
731
|
}
|
|
@@ -2,9 +2,31 @@ import type { ChainConfig, ChainStepConfig } from "./agents.ts";
|
|
|
2
2
|
import { buildRuntimeName, frontmatterNameForConfig, parsePackageName } from "./identity.ts";
|
|
3
3
|
import { parseFrontmatter } from "./frontmatter.ts";
|
|
4
4
|
import { ChainOutputValidationError, validateChainOutputBindings } from "../runs/shared/chain-outputs.ts";
|
|
5
|
-
import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
6
5
|
import type { ChainStep } from "../shared/settings.ts";
|
|
7
6
|
|
|
7
|
+
const REMOVED_CHAIN_CONFIG_FIELDS = new Set(["acceptance"]);
|
|
8
|
+
|
|
9
|
+
function stripRemovedChainConfigFields(value: unknown): unknown {
|
|
10
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
11
|
+
const input = value as Record<string, unknown>;
|
|
12
|
+
const output: Record<string, unknown> = {};
|
|
13
|
+
for (const [key, entry] of Object.entries(input)) {
|
|
14
|
+
if (REMOVED_CHAIN_CONFIG_FIELDS.has(key)) continue;
|
|
15
|
+
if (key === "parallel") {
|
|
16
|
+
output[key] = Array.isArray(entry)
|
|
17
|
+
? entry.map((item) => stripRemovedChainConfigFields(item))
|
|
18
|
+
: stripRemovedChainConfigFields(entry);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
output[key] = entry;
|
|
22
|
+
}
|
|
23
|
+
return output;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function stripRemovedChainConfigSteps(steps: readonly unknown[]): ChainStepConfig[] {
|
|
27
|
+
return steps.map((step) => stripRemovedChainConfigFields(step) as ChainStepConfig);
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
function parseStepBody(agent: string, sectionBody: string): ChainStepConfig {
|
|
9
31
|
const lines = sectionBody.split("\n");
|
|
10
32
|
const blankIndex = lines.findIndex((line) => line.trim() === "");
|
|
@@ -150,30 +172,10 @@ export function parseJsonChain(content: string, source: "user" | "project", file
|
|
|
150
172
|
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
151
173
|
throw new Error(`JSON chain '${filePath}' step ${i + 1} must be an object.`);
|
|
152
174
|
}
|
|
153
|
-
const stepRecord = step as Record<string, unknown>;
|
|
154
|
-
const acceptanceErrors = validateAcceptanceInput(stepRecord.acceptance, `step ${i + 1} acceptance`);
|
|
155
|
-
if (acceptanceErrors.length > 0) {
|
|
156
|
-
throw new Error(`Invalid JSON chain '${filePath}': ${acceptanceErrors.join(" ")}`);
|
|
157
|
-
}
|
|
158
|
-
const parallel = stepRecord.parallel;
|
|
159
|
-
if (Array.isArray(parallel)) {
|
|
160
|
-
for (let taskIndex = 0; taskIndex < parallel.length; taskIndex++) {
|
|
161
|
-
const task = parallel[taskIndex];
|
|
162
|
-
if (!task || typeof task !== "object" || Array.isArray(task)) continue;
|
|
163
|
-
const taskErrors = validateAcceptanceInput((task as Record<string, unknown>).acceptance, `step ${i + 1} parallel task ${taskIndex + 1} acceptance`);
|
|
164
|
-
if (taskErrors.length > 0) {
|
|
165
|
-
throw new Error(`Invalid JSON chain '${filePath}': ${taskErrors.join(" ")}`);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
} else if (parallel && typeof parallel === "object") {
|
|
169
|
-
const templateErrors = validateAcceptanceInput((parallel as Record<string, unknown>).acceptance, `step ${i + 1} dynamic template acceptance`);
|
|
170
|
-
if (templateErrors.length > 0) {
|
|
171
|
-
throw new Error(`Invalid JSON chain '${filePath}': ${templateErrors.join(" ")}`);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
175
|
}
|
|
176
|
+
const chainSteps = stripRemovedChainConfigSteps(input.chain);
|
|
175
177
|
try {
|
|
176
|
-
validateChainOutputBindings(
|
|
178
|
+
validateChainOutputBindings(chainSteps as ChainStep[], { maxItems: Number.MAX_SAFE_INTEGER });
|
|
177
179
|
} catch (error) {
|
|
178
180
|
if (error instanceof ChainOutputValidationError) throw new Error(`Invalid JSON chain '${filePath}': ${error.message}`);
|
|
179
181
|
throw error;
|
|
@@ -192,7 +194,7 @@ export function parseJsonChain(content: string, source: "user" | "project", file
|
|
|
192
194
|
description: input.description.trim(),
|
|
193
195
|
source,
|
|
194
196
|
filePath,
|
|
195
|
-
steps:
|
|
197
|
+
steps: chainSteps,
|
|
196
198
|
extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined,
|
|
197
199
|
};
|
|
198
200
|
}
|
|
@@ -201,7 +203,7 @@ export function serializeJsonChain(config: ChainConfig): string {
|
|
|
201
203
|
const root: Record<string, unknown> = {
|
|
202
204
|
name: frontmatterNameForConfig(config),
|
|
203
205
|
description: config.description,
|
|
204
|
-
chain: config.steps,
|
|
206
|
+
chain: stripRemovedChainConfigSteps(config.steps),
|
|
205
207
|
};
|
|
206
208
|
if (config.packageName) root.package = config.packageName;
|
|
207
209
|
if (config.extraFields) {
|