Skip to content

docs(rust/README): document xAI and Kimi model aliases - #3268

Open
nankingjing wants to merge 2 commits into
ultraworkers:mainfrom
nankingjing:docs-model-aliases
Open

nankingjing wants to merge 2 commits into
ultraworkers:mainfrom
nankingjing:docs-model-aliases

Conversation

@nankingjing

Copy link
Copy Markdown

What

The Model Aliases table in rust/README.md only listed the three Anthropic
aliases (opus, sonnet, haiku), but resolve_model_alias in
rust/crates/api/src/providers/mod.rs also resolves xAI and Kimi aliases. This
PR documents the full alias set, adds a Provider and Auth env var column
so each alias is actionable, and notes that resolution is case-insensitive.

Newly documented aliases (verified against MODEL_REGISTRY / resolve_model_alias):

Alias Resolves To Provider Auth env var
grok, grok-3 grok-3 xAI XAI_API_KEY
grok-mini, grok-3-mini grok-3-mini xAI XAI_API_KEY
grok-2 grok-2 xAI XAI_API_KEY
kimi kimi-k2.5 DashScope (OpenAI-compatible) DASHSCOPE_API_KEY

Why it's correct

Everything added is verifiable in the source, not invented:

  • resolve_model_alias() maps grok/grok-3 → grok-3, grok-mini/grok-3-mini
    → grok-3-mini, grok-2 → grok-2, and kimi → kimi-k2.5.
  • MODEL_REGISTRY sets the auth/base-url env vars for each provider:
    xAI → XAI_API_KEY / XAI_BASE_URL, Kimi → DASHSCOPE_API_KEY /
    DASHSCOPE_BASE_URL.
  • Case-insensitivity: resolve_model_alias lowercases input before matching, and
    existing tests assert this (kimi_alias_resolves_to_kimi_k2_5 checks "KIMI",
    resolves_grok_aliases checks the grok family).
  • Provider diagnostics already point users at these aliases (e.g. the hint to
    "use an xAI model alias such as --model grok"), and docs/MODEL_COMPATIBILITY.md
    documents the corresponding request handling — this PR just surfaces the aliases
    where they are listed.

Scope

Docs-only change to rust/README.md. No code or behavior changes. The existing
opus/sonnet/haiku rows are unchanged.

@1716775457damn

Copy link
Copy Markdown

Good catch — the model aliases table was indeed incomplete. Having the full alias set documented alongside the Provider and Auth env var columns makes it much more actionable for users. The case-insensitivity note is also a helpful detail.

@simawulei

simawulei commented Jul 10, 2026 via email

Copy link
Copy Markdown

@nankingjing

Copy link
Copy Markdown
Author

Thanks for the quick review, @1716775457damn! Glad the Provider / Auth-env columns are useful. I noticed a couple of other small doc nits while in there (a broken link and an out-of-date crate count) and have a follow-up PR incoming, kept separate to keep this one focused.

@1716775457damn

Copy link
Copy Markdown

Sounds good, keeping the follow-up PR focused on those doc nits separately makes sense. Looking forward to reviewing it — especially the broken link fix. Thanks for the thorough docs work!

@nankingjing

Copy link
Copy Markdown
Author

Quick note: #3269 is just the crate-count fix; I haven't opened the broken-link follow-up yet — will get to that separately. Thanks for flagging it!

@1716775457damn

Copy link
Copy Markdown

Got it, thanks for the clarification. #3269 looks good for the crate count — will review that next. No rush on the broken link, just drop a mention when it's up.

@1716775457damn

Copy link
Copy Markdown

The alias table now covers all provider models consistently — having xAI and Kimi documented alongside Anthropic makes it much easier to discover available options. Thanks for filling this gap @nankingjing!

@1716775457damn

Copy link
Copy Markdown

Thanks for the update @nankingjing! The alias table looks complete now — covers xAI and Kimi models cleanly. Docs-only change, good to go.

@nankingjing

Copy link
Copy Markdown
Author

Thanks for the review feedback @1716775457damn! All 6 PRs are green on CI. If you have a moment, could you submit a formal PR review approval (Review changes → Approve) on each? That would let them merge cleanly. Much appreciated!

