feat: add Xiaomi MiMo provider support#2240
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds support for the Xiaomi MiMo Token Plan provider, integrating its models (mimo-v2.5-pro, mimo-v2.5, and mimo-v2-flash) into the configuration, CLI, and interactive TUI. The review feedback highlights three key issues: a regression in the model picker that removes the "auto" option for other pass-through providers, an issue where switching to Xiaomi with a "Max" reasoning effort silently disables thinking, and an overly restrictive model name normalization bypass that prevents the use of "auto" or custom models.
| let provider_models: &'static [(&'static str, &'static str)] = match app.api_provider { | ||
| crate::config::ApiProvider::Xiaomi => PICKER_MODELS_XIAOMI, | ||
| p if crate::config::provider_passes_model_through(p) => &[], | ||
| _ => PICKER_MODELS, | ||
| }; |
There was a problem hiding this comment.
For other pass-through providers, setting provider_models to &[] removes the "auto" ("select per turn") option from the model picker, which is a regression from the previous behavior where vec!["auto"] was shown. We should return &[("auto", "select per turn")] for other pass-through providers to preserve this option.
| let provider_models: &'static [(&'static str, &'static str)] = match app.api_provider { | |
| crate::config::ApiProvider::Xiaomi => PICKER_MODELS_XIAOMI, | |
| p if crate::config::provider_passes_model_through(p) => &[], | |
| _ => PICKER_MODELS, | |
| }; | |
| let provider_models: &'static [(&'static str, &'static str)] = match app.api_provider { | |
| crate::config::ApiProvider::Xiaomi => PICKER_MODELS_XIAOMI, | |
| p if crate::config::provider_passes_model_through(p) => &[("auto", "select per turn")], | |
| _ => PICKER_MODELS, | |
| }; |
| let selected_effort_idx = provider_efforts | ||
| .iter() | ||
| .position(|e| *e == normalized) | ||
| .unwrap_or(2); // default to High if somehow unknown | ||
| .unwrap_or(0); // default to first effort if unknown |
There was a problem hiding this comment.
If the user has ReasoningEffort::Max selected (which is common for DeepSeek), switching to Xiaomi MiMo will result in normalized being Max. Since PICKER_EFFORTS_MIMO does not contain Max, the position search will fail and default to 0 (ReasoningEffort::Off), silently disabling thinking. We should map ReasoningEffort::Max to ReasoningEffort::High when is_xiaomi is true.
let selected_effort_idx = provider_efforts
.iter()
.position(|e| {
if is_xiaomi && normalized == ReasoningEffort::Max {
*e == ReasoningEffort::High
} else {
*e == normalized
}
})
.unwrap_or(0);| if matches!(provider, ApiProvider::Xiaomi) && trimmed.to_ascii_lowercase().starts_with("mimo") { | ||
| if trimmed | ||
| .chars() | ||
| .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.' | ':')) | ||
| { | ||
| return Some(trimmed.to_string()); | ||
| } | ||
| return None; | ||
| } |
There was a problem hiding this comment.
Restricting the bypass to only models starting with "mimo" prevents the use of "auto" (the special TUI-level model name for auto-selection) or any custom/fine-tuned models that do not follow the "mimo" prefix. Since Xiaomi is a pass-through provider, we should allow any valid model name format.
if matches!(provider, ApiProvider::Xiaomi) {
if trimmed
.chars()
.all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.' | ':'))
{
return Some(trimmed.to_string());
}
return None;
}- New ProviderKind::Xiaomi across config, TUI, CLI, and agent crates - Default endpoint: https://token-plan-cn.xiaomimimo.com/v1 - Models: mimo-v2.5-pro, mimo-v2.5, mimo-v2-flash - MiMo-specific thinking toggle (enabled/disabled) - /models command for Xiaomi provider - Provider-specific model picker UI Co-Authored-By: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Add first-class support for the Xiaomi MiMo API platform: - New provider variant `Xiaomi` across config, TUI, CLI, and agent crates - Default endpoint: https://api.xiaomimimo.com/v1 - Supports reasoning/thinking via reasoning_content field (same as DeepSeek) - Model registry entries for mimo-v2.5-pro and mimo-v2-flash - Provider picker, UI display names, and capability detection - Environment variable: MIMO_API_KEY - Example configuration in config.example.toml and .env.example Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove unused DEFAULT_XIAOMI_FLASH_MODEL constant from config/src/lib.rs - Add missing xiaomi field to ProvidersConfig struct and merge function - Update picker_lists_all_providers test to include Xiaomi MiMo Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Change default base_url to token-plan-cn.xiaomimimo.com/v1 (Token Plan API, not pay-as-you-go) - Add mimo-v2.5 (omni) model to registry with aliases - Fix provider_capability: mimo-v2.5 gets 1M/128K context (not 256K) Logic now checks for "flash" instead of "pro" to correctly classify - Update config examples with token-plan URLs, tp-xxxxx key format, and all three model options (pro/omni/flash) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When switching from DeepSeek to Xiaomi, the global default_text_model
("deepseek-v4-pro") was being inherited because Xiaomi is a pass-through
provider. Add dominated_model_prefix() guard to skip default_text_model
when it doesn't belong to the target provider's model namespace.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The dominated_model_prefix guard broke the existing multi-provider switching behavior where default_text_model is inherited across providers. Users can set provider-specific models via the [providers.xiaomi] config section instead. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…toggle
- Add provider-specific model list in /model picker (mimo-v2.5-pro, mimo-v2.5)
- Add provider-specific thinking effort (off/high only, MiMo doesn't support auto/max)
- Fix /models command to work with Xiaomi provider (fetches from /v1/models)
- Fix model validation to accept MiMo model names (not just DeepSeek)
- Fix thinking:off to send { type: "disabled" } instead of no-op for Xiaomi
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Restore "auto" option for pass-through providers (OpenAI, Moonshot, etc.) that was accidentally removed in the model picker refactor - Add mimo-v2-flash to PICKER_MODELS_XIAOMI so users can select it from /model - Add mimo-v2.5 to model_completion_names_for_provider for tab-completion - Map ReasoningEffort::Max → High when switching to Xiaomi (MiMo only supports on/off, so Max should map to High, not silently fall back to Off) - Broaden Xiaomi model name validation to accept "auto" and custom models, not just "mimo"-prefixed names Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove all mimo-v2-flash references: model registry entry, picker list, completion names, env/config examples, and the unused DEFAULT_XIAOMI_FLASH_MODEL constant. Only mimo-v2.5-pro and mimo-v2.5 are supported. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
580e90d to
af98fc1
Compare
Adds MiMo provider usage examples, env var references, and capability metadata across all three README languages, the provider registry, and the configuration reference. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
https://token-plan-cn.xiaomimimo.com/v1)mimo-v2.5-pro(reasoning flagship) andmimo-v2.5(omni)thinking: { type: "enabled"/"disabled" }) instead of DeepSeek-style reasoning_effort/modelscommand for Xiaomi provider to fetch available models from the APIChanges
Provider registration:
crates/config/src/lib.rs—ProviderKind::Xiaomivariant, default model/base_url constants, parse/as_strcrates/tui/src/config.rs—ApiProvider::Xiaomivariant, provider_capability (thinking enabled), all match armscrates/cli/src/lib.rs—ProviderArg::Xiaomi, provider list, env var mappingModel picker & validation:
crates/tui/src/tui/model_picker.rs— Provider-specific model lists (PICKER_MODELS_XIAOMI) and thinking effort lists (PICKER_EFFORTS_MIMOwith only off/high)crates/tui/src/config.rs—normalize_model_name_for_provideraccepts MiMo model names for Xiaomi providerAPI integration:
crates/tui/src/client.rs—apply_reasoning_effortsendsthinking: { type: "disabled" }for off,thinking: { type: "enabled" }for high/maxcrates/tui/src/client/chat.rs—requires_reasoning_content()includesmimoprefix for reasoning token replaycrates/tui/src/tui/ui.rs— Allow/modelscommand for Xiaomi providerModel registry:
crates/agent/src/lib.rs—ModelInfoentries formimo-v2.5-proandmimo-v2.5with aliasesConfig & docs:
config.example.toml—[providers.xiaomi]section with token-plan URL and model examples.env.example—MIMO_API_KEY,MIMO_BASE_URL,MIMO_MODELdocumentationTest plan
cargo fmt --all -- --checkpassescargo clippy --workspace --all-targets --all-features --locked -- -D warningspassescargo test --workspace --all-features --lockedpasses (4 pre-existing failures unrelated to this change)/provider→ Xiaomi MiMo,/model→ mimo-v2.5-pro, send a message/model→ switch thinking effort off/high, verify API accepts the request/models→ verify model list is fetched from Xiaomi APIGreptile Summary
This PR adds first-class Xiaomi MiMo provider support, wiring
ProviderKind::Xiaomi/ApiProvider::Xiaomithrough every layer of the stack — config, secrets, CLI, TUI engine, model picker, reasoning-effort translation, and reasoning-content replay. The implementation is comprehensive and follows the existing provider-addition pattern faithfully.apply_reasoning_effortmaps MiMo'sthinking: { type: \"enabled\"/\"disabled\" }format (noreasoning_effortfield) across all effort levels;requires_reasoning_contentandprovider_accepts_reasoning_contentare extended so multi-turn tool-call reasoning content is replayed correctly per MiMo docs.hide_deepseek_modelsboolean is replaced with provider-specificprovider_models/provider_effortsslices; Xiaomi getsPICKER_MODELS_XIAOMI(auto, mimo-v2.5-pro, mimo-v2.5) and a two-item effort list (off/high)./modelssupport: Xiaomi is allowed to fetch available models despite living insideprovider_passes_model_through, achieved via a&& !is_xiaomicarve-out in theFetchModelsgate.Confidence Score: 5/5
Safe to merge — all Xiaomi variant arms are exhaustive (Rust compile-time enforcement), the reasoning-content replay path is consistent with existing providers, and manual end-to-end testing is confirmed in the test plan.
The change is a well-scoped provider addition that follows the existing pattern exactly. Every match arm across config, secrets, CLI, TUI, and model picker is complete. The reasoning-effort translation correctly maps MiMo's thinking toggle across all effort levels. The only non-trivial design choice — placing Xiaomi in provider_passes_model_through while also supporting /models — is functional and safe, if slightly surprising to future readers.
crates/tui/src/tui/ui.rs — the FetchModels guard uses a double-negative carve-out for Xiaomi that should be understood by anyone refactoring provider_passes_model_through in the future.
Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant TUI participant Config participant Client participant MiMoAPI User->>TUI: /provider → Xiaomi, /model → mimo-v2.5-pro TUI->>Config: "api_provider() == Xiaomi" Config-->>TUI: DEFAULT_XIAOMI_BASE_URL, MIMO_API_KEY User->>TUI: "Send message (effort = high)" TUI->>Client: apply_reasoning_effort(body, high, Xiaomi) Client->>Client: "body[thinking] = {type:enabled}" Note over Client: No reasoning_effort field (MiMo-specific) TUI->>Client: build_chat_request(messages) Client->>Client: requires_reasoning_content(mimo-v2.5-pro) → true Client->>Client: "should_replay_reasoning_content → replay if effort != off" Client->>MiMoAPI: POST /v1/chat/completions Note over Client,MiMoAPI: Bearer MIMO_API_KEY MiMoAPI-->>Client: SSE stream with reasoning_content + content Client-->>TUI: parsed MessageResponse TUI-->>User: display thinking + answerReviews (4): Last reviewed commit: "chore: bump version to 0.8.47 (dev)" | Re-trigger Greptile