Skip to content

feat: support Xiaomi MiMo Token Plan mode#2627

Closed
xyuai wants to merge 3 commits into
Hmbown:mainfrom
xyuai:fix-xiaomi-mimo-token-plan-2621
Closed

feat: support Xiaomi MiMo Token Plan mode#2627
xyuai wants to merge 3 commits into
Hmbown:mainfrom
xyuai:fix-xiaomi-mimo-token-plan-2621

Conversation

@xyuai
Copy link
Copy Markdown
Contributor

@xyuai xyuai commented Jun 3, 2026

Addresses #2621.

Summary

  • Add Xiaomi MiMo Token Plan mode via [providers.xiaomi_mimo].mode, with token-plan, token-plan-sgp, and token-plan-ams cluster aliases.
  • Prefer Token Plan tp-* key env aliases (XIAOMI_MIMO_TOKEN_PLAN_API_KEY, MIMO_TOKEN_PLAN_API_KEY) while preserving existing standard MiMo key aliases.
  • Select the documented Token Plan /v1 endpoints by mode and send api-key auth for Token Plan hosts, while keeping Authorization: Bearer for the standard MiMo endpoint.
  • Normalize Xiaomi MiMo chat / ASR / TTS model aliases and update README, sample config, and provider docs.

Notes

  • Xiaomi's current Token Plan docs describe subscription credits, conversion factors, and rate-limit quotas in the docs / console, but I did not find a documented balance API endpoint to poll. This PR wires the first-class endpoint/auth/model path and leaves live remaining-credit telemetry for a future documented API.

Tests

  • cargo test -p codewhale-config xiaomi_mimo
  • cargo test -p codewhale-secrets xiaomi_mimo_env_aliases_resolve
  • cargo test -p codewhale-tui --bin codewhale-tui xiaomi_mimo

Greptile Summary

This PR adds first-class mode config and env support for Xiaomi MiMo Token Plan clusters, routing users to the correct /v1 endpoint (token-plan-cn, token-plan-sgp, token-plan-ams) based on a declared mode rather than key-prefix heuristics, and adds XIAOMI_MIMO_TOKEN_PLAN_API_KEY / MIMO_TOKEN_PLAN_API_KEY env aliases that are selected in a mode-aware way.

  • Adds mode field to ProviderConfigToml / ProviderConfig and wires it through get/set/unset/flatten/merge in both the codewhale-config and codewhale-tui crates.
  • Introduces xiaomi_mimo_env_api_key_for_runtime which picks TOKEN_PLAN or STANDARD env vars based on the active mode and resolved base URL, replacing the old unconditional XIAOMI_MIMO_API_KEY lookup; the new block runs before codewhale_secrets::env_for in deepseek_api_key() to ensure mode-aware selection takes precedence.
  • Updates README, README.zh-CN.md, config.example.toml, and docs/PROVIDERS.md to document the new env vars and mode values; adds six targeted tests in each crate covering mode-to-endpoint mapping, env key selection, and unknown-mode fallback.

Confidence Score: 5/5

Safe to merge; the mode-aware endpoint and key selection logic is well-tested and the known priority concerns are handled by the new mode-aware lookup that precedes the secrets fallback.

The mode resolution path is covered by six targeted tests in each crate (unknown mode, region aliases, env key preference, pay-as-you-go mode). The previous concerns about silent fallback to the standard endpoint and the 'orbit' alias have both been addressed. The remaining finding is a documentation gap around accepted-but-undocumented mode aliases, which does not affect runtime correctness.

crates/config/src/lib.rs and crates/tui/src/config.rs share an identical but undocumented alias table in xiaomi_mimo_base_url_for_mode; the documented and accepted mode values are out of sync.

Important Files Changed

