@bastani/atomic 0.8.30-alpha.3 → 0.8.31-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +7 -1
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  5. package/dist/builtin/intercom/package.json +2 -2
  6. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  7. package/dist/builtin/mcp/package.json +3 -3
  8. package/dist/builtin/subagents/CHANGELOG.md +6 -0
  9. package/dist/builtin/subagents/package.json +4 -4
  10. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  11. package/dist/builtin/web-access/package.json +2 -2
  12. package/dist/builtin/workflows/CHANGELOG.md +12 -0
  13. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +1 -1
  14. package/dist/builtin/workflows/builtin/goal.ts +2 -2
  15. package/dist/builtin/workflows/builtin/open-claude-design.ts +1 -1
  16. package/dist/builtin/workflows/builtin/ralph.ts +61 -11
  17. package/dist/builtin/workflows/package.json +2 -2
  18. package/dist/builtin/workflows/src/extension/workflow-schema.ts +3 -1
  19. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +5 -0
  20. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +95 -8
  21. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +11 -0
  22. package/dist/cli/args.d.ts +1 -0
  23. package/dist/cli/args.d.ts.map +1 -1
  24. package/dist/cli/args.js +20 -0
  25. package/dist/cli/args.js.map +1 -1
  26. package/dist/cli/list-models.d.ts.map +1 -1
  27. package/dist/cli/list-models.js +2 -1
  28. package/dist/cli/list-models.js.map +1 -1
  29. package/dist/core/agent-session-services.d.ts +2 -0
  30. package/dist/core/agent-session-services.d.ts.map +1 -1
  31. package/dist/core/agent-session-services.js +2 -0
  32. package/dist/core/agent-session-services.js.map +1 -1
  33. package/dist/core/agent-session.d.ts +17 -0
  34. package/dist/core/agent-session.d.ts.map +1 -1
  35. package/dist/core/agent-session.js +161 -18
  36. package/dist/core/agent-session.js.map +1 -1
  37. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  38. package/dist/core/compaction/branch-summarization.js +20 -5
  39. package/dist/core/compaction/branch-summarization.js.map +1 -1
  40. package/dist/core/compaction/context-compaction.d.ts.map +1 -1
  41. package/dist/core/compaction/context-compaction.js +14 -3
  42. package/dist/core/compaction/context-compaction.js.map +1 -1
  43. package/dist/core/context-window.d.ts +29 -0
  44. package/dist/core/context-window.d.ts.map +1 -0
  45. package/dist/core/context-window.js +86 -0
  46. package/dist/core/context-window.js.map +1 -0
  47. package/dist/core/copilot-errors.d.ts +9 -0
  48. package/dist/core/copilot-errors.d.ts.map +1 -0
  49. package/dist/core/copilot-errors.js +32 -0
  50. package/dist/core/copilot-errors.js.map +1 -0
  51. package/dist/core/copilot-model-catalog.d.ts +132 -0
  52. package/dist/core/copilot-model-catalog.d.ts.map +1 -0
  53. package/dist/core/copilot-model-catalog.js +254 -0
  54. package/dist/core/copilot-model-catalog.js.map +1 -0
  55. package/dist/core/export-html/template.js +10 -1
  56. package/dist/core/extensions/types.d.ts +3 -1
  57. package/dist/core/extensions/types.d.ts.map +1 -1
  58. package/dist/core/extensions/types.js.map +1 -1
  59. package/dist/core/model-registry.d.ts +10 -0
  60. package/dist/core/model-registry.d.ts.map +1 -1
  61. package/dist/core/model-registry.js +107 -4
  62. package/dist/core/model-registry.js.map +1 -1
  63. package/dist/core/model-resolver.d.ts.map +1 -1
  64. package/dist/core/model-resolver.js +4 -0
  65. package/dist/core/model-resolver.js.map +1 -1
  66. package/dist/core/provider-attribution.d.ts.map +1 -1
  67. package/dist/core/provider-attribution.js +17 -7
  68. package/dist/core/provider-attribution.js.map +1 -1
  69. package/dist/core/sdk.d.ts +8 -0
  70. package/dist/core/sdk.d.ts.map +1 -1
  71. package/dist/core/sdk.js +47 -0
  72. package/dist/core/sdk.js.map +1 -1
  73. package/dist/core/session-manager.d.ts +8 -1
  74. package/dist/core/session-manager.d.ts.map +1 -1
  75. package/dist/core/session-manager.js +19 -3
  76. package/dist/core/session-manager.js.map +1 -1
  77. package/dist/core/settings-manager.d.ts +6 -0
  78. package/dist/core/settings-manager.d.ts.map +1 -1
  79. package/dist/core/settings-manager.js +69 -0
  80. package/dist/core/settings-manager.js.map +1 -1
  81. package/dist/index.d.ts +2 -1
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +1 -0
  84. package/dist/index.js.map +1 -1
  85. package/dist/main.d.ts.map +1 -1
  86. package/dist/main.js +24 -1
  87. package/dist/main.js.map +1 -1
  88. package/dist/modes/index.d.ts +1 -1
  89. package/dist/modes/index.d.ts.map +1 -1
  90. package/dist/modes/index.js.map +1 -1
  91. package/dist/modes/interactive/components/context-window-selector.d.ts +53 -0
  92. package/dist/modes/interactive/components/context-window-selector.d.ts.map +1 -0
  93. package/dist/modes/interactive/components/context-window-selector.js +136 -0
  94. package/dist/modes/interactive/components/context-window-selector.js.map +1 -0
  95. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  96. package/dist/modes/interactive/components/tree-selector.js +7 -0
  97. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  98. package/dist/modes/interactive/interactive-mode.d.ts +5 -0
  99. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  100. package/dist/modes/interactive/interactive-mode.js +91 -1
  101. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  102. package/dist/modes/rpc/rpc-client.d.ts +14 -2
  103. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  104. package/dist/modes/rpc/rpc-client.js +23 -3
  105. package/dist/modes/rpc/rpc-client.js.map +1 -1
  106. package/dist/modes/rpc/rpc-mode.d.ts +1 -1
  107. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  108. package/dist/modes/rpc/rpc-mode.js +30 -1
  109. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  110. package/dist/modes/rpc/rpc-types.d.ts +23 -0
  111. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  112. package/dist/modes/rpc/rpc-types.js.map +1 -1
  113. package/docs/custom-provider.md +4 -1
  114. package/docs/json.md +3 -1
  115. package/docs/models.md +78 -2
  116. package/docs/providers.md +3 -0
  117. package/docs/rpc.md +80 -1
  118. package/docs/sdk.md +23 -3
  119. package/docs/session-format.md +15 -1
  120. package/docs/sessions.md +1 -1
  121. package/docs/settings.md +7 -2
  122. package/docs/workflows.md +26 -4
  123. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Added
