@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.
- package/CHANGELOG.md +20 -0
- package/dist/builtin/cursor/CHANGELOG.md +7 -1
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/package.json +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +4 -4
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +12 -0
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +1 -1
- package/dist/builtin/workflows/builtin/goal.ts +2 -2
- package/dist/builtin/workflows/builtin/open-claude-design.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph.ts +61 -11
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +3 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +5 -0
- package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +95 -8
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +11 -0
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +20 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +2 -1
- package/dist/cli/list-models.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +2 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +2 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +17 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +161 -18
- 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 +20 -5
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/context-compaction.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction.js +14 -3
- package/dist/core/compaction/context-compaction.js.map +1 -1
- package/dist/core/context-window.d.ts +29 -0
- package/dist/core/context-window.d.ts.map +1 -0
- package/dist/core/context-window.js +86 -0
- package/dist/core/context-window.js.map +1 -0
- package/dist/core/copilot-errors.d.ts +9 -0
- package/dist/core/copilot-errors.d.ts.map +1 -0
- package/dist/core/copilot-errors.js +32 -0
- package/dist/core/copilot-errors.js.map +1 -0
- package/dist/core/copilot-model-catalog.d.ts +132 -0
- package/dist/core/copilot-model-catalog.d.ts.map +1 -0
- package/dist/core/copilot-model-catalog.js +254 -0
- package/dist/core/copilot-model-catalog.js.map +1 -0
- package/dist/core/export-html/template.js +10 -1
- package/dist/core/extensions/types.d.ts +3 -1
- 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 +10 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +107 -4
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-attribution.js +17 -7
- package/dist/core/provider-attribution.js.map +1 -1
- package/dist/core/sdk.d.ts +8 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +47 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +8 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +19 -3
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +69 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +24 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/index.d.ts +1 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/context-window-selector.d.ts +53 -0
- package/dist/modes/interactive/components/context-window-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/context-window-selector.js +136 -0
- package/dist/modes/interactive/components/context-window-selector.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +7 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +91 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +14 -2
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +23 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +30 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +23 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/custom-provider.md +4 -1
- package/docs/json.md +3 -1
- package/docs/models.md +78 -2
- package/docs/providers.md +3 -0
- package/docs/rpc.md +80 -1
- package/docs/sdk.md +23 -3
- package/docs/session-format.md +15 -1
- package/docs/sessions.md +1 -1
- package/docs/settings.md +7 -2
- package/docs/workflows.md +26 -4
- 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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
36
|
-
"@earendil-works/pi-tui": "^0.79.
|
|
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.
|
|
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.
|
|
42
|
-
"@earendil-works/pi-ai": "^0.79.
|
|
43
|
-
"@earendil-works/pi-tui": "^0.79.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
"
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
|
833
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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";
|