Filename Overview
crates/config/src/lib.rs Core config crate: adds mode-aware endpoint and key resolution for Xiaomi MiMo Token Plan; logic is sound but accepts ~20 undocumented mode aliases not present in any user-facing docs.
crates/tui/src/config.rs TUI config crate: mirrors the same mode resolution and key-selection logic from the config crate; mode-aware env key lookup correctly inserted before the non-mode-aware secrets fallback in deepseek_api_key().
docs/PROVIDERS.md Documents the four officially supported mode values and the new Token Plan env key aliases.
config.example.toml Adds the new mode field to the Xiaomi MiMo provider example section; correctly documents the four valid mode strings.
README.md Adds new Token Plan env key aliases and mode env vars to the env-variable reference table.
README.zh-CN.md Chinese README updated in parallel with English README to reflect the same new env vars.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User Config / Env] --> B{mode set?}
    B -- yes, standard\npay-as-you-go etc. --> C[Use STANDARD_ENV_VARS\nXIAOMI_MIMO_API_KEY etc.]
    B -- yes, token-plan-cn/sgp/ams\nor unknown --> D[Use TOKEN_PLAN_ENV_VARS\nXIAOMI_MIMO_TOKEN_PLAN_API_KEY]
    B -- no mode --> E{base_url set?}
    E -- pay-as-you-go URL --> C
    E -- token-plan-* URL --> D
    E -- no URL --> F[Try TOKEN_PLAN first,\nthen STANDARD]
    C --> G{resolve_xiaomi_mimo_base_url}
    D --> G
    F --> G
    G --> H{configured\nbase_url?}
    H -- Some, uses_standard_mode --> I[Use configured URL as-is]
    H -- Some, tp- key + payg URL --> J[Override to mode URL\nor DEFAULT_SGP]
    H -- Some, other --> K[Use configured URL]
    H -- None, mode has URL --> L[Use mode endpoint]
    H -- None, standard mode --> M[api.xiaomimimo.com/v1]
    H -- None, tp- key or no key --> N[token-plan-sgp.xiaomimimo.com/v1]
    H -- None, sk- key --> M
Loading

Comments Outside Diff (3)

  1. crates/config/src/lib.rs, line 94-95 (link)

    P2 Redundant identical constants

    DEFAULT_XIAOMI_MIMO_TOKEN_PLAN_BASE_URL and XIAOMI_MIMO_TOKEN_PLAN_CN_BASE_URL are both "https://token-plan-cn.xiaomimimo.com/v1". Having two constants with the same value but different names suggests they might diverge in the future when they should always track the same URL (the CN cluster), making the code misleading. Callers that want "CN explicitly" and callers that want "default Token Plan" both resolve to the same string today, but a future change to the default cluster would silently break one or the other. The same duplication exists in crates/tui/src/config.rs lines 87–88.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Codex Fix in Claude Code Fix in Cursor

  2. crates/config/src/lib.rs, line 1776-1803 (link)

    P2 xiaomi_mimo_token_plan_base_url_for_mode is duplicated across crates

    This function (including its match arms, normalization logic, and alias list) is copy-pasted verbatim into crates/tui/src/config.rs at fn xiaomi_mimo_token_plan_base_url_for_mode. The same duplication exists for xiaomi_mimo_base_url_is_official. Keeping two independent copies means that any future addition of a new cluster alias, a normalization fix, or a renamed variant must be applied twice, and the two implementations can silently diverge.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Codex Fix in Claude Code Fix in Cursor

  3. crates/secrets/src/lib.rs, line 437-443 (link)

    P1 Token Plan key always takes priority regardless of active mode

    XIAOMI_MIMO_TOKEN_PLAN_API_KEY is now tried first for every Xiaomi MiMo connection, even when no Token Plan mode is active. A user who has both XIAOMI_MIMO_TOKEN_PLAN_API_KEY (a tp- key) and XIAOMI_MIMO_API_KEY (a standard sk- key) set in their environment — for example while managing both a subscription and a direct API account — will have the Token Plan key sent with Authorization: Bearer to the standard api.xiaomimimo.com endpoint. The standard endpoint is unlikely to accept Token Plan keys, so the request will fail with an opaque authentication error rather than falling through to the standard key. The new test explicitly confirms this priority (Some("token-plan-key")) but does not exercise the standard-endpoint path with both keys present.

    Fix in Codex Fix in Claude Code Fix in Cursor

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Reviews (5): Last reviewed commit: "refactor(xiaomi-mimo): narrow PR to mode..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Thanks @xyuai for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 3, 2026

Thanks @xyuai for jumping on #2621 so quickly. I saw this come in during the v0.8.52 stabilization pass.

