Commit Graph

82 Commits

Author SHA1 Message Date
enieuwy 77ee3f2e7e fix(task): key subagent fallback chains off the pre-expansion model role
A single-model subagent is pinned to a `subagent:<id>` role whose
`retry.fallbackChains` entry shadows every configured role chain, so the
chain it inherits decides where the child retries. Inheritance resolved
the role by re-deriving it from the child's `modelPatterns` — but every
spawn path expands the role alias into `modelOverride` before calling
`runSubprocess` (`modelPatterns = normalizeModelPatterns(modelOverride ??
agent.model)`), so `@task` never reached the derivation and it returned
`undefined` every time. Every task subagent inherited `chains.default`.

With `modelRoles.task: anthropic/claude-sonnet-5`, `task` chained to
sonnet alone, and `default` chained to sonnet plus a second provider, a
transient stall on sonnet routed the child onto the default chain's
second model — one the operator had deliberately kept out of the `task`
chain — and a quota error there killed a 28-minute run.

#7694 fixed only the shape where an unexpanded alias reaches the
executor, which no production caller produces; its tests supplied a bare
`agent.model: ["@smol"]` with no `modelOverride`. The incident above
happened on v17.2.10, which contains that fix.

Route inheritance off the role identity the spawn path already computes
and passes as `modelRole`. Since that leaves the pattern-derived operand
unreachable, drop it and the parameter it was the only user of.

The vibe worker path had the same defect independently: `#resolveWorker`
expanded `@task`/`@smol` for the bundled `task`/`sonic` workers and kept
no role, so vibe children inherited `default` no matter what the
executor did. It now carries `modelRole` on `ResolvedVibeWorker` and
`VibeRecord` through both the spawn and rehydrate sites.

To stop the two halves drifting apart again — the mistake that caused
this bug — `resolveAgentModelSelection` returns the expanded `patterns`
and the pre-expansion `role` from one call, and both spawn paths take
both from it. `resolveAgentModelSource` is removed: its only use was
being fed to `resolveExplicitModelRole`, and keeping it invites the same
split derivation. `resolveAgentModelPatterns` stays for the UI callers
that legitimately want patterns alone.

Tests cover the producible shapes: the incident's chain layout (role
chain equal to the primary, default chain a superset), role identity
surviving expansion for every alias-routed bundled agent, and the
patterns/role pairing itself. #7694's two tests are re-anchored to a
shape a real caller produces.
2026-08-07 21:16:27 +08:00
Kyle McCleary 8f1de61e9f refactor(coding-agent): densify Agent Hub metrics 2026-08-03 19:42:11 -07:00
roboomp 8191cf41d3 fix(coding-agent): used authenticated registry models by default
Required CLI model registries to expose getAvailable() and used that authenticated
set whenever callers omit availableModels. Deferred SDK and bench/dry-balance
resolution now lets configured roles beat unauthenticated catalog id collisions.

Updated resolver test registries and made the #6508 regression omit the explicit
availableModels option, covering the deferred-caller path from the review.

Fixes #6508
2026-07-24 11:41:58 +00:00
roboomp df0e77c584 fix(coding-agent): honor modelRoles.default over cursor/default catalog id
`resolveCliModel` ran findExactCliModel's unauthenticated catalog fallback
before configured-role resolution, so the bundled `cursor/default` model (bare
id `default`) shadowed a configured `modelRoles.default`. On machines without
Cursor credentials `--model default` failed with `No API key found for cursor`
instead of resolving the configured, authenticated default role.

Defer the catalog fallback: explicit provider/id references and authenticated
bare ids still win over roles, a configured role now beats an unauthenticated
catalog-only id, and the catalog id is still recovered via the trailing fuzzy
fallback when no role matches.

