hasAuth() consults $HOME/.env via getEnvApiKey, so a CEREBRAS_API_KEY in the
runner's home .env legitimately armed prewalk and failed the no-auth case.
Force the condition with a hasConfiguredAuth spy.
Flat aggregator ids whose prefix collides with a provider slug (e.g.
openai/gpt-oss-120b hosted on OpenRouter) bypassed the authenticated-model
preference: the explicit-provider branch searched the full catalog only.
Keep provider/id exact references authoritative, but let the flat-id
fallback prefer authenticated providers before catalog order.
A retry-chain entry without its own :level suffix now inherits the
unavailable primary's configured thinking level, matching runtime
fallback-chain semantics. Regression test asserts a level that differs
from the fallback model's default.
- Carried startup-selected fallback role and primary selector into AgentSession.
- Continued remaining role fallback entries after the startup fallback fails.
- Added regression coverage for chained startup failover.
Fixes#6283
Versioned request-header restoration metadata inside v10 cache rows so only markers written by the old id-only matcher can bypass an unrestorable marker through requestModelId. Current aliases whose live headers differ from their static base remain unresolved and are refetched or dropped.
Added catalog and startup-registry regressions for custom-header aliases while preserving legacy Copilot -1m cache recovery.
Fixes#6284
Copilot -1m long-context variants are synthesized with transport
headers and a requestModelId to a bundled base. The v10 cache omits
headers; the writer only matched a same-id static entry, so these
variants were flagged unrestorable and dropped on the next offline
read, vanishing from the picker with a "Could not restore model"
warning. The startup registry loader dropped them the same way.
Restore/match headers through requestModelId in the cache writer, the
model-manager restore path, and the coding-agent startup loader, and
bypass a stale unrestorable marker written by the old id-only writer.
Fixes#6284
- Carried configured role identity through deferred CLI model resolution.
- Consulted ordered authenticated role fallbacks after unavailable primaries.
- Added startup regression coverage for missing primary and fallback entries.
Fixes#6283
resolveCodexDiscoveryAccounts now returns null when any stored Codex OAuth
account fails to resolve (e.g. a transient refresh failure), and the manager's
resolveAccounts callback propagates null to skip discovery. Previously a failed
account was silently dropped before unionCodexModels saw it, so the remaining
accounts were unioned and cached as the authoritative catalog, hiding the
failed account's models for the cache TTL. Aborting keeps the previous/bundled
catalog.
Add a ModelRegistry regression test with one refreshable and one failing Codex
account asserting discovery makes no /models call and bundled models survive.
Fixes#6265
Keep the bearer resolved by the discovery preflight when it is not among the
stored OAuth account resolutions. This preserves Codex discovery for env,
runtime/config override, and stored non-OAuth credential sources while still
unioning all configured OAuth account catalogs.
Add a ModelRegistry regression test that drives runtime-key discovery and
asserts the resolved bearer reaches the Codex models endpoint.
Fixes#6265
Serialize queued global saves and remove opportunistically persisted roles from the pending set after a successful write when their value has not changed again. This prevents a redundant follow-up save from replaying stale local values over newer external edits.
Expanded the locked-save regression to externally change the same role after the first write and verify flush leaves that newer disk value intact.
Snapshot model roles when each save starts and merge any newer pending values before replacing the in-memory global settings. This keeps a second model switch intact while an earlier locked save is in flight.
Added a deterministic regression test that blocks the first file-lock operation, changes another role, and verifies both memory and disk.
Global setModelRole marked the whole modelRoles path modified and
saveNow overwrote the freshly re-read disk record with the stale
in-memory map, clobbering concurrent/external per-role edits despite
the re-read intended to preserve them. Track modified global roles
individually and merge only those into the re-read file, mirroring the
project save path.
Fixes#6260
A non-retriable provider error on the continuation turn after a failed
tool result ended the run, but #persistSessionMessageIfMissing dropped
the empty error turn as reload poison, so the session JSONL stopped at
the last tool result and the provider errorMessage was lost with no
durable record of why the run stopped. When retry, model fallback, and
compaction all decline the turn, the non-retry terminal error tail now
persists it via the same helper the retry-lifecycle dead-ends use; the
empty turn stays off the wire on reload via the transform-messages
empty-assistant filter, matching the existing retry-exhaustion path.
Fixes#6249
On a cache-cold interactive launch, a modelRoles.default pointing at a
models.yml discovery provider (openai-models-list) was silently replaced
by an unrelated authenticated provider's default. createAgentSession
resolves the default role before background discovery populates the
catalog, so the configured provider had no models yet and the fallback
fell through to pickDefaultAvailableModel.
Await one cache-aware discovery pass and re-resolve the configured
default whenever it is still unresolved (not only when nothing resolved
at all) before accepting a bundled-provider fallback.
Fixes#6162
Made startup resolution rank configured providers before catalog-only matches while preserving explicit provider pins and catalog fallback behavior.
Added regression coverage for shared bare model IDs across authenticated and unauthenticated providers.
Fixes#6150
Short-circuited session_stop emission when an abort or disposal is already in progress, avoiding extension work whose result cannot be used.
Added deterministic coverage for an abort racing the final settle pass.
Fixes#6134
prewalk.enabled resolved the hand-off target (default @smol) and threw
"No API key for <provider>/<id>" inside buildSessionOptions when the
target had no configured auth, aborting startup and locking the user out
of the app. Prewalk is an optional, off-by-default optimization, so an
unresolvable or unauthorized target now warns and leaves prewalk unarmed
instead of crashing.
Fixes#6064
Merged provider compatibility configuration after dynamic discovery so explicit models.yml fields remain authoritative across refreshes.
Added a regression covering Anthropic unsigned-thinking replay through refreshProvider.
Fixes#6041
- runPrintMode dereferenced session.sessionManager before checking whether
plan.defaultOnStartup was even enabled, crashing partial-session harnesses;
the settings check now short-circuits first.
- Extended the print-mode session fakes with the settings/sessionManager
members every real session provides.
- Scoped the rpc-stdin-lock stderr assertion to non-load-notice lines: the
adversarial fixture's load failure is now legitimately surfaced (#4954)
and mentions the locked stream by design.
Narrow the invalid-yield guard to !abortSent so array-typed incremental
yield sections no longer suppress the infinite-submit-loop abort; add
regression coverage for incremental yield followed by repeated malformed
terminal yields.