@1716775457damn

Copy link
Copy Markdown

Approved. Filling the gap where xAI and Kimi aliases were missing from the documented table while already supported in resolve_model_alias is the right fix. The additional Provider and Auth env var columns make each alias immediately actionable rather than requiring users to cross-reference config files. Good docs improvement.

@1716775457damn

Copy link
Copy Markdown

Useful addition. xAI and Kimi are increasingly popular, documenting their aliases helps users get started quickly.

@1716775457damn

Copy link
Copy Markdown

One follow-up worth considering: this drift happened because the alias table is maintained by hand while the real resolution lives in resolve_model_alias, so the same gap reopens the next time an alias is added. Generating the table from the resolver, or adding a small test asserting that every alias listed in the README actually resolves (and that every resolver alias is documented), would keep docs and behaviour from diverging. It would also help to state whether alias resolution happens before or after the provider-prefix stripping from #3232, since that ordering is what users will hit.

@nankingjing

Copy link
Copy Markdown
Author

Correction to my earlier note (the one asking for a formal approval). I wrote there that "All 6 PRs are green on CI". That was wrong, I had not verified it, and I retract it.

The head commit (b89ddda387) has 0 check runs and 0 workflow runs — CI has never run on this PR at all. commits/b89ddda387/status reports pending with 0 statuses, which is an absence of results rather than a pass.

The PR body is accurate on this point — it states plainly that a full cargo test was not run in this environment — so the mistake was confined to that comment.

The follow-up ask in that note was misdirected too: @1716775457damn shows author_association: NONE on their comments here, so they are an outside contributor like me — an "Approve" from them neither gates the held workflow runs nor carries merge rights. There was nothing useful for them to do, and that was my error, not theirs.

What these PRs are actually waiting on is a maintainer: approving the queued workflow runs so Rust CI can execute, then reviewing and merging. The code changes are unchanged by this note — only my claim about their CI status was wrong.

@nankingjing

Copy link
Copy Markdown
Author

Answering the follow-up from @1716775457damn (2026-09-07) properly, rather than only the CI note above.

The drift is real, and slightly wider than this diff implies. In rust/crates/api/src/providers/mod.rs, MODEL_REGISTRY (line 121) holds nine aliases: opus, sonnet, haiku, grok, grok-3, grok-mini, grok-3-mini, grok-2, kimi. The README documented three — the ## Model Aliases table is three rows, and the feature matrix row says "Model aliases (opus/sonnet/haiku)". The six undocumented ones are exactly the six this PR adds, so the table is now complete; you're right that nothing keeps it that way.

On generating the table. I'd rather land a parity test than promise a generator, and it's worth being precise about why the generator is not trivial: the alias→canonical-id mapping is not in MODEL_REGISTRY. It is a second, separate match inside resolve_model_alias (providers/mod.rs:206) — ProviderKind::Anthropic => match *alias { "opus" => "claude-opus-4-7", ... }, and likewise for Xai and OpenAi. So a generator would have to read both structures, and would still be guessing which one owns the mapping. The cleaner fix is to move the canonical id onto the registry entry so resolve_model_alias becomes a lookup and the README row is a projection of one structure. That is a refactor of the resolver, not of the docs, so I'd rather not smuggle it into a docs PR — happy to open it separately if you want it. A parity test, by contrast, I can add here and it costs nothing.

On the ordering question (alias resolution vs the provider-prefix stripping). I traced it: the two do not compete, and the order is alias-first, with prefix handling only ever seeing the already-resolved name.

  • rust/crates/api/src/client.rs:25 — let resolved_model = providers::resolve_model_alias(model);, and detect_provider_kind is then called on the result.
  • detect_provider_kind (providers/mod.rs:362) also calls resolve_model_alias itself, then delegates to metadata_for_model.
  • metadata_for_model (providers/mod.rs:235) is where prefixes are inspected — anthropic/, openai/, gpt-, local/ — each a starts_with on the canonical string.

Two consequences worth stating for users:

  1. Alias matching is a whole-string equality test against the registry, so anthropic/opus is not an alias and won't become one; it routes through the anthropic/ prefix branch instead. Every alias this PR documents is a bare name.
  2. The only place a provider prefix is actually stripped is downstream of routing, in the Anthropic client — anthropic_wire_model at providers/anthropic.rs:1038, model.strip_prefix("anthropic/") — applied when the request is built. So the pipeline is: alias resolves → prefix decides routing → strip happens at request build.

Tell me if you want the parity test in this PR or as a follow-up; either is fine by me.

@1716775457damn

Copy link
Copy Markdown

Parity test in this PR, please — it's cheap and it locks the exact property that drifted, so there's no reason to defer it. Agreed on keeping the registry refactor out: moving the canonical id onto the registry entry is a resolver change, and doing it as its own PR keeps this docs fix reviewable. Thanks for tracing the ordering — alias-first with prefix stripping only at request-build time is worth one line in the README so users don't have to guess whether "anthropic/opus" is a valid alias (it isn't).

The `## Model Aliases` table and `MODEL_REGISTRY` had drifted: the table
listed only the three Anthropic aliases while the resolver had grown the
xAI and Kimi entries, so an alias could resolve without being documented.

Assert the two agree in both directions — every registry alias appears in
the table with the canonical id and auth env var it actually resolves to,
and the table introduces no alias the resolver does not know. Each row is
also checked case-insensitively, since the README claims `OPUS` behaves
the same as `opus`.

Also pin that a provider-prefixed form such as `anthropic/opus` is not an
alias: it is passed through as-is rather than expanded. The README now
says so, which is what made the distinction worth a test rather than a
comment.
@nankingjing

Copy link
Copy Markdown
Author

Done — the parity test is in (072594d), with the README line alongside it.

What it locks, in both directions:

  • every alias in MODEL_REGISTRY appears in the ## Model Aliases table, carrying the canonical id it actually resolves to and the auth env var its provider metadata reports;
  • the table introduces no alias the resolver does not know — it is set equality, so a stale row fails as loudly as a missing one;
  • each row is re-checked uppercased, since the README claims OPUS behaves the same as opus.

It parses the README rather than hardcoding expectations, so editing the table without the registry (or the reverse) fails with the offending row named in the assertion message.

One deviation worth flagging, since it changes the wording you suggested. I wrote the README line as "a prefixed form such as anthropic/opus is not an alias, and is passed through as-is rather than expanded to claude-opus-4-7" instead of describing prefix stripping at request-build time. strip_provider_prefix in providers/mod.rs has no call sites anywhere in the workspace — it is currently dead code. The slash handling that does run at request-build time (rsplit('/').next() in model_token_limit and the openai_compat paths) takes the suffix, so "stripping" is not what happens to a prefixed alias today. The user-visible claim is the same either way — anthropic/opus does not expand to claude-opus-4-7 — and that is the property the test asserts, so I documented the behaviour rather than the mechanism. Happy to reword to the mechanism if you would rather the README describe the intent, though that reads to me like it would promise something the code does not yet do.

cargo test -p api is green locally: 160 passed, 0 failed. cargo fmt --check and cargo clippy -p api are clean with no new warnings.

Worth knowing for this and the other PRs: the push created two workflow runs (Rust, Rust CI) and both are sitting at action_required with zero check runs, so nothing will show up on CI until a maintainer approves the runs for the new head commit.

@1716775457damn

Copy link
Copy Markdown

Parity test 的设计很到位:解析 README 而非硬编码期望,集合相等让 stale row 和缺失行同样失败,大写复查也覆盖了 README 的声明。文档化行为而不是机制的取舍我赞成——写成 prefix stripping 反而会承诺 strip_provider_prefix 这个死代码做不到的事,现在这句 user-visible 声明才是测试真正断言的属性。CI 等维护者批准 action_required 即可,本地 160 passed 已经有足够信心。

@1716775457damn

Copy link
Copy Markdown

Parity test 已落进 PR(072594d),双向往返校验 + 大写复查把 docs 与 resolver 的漂移彻底钉死,这条文档修复可以合了。CI 等维护者批准 action_required 后确认全绿即可。后续若做 resolver 侧的 canonical id 重构,记得单独开 PR 并保持 README 声明同步。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants