Repository navigation
feat(aliases): provider and model aliases across router, API, CLI and GUI (#2463) - #2610
Conversation
Semantic resolution across 13 files. Both branches touched the same tail positions in nine locale files, the Models page, the config schema, the model routes and the convergence contract, so this is not a take-ours/take-theirs merge - every conflict is two additive features that must both survive. Locales: git merge-file --union, since both sides append disjoint keys. model-routes.ts: both route blocks kept in order; the convergence count goes 10 -> 13 (two model-discovery routes plus three alias routes). codex-convergence-contract.test.ts: the model-discovery companion test sliced to /api/catalog, which the alias routes now sit before - a fixed far boundary would have swallowed their convergence calls and counted them as the discovery route's. Retargeted to the next route so each assertion still bounds only its own handler.
|
✅ Deterministic PR hygiene checks passed. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (32)
📝 WalkthroughWalkthroughThis change adds provider and model aliases across configuration, routing, management APIs, CLI commands, model discovery, request logging, GUI controls, localization, tests, and reference documentation. ChangesAlias contracts and effective resolution
Alias routing and request metadata
Management APIs and CLI
GUI alias controls and localization
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant Router
participant AliasResolver
participant Provider
Client->>Router: request with provider/model alias
Router->>AliasResolver: resolveModelAlias(requested)
AliasResolver->>Provider: inspect effective aliases and known model IDs
Provider-->>AliasResolver: native model ID
AliasResolver-->>Router: resolved model
Router-->>Client: routed completion
Suggested reviewers: ✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
⏳ DRAFT
What to do
Automatic draft conversion failed (token cannot change draft status). Please convert this pull request to a draft manually. The required |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42a8102204
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const nativeModel = known.includes(decoded) | ||
| ? decoded | ||
| : resolveModelAlias(config, prov, known, requestedModel) ?? decoded; |
There was a problem hiding this comment.
Canonicalize aliases before storing combo targets
When a combo target is configured as alpha/tiny and tiny is a model alias, combo validation accepts and persists the alias verbatim; this new qualified resolution then makes it work only while that alias exists. Renaming or removing the alias leaves the combo pointing at tiny, which is subsequently passed upstream as an unknown native model despite aliases being intended as rename-safe presentation metadata. Resolve model aliases to their canonical native IDs in the combo write path before persisting targets.
Useful? React with 👍 / 👎.
| const heldBy = Object.entries(next).find(([other, alias]) => other !== id && alias.toLowerCase() === lower)?.[0] | ||
| ?? known.find(native => native.toLowerCase() === lower) | ||
| ?? Object.entries(config.combos ?? {}).find(([, combo]) => comboPublicModelId("", combo).toLowerCase() === lower)?.[0]; |
There was a problem hiding this comment.
Reject aliases that collide with encoded native model IDs
For a provider containing native vendor/model, the API accepts assigning vendor-model as an alias for another model because this check compares only exact native IDs. Both bare and qualified vendor-model are resolved by the existing slash-ID codec to vendor/model before alias lookup, so the saved alias silently selects the wrong model and is unusable. Include each known model's encodeRoutedModelId form in this collision check.
Useful? React with 👍 / 👎.
… GUI (lidge-jun#2463) (lidge-jun#2610) * feat(aliases): add provider and model short names * fix(logs): retain requested model aliases
… GUI (lidge-jun#2463) (lidge-jun#2610) * feat(aliases): add provider and model short names * fix(logs): retain requested model aliases
Summary
Closes #2463. Real routed slugs are things like
google-antigravity/gemini-3-pro-preview-11-2025, and the user types them into Codex's picker,/model, CLI flags and combo targets. This adds a user-chosen short name that resolves on all of those surfaces.Aliases are a resolution and display layer, never a storage format.
selectedModels,disabledModels, combos and usage rows keep canonical slugs only, so an alias can be renamed or deleted without touching persisted state, andslugEquals/ the visibility filters are untouched./v1/modelsannotates rows withalias_ofrather than adding alias rows — the annotate-only reading of the design's open question 1, so no existing client sees a row it does not recognise.Resolution extends the ladder at exactly two points rather than one: qualified
head/tailaliases sit below combo aliases, so anything a combo already claims keeps its meaning; bare aliases sit after every existing bare step and immediately before thedefaultProviderfallback. That ordering is what makes the collision rules sufficient — an alias can never shadow something that resolves earlier.One deliberate behavior change, and it is tested in both directions: a bare id that today reaches the
defaultProviderfallback resolves via alias when the user defined a matching one. That only fires for aliases the user created or a built-in set they explicitly enabled, which is the point of defining an alias. Users with no aliases configured are unaffected, which has its own test.Built-ins are patterns, not ids, so a snapshot suffix does not stale them. When two models on one provider match the same rule, the built-in is disabled for that provider rather than guessed — deterministic beats "latest wins", and the user resolves it with an explicit entry.
Verification
Falsified per hunk: removing qualified resolution fails the qualified and ambiguity tests; removing the late bare-alias hook fails the bare-fallback and ambiguity tests; removing built-in derivation fails the aggregator test. Each was restored before the final run. The GUI was rendered against a stubbed management API, not trusted to typecheck — the first render exposed provider-header wrapping, which was fixed and re-rendered.
Merge note (why this PR carries a merge commit)
The branch was cut before #2464 landed, and the two features collide in 13 files: nine locale tails, the Models page, the config schema, the model routes and the convergence contract. Every conflict is two additive features that both have to survive, so none of it was resolved by taking a side.
Locale files were merged with
git merge-file --union— both branches append disjoint keys at the same tail.model-routes.tskeeps both route blocks in order, taking the convergence count 10 → 13.The one that mattered: #2464's companion test sliced from its acknowledge route to
/api/catalog, and the alias routes now sit in between. Left alone it would have silently swallowed three alias convergence calls and counted them as the discovery route's — passing while asserting nothing. It is retargeted to the next route so each assertion bounds only its own handler.Checklist
devdocs-site/updatedSummary by CodeRabbit
New Features
ocx aliascommand to list, set, remove, and manage default aliases.Documentation