I am intentionally not pulling this into #2626: Token Plan changes endpoint selection, credential precedence, auth headers, model aliases, and docs, and the current PR checks are red. That makes it a good follow-up feature PR, not something to squeeze into the corrective 0.8.52 release.

After 0.8.52 is merged/released, this should get a normal provider-surface review: config/env/auth behavior, docs, provider-registry drift, and ideally live verification against a Token Plan key or official examples. Thanks again, and sorry the current release branch is noisy right now.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Xiaomi MiMo Token Plan subscriptions, enabling the use of tp-* API keys with api-key header authentication and adding regional cluster configuration options (mode) via config files and environment variables. The review feedback suggests several improvements to the HTTP client implementation in crates/tui/src/client.rs: adding a fallback check for API keys starting with tp- to support custom base URLs, comparing HeaderName directly instead of converting to strings for the authorization header check, and simplifying the header filtering logic by leveraging case-insensitive HeaderName equality.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/tui/src/client.rs Outdated
Comment on lines +665 to +674
let auth_header_name = if !api_key.is_empty()
&& api_provider == ApiProvider::XiaomiMimo
&& xiaomi_mimo_base_url_uses_token_plan(base_url)
{
Some(HeaderName::from_static("api-key"))
} else if !api_key.is_empty() {
Some(AUTHORIZATION)
} else {
None
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For users utilizing a custom base_url (such as a local proxy, mock server, or internal load balancer) with the Xiaomi MiMo Token Plan, the xiaomi_mimo_base_url_uses_token_plan(base_url) check will return false because the domain won't match *.xiaomimimo.com. Since Token Plan API keys are documented to start with tp-, we can add a fallback check for api_key.starts_with("tp-") to ensure the correct api-key header is sent even when a custom base_url is used.

Suggested change
let auth_header_name = if !api_key.is_empty()
&& api_provider == ApiProvider::XiaomiMimo
&& xiaomi_mimo_base_url_uses_token_plan(base_url)
{
Some(HeaderName::from_static("api-key"))
} else if !api_key.is_empty() {
Some(AUTHORIZATION)
} else {
None
};
let auth_header_name = if !api_key.is_empty()
&& api_provider == ApiProvider::XiaomiMimo
&& (xiaomi_mimo_base_url_uses_token_plan(base_url) || api_key.starts_with("tp-"))
{
Some(HeaderName::from_static("api-key"))
} else if !api_key.is_empty() {
Some(AUTHORIZATION)
} else {
None
};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest push: tp-* Xiaomi MiMo keys now use api-key auth even when the request goes through a custom base URL / gateway, with a regression test covering the custom URL case.

Comment thread crates/tui/src/client.rs Outdated
None
};
if let Some(header_name) = auth_header_name.as_ref() {
let header_value = if header_name.as_str() == AUTHORIZATION.as_str() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Comparing HeaderName directly is more idiomatic and efficient than comparing their string representations via .as_str(). We can simplify header_name.as_str() == AUTHORIZATION.as_str() to header_name == AUTHORIZATION.

Suggested change
let header_value = if header_name.as_str() == AUTHORIZATION.as_str() {
let header_value = if header_name == AUTHORIZATION {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest push by comparing HeaderName directly against AUTHORIZATION.

Comment thread crates/tui/src/client.rs Outdated
Comment on lines +692 to +694
|| auth_header_name
.as_ref()
.is_some_and(|auth| header_name.as_str().eq_ignore_ascii_case(auth.as_str()))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since HeaderName equality is case-insensitive by default in the http crate, we can simplify the check to see if header_name matches auth_header_name by comparing them directly. This avoids string allocation, formatting, and manual case-insensitive string comparison.

Suggested change
|| auth_header_name
.as_ref()
.is_some_and(|auth| header_name.as_str().eq_ignore_ascii_case(auth.as_str()))
|| auth_header_name.as_ref() == Some(&header_name)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest push by comparing auth_header_name.as_ref() == Some(&header_name) directly.

Comment thread crates/config/src/lib.rs Outdated
Comment thread crates/tui/src/config.rs
@xyuai xyuai force-pushed the fix-xiaomi-mimo-token-plan-2621 branch from 9190cb3 to 4d1c5cd Compare June 3, 2026 10:25
@xyuai
Copy link
Copy Markdown
Contributor Author

xyuai commented Jun 3, 2026

Updated this PR after the review feedback and rebased it onto the latest main (c8ce2b8e92b6366070308118e397cc97b3c4a220).

Follow-up changes:

  • Removed the undocumented orbit mode alias.
  • Unknown non-standard MiMo mode values now stay on the Token Plan CN endpoint instead of silently falling back to the standard endpoint/auth scheme.
  • tp-* MiMo keys now use api-key auth even with custom base URLs / gateways.
  • Simplified HeaderName comparisons as suggested.

Re-validated:

  • cargo test -p codewhale-config xiaomi_mimo
  • cargo test -p codewhale-secrets xiaomi_mimo_env_aliases_resolve
  • cargo test -p codewhale-tui --bin codewhale-tui xiaomi_mimo
  • cargo fmt -- --check
  • git diff --check

@xyuai xyuai force-pushed the fix-xiaomi-mimo-token-plan-2621 branch from 4d1c5cd to fbf88c9 Compare June 3, 2026 10:33
@xyuai
Copy link
Copy Markdown
Contributor Author

xyuai commented Jun 3, 2026

The two CI issues were from the previous run: Windows failed before tests in the cache restore step, which cancelled the macOS matrix leg. I refreshed the PR head to rerun CI; the latest run is now green across GitGuardian, GitHub Actions, and Greptile, including Test (windows-latest) and Test (macos-latest).

@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 3, 2026

Thanks for the quick follow-up @xyuai. I see the refreshed CI is green now, including macOS and Windows, and the narrower Token Plan behavior is a much better review surface.

I am still keeping this out of the corrective 0.8.52 release because it is a new provider sub-mode that changes endpoint/auth/model behavior and really deserves live verification against Xiaomi Token Plan docs or a test key before it ships as first-class. This should get a normal provider review right after 0.8.52 is fully repaired/published rather than being lost in the release cleanup. Appreciate the fast cleanup here.

@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 5, 2026

Thanks @xyuai. We harvested the Token Plan api-key header fix into the v0.9 branch with credit. I’m leaving this open for the remaining mode/env behavior, since that conflicts with the current provider-config path.

@xyuai
Copy link
Copy Markdown
Contributor Author

xyuai commented Jun 5, 2026

@Hmbown Thanks - I narrowed this PR further to keep only the remaining mode/env behavior you mentioned.

  • Removed the crates/tui/src/client.rs changes related to the Token Plan api-key / header handling that was already harvested into v0.9
  • Removed the crates/secrets/src/lib.rs changes that globally reshuffled Xiaomi MiMo env-key precedence
  • Kept the providers.xiaomi_mimo.mode, XIAOMI_MIMO_MODE / MIMO_MODE, and the config-path logic that selects the Token Plan vs pay-as-you-go env key based on mode / base_url
  • Synced the docs and config example to match the narrower scope

I also re-ran the local checks:

  • cargo fmt --all --check
  • cargo test -p codewhale-config xiaomi_mimo
  • cargo test -p codewhale-tui --bin codewhale-tui xiaomi_mimo
  • cargo test -p codewhale-secrets xiaomi

If you have a moment, could you please take another look at this narrower review surface to see whether it now matches the remaining mode/env behavior you had in mind? Thanks!

@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 5, 2026

Thanks @xyuai. We harvested the safe v0.9 Token Plan mode/env-selection slice in #2800 with your authorship preserved and merged it into the stewardship branch at 125612575a3aaeb81c3a21456161716ad9bfc8ec. The landed version keeps the existing Token Plan api-key header behavior, adds mode / XIAOMI_MIMO_MODE / MIMO_MODE selection for token-plan-sgp, token-plan-cn, token-plan-ams, and pay-as-you-go, and documents the token-plan env keys.

#2762 is green at 125612575a3aaeb81c3a21456161716ad9bfc8ec, which includes this harvest. Closing this source PR as harvested/superseded. #2621 remains open for the remaining model-list, credit/cost display, and rate-limit work.

@Hmbown Hmbown closed this Jun 5, 2026
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.

2 participants