Fixes #6508
2026-07-24 11:30:51 +00:00
can1357 e49426c949 fix(cli): prefer authenticated provider for flat slashful model ids
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.
2026-07-22 21:13:14 +02:00
roboomp 62b47dede8 fix(cli): preferred authenticated provider for bare models
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
2026-07-21 21:50:36 +00:00
Christian Stewart 670304eafa fix(coding-agent): resolve bare model role aliases
Signed-off-by: Christian Stewart <christian@aperture.us>
2026-07-18 03:51:09 -07:00
can1357 a55e4b1a7b fix(model-resolver): preserve fuzzy literal thinking suffixes 2026-07-16 03:32:01 +02:00
can1357 0b6ce1d185 merged PR #5447: fix(model-resolver): strip thinking suffix before fuzzy model match 2026-07-16 03:32:01 +02:00
can1357 425e583ae0 feat(coding-agent): added support for task-agent field and model resolution
- Added schema and type updates for task-agent fields and model resolver settings.
- Extended discovery helper logic to carry resolved task-agent metadata through execution setup.
- Updated task/agent registration and execution paths to use the new capability/field data.
- Expanded test coverage for agent-field parsing, model resolution, and executor prewalk behavior.
2026-07-15 00:50:55 +02:00
roboomp 8dfbe8e09d fix(model-resolver): strip thinking suffix before fuzzy model match
parseModelPatternWithContext ran matchModel on the whole pattern
(including a trailing :level thinking suffix) and only stripped the
suffix if that first pass missed. matchModel's provider-scoped fuzzy
match normalizes colons away and does subsequence matching, so
kimi-for-coding:high matched the longer sibling kimi-for-coding-highspeed
before the suffix was recognized as a thinking level, silently switching
model and billing tier.

Match the full pattern exactly first (new exactOnly mode skips the
fuzzy/substring fallbacks), then strip a valid :level suffix and recurse
before any fuzzy match; fuzzy-match the whole pattern only as a last
resort. Literal ids ending in :max still win via the exact pass.

Fixes #5151
2026-07-14 17:21:19 +00:00
can1357 f9f6ed9e8d feat(coding-agent): replaced legacy pi/ role alias prefix with
- Replaced legacy `pi/` role alias prefix with canonical `@` syntax across model resolution, documentation, and tests.
- Added support for bare `*` default alias and multiple alias prefix detection with custom role resolution in `resolveConfiguredRolePattern()`.
- Enhanced thinking suffix parsing to accept unambiguous abbreviations (minimum 2 characters) for effort and level selectors.
- Extended `resolveCliModel()` and `filterAvailableModelsByEnabledPatterns()` to accept settings parameter for role alias resolution from `--model` flag.
2026-07-13 23:26:33 +02:00
can1357 d435385ab1 feat: introduced max reasoning effort tier across model and rpc systems
- Introduced `Max` as a first-class reasoning effort tier across all packages, including AI providers, coding agent configurations, and RPC protocols.
- Refactored model effort ladders to use wire-exact mappings and removed legacy effort aliasing (e.g., `max-to-xhigh` mapping).
- Updated model registry and provider configurations to support `Max` tier routing, color themes, and UI icon associations.
- Expanded test suites to provide end-to-end coverage for the new reasoning tier, including updated compatibility and fallback scenarios.
2026-07-10 13:39:42 +02:00
roboomp db9cb30763 fix(models): normalized list-valued model roles
- 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
2026-07-04 05:20:55 +00:00
roboomp e009c623d8 fix(catalog): restore zhipu coding plan availability
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
2026-07-02 10:12:13 +00:00
roboomp 9f3e648e5a fix(coding-agent): gated :auto suffix behind allowAutoAlias
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.
2026-07-01 08:30:58 +00:00
roboomp a4ae4c130c fix(coding-agent): preserved explicit :auto suffix in modelRoles
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
2026-07-01 08:18:42 +00:00
can1357 ef7636805b feat(coding-agent): removed canonical model variant selection and tracking
- 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.
2026-07-01 05:22:42 +02:00
can1357 052b6b0c61 Merge PR #3006: fix(providers): accept Bedrock inference profile ARNs (@roboomp) 2026-06-19 17:16:18 +02:00
can1357 3e91783da8 fix(coding-agent): treat openrouter :max suffix as thinking selector
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.
2026-06-19 00:58:52 +02:00
can1357 5d72ce1237 Merge PR #2729: fix(coding-agent): accept max thinking alias (@roboomp)
# Conflicts:
#	packages/coding-agent/test/model-resolver.test.ts
#	packages/coding-agent/test/sdk-model-selection.test.ts
2026-06-19 00:58:52 +02:00
roboomp e956a3f6ba fix(providers): preserved scoped bedrock profile models
Kept synthetic Bedrock inference profile ARN models in enabledModels and SDK scope filtering instead of dropping them when returning available models.

Fixes #3004
2026-06-18 22:12:28 +00:00
roboomp 12f608e0f4 fix(providers): used neutral bedrock profile metadata
Stopped synthetic Bedrock inference profile ARN models from inheriting Claude Opus reasoning and context metadata.