6
+
7
+ - Added configurable context-window support for models that declare `contextWindowOptions`, including explicit `--context-window` CLI/settings control, a GitHub Copilot CLI-style `/model`-flow picker (numbered `Default`/`Long context` tiers with token counts), session replay, SDK/runtime/RPC APIs, and docs while preserving each model's scalar default context window. For GitHub Copilot, context windows are measured in **input (prompt) tokens** (consistent with every other provider) and derived **dynamically from GitHub's live CAPI model catalog** (`GET /models`) instead of a hardcoded model list: Atomic resolves each model's input budget as `max_prompt_tokens || max_context_window_tokens || 128_000` and, for tiered models, exposes the per-tier input budgets (`token_prices.<tier>.context_max`) as a selectable default/long window — gated on the user actually having the GitHub Copilot provider and cached on disk for 30 minutes (for example `github-copilot/gpt-5.5` resolves to `272k` default / `922k` long, and the Claude/Gemini long-context models to `200k` default / `936k` long). Atomic raises the local budget and sends `X-GitHub-Api-Version: 2026-06-01`, while GitHub applies the long-context billing tier server-side by prompt token count. Long-context Copilot requests consume more AI credits and require Copilot long-context/usage-based billing entitlement; offline, unauthenticated, or non-Copilot sessions leave the built-in window untouched and show no picker; custom providers and explicit model overrides can still expose their own selectable windows ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
8
+ - Exported context-window helper functions and types from the package root, including parser/formatter/normalizer/selection utilities and the `Model<Api>` augmentation for `contextWindowOptions`/`defaultContextWindow`, so SDK consumers can use the public API without importing internal source paths ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
9
+ - Added RPC mode runtime context-window commands so headless clients can read supported token budgets with `get_available_context_windows` and select the active runtime budget with `set_context_window` without persisting `defaultContextWindow` settings ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
10
+
11
+ ### Changed
12
+
13
+ - Changed built-in GitHub Copilot context windows to be measured in **input (prompt) tokens** (matching every other provider) and derived from GitHub's live CAPI model catalog (`GET /models`, cached 30 minutes, gated on the Copilot provider) instead of a hardcoded long-context model list, so newly added/removed Copilot models and retiered windows are reflected automatically without shipping a stale snapshot. Each model's window now resolves to `max_prompt_tokens || max_context_window_tokens || 128_000`, and tiered models expose their per-tier input budgets (`token_prices.<tier>.context_max`) as the selectable default/long windows (e.g. `gpt-5.5` 272k/922k, Claude/Gemini 200k/936k) — replacing the previous input+output totals — while preserving custom provider entries and explicit `models.json` overrides and relying on GitHub's API-version header and server-side tier selection rather than payload fields or model-id variants ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
14
+ - Bumped the bundled upstream pi runtime libraries `@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui` from `^0.79.4` to `^0.79.6` so Atomic's installed pi runtime packages pick up upstream v0.79.5/v0.79.6 provider, model, thinking-payload, and shared TUI compatibility fixes; no Atomic coding-agent source changes were made for upstream coding-agent-only marked export or fetch-override behavior in this dependency sync ([#1413](https://github.com/bastani-inc/atomic/issues/1413)).
15
+
16
+ ### Fixed
17
+
18
+ - Fixed a GitHub Copilot context-window warning on restart: after selecting a long-context window (e.g. `claude-opus-4.8` → `936k`) and reopening Atomic, startup validated the persisted selection before the (async, auth-gated) Copilot catalog loaded, so the model still looked limited to its default window and Atomic warned “Context window 936k is not supported… Supported values: 200k” and reset the choice. The model registry now seeds the Copilot context-window catalog synchronously from its on-disk cache at construction (ignoring the refresh TTL, gated on a `github-copilot` credential), so a returning user's selection is recognized immediately while the live refresh still runs in the background ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
19
+ - Fixed context-window startup, session-switch, settings, and RPC edge cases: unknown provider fallback models no longer inherit selectable context-window options from provider defaults, fatal startup diagnostics no longer persist `defaultContextWindow`, `AgentSession.setModel()` preserves an incoming target model's explicit selected context window, model-switch paths that change effective context windows now notify listeners via `context_window_changed`, the interactive context-window picker keys selection on raw token counts so colliding formatted labels never change which window is selected, RPC `set_model` returns the effective post-switch session model, and explicit startup `contextWindow` selections are journaled even when they equal the model scalar default ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
20
+ - Fixed `AgentSession.setContextWindow()` so bare SDK/runtime calls update the active session, append `context_window_change`, and emit `context_window_changed` without persisting `defaultContextWindow`; callers must pass `{ persistDefault: true }` to update settings ([#1409](https://github.com/bastani-inc/atomic/issues/1409)).
21
+ - Fixed `packages/coding-agent` source-CLI subprocess tests (`session-id-readonly`, `startup-session-name`, `stdout-cleanliness`) crashing with `ERR_MODULE_NOT_FOUND` (for example `src/core/tools/oversized-tool-result.js`) when the Vitest worker pool runs under Node. They now launch the TypeScript source CLI with Bun explicitly via a `bunExecutable()` helper (matching `context-window-cli`/`rpc-context-window`) instead of assuming `process.execPath` is Bun, so the package test suite is portable across environments. The repo-wide `.js`->`.ts` source-import convention and shipped `dist/` are unchanged ([#1419](https://github.com/bastani-inc/atomic/issues/1419)).
22
+
23
+ ## [0.8.30] - 2026-06-17
24
+
5
25
  ### Changed
6
26
 
7
27
  - 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.
@@ -4,7 +4,13 @@
4
4
 
5
5
  ### Changed
6
6
 
7
- - Published a synchronized Atomic 0.8.30-alpha.1 prerelease; no functional Cursor provider changes were made after 0.8.29.
7
+ - Published a synchronized Atomic 0.8.31-alpha.1 prerelease; no functional Cursor provider changes were made after 0.8.30.
8
+
9
+ ## [0.8.30] - 2026-06-17
10
+
11
+ ### Changed
12
+
13
+ - Published a synchronized Atomic 0.8.30 stable release; no functional Cursor provider changes were made after 0.8.29.
8
14
 
9
15
  ## [0.8.29] - 2026-06-15
10
16
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/cursor",
3
- "version": "0.8.30-alpha.3",
3
+ "version": "0.8.31-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.30-alpha.3",
43
+ "@bastani/atomic-natives": "0.8.31-alpha.1",
44
44
  "@bufbuild/protobuf": "^2.0.0"
45
45
  }
46
46
  }
@@ -6,6 +6,12 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
6
6
 
7
7
  ### Changed
8
8
 
9
+ - Aligned the intercom extension peer dependency with upstream pi TUI `^0.79.6` so coordination UI surfaces consume the latest shared TUI compatibility fixes; no intercom extension code changes were made for this metadata sync ([#1413](https://github.com/bastani-inc/atomic/issues/1413)).
10
+
11
+ ## [0.8.30] - 2026-06-17
12
+
13
+ ### Changed
14
+
9
15
  - Aligned the intercom extension peer dependency with upstream pi TUI `^0.79.4`; no intercom extension code changes were made.
10
16
 
11
17
  ## [0.8.29] - 2026-06-15
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.8.30-alpha.3",
3
+ "version": "0.8.31-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.4"
42
+ "@earendil-works/pi-tui": "^0.79.6"
43
43
  },
44
44
  "peerDependenciesMeta": {
45
45
  "@bastani/atomic": {
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
+ - Aligned the MCP extension peer dependencies with upstream pi AI/TUI `^0.79.6` so MCP-backed sessions can use the host's latest provider, model, thinking-payload, and shared TUI compatibility fixes; no MCP extension code changes were made for this metadata sync ([#1413](https://github.com/bastani-inc/atomic/issues/1413)).
13
+
14
+ ## [0.8.30] - 2026-06-17
15
+
16
+ ### Changed
17
+
12
18
  - Aligned the MCP extension peer dependencies with upstream pi AI/TUI `^0.79.4`; no MCP extension code changes were made.
13
19
 
14
20
  ## [0.8.29] - 2026-06-15
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.8.30-alpha.3",
3
+ "version": "0.8.31-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.4",
36
- "@earendil-works/pi-tui": "^0.79.4",
35
+ "@earendil-works/pi-ai": "^0.79.6",
36
+ "@earendil-works/pi-tui": "^0.79.6",
37
37
  "zod": "^3.25.0 || ^4.0.0"
38
38
  },
39
39
  "peerDependenciesMeta": {
@@ -4,6 +4,12 @@
4
4
 
5
5
  ### Changed
6
6
 
7
+ - Aligned the subagents extension peer dependencies with upstream pi `^0.79.6` runtime packages (`@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`, and `@earendil-works/pi-tui`) so child sessions can use the host's latest provider, model, thinking-payload, and shared TUI compatibility fixes; no subagents extension code changes were made for this metadata sync ([#1413](https://github.com/bastani-inc/atomic/issues/1413)).
8
+
9
+ ## [0.8.30] - 2026-06-17
10
+
11
+ ### Changed
12
+
7
13
  - 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
14
  - 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
15
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.8.30-alpha.3",
3
+ "version": "0.8.31-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.4",
42
- "@earendil-works/pi-ai": "^0.79.4",
43
- "@earendil-works/pi-tui": "^0.79.4"
41
+ "@earendil-works/pi-agent-core": "^0.79.6",
42
+ "@earendil-works/pi-ai": "^0.79.6",
43
+ "@earendil-works/pi-tui": "^0.79.6"
44
44
  },
45
45
  "peerDependenciesMeta": {
46
46
  "@bastani/atomic": {
@@ -6,6 +6,12 @@ All notable changes to this project will be documented in this file.
6
6
 
7
7
  ### Changed
8
8
 
9
+ - Aligned the web-access extension peer dependency with upstream pi TUI `^0.79.6` so web-access curator and summary UI surfaces consume the latest shared TUI compatibility fixes; no web-access extension code changes were made for this metadata sync ([#1413](https://github.com/bastani-inc/atomic/issues/1413)).
10
+
11
+ ## [0.8.30] - 2026-06-17
12
+
13
+ ### Changed
14
+
9
15
  - Aligned the web-access extension peer dependency with upstream pi TUI `^0.79.4`; no web-access extension code changes were made.
10
16
 
11
17
  ## [0.8.29] - 2026-06-15
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.8.30-alpha.3",
3
+ "version": "0.8.31-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@bastani/atomic": "*",
33
- "@earendil-works/pi-tui": "^0.79.4"
33
+ "@earendil-works/pi-tui": "^0.79.6"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@bastani/atomic": {
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ### Added
10
+
11
+ - Added a per-model context-window authoring token to workflow model strings: a parenthesized size token placed in the model-name portion, *before* the optional `:reasoning` suffix, e.g. `github-copilot/claude-opus-4.8 (1m):xhigh`. Adopting GitHub Copilot's `Claude Opus 4.8 (1M context)` naming convention keeps the window separate from the reasoning level so the two never collide. The token is resolved against the candidate model's advertised windows — an exact match wins, otherwise the largest supported window not exceeding the request (so `(1m)` selects a model's ~936K long-context tier), and it falls back to the model's default (short) window when no larger tier is available. It applies only to the candidate that carries the token, leaving primary and other fallback models untouched. Also surfaced `contextWindow`/`contextWindowStrict` on `StageOptions` and the workflow tool's direct-task schema for stage-level selection.
12
+
13
+ ### Changed
14
+
15
+ - Changed the builtin `ralph` workflow review fan-out from two reviewers to three independent reviewers, each running on a different primary model family (Claude Fable 5, GPT-5.5 Codex, and Gemini 3.1 Pro) with shared fallbacks, so the adversarial review gets cross-model coverage instead of repeated passes from one model. The review loop stops only when all three reviewers independently approve (find no issues), so a P0–P3 finding from any single reviewer keeps Ralph iterating instead of being out-voted by a majority quorum. Also strengthened the orchestrator's implementation-notes contract to require verifiable evidence for any claims recorded in the notes and reviewer artifacts.
16
+ - Changed the builtin `deep-research-codebase`, `goal`, `ralph`, and `open-claude-design` workflows to run their GitHub Copilot `claude-opus-4.8` fallbacks at the model's largest advertised long-context (~1M/936K) window via the new `(1m)` token, automatically degrading to the 200K short window when Copilot's long-context tier is unavailable. Other models in each fallback chain are unaffected.
17
+ - Aligned the workflows extension peer dependency with upstream pi TUI `^0.79.6` so workflow graph, custom UI, and prompt-broker integrations consume the latest shared TUI compatibility fixes; no workflows extension code changes were made for this metadata sync ([#1413](https://github.com/bastani-inc/atomic/issues/1413)).
18
+
19
+ ## [0.8.30] - 2026-06-17
20
+
9
21
  ### Changed
10
22
 
11
23
  - Aligned the workflows extension peer dependency with upstream pi TUI `^0.79.4` so workflow graph, custom UI, and prompt-broker integrations consume the latest shared TUI fixes; no workflows extension code changes were made for this metadata sync.
@@ -399,7 +399,7 @@ export default defineWorkflow("deep-research-codebase")
399
399
  "openai-codex/gpt-5.5:xhigh",
400
400
  "github-copilot/gpt-5.5:xhigh",
401
401
  "openai/gpt-5.5:xhigh",
402
- "github-copilot/claude-opus-4.8:xhigh",
402
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
403
403
  "anthropic/claude-opus-4-8:xhigh"
404
404
  ],
405
405
  excludedTools: ["ask_user_question"],
@@ -976,7 +976,7 @@ export default defineWorkflow("goal")
976
976
  fallbackModels: [
977
977
  "github-copilot/gpt-5.5:medium",
978
978
  "openai/gpt-5.5:medium",
979
- "github-copilot/claude-opus-4.8:medium",
979
+ "github-copilot/claude-opus-4.8 (1m):medium",
980
980
  "anthropic/claude-opus-4-8:medium",
981
981
  ],
982
982
  tools: goalRunnerTools,
@@ -988,7 +988,7 @@ export default defineWorkflow("goal")
988
988
  "openai-codex/gpt-5.5:xhigh",
989
989
  "github-copilot/gpt-5.5:xhigh",
990
990
  "openai/gpt-5.5:xhigh",
991
- "github-copilot/claude-opus-4.8:xhigh",
991
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
992
992
  "anthropic/claude-opus-4-8:xhigh"
993
993
  ],
994
994
  tools: goalRunnerTools,
@@ -407,7 +407,7 @@ export default defineWorkflow("open-claude-design")
407
407
  const designModelConfig = {
408
408
  model: "anthropic/claude-fable-5:xhigh",
409
409
  fallbackModels: [
410
- "github-copilot/claude-opus-4.8:xhigh",
410
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
411
411
  "anthropic/claude-opus-4-8:xhigh",
412
412
  "github-copilot/claude-sonnet-4.6:high",
413
413
  "anthropic/claude-sonnet-4-6:high",
@@ -22,6 +22,11 @@ const DEFAULT_MAX_LOOPS = 10;
22
22
  const DEFAULT_RESEARCH_DIR = "research";
23
23
  const IMPLEMENTATION_NOTES_FILENAME = "implementation-notes.md";
24
24
  const MAX_RESEARCH_SLUG_LENGTH = 80;
25
+ // Reviewer fan-out launches three independent reviewers; the loop stops only when
26
+ // all three reviewers independently approve (find no issues). Requiring unanimous
27
+ // approval means a P0–P3 finding from any single reviewer keeps the loop iterating
28
+ // instead of being out-voted by a majority, so lower-severity issues stay surfaced.
29
+ const REVIEWER_COUNT = 3;
25
30
 
26
31
  type ReviewFinding = {
27
32
  readonly title: string;
@@ -376,7 +381,7 @@ function renderForkedOrchestratorPrompt(args: {
376
381
  "implementation_notes",
377
382
  [
378
383
  `Keep updating the running Markdown implementation notes file at: ${args.implementationNotesPath}`,
379
- "Record decisions, research deviations, tradeoffs, blockers, validation outcomes, and anything else the user should know before your final report.",
384
+ "Record decisions, research deviations, tradeoffs, blockers, validation outcomes, and anything else the user should know before your final report. Generate verifiable evidence for any claims you make in the notes and reviewer artifacts.",
380
385
  ].join("\n"),
381
386
  ],
382
387
  ["e2e_verification", E2E_VERIFICATION_GUIDANCE],
@@ -464,7 +469,7 @@ async function runRalphWorkflow(
464
469
  "openai-codex/gpt-5.5:xhigh",
465
470
  "github-copilot/gpt-5.5:xhigh",
466
471
  "openai/gpt-5.5:xhigh",
467
- "github-copilot/claude-opus-4.8:xhigh",
472
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
468
473
  "anthropic/claude-opus-4-8:xhigh"
469
474
  ],
470
475
  noTools: "all" as const,
@@ -475,7 +480,7 @@ async function runRalphWorkflow(
475
480
  fallbackModels: [
476
481
  "github-copilot/gpt-5.5:medium",
477
482
  "openai/gpt-5.5:medium",
478
- "github-copilot/claude-opus-4.8:medium",
483
+ "github-copilot/claude-opus-4.8 (1m):medium",
479
484
  "anthropic/claude-opus-4-8:medium",
480
485
  ],
481
486
  excludedTools: ["ask_user_question"],
@@ -486,19 +491,47 @@ async function runRalphWorkflow(
486
491
  fallbackModels: [
487
492
  "github-copilot/gpt-5.5:medium",
488
493
  "openai/gpt-5.5:medium",
489
- "github-copilot/claude-opus-4.8:medium",
494
+ "github-copilot/claude-opus-4.8 (1m):medium",
490
495
  "anthropic/claude-opus-4-8:medium",
491
496
  ],
492
497
  excludedTools: ["ask_user_question"],
493
498
  };
494
499
 
495
- const reviewerModelConfig = {
500
+ const reviewerAModelConfig = {
496
501
  model: "anthropic/claude-fable-5:xhigh",
497
502
  fallbackModels: [
503
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
504
+ "anthropic/claude-opus-4-8:xhigh",
498
505
  "openai-codex/gpt-5.5:xhigh",
506
+ "github-copilot/gpt-5.5:xhigh",
507
+ "openai/gpt-5.5:xhigh"
508
+ ],
509
+ excludedTools: ["ask_user_question"],
510
+ schema: reviewDecisionSchema,
511
+ };
512
+
513
+ const reviewerBModelConfig = {
514
+ model: "openai-codex/gpt-5.5:xhigh",
515
+ fallbackModels: [
499
516
  "github-copilot/gpt-5.5:xhigh",
500
517
  "openai/gpt-5.5:xhigh",
501
- "github-copilot/claude-opus-4.8:xhigh",
518
+ "anthropic/claude-fable-5:xhigh",
519
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
520
+ "anthropic/claude-opus-4-8:xhigh"
521
+ ],
522
+ excludedTools: ["ask_user_question"],
523
+ schema: reviewDecisionSchema,
524
+ };
525
+
526
+ const reviewerCModelConfig = {
527
+ model: "github-copilot/gemini-3.1-pro-preview (1m):high",
528
+ fallbackModels: [
529
+ "google/gemini-3.1-pro-preview:high",
530
+ "openai-codex/gpt-5.5:xhigh",
531
+ "github-copilot/gpt-5.5:xhigh",
532
+ "openai/gpt-5.5:xhigh",
533
+ "anthropic/claude-fable-5:xhigh",
534
+ "github-copilot/claude-opus-4.8 (1m):xhigh",
502
535
  "anthropic/claude-opus-4-8:xhigh"
503
536
  ],
504
537
  excludedTools: ["ask_user_question"],
@@ -789,7 +822,7 @@ async function runRalphWorkflow(
789
822
  implementationNotesPath,
790
823
  orchestratorReportPath,
791
824
  ],
792
- ...reviewerModelConfig,
825
+ ...reviewerAModelConfig,
793
826
  },
794
827
  {
795
828
  name: "reviewer-b",
@@ -799,7 +832,17 @@ async function runRalphWorkflow(
799
832
  implementationNotesPath,
800
833
  orchestratorReportPath,
801
834
  ],
802
- ...reviewerModelConfig,
835
+ ...reviewerBModelConfig,
836
+ },
837
+ {
838
+ name: "reviewer-c",
839
+ task: reviewPrompt,
840
+ reads: [
841
+ researchPath,
842
+ implementationNotesPath,
843
+ orchestratorReportPath,
844
+ ],
845
+ ...reviewerCModelConfig,
803
846
  },
804
847
  ],
805
848
  {
@@ -828,9 +871,16 @@ async function runRalphWorkflow(
828
871
  });
829
872
  return { reviewer, artifact_path: artifactPath, decision };
830
873
  }));
874
+ const approvalCount = reviewEntries.filter((review) =>
875
+ reviewDecisionApproved(review.decision),
876
+ ).length;
877
+ // Require unanimous approval: every reviewer must have run and independently
878
+ // approved. A fan-out error that collapses to a single error entry (fewer than
879
+ // REVIEWER_COUNT reviews) or any reviewer surfacing a finding keeps the loop
880
+ // iterating rather than letting a majority paper over outstanding issues.
831
881
  approved =
832
- reviewEntries.length > 0 &&
833
- reviewEntries.every((review) => reviewDecisionApproved(review.decision));
882
+ reviewEntries.length === REVIEWER_COUNT &&
883
+ approvalCount === REVIEWER_COUNT;
834
884
  latestReviewReportPath = await writeJsonArtifact(
835
885
  join(artifactDir, `review-round-${iteration}.json`),
836
886
  { iteration, reviews: reviewEntries },
@@ -916,7 +966,7 @@ async function runRalphWorkflow(
916
966
 
917
967
  export default defineWorkflow("ralph")
918
968
  .description(
919
- "Prompt-engineer → research → orchestrate → parallel review loop with bounded iteration.",
969
+ "Prompt-engineer → research → orchestrate → multi-model parallel review loop with bounded iteration.",
920
970
  )
921
971
  .input("prompt", Type.String({ description: "The task or goal to research, execute, and refine." }))
922
972
  .input("max_loops", Type.Number({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.8.30-alpha.3",
3
+ "version": "0.8.31-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -83,7 +83,7 @@
83
83
  },
84
84
  "peerDependencies": {
85
85
  "@bastani/atomic": "*",
86
- "@earendil-works/pi-tui": "^0.79.4"
86
+ "@earendil-works/pi-tui": "^0.79.6"
87
87
  },
88
88
  "peerDependenciesMeta": {
89
89
  "@bastani/atomic": {
@@ -66,7 +66,9 @@ const StageSessionOptionProperties = {
66
66
  agentDir: Type.Optional(Type.String()),
67
67
  authStorage: Type.Optional(SdkSessionOptionSchema("authStorage")),
68
68
  modelRegistry: Type.Optional(SdkSessionOptionSchema("modelRegistry")),
69
- model: Type.Optional(Type.Unsafe<WorkflowModelValue>({ description: "Primary model id or SDK model object. String ids may include a reasoning suffix, e.g. openai/gpt-5:high; valid levels: off|minimal|low|medium|high|xhigh." })),
69
+ model: Type.Optional(Type.Unsafe<WorkflowModelValue>({ description: "Primary model id or SDK model object. String ids may include a reasoning suffix, e.g. openai/gpt-5:high; valid levels: off|minimal|low|medium|high|xhigh. A parenthesized context-window token may precede the suffix, e.g. github-copilot/claude-opus-4.8 (1m):high." })),
70
+ contextWindow: Type.Optional(Type.Number({ description: "Context-window token budget for the stage session (e.g. 1000000). Non-strict by default: an unsupported value keeps the model's default window. Prefer the per-model `(1m)` token in a model/fallbackModels entry when only specific models should use a larger window." })),
71
+ contextWindowStrict: Type.Optional(Type.Boolean({ description: "Treat an unsupported contextWindow as an error instead of falling back to the model's default window." })),
70
72
  thinkingLevel: Type.Optional(SdkSessionOptionSchema("thinkingLevel")),
71
73
  scopedModels: Type.Optional(Type.Array(SdkSessionOptionArrayElementSchema("scopedModels"))),
72
74
  noTools: Type.Optional(Type.Unsafe<NonNullable<CreateAgentSessionOptions["noTools"]>>({
@@ -755,6 +755,11 @@ export function createStageContext(opts: StageRunnerOpts): InternalStageContext
755
755
  ...(effectiveStageOptions ?? {}),
756
756
  model: candidate.value,
757
757
  ...(candidate.reasoningLevel !== undefined ? { thinkingLevel: candidate.reasoningLevel } : {}),
758
+ // A per-candidate context window (parsed from a parenthesized token in
759
+ // the model string) overrides any stage-level contextWindow so only
760
+ // that specific model — e.g. a github-copilot opus fallback — requests
761
+ // its larger window; other candidates keep the stage default.
762
+ ...(candidate.contextWindow !== undefined ? { contextWindow: candidate.contextWindow } : {}),
758
763
  fallbackModels: undefined,
759
764
  fallbackThinkingLevels: undefined,
760
765
  };
@@ -1,3 +1,4 @@
1
+ import { getModelDefaultContextWindow, getSupportedContextWindows, parseContextWindowValue } from "@bastani/atomic";
1
2
  import type { CreateAgentSessionOptions } from "@bastani/atomic";
2
3
  import type {
3
4
  WorkflowModelCatalogPort,
@@ -10,14 +11,91 @@ export interface WorkflowResolvedModelCandidate {
10
11
  readonly id: string;
11
12
  readonly value: WorkflowModelValue;
12
13
  readonly reasoningLevel?: WorkflowThinkingLevel;
14
+ /**
15
+ * Resolved context-window token budget for this candidate's session, parsed
16
+ * from a parenthesized authoring token in the model string (e.g.
17
+ * `github-copilot/claude-opus-4.8 (1m):xhigh`). Resolved against the
18
+ * candidate model's advertised windows: an exact match wins, otherwise the
19
+ * largest supported window <= the request (so `(1m)` selects a model's ~936K
20
+ * long-context tier). Left `undefined` when the model exposes no matching
21
+ * window, so the session keeps the model's default (short) window.
22
+ */
23
+ readonly contextWindow?: number;
13
24
  }
14
25
 
15
26
  function makeCandidate(
16
27
  id: string,
17
28
  value: WorkflowModelValue,
18
29
  level: WorkflowThinkingLevel | undefined,
30
+ contextWindow?: number,
19
31
  ): WorkflowResolvedModelCandidate {
20
- return level !== undefined ? { id, value, reasoningLevel: level } : { id, value };
32
+ return {
33
+ id,
34
+ value,
35
+ ...(level !== undefined ? { reasoningLevel: level } : {}),
36
+ ...(contextWindow !== undefined ? { contextWindow } : {}),
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Extract a trailing parenthesized context-window authoring token, e.g. the
42
+ * `(1m)` in `github-copilot/claude-opus-4.8 (1m)`. Mirrors GitHub Copilot's
43
+ * model-name convention (`Claude Opus 4.8 (1M context)`) and intentionally
44
+ * lives in the model-name portion — *not* a `:` suffix — so it never collides
45
+ * with the `:off|minimal|low|medium|high|xhigh` reasoning-level suffix.
46
+ *
47
+ * Parsed with plain string scanning rather than a regular expression so that
48
+ * adversarial model strings (e.g. `(` followed by long whitespace runs) cannot
49
+ * trigger super-linear backtracking (CodeQL js/polynomial-redos).
50
+ */
51
+ function extractContextWindowToken(
52
+ model: string,
53
+ ): { readonly baseModel: string; readonly requestedContextWindow?: number } {
54
+ const trimmedEnd = model.trimEnd();
55
+ if (!trimmedEnd.endsWith(")")) return { baseModel: model };
56
+ const open = trimmedEnd.lastIndexOf("(");
57
+ // Require at least one character before the `(` so a bare `(1m)` is not a model.
58
+ if (open <= 0) return { baseModel: model };
59
+ const inner = trimmedEnd.slice(open + 1, -1);
60
+ // The token must be a single flat `(...)` group with no nested parentheses.
61
+ if (inner.includes("(") || inner.includes(")")) return { baseModel: model };
62
+ const token = inner.trim();
63
+ const baseModel = trimmedEnd.slice(0, open).trim();
64
+ if (token.length === 0 || baseModel.length === 0) return { baseModel: model };
65
+ const parsed = parseContextWindowValue(token);
66
+ // A parenthesized token that does not parse as a context size (e.g. an
67
+ // accidental `(preview)`) is left attached to the model id so the normal
68
+ // "not available" lookup surfaces the typo instead of being silently dropped.
69
+ if (parsed.value === undefined) return { baseModel: model };
70
+ return { baseModel, requestedContextWindow: parsed.value };
71
+ }
72
+
73
+ /**
74
+ * Resolve a requested context-window budget against a candidate model's
75
+ * advertised windows. Returns the exact value when supported, otherwise the
76
+ * largest supported window that does not exceed the request (so `(1m)` lands on
77
+ * a ~936K long-context tier), or `undefined` when nothing fits — in which case
78
+ * the session keeps the model's default window. Model values that are plain
79
+ * strings (not resolved against the live catalog) cannot be introspected and
80
+ * yield `undefined`.
81
+ */
82
+ function resolveRequestedContextWindow(
83
+ value: WorkflowModelValue,
84
+ requested: number,
85
+ ): number | undefined {
86
+ if (typeof value === "string") return undefined;
87
+ const supported = getSupportedContextWindows(value);
88
+ if (supported.length === 0) return undefined;
89
+ const chosen = supported.includes(requested)
90
+ ? requested
91
+ : (() => {
92
+ const atOrBelow = supported.filter((window) => window <= requested);
93
+ return atOrBelow.length > 0 ? Math.max(...atOrBelow) : undefined;
94
+ })();
95
+ if (chosen === undefined) return undefined;
96
+ // Only override when the request actually upgrades past the model's default
97
+ // window; otherwise leave it unset so the session simply keeps its default.
98
+ return chosen === getModelDefaultContextWindow(value) ? undefined : chosen;
21
99
  }
22
100
 
23
101
  const WORKFLOW_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const satisfies readonly WorkflowThinkingLevel[];
@@ -34,7 +112,7 @@ export function splitReasoningSuffix(model: string): { readonly baseModel: strin
34
112
  }
35
113
 
36
114
  function candidateKey(candidate: WorkflowResolvedModelCandidate): string {
37
- return `${candidate.id}::${candidate.reasoningLevel ?? ""}`;
115
+ return `${candidate.id}::${candidate.reasoningLevel ?? ""}::${candidate.contextWindow ?? ""}`;
38
116
  }
39
117
 
40
118
  interface ModelResolutionFailure {
@@ -99,16 +177,25 @@ function resolveStringModel(
99
177
  ): WorkflowResolvedModelCandidate | ModelResolutionFailure {
100
178
  const input = rawInput.trim();
101
179
  if (!input) return { input: rawInput, reason: "empty model id" };
102
- const { baseModel, level } = splitReasoningSuffix(input);
180
+ const { baseModel: afterReasoning, level } = splitReasoningSuffix(input);
181
+ const { baseModel, requestedContextWindow } = extractContextWindowToken(afterReasoning);
182
+
183
+ const candidate = (id: string, value: WorkflowModelValue): WorkflowResolvedModelCandidate =>
184
+ makeCandidate(
185
+ id,
186
+ value,
187
+ level,
188
+ requestedContextWindow === undefined ? undefined : resolveRequestedContextWindow(value, requestedContextWindow),
189
+ );
103
190
 
104
191
  if (availableModels === undefined) {
105
- return makeCandidate(baseModel, baseModel, level);
192
+ return candidate(baseModel, baseModel);
106
193
  }
107
194
 
108
195
  const models = uniqueByFullId(availableModels);
109
196
  const explicit = models.find((model) => model.fullId === baseModel);
110
197
  if (explicit !== undefined) {
111
- return makeCandidate(explicit.fullId, explicit.model ?? explicit.fullId, level);
198
+ return candidate(explicit.fullId, explicit.model ?? explicit.fullId);
112
199
  }
113
200
 
114
201
  if (baseModel.includes("/")) {
@@ -122,7 +209,7 @@ function resolveStringModel(
122
209
  // currentModel — discarding the workflow's defined primary and fallbacks.
123
210
  // Pass it through with the reasoning suffix split off; the runtime fallback
124
211
  // loop skips it only if the SDK genuinely cannot create a session for it.
125
- return makeCandidate(baseModel, baseModel, level);
212
+ return candidate(baseModel, baseModel);
126
213
  }
127
214
 
128
215
  const byBareId = models.filter((model) => model.id === baseModel);
@@ -131,14 +218,14 @@ function resolveStringModel(
131
218
  }
132
219
  if (byBareId.length === 1) {
133
220
  const only = byBareId[0]!;
134
- return makeCandidate(only.fullId, only.model ?? only.fullId, level);
221
+ return candidate(only.fullId, only.model ?? only.fullId);
135
222
  }
136
223
 
137
224
  const preferred = preferredProvider === undefined
138
225
  ? undefined
139
226
  : byBareId.find((model) => model.provider === preferredProvider);
140
227
  if (preferred !== undefined) {
141
- return makeCandidate(preferred.fullId, preferred.model ?? preferred.fullId, level);
228
+ return candidate(preferred.fullId, preferred.model ?? preferred.fullId);
142
229
  }
143
230
 
144
231
  return {
@@ -116,6 +116,17 @@ export interface StageOptions<TSchemaDef extends TSchema | undefined = TSchema |
116
116
  /** Optional structured final-answer schema. When set, the stage receives a schema-specific final-answer tool. */
117
117
  readonly schema?: TSchemaDef;
118
118
  readonly model?: WorkflowModelValue;
119
+ /**
120
+ * Context-window token budget for the stage session. May also be expressed
121
+ * per-model via a parenthesized token in a `model`/`fallbackModels` entry
122
+ * (e.g. `github-copilot/claude-opus-4.8 (1m):xhigh`), which is preferred when
123
+ * only specific fallbacks should use a larger window. Non-strict by default:
124
+ * an unsupported value keeps the model's default window (see
125
+ * `contextWindowStrict`).
126
+ */
127
+ readonly contextWindow?: number;
128
+ /** Treat an unsupported `contextWindow` as an error instead of falling back to the model default. */
129
+ readonly contextWindowStrict?: boolean;
119
130
  readonly mcp?: StageMcpOptions;
120
131
  readonly tools?: readonly string[];
121
132
  readonly noTools?: "all" | "builtin";
@@ -11,6 +11,7 @@ export interface Args {
11
11
  systemPrompt?: string;
12
12
  appendSystemPrompt?: string[];
13
13
  thinking?: ThinkingLevel;
14
+ contextWindow?: number;
14
15
  continue?: boolean;
15
16
  resume?: boolean;
16
17
  help?: boolean;