feat: support xiaomi/mimo-v2-flash

This commit is contained in:
Vibe Kanban 2026-01-29 00:30:17 +08:00 committed by Peter Steinberger
parent cb4b3f74b5
commit 50d44d0bd9
19 changed files with 334 additions and 1 deletions

View File

@ -69,6 +69,14 @@
"source": "/minimax/", "source": "/minimax/",
"destination": "/providers/minimax" "destination": "/providers/minimax"
}, },
{
"source": "/xiaomi",
"destination": "/providers/xiaomi"
},
{
"source": "/xiaomi/",
"destination": "/providers/xiaomi"
},
{ {
"source": "/openai", "source": "/openai",
"destination": "/providers/openai" "destination": "/providers/openai"

View File

@ -42,6 +42,7 @@ See [Venice AI](/providers/venice).
- [OpenCode Zen](/providers/opencode) - [OpenCode Zen](/providers/opencode)
- [Amazon Bedrock](/bedrock) - [Amazon Bedrock](/bedrock)
- [Z.AI](/providers/zai) - [Z.AI](/providers/zai)
- [Xiaomi](/providers/xiaomi)
- [GLM models](/providers/glm) - [GLM models](/providers/glm)
- [MiniMax](/providers/minimax) - [MiniMax](/providers/minimax)
- [Venius (Venice AI, privacy-focused)](/providers/venice) - [Venius (Venice AI, privacy-focused)](/providers/venice)

62
docs/providers/xiaomi.md Normal file
View File

@ -0,0 +1,62 @@
---
summary: "Use Xiaomi MiMo (mimo-v2-flash) with Moltbot"
read_when:
- You want Xiaomi MiMo models in Moltbot
- You need XIAOMI_API_KEY setup
---
# Xiaomi MiMo
Xiaomi MiMo is the API platform for **MiMo** models. It provides REST APIs compatible with
OpenAI and Anthropic formats and uses API keys for authentication. Create your API key in
the [Xiaomi MiMo console](https://platform.xiaomimimo.com/#/console/api-keys). Moltbot uses
the `xiaomi` provider with a Xiaomi MiMo API key.
## Model overview
- **mimo-v2-flash**: 262144-token context window, Anthropic Messages API compatible.
- Base URL: `https://api.xiaomimimo.com/anthropic`
- Authorization: `Bearer $XIAOMI_API_KEY`
## CLI setup
```bash
moltbot onboard --auth-choice xiaomi-api-key
# or non-interactive
moltbot onboard --auth-choice xiaomi-api-key --xiaomi-api-key "$XIAOMI_API_KEY"
```
## Config snippet
```json5
{
env: { XIAOMI_API_KEY: "your-key" },
agents: { defaults: { model: { primary: "xiaomi/mimo-v2-flash" } } },
models: {
mode: "merge",
providers: {
xiaomi: {
baseUrl: "https://api.xiaomimimo.com/anthropic",
api: "anthropic-messages",
apiKey: "XIAOMI_API_KEY",
models: [
{
id: "mimo-v2-flash",
name: "Xiaomi MiMo V2 Flash",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 262144,
maxTokens: 8192
}
]
}
}
}
}
```
## Notes
- Model ref: `xiaomi/mimo-v2-flash`.
- The provider is injected automatically when `XIAOMI_API_KEY` is set (or an auth profile exists).
- See [/concepts/model-providers](/concepts/model-providers) for provider rules.

View File

@ -281,6 +281,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null {
moonshot: "MOONSHOT_API_KEY", moonshot: "MOONSHOT_API_KEY",
"kimi-code": "KIMICODE_API_KEY", "kimi-code": "KIMICODE_API_KEY",
minimax: "MINIMAX_API_KEY", minimax: "MINIMAX_API_KEY",
xiaomi: "XIAOMI_API_KEY",
synthetic: "SYNTHETIC_API_KEY", synthetic: "SYNTHETIC_API_KEY",
venice: "VENICE_API_KEY", venice: "VENICE_API_KEY",
mistral: "MISTRAL_API_KEY", mistral: "MISTRAL_API_KEY",

View File

@ -30,6 +30,17 @@ const MINIMAX_API_COST = {
cacheWrite: 10, cacheWrite: 10,
}; };
const XIAOMI_BASE_URL = "https://api.xiaomimimo.com/anthropic";
const XIAOMI_DEFAULT_MODEL_ID = "mimo-v2-flash";
const XIAOMI_DEFAULT_CONTEXT_WINDOW = 262144;
const XIAOMI_DEFAULT_MAX_TOKENS = 8192;
const XIAOMI_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
const MOONSHOT_BASE_URL = "https://api.moonshot.ai/v1"; const MOONSHOT_BASE_URL = "https://api.moonshot.ai/v1";
const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2.5"; const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2.5";
const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000; const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000;
@ -341,6 +352,24 @@ function buildSyntheticProvider(): ProviderConfig {
}; };
} }
export function buildXiaomiProvider(): ProviderConfig {
return {
baseUrl: XIAOMI_BASE_URL,
api: "anthropic-messages",
models: [
{
id: XIAOMI_DEFAULT_MODEL_ID,
name: "Xiaomi MiMo V2 Flash",
reasoning: false,
input: ["text"],
cost: XIAOMI_DEFAULT_COST,
contextWindow: XIAOMI_DEFAULT_CONTEXT_WINDOW,
maxTokens: XIAOMI_DEFAULT_MAX_TOKENS,
},
],
};
}
async function buildVeniceProvider(): Promise<ProviderConfig> { async function buildVeniceProvider(): Promise<ProviderConfig> {
const models = await discoverVeniceModels(); const models = await discoverVeniceModels();
return { return {
@ -410,6 +439,13 @@ export async function resolveImplicitProviders(params: {
}; };
} }
const xiaomiKey =
resolveEnvApiKeyVarName("xiaomi") ??
resolveApiKeyFromProfiles({ provider: "xiaomi", store: authStore });
if (xiaomiKey) {
providers.xiaomi = { ...buildXiaomiProvider(), apiKey: xiaomiKey };
}
// Ollama provider - only add if explicitly configured // Ollama provider - only add if explicitly configured
const ollamaKey = const ollamaKey =
resolveEnvApiKeyVarName("ollama") ?? resolveEnvApiKeyVarName("ollama") ??

View File

@ -52,7 +52,7 @@ export function registerOnboardCommand(program: Command) {
.option("--mode <mode>", "Wizard mode: local|remote") .option("--mode <mode>", "Wizard mode: local|remote")
.option( .option(
"--auth-choice <choice>", "--auth-choice <choice>",
"Auth: setup-token|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", "Auth: setup-token|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip",
) )
.option( .option(
"--token-provider <id>", "--token-provider <id>",
@ -72,6 +72,7 @@ export function registerOnboardCommand(program: Command) {
.option("--kimi-code-api-key <key>", "Kimi Code API key") .option("--kimi-code-api-key <key>", "Kimi Code API key")
.option("--gemini-api-key <key>", "Gemini API key") .option("--gemini-api-key <key>", "Gemini API key")
.option("--zai-api-key <key>", "Z.AI API key") .option("--zai-api-key <key>", "Z.AI API key")
.option("--xiaomi-api-key <key>", "Xiaomi API key")
.option("--minimax-api-key <key>", "MiniMax API key") .option("--minimax-api-key <key>", "MiniMax API key")
.option("--synthetic-api-key <key>", "Synthetic API key") .option("--synthetic-api-key <key>", "Synthetic API key")
.option("--venice-api-key <key>", "Venice API key") .option("--venice-api-key <key>", "Venice API key")
@ -122,6 +123,7 @@ export function registerOnboardCommand(program: Command) {
kimiCodeApiKey: opts.kimiCodeApiKey as string | undefined, kimiCodeApiKey: opts.kimiCodeApiKey as string | undefined,
geminiApiKey: opts.geminiApiKey as string | undefined, geminiApiKey: opts.geminiApiKey as string | undefined,
zaiApiKey: opts.zaiApiKey as string | undefined, zaiApiKey: opts.zaiApiKey as string | undefined,
xiaomiApiKey: opts.xiaomiApiKey as string | undefined,
minimaxApiKey: opts.minimaxApiKey as string | undefined, minimaxApiKey: opts.minimaxApiKey as string | undefined,
syntheticApiKey: opts.syntheticApiKey as string | undefined, syntheticApiKey: opts.syntheticApiKey as string | undefined,
veniceApiKey: opts.veniceApiKey as string | undefined, veniceApiKey: opts.veniceApiKey as string | undefined,

View File

@ -33,6 +33,16 @@ describe("buildAuthChoiceOptions", () => {
expect(options.some((opt) => opt.value === "zai-api-key")).toBe(true); expect(options.some((opt) => opt.value === "zai-api-key")).toBe(true);
}); });
it("includes Xiaomi auth choice", () => {
const store: AuthProfileStore = { version: 1, profiles: {} };
const options = buildAuthChoiceOptions({
store,
includeSkip: false,
});
expect(options.some((opt) => opt.value === "xiaomi-api-key")).toBe(true);
});
it("includes MiniMax auth choice", () => { it("includes MiniMax auth choice", () => {
const store: AuthProfileStore = { version: 1, profiles: {} }; const store: AuthProfileStore = { version: 1, profiles: {} };
const options = buildAuthChoiceOptions({ const options = buildAuthChoiceOptions({

View File

@ -16,6 +16,7 @@ export type AuthChoiceGroupId =
| "ai-gateway" | "ai-gateway"
| "moonshot" | "moonshot"
| "zai" | "zai"
| "xiaomi"
| "opencode-zen" | "opencode-zen"
| "minimax" | "minimax"
| "synthetic" | "synthetic"
@ -107,6 +108,12 @@ const AUTH_CHOICE_GROUP_DEFS: {
hint: "API key", hint: "API key",
choices: ["zai-api-key"], choices: ["zai-api-key"],
}, },
{
value: "xiaomi",
label: "Xiaomi",
hint: "API key",
choices: ["xiaomi-api-key"],
},
{ {
value: "opencode-zen", value: "opencode-zen",
label: "OpenCode Zen", label: "OpenCode Zen",
@ -164,6 +171,10 @@ export function buildAuthChoiceOptions(params: {
hint: "Uses the bundled Gemini CLI auth plugin", hint: "Uses the bundled Gemini CLI auth plugin",
}); });
options.push({ value: "zai-api-key", label: "Z.AI (GLM 4.7) API key" }); options.push({ value: "zai-api-key", label: "Z.AI (GLM 4.7) API key" });
options.push({
value: "xiaomi-api-key",
label: "Xiaomi API key",
});
options.push({ value: "qwen-portal", label: "Qwen OAuth" }); options.push({ value: "qwen-portal", label: "Qwen OAuth" });
options.push({ options.push({
value: "copilot-proxy", value: "copilot-proxy",

View File

@ -27,6 +27,8 @@ import {
applyVeniceProviderConfig, applyVeniceProviderConfig,
applyVercelAiGatewayConfig, applyVercelAiGatewayConfig,
applyVercelAiGatewayProviderConfig, applyVercelAiGatewayProviderConfig,
applyXiaomiConfig,
applyXiaomiProviderConfig,
applyZaiConfig, applyZaiConfig,
KIMI_CODE_MODEL_REF, KIMI_CODE_MODEL_REF,
MOONSHOT_DEFAULT_MODEL_REF, MOONSHOT_DEFAULT_MODEL_REF,
@ -34,6 +36,7 @@ import {
SYNTHETIC_DEFAULT_MODEL_REF, SYNTHETIC_DEFAULT_MODEL_REF,
VENICE_DEFAULT_MODEL_REF, VENICE_DEFAULT_MODEL_REF,
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
XIAOMI_DEFAULT_MODEL_REF,
setGeminiApiKey, setGeminiApiKey,
setKimiCodeApiKey, setKimiCodeApiKey,
setMoonshotApiKey, setMoonshotApiKey,
@ -42,6 +45,7 @@ import {
setSyntheticApiKey, setSyntheticApiKey,
setVeniceApiKey, setVeniceApiKey,
setVercelAiGatewayApiKey, setVercelAiGatewayApiKey,
setXiaomiApiKey,
setZaiApiKey, setZaiApiKey,
ZAI_DEFAULT_MODEL_REF, ZAI_DEFAULT_MODEL_REF,
} from "./onboard-auth.js"; } from "./onboard-auth.js";
@ -79,6 +83,8 @@ export async function applyAuthChoiceApiProviders(
authChoice = "gemini-api-key"; authChoice = "gemini-api-key";
} else if (params.opts.tokenProvider === "zai") { } else if (params.opts.tokenProvider === "zai") {
authChoice = "zai-api-key"; authChoice = "zai-api-key";
} else if (params.opts.tokenProvider === "xiaomi") {
authChoice = "xiaomi-api-key";
} else if (params.opts.tokenProvider === "synthetic") { } else if (params.opts.tokenProvider === "synthetic") {
authChoice = "synthetic-api-key"; authChoice = "synthetic-api-key";
} else if (params.opts.tokenProvider === "venice") { } else if (params.opts.tokenProvider === "venice") {
@ -431,6 +437,54 @@ export async function applyAuthChoiceApiProviders(
return { config: nextConfig, agentModelOverride }; return { config: nextConfig, agentModelOverride };
} }
if (authChoice === "xiaomi-api-key") {
let hasCredential = false;
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "xiaomi") {
await setXiaomiApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir);
hasCredential = true;
}
const envKey = resolveEnvApiKey("xiaomi");
if (envKey) {
const useExisting = await params.prompter.confirm({
message: `Use existing XIAOMI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
initialValue: true,
});
if (useExisting) {
await setXiaomiApiKey(envKey.apiKey, params.agentDir);
hasCredential = true;
}
}
if (!hasCredential) {
const key = await params.prompter.text({
message: "Enter Xiaomi API key",
validate: validateApiKeyInput,
});
await setXiaomiApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
}
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "xiaomi:default",
provider: "xiaomi",
mode: "api_key",
});
{
const applied = await applyDefaultModelChoice({
config: nextConfig,
setDefaultModel: params.setDefaultModel,
defaultModel: XIAOMI_DEFAULT_MODEL_REF,
applyDefaultConfig: applyXiaomiConfig,
applyProviderConfig: applyXiaomiProviderConfig,
noteDefault: XIAOMI_DEFAULT_MODEL_REF,
noteAgentModel,
prompter: params.prompter,
});
nextConfig = applied.config;
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
}
return { config: nextConfig, agentModelOverride };
}
if (authChoice === "synthetic-api-key") { if (authChoice === "synthetic-api-key") {
if (params.opts?.token && params.opts?.tokenProvider === "synthetic") { if (params.opts?.token && params.opts?.tokenProvider === "synthetic") {
await setSyntheticApiKey(String(params.opts.token).trim(), params.agentDir); await setSyntheticApiKey(String(params.opts.token).trim(), params.agentDir);

View File

@ -18,6 +18,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
"google-antigravity": "google-antigravity", "google-antigravity": "google-antigravity",
"google-gemini-cli": "google-gemini-cli", "google-gemini-cli": "google-gemini-cli",
"zai-api-key": "zai", "zai-api-key": "zai",
"xiaomi-api-key": "xiaomi",
"synthetic-api-key": "synthetic", "synthetic-api-key": "synthetic",
"venice-api-key": "venice", "venice-api-key": "venice",
"github-copilot": "github-copilot", "github-copilot": "github-copilot",

View File

@ -1,3 +1,4 @@
import { buildXiaomiProvider } from "../agents/models-config.providers.js";
import { import {
buildSyntheticModelDefinition, buildSyntheticModelDefinition,
SYNTHETIC_BASE_URL, SYNTHETIC_BASE_URL,
@ -14,6 +15,7 @@ import type { MoltbotConfig } from "../config/config.js";
import { import {
OPENROUTER_DEFAULT_MODEL_REF, OPENROUTER_DEFAULT_MODEL_REF,
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
XIAOMI_DEFAULT_MODEL_REF,
ZAI_DEFAULT_MODEL_REF, ZAI_DEFAULT_MODEL_REF,
} from "./onboard-auth.credentials.js"; } from "./onboard-auth.credentials.js";
import { import {
@ -336,6 +338,70 @@ export function applySyntheticConfig(cfg: MoltbotConfig): MoltbotConfig {
}; };
} }
export function applyXiaomiProviderConfig(cfg: MoltbotConfig): MoltbotConfig {
const models = { ...cfg.agents?.defaults?.models };
models[XIAOMI_DEFAULT_MODEL_REF] = {
...models[XIAOMI_DEFAULT_MODEL_REF],
alias: models[XIAOMI_DEFAULT_MODEL_REF]?.alias ?? "Xiaomi",
};
const providers = { ...cfg.models?.providers };
const existingProvider = providers.xiaomi;
const defaultProvider = buildXiaomiProvider();
const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : [];
const mergedModels = existingModels.length > 0 ? existingModels : (defaultProvider.models ?? []);
const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record<
string,
unknown
> as { apiKey?: string };
const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined;
const normalizedApiKey = resolvedApiKey?.trim();
providers.xiaomi = {
...existingProviderRest,
baseUrl: defaultProvider.baseUrl,
api: defaultProvider.api,
...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}),
models: mergedModels.length > 0 ? mergedModels : defaultProvider.models,
};
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
models,
},
},
models: {
mode: cfg.models?.mode ?? "merge",
providers,
},
};
}
export function applyXiaomiConfig(cfg: MoltbotConfig): MoltbotConfig {
const next = applyXiaomiProviderConfig(cfg);
const existingModel = next.agents?.defaults?.model;
return {
...next,
agents: {
...next.agents,
defaults: {
...next.agents?.defaults,
model: {
...(existingModel && "fallbacks" in (existingModel as Record<string, unknown>)
? {
fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks,
}
: undefined),
primary: XIAOMI_DEFAULT_MODEL_REF,
},
},
},
};
}
/** /**
* Apply Venice provider configuration without changing the default model. * Apply Venice provider configuration without changing the default model.
* Registers Venice models and sets up the provider, but preserves existing model selection. * Registers Venice models and sets up the provider, but preserves existing model selection.

View File

@ -113,6 +113,7 @@ export async function setVeniceApiKey(key: string, agentDir?: string) {
} }
export const ZAI_DEFAULT_MODEL_REF = "zai/glm-4.7"; export const ZAI_DEFAULT_MODEL_REF = "zai/glm-4.7";
export const XIAOMI_DEFAULT_MODEL_REF = "xiaomi/mimo-v2-flash";
export const OPENROUTER_DEFAULT_MODEL_REF = "openrouter/auto"; export const OPENROUTER_DEFAULT_MODEL_REF = "openrouter/auto";
export const VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF = "vercel-ai-gateway/anthropic/claude-opus-4.5"; export const VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF = "vercel-ai-gateway/anthropic/claude-opus-4.5";
@ -129,6 +130,18 @@ export async function setZaiApiKey(key: string, agentDir?: string) {
}); });
} }
export async function setXiaomiApiKey(key: string, agentDir?: string) {
upsertAuthProfile({
profileId: "xiaomi:default",
credential: {
type: "api_key",
provider: "xiaomi",
key,
},
agentDir: resolveAuthAgentDir(agentDir),
});
}
export async function setOpenrouterApiKey(key: string, agentDir?: string) { export async function setOpenrouterApiKey(key: string, agentDir?: string) {
upsertAuthProfile({ upsertAuthProfile({
profileId: "openrouter:default", profileId: "openrouter:default",

View File

@ -17,6 +17,8 @@ export {
applyVeniceProviderConfig, applyVeniceProviderConfig,
applyVercelAiGatewayConfig, applyVercelAiGatewayConfig,
applyVercelAiGatewayProviderConfig, applyVercelAiGatewayProviderConfig,
applyXiaomiConfig,
applyXiaomiProviderConfig,
applyZaiConfig, applyZaiConfig,
} from "./onboard-auth.config-core.js"; } from "./onboard-auth.config-core.js";
export { export {
@ -44,9 +46,11 @@ export {
setSyntheticApiKey, setSyntheticApiKey,
setVeniceApiKey, setVeniceApiKey,
setVercelAiGatewayApiKey, setVercelAiGatewayApiKey,
setXiaomiApiKey,
setZaiApiKey, setZaiApiKey,
writeOAuthCredentials, writeOAuthCredentials,
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
XIAOMI_DEFAULT_MODEL_REF,
ZAI_DEFAULT_MODEL_REF, ZAI_DEFAULT_MODEL_REF,
} from "./onboard-auth.credentials.js"; } from "./onboard-auth.credentials.js";
export { export {

View File

@ -17,6 +17,7 @@ import {
applySyntheticConfig, applySyntheticConfig,
applyVeniceConfig, applyVeniceConfig,
applyVercelAiGatewayConfig, applyVercelAiGatewayConfig,
applyXiaomiConfig,
applyZaiConfig, applyZaiConfig,
setAnthropicApiKey, setAnthropicApiKey,
setGeminiApiKey, setGeminiApiKey,
@ -28,6 +29,7 @@ import {
setSyntheticApiKey, setSyntheticApiKey,
setVeniceApiKey, setVeniceApiKey,
setVercelAiGatewayApiKey, setVercelAiGatewayApiKey,
setXiaomiApiKey,
setZaiApiKey, setZaiApiKey,
} from "../../onboard-auth.js"; } from "../../onboard-auth.js";
import type { AuthChoice, OnboardOptions } from "../../onboard-types.js"; import type { AuthChoice, OnboardOptions } from "../../onboard-types.js";
@ -177,6 +179,25 @@ export async function applyNonInteractiveAuthChoice(params: {
return applyZaiConfig(nextConfig); return applyZaiConfig(nextConfig);
} }
if (authChoice === "xiaomi-api-key") {
const resolved = await resolveNonInteractiveApiKey({
provider: "xiaomi",
cfg: baseConfig,
flagValue: opts.xiaomiApiKey,
flagName: "--xiaomi-api-key",
envVar: "XIAOMI_API_KEY",
runtime,
});
if (!resolved) return null;
if (resolved.source !== "profile") await setXiaomiApiKey(resolved.key);
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "xiaomi:default",
provider: "xiaomi",
mode: "api_key",
});
return applyXiaomiConfig(nextConfig);
}
if (authChoice === "openai-api-key") { if (authChoice === "openai-api-key") {
const resolved = await resolveNonInteractiveApiKey({ const resolved = await resolveNonInteractiveApiKey({
provider: "openai", provider: "openai",

View File

@ -23,6 +23,7 @@ export type AuthChoice =
| "google-antigravity" | "google-antigravity"
| "google-gemini-cli" | "google-gemini-cli"
| "zai-api-key" | "zai-api-key"
| "xiaomi-api-key"
| "minimax-cloud" | "minimax-cloud"
| "minimax" | "minimax"
| "minimax-api" | "minimax-api"
@ -67,6 +68,7 @@ export type OnboardOptions = {
kimiCodeApiKey?: string; kimiCodeApiKey?: string;
geminiApiKey?: string; geminiApiKey?: string;
zaiApiKey?: string; zaiApiKey?: string;
xiaomiApiKey?: string;
minimaxApiKey?: string; minimaxApiKey?: string;
syntheticApiKey?: string; syntheticApiKey?: string;
veniceApiKey?: string; veniceApiKey?: string;

View File

@ -96,6 +96,33 @@ function resolveMinimaxApiKey(): string | undefined {
return undefined; return undefined;
} }
function resolveXiaomiApiKey(): string | undefined {
const envDirect = process.env.XIAOMI_API_KEY?.trim();
if (envDirect) return envDirect;
const envResolved = resolveEnvApiKey("xiaomi");
if (envResolved?.apiKey) return envResolved.apiKey;
const cfg = loadConfig();
const key = getCustomProviderApiKey(cfg, "xiaomi");
if (key) return key;
const store = ensureAuthProfileStore();
const apiProfile = listProfilesForProvider(store, "xiaomi").find((id) => {
const cred = store.profiles[id];
return cred?.type === "api_key" || cred?.type === "token";
});
if (!apiProfile) return undefined;
const cred = store.profiles[apiProfile];
if (cred?.type === "api_key" && cred.key?.trim()) {
return cred.key.trim();
}
if (cred?.type === "token" && cred.token?.trim()) {
return cred.token.trim();
}
return undefined;
}
async function resolveOAuthToken(params: { async function resolveOAuthToken(params: {
provider: UsageProviderId; provider: UsageProviderId;
agentDir?: string; agentDir?: string;
@ -199,6 +226,11 @@ export async function resolveProviderAuths(params: {
if (apiKey) auths.push({ provider, token: apiKey }); if (apiKey) auths.push({ provider, token: apiKey });
continue; continue;
} }
if (provider === "xiaomi") {
const apiKey = resolveXiaomiApiKey();
if (apiKey) auths.push({ provider, token: apiKey });
continue;
}
if (!oauthProviders.includes(provider)) continue; if (!oauthProviders.includes(provider)) continue;
const auth = await resolveOAuthToken({ const auth = await resolveOAuthToken({

View File

@ -66,6 +66,12 @@ export async function loadProviderUsageSummary(
return await fetchCodexUsage(auth.token, auth.accountId, timeoutMs, fetchFn); return await fetchCodexUsage(auth.token, auth.accountId, timeoutMs, fetchFn);
case "minimax": case "minimax":
return await fetchMinimaxUsage(auth.token, timeoutMs, fetchFn); return await fetchMinimaxUsage(auth.token, timeoutMs, fetchFn);
case "xiaomi":
return {
provider: "xiaomi",
displayName: PROVIDER_LABELS.xiaomi,
windows: [],
};
case "zai": case "zai":
return await fetchZaiUsage(auth.token, timeoutMs, fetchFn); return await fetchZaiUsage(auth.token, timeoutMs, fetchFn);
default: default:

View File

@ -10,6 +10,7 @@ export const PROVIDER_LABELS: Record<UsageProviderId, string> = {
"google-antigravity": "Antigravity", "google-antigravity": "Antigravity",
minimax: "MiniMax", minimax: "MiniMax",
"openai-codex": "Codex", "openai-codex": "Codex",
xiaomi: "Xiaomi",
zai: "z.ai", zai: "z.ai",
}; };
@ -20,6 +21,7 @@ export const usageProviders: UsageProviderId[] = [
"google-antigravity", "google-antigravity",
"minimax", "minimax",
"openai-codex", "openai-codex",
"xiaomi",
"zai", "zai",
]; ];

View File

@ -24,4 +24,5 @@ export type UsageProviderId =
| "google-antigravity" | "google-antigravity"
| "minimax" | "minimax"
| "openai-codex" | "openai-codex"
| "xiaomi"
| "zai"; | "zai";