Fixes #3004
2026-06-18 21:40:08 +00:00
roboomp b67d07e829 fix(providers): preserved bedrock profile thinking suffixes
Handled Bedrock inference profile ARNs through the normal thinking selector parser so suffixes such as :off do not become part of the ARN.

Fixes #3004
2026-06-18 21:26:35 +00:00
roboomp 3a736ff7c1 fix(providers): accepted bedrock inference profile arns
Resolved Amazon Bedrock application inference profile ARNs through the provider-specific model resolver and routed Bedrock requests to the ARN region.

Fixes #3004
2026-06-18 21:06:01 +00:00
can1357 abe4453234 fix(coding-agent): stopped coercing explicit provider-id models to Codex
- 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.
2026-06-17 01:28:10 +02:00
roboomp 49259311d5 fix(coding-agent): preserve fallback provider order
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
2026-06-16 23:12:39 +00:00
roboomp aec9355b26 fix(coding-agent): prefer codex default auth
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
2026-06-16 23:01:57 +00:00
can1357 6b6e9aaffc fix(coding-agent): limit @upstream fuzzy bypass to aggregators
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.
2026-06-16 14:25:53 +02:00
roboomp 07958045c3 fix(coding-agent): guarded thinking selector maps
Checked thinking selector maps with own-property lookup so inherited Object keys cannot parse as valid efforts or thinking levels.\n\nFixes #2727
2026-06-16 03:35:22 +00:00
roboomp 12d9df1b6d fix(coding-agent): preserved literal max role ids
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
2026-06-16 03:20:01 +00:00
roboomp 1fe22211c1 fix(coding-agent): parsed max provider selectors
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
2026-06-16 02:59:04 +00:00
roboomp fe3401a18d fix(coding-agent): propagated max suffix aliases
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
2026-06-16 01:55:54 +00:00
roboomp 46a9867773 fix(coding-agent): preserved max model globs
Kept max as a selector alias only after literal model lookup misses and left scoped globs matching literal :max model ids.\n\nFixes #2727
2026-06-16 01:32:49 +00:00
roboomp 8b17764e08 fix(providers): preserved openrouter upstream routing
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
2026-06-15 22:09:13 +00:00
can1357 0bf5f5f7bf test: drop stale priority-default and memory-tab assertions
- 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.
2026-06-14 17:20:18 +02:00
can1357 e78e936fb6 feat(coding-agent): kept retired variant-id selectors resolving after catalog collapsing
- 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.
2026-06-12 07:37:26 +02:00
roboomp fa613d438d fix(agent): inherited default for unset designer role
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
2026-06-11 20:40:08 +00:00
roboomp 9a94faac0d fix(agent): expanded inherited default role aliases
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
2026-06-11 20:37:07 +00:00
roboomp d79b761aca fix(agent): preserved self-aliased role priorities
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
2026-06-11 20:30:23 +00:00
roboomp da5a2baace fix(agent): used default for unset smol and slow roles
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
2026-06-11 20:24:43 +00:00
can1357 95146192e9 fix(coding-agent): evaluate enabledModels globs and fuzzy selectors in the sync ACP filter 2026-06-10 09:51:45 +02:00
can1357 e3501e3f76 chore: fix merge issues 2026-06-10 08:35:51 +02:00
can1357 19b83bcc1d fix(coding-agent): repair post-rebase blockers in enabledModels ACP filter
- 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.
2026-06-10 08:31:30 +02:00
Theo Mathieu 58f9e1c5c0 fix: match bare OpenRouter-style model ids in filterAvailableModelsByEnabledPatterns
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>
2026-06-10 08:31:30 +02:00
Theo 231cf6eb4b fix review: colon stripping, glob handling, no-match contract, changelog
- 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
2026-06-10 08:31:30 +02:00
Theo 9e28ec4b7e fix: apply enabledModels filter to ACP model list
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.
2026-06-10 08:31:30 +02:00
can1357 529706c368 Merge remote-tracking branch 'origin/farm/d501d509/modelroles-comma-fallback' 2026-06-10 07:26:15 +02:00
can1357 a25d521cab refactor(catalog): baked thinking metadata into buildModel pipeline
- 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.
2026-06-10 07:22:11 +02:00
roboomp 3110304040 fix(models): split direct model role fallback chains
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
2026-06-10 04:44:50 +00:00