- Normalized string-array modelRoles values at the settings accessor boundary so existing role resolution paths keep receiving comma-list strings.
- Added regression coverage for resolving pi/task from a YAML-equivalent modelRoles.task list.
Fixes#4492
Use the domestic Zhipu Coding Plan default that the login probe validates and make authenticated Zhipu model discovery authoritative so account-scoped model lists remove unavailable bundled fallbacks.
Fixes#4296
Follow-up on the review: the widened parseThinkingSuffix recognized :auto unconditionally, so parseModelString and extractExplicitThinkingSelector would silently strip a literal provider/model:auto id before the isLiteralModelId guard the :max path already uses.
- Add allowAutoAlias option and require callers to opt in, mirroring allowMaxAlias.
- MAX_THINKING_SUFFIX_OPTIONS enables both aliases; parseModelPatternWithContext still tries exact match first, so a real :auto id wins there too.
- sdk.ts (session restore x2), agent-session.ts (retry fallback selector, context-promotion/compaction targets), and model-registry.ts (normalizeSuppressedSelector) now pass allowAutoAlias: true alongside allowMaxAlias.
- Regressions: literal example/runtime:auto wins over the sentinel in parseModelPattern, parseModelString (with and without isLiteralModelId), resolveModelFromString, and extractExplicitThinkingSelector; auto is still extracted when the id isn't literal.
The model selector's persistence path dropped the `:auto` selector when parsing role values, producing a warning ('Invalid thinking level "auto"') and rendering the badge as `inherit` instead of `auto`. Reload of the default role also lost the auto state whenever the role value carried an explicit `:auto` suffix instead of relying on `defaultThinkingLevel`.
Widen the resolver chain (`parseThinkingSuffix`, `splitThinkingSuffix`, `parseModelString`, `parseModelPattern*`, `ResolvedModelRoleValue`, `ResolvedRoleModel`, `ResolveCliModelResult`) to carry the `AUTO_THINKING` sentinel end to end, and coerce it back to `undefined` at concrete-only boundaries (glob scope patterns, retry fallback, advisor, commit pipeline, guided-goal, bench).
Regression tests cover:
- `resolveModelRoleValue("provider/model:auto")` returns explicit auto without a warning.
- `ModelSelector` renders `DEFAULT (auto)` and `SMOL (auto)` when the role value has `:auto`.
- `cycleRoleModels` activates auto thinking on entering a `:auto` role.
- Startup resume activates auto thinking when `modelRoles.default` carries `:auto`.
Fixes#4128
- Removed the canonical model variant indexing, selection, and tracking logic from the model registry and resolver.
- Eliminated the `canonical` sub-command, tab view, search tokens, and equivalence configuration structures from the CLI and model selector components.
- Refined model identification, lookup, and provider fallback resolution to bind exclusively to standard, raw model IDs.
- Relocated the equivalence utility script within the catalog package to support script-only policy generation.
getOpenRouterRouteSuffix() used strict parseThinkingLevel(), which never
recognizes the max->xhigh alias, so openrouter/<id>:max was consumed as an
OpenRouter route suffix and cloned into a literal <id>:max model id with the
reasoning level dropped. This hit every exact-selector funnel
(parseModelPattern -> resolveCliModel/--model, resolveModelRoleValue/modelRoles
+ model picker, SDK default role) for the dominant aggregator provider.
Exclude max via parseThinkingSuffix(.., MAX_THINKING_SUFFIX_OPTIONS) so the
pattern falls through to the existing max-aware selector split. Literal :max
ids stay safe (none exist under openrouter; nanogpt literals win via exact
lookup before this path). Adds an openrouter/<id>:max regression test.
Kept synthetic Bedrock inference profile ARN models in enabledModels and SDK scope filtering instead of dropping them when returning available models.
Fixes#3004
Resolved Amazon Bedrock application inference profile ARNs through the provider-specific model resolver and routed Bedrock requests to the ARN region.
Fixes#3004
- Removed the Codex-preferred canonical remapping path for exact `provider/id` model matches.
- Resolved explicit `openai/gpt-5.5` references as `openai` provider without redirecting to `openai-codex`.
- Added regression tests to confirm explicit provider/id and enabled-model patterns are not coalesced to Codex.
Limit provider-priority ranking to provider defaults that share the first fallback default id, preserving mixed-provider startup precedence while keeping the OpenAI/Codex tie fix.\n\nFixes #2807
Route stale OpenAI GPT default roles through canonical Codex selection when the catalog prefers the Codex OAuth transport, and rank shared provider defaults by canonical provider priority.\n\nFixes #2807
The routing bypass in matchModel() returned early for any provider whose
post-slash id contained a valid @slug, so fuzzy provider-qualified patterns
over non-aggregator ids that legitimately end in @ (e.g. google-vertex/opus@default
-> claude-opus-4-8@default) resolved to nothing. Gate the bypass on
providerModels.some(supportsUpstreamRouting) so only OpenRouter / Vercel Gateway
short-circuit to the routing fallback. Addresses Codex review feedback on #2710.
Avoided carrying max as an explicit thinking selector from literal provider/model role values while preserving max suffixes on pi role aliases and non-literal selectors.\n\nFixes #2727
Recognized max in provider/model selector parsing where a concrete model lookup can preserve literal :max IDs before falling back to the xhigh alias.\n\nFixes #2727
Recognized max in role aliases, canonical scope expansion, and glob selectors while keeping literal :max model IDs matched before the alias path.\n\nFixes #2727
Prevented provider-scoped fuzzy matching from consuming OpenRouter @upstream selectors whose slug also appears in the model id.
Added resolver coverage for openrouter/deepseek/deepseek-v4-pro@deepseek:high so the upstream routing block and thinking level are both preserved.
Fixes#2708
- model-resolver: removed three resolveAgentModelPatterns cases that pinned exact
priority.json model names (gpt-5.4 / gemini-3 designer list); priority.json now
leads slow with gpt-5.5 and includes gemini-3.5-flash, so the hardcoded lists
were stale. The remaining cases still cover cross-role alias inheritance and
configured-override precedence.
- settings-selector: removed the condition-hidden group-title assertion that
depended on the pre-autolearn memory-tab group layout.
- Resolved retired effort-tier variant ids in `model-resolver.ts` through the hand-table aliases (`resolveVariantAlias`, `resolveBareVariantAlias`) plus the `X-thinking` → `X` grammar (`stripThinkingVariantToken`), with exact matches always winning while a raw id is live and explicit `:effort` suffixes transferring unchanged.
- Re-keyed models.yml `modelOverrides` and rate-limit selector suppressions from raw member ids onto the collapsed model in `model-registry.ts` (`normalizeSuppressedSelector`, lazy `hasLiveModel` checks so live raw ids keep their own overrides).
- Collapsed custom/config provider model lists at registry rebuild via `collapseBuiltModelVariants`, folding config-defined `X`/`X-thinking` twins into one entry.
- Extended `model-registry.test.ts` and `model-resolver.test.ts` with effort-tier variant collapsing and alias-resolution coverage.
Unconfigured pi/designer now follows modelRoles.default before consulting the Gemini priority chain, matching the smol and slow fallback behavior while preserving priority defaults when no default is configured.
Added regression coverage and updated the coding-agent changelog.
Fixes#2336
When modelRoles.default points at another role alias (e.g. "pi/slow") and the inheriting role is unset, the resolver now recurses through resolveConfiguredRolePattern with a visited-role set so downstream one-layer expanders like completion-bridge's resolveTierModel see concrete model patterns instead of pi/<role>. Self-aliased defaults still collapse to the role's built-in priority chain.
Added regression coverage for both cross-role expansion paths.
Fixes#2336
When modelRoles.default points at pi/smol or pi/slow, unset matching roles now expand back to their built-in priority chain instead of returning the alias as a literal model pattern.
Added regression coverage for self-aliased smol and slow defaults.
Fixes#2336
Unconfigured pi/smol and pi/slow role aliases now inherit modelRoles.default before consulting the cloud-priority list, avoiding silent paid-provider routing for local-default setups.
Added resolver coverage for both roles and updated the coding-agent changelog.
Fixes#2336
- Type test registry mocks as CanonicalModelVariant[] (main's catalog split
added canonicalId/selector/source to the variant shape; tsgo failed on the
PR's loose { model } mocks)
- Move the CHANGELOG entry back under [Unreleased] (rebase auto-merge dropped
it into the released 15.10.2 section)
Addresses review feedback on #2044.
When a pattern like "qwen/qwen3-coder:exacto" contains "/" but no
recognised provider prefix, findExactModelReferenceMatch fails (it
treats "qwen" as the provider). Fall through to scan available models
by id so the pattern still matches the openrouter-hosted model.
Adds a regression test covering this case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use parseThinkingLevel to validate :suffix before stripping, so
colon-bearing OpenRouter ids (openrouter/qwen/qwen3-coder:exacto) are
preserved and matched correctly
- Skip glob patterns instead of early-returning, so mixed glob + exact
patterns still apply the exact ones; only-globs falls back to all
- Return [] on no-match (consistent with resolveAllowedModels contract)
instead of the full list, so a typo in enabledModels gives consistent
signals (session fails to start + picker is hidden)
- Remove double blank line (nit)
- Add CHANGELOG entry
- Add OpenRouter regression test and update no-match expectation
getAvailableModels() was calling modelRegistry.getAvailable() directly,
which skips the enabledModels setting. The setting was only applied
during session init to pick the starting model, not to the list
advertised to ACP clients (Zed, etc.).
Add filterAvailableModelsByEnabledPatterns() to model-resolver.ts - a
synchronous subset of resolveAllowedModels() that handles the patterns
used in real configs (exact provider/modelId, canonical ids, bare model
ids, thinking-level suffixes). Glob patterns fall back to showing all
models rather than accidentally emptying the picker.
Update getAvailableModels() to call it, so the ACP model dropdown in
Zed (and any other ACP client) respects the users enabledModels config.
- Replaced minLevel/maxLevel range with explicit efforts array plus baked effortMap/supportsDisplay wire facts.
- Removed runtime enrichment layer and modelOmitsReasoningEffort; providers now read baked fields.
- Fixed dotted Opus 4.7/4.8 ids missing adaptive display via classifier-based predicates (#1373).
- Bumped model cache schema to v4 to invalidate pre-efforts rows.
Route direct model role resolution through the configured pattern normalizer so comma-separated fallbacks are parsed before thinking selectors. Add resolver coverage for preserving :off and trying later entries.\n\nFixes #2228
- Centralized catalog and registry handling on `ModelSpec` and `buildModel`, resolving compatibility at model build time.
- Removed runtime compatibility detectors and switched provider request flows to direct `model.compat` reads.
- Added compat fields (`supportsReasoningParams`, `alwaysSendMaxTokens`, `strictResponsesPairing`, `whenThinking`).
- Persisted explicit compatibility overrides through `compatConfig` in discovery and cache merge paths.
- Added optional FetchImpl fields to compaction, proxy, AI, coding-agent, and mnemopi options.
- Threaded injected fetch implementations through OAuth, discovery, and search/LLM request flows.
- Removed exported hookFetch utility and its package entrypoint from utils.
- Replaced global-fetch test monkeypatching with per-test FetchImpl mocks across test suites.
- Parsed a trailing `@slug` to set OpenRouter `provider.only` or Vercel Gateway routing per invocation.
- Resolved via `parseModelPattern`, composing with thinking levels and round-tripping through selectors.
- Split only when the base resolves to an aggregator, so ids containing `@` stay intact.
- Added first-party-first provider priority defaults for model ranking.
- Consolidated model resolution to use getModelMatchPreferences from session settings.
- Prioritized providerPriorityRank ahead of usage rank when picking preferred models.
- Added second-pass fallback to default-model or API-key-valid matching order.
- Added `toolStrictMode` support with `all_strict`/`none`/`mixed` options to OpenAI compatibility.
- Fixed OpenAI-completion strict-mode flows by capturing failed HTTP responses and retrying once as non-strict.
- Fixed completion error reporting by surfacing captured status, headers, and JSON `type`/`param`/`code` details.
- Improved strict-schema enforcement with WeakMap memoization and circular-schema detection in sanitization.
- Fixed OpenRouter provider lookup by resolving fallback model IDs for suffix and date variants in registry resolution.
- Refactored benchmark tooling and added async RPC error-window tracking for scheduled run execution.
- Added canonical model equivalence types, cache helpers, and registry APIs for provider variant lookup.
- Changed model resolution to apply canonical ID overrides/excludes with provider order before fallback matching.
- Added canonical and provider model views in list-models and selector UI with canonical sorting/persistence.
- Updated role/model persistence to store selectors while runtime now resolves concrete canonical-backed provider models.
- Added designer model role for UI/UX design tasks with Gemini 3.1 Pro as default model.
- Implemented model role fallback list support enabling automatic fallback to next available model when primary is unavailable.
- Refactored model role resolution to support multiple fallback patterns per role with thinking level mapping.
- Updated designer agent to use pi/designer role alias instead of explicit model list, removing spawns configuration.
- Added test coverage for model resolver fallback patterns and designer role override preferences.
- Added test coverage for geminiImageTool X-Title header routing through OpenRouter.
fixes#560
When the CLI input has provider/id format (e.g. zai/glm-5), the exact
match now checks decomposed provider+id first (provider=zai, id=glm-5)
before falling back to flat model.id string match. This prevents
vercel-ai-gateway's 'zai/glm-5' model from winning over the zai
provider's 'glm-5' model due to Array.find catalog ordering.
Keeps getAll() rather than switching to getAvailable() to preserve
the --api-key ephemeral flow, where auth is injected after resolution.
- Added task model role configuration enabling dedicated subtask execution with independent model selection.
- Changed default agent model from 'default' to 'pi/task' for independent subtask model configuration.
- Added single-pattern inheritance fallback allowing pi/task agents to inherit session model when unconfigured.
- Refactored model resolution logic into resolveAgentModelPatterns() function with structured fallback handling.
- Added resolveConfiguredModelPatterns() and helper functions for improved model pattern resolution.
- Introduced Effort enum and ThinkingConfig metadata for per-model reasoning capabilities with min/max effort levels.
- Migrated thinking level API from string-based ThinkingLevel to structured Effort enum across agent and AI packages.
- Added model-thinking module with effort mapping, policy application, and semantic versioning utilities for provider-specific thinking modes.
- Removed supportsXhigh() function and replaced effort clamping with model-aware validation using ThinkingConfig metadata.
- Expanded models.json with thinking configuration objects for 50+ models including Claude, Gemini, and OpenAI variants.
- Added Python analysis scripts for edit tool usage patterns and tool invocation stream processing.
- Added formatRoleThinkingModeLabel helper to display 'inherit' for default thinking mode, preventing badge ambiguity when multiple roles share the same model. Enhanced role menu labels to include role tags for clarity. Fixed model resolver to avoid substring matching that could incorrectly resolve exact model IDs to similar variants.