feat(plugins): externalize Xiaomi provider (#116861)

This commit is contained in:
Vincent Koc
2026-07-31 22:02:07 +08:00
committed by GitHub
parent 08f1053182
commit fab2c33cad
15 changed files with 250 additions and 23 deletions
+4 -4
View File
@@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
## Core npm package
62 plugins
61 plugins
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
@@ -175,11 +175,9 @@ Each entry lists the package, distribution route, and description.
- **[xai](/plugins/reference/xai)** (`@openclaw/xai-plugin`) - included in OpenClaw. Adds xAI model provider support to OpenClaw.
- **[xiaomi](/plugins/reference/xiaomi)** (`@openclaw/xiaomi-provider`) - included in OpenClaw. Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw.
## Official external packages
83 plugins
84 plugins
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
@@ -339,6 +337,8 @@ Each entry lists the package, distribution route, and description.
- **[whatsapp](/plugins/reference/whatsapp)** (`@openclaw/whatsapp`) - ClawHub: `clawhub:@openclaw/whatsapp`; npm. OpenClaw WhatsApp channel plugin for WhatsApp Web chats.
- **[xiaomi](/plugins/reference/xiaomi)** (`@openclaw/xiaomi-provider`) - npm; ClawHub: `clawhub:@openclaw/xiaomi-provider`. Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw.
- **[zai](/plugins/reference/zai)** (`@openclaw/zai-provider`) - npm; ClawHub: `clawhub:@openclaw/zai-provider`. Adds Z.AI model provider support to OpenClaw.
- **[zalo](/plugins/reference/zalo)** (`@openclaw/zalo`) - npm; ClawHub. OpenClaw Zalo channel plugin for bot and webhook chats.
+1 -1
View File
@@ -12,7 +12,7 @@ Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/xiaomi-provider`
- Install route: included in OpenClaw
- Install route: npm; ClawHub: `clawhub:@openclaw/xiaomi-provider`
## Surface
+17 -8
View File
@@ -6,9 +6,8 @@ read_when:
title: "Xiaomi MiMo"
---
Xiaomi MiMo is the API platform for **MiMo** models. The bundled `xiaomi`
plugin (`enabledByDefault: true`, no install step) registers two text
providers plus a speech (TTS) provider:
Xiaomi MiMo is the API platform for **MiMo** models. The official external
`xiaomi` plugin registers two text providers plus a speech (TTS) provider:
- `xiaomi` - pay-as-you-go keys (`sk-...`)
- `xiaomi-token-plan` - Token Plan keys (`tp-...`) with regional endpoint presets
@@ -28,6 +27,13 @@ providers plus a speech (TTS) provider:
## Getting started
<Steps>
<Step title="Install the plugin">
```bash
openclaw plugins install @openclaw/xiaomi-provider
openclaw gateway restart
```
</Step>
<Step title="Get the right key">
Create a pay-as-you-go key in the [Xiaomi MiMo console](https://platform.xiaomimimo.com/#/console/api-keys), or open your Token Plan subscription page and copy the regional OpenAI-compatible base URL plus the matching `tp-...` key.
</Step>
@@ -88,7 +94,7 @@ Choose the Token Plan auth choice that matches the regional base URL shown in Xi
| `xiaomi-token-plan/mimo-v2.5` | text, image | 1,048,576 | 131,072 | Yes | Multimodal |
`xiaomi-token-plan` needs a regional base URL to resolve. The supported path
is a bundled Token Plan onboarding choice or an explicit
is a Token Plan onboarding choice or an explicit
`models.providers.xiaomi-token-plan` config block with `baseUrl` set; the
provider is not offered without one of those.
@@ -100,7 +106,7 @@ OpenClaw's [`/think` directive](/tools/thinking) with levels `off`,
## Text-to-speech
The bundled `xiaomi` plugin also registers Xiaomi MiMo as a speech provider
The `xiaomi` plugin also registers Xiaomi MiMo as a speech provider
for `tts`. It calls Xiaomi's chat-completions TTS contract with the
text as an `assistant` message and optional style guidance as a `user`
message.
@@ -197,7 +203,8 @@ mono Opus with `ffmpeg` before delivery.
}
```
Pricing and compat flags come from the bundled plugin manifest, so the config example omits `cost` and `compat` to avoid diverging from runtime behavior.
Pricing and compat flags come from the plugin manifest, so the config example
omits `cost` and `compat` to avoid diverging from runtime behavior.
Token Plan:
@@ -236,11 +243,13 @@ Token Plan:
}
```
Token Plan charges against a fixed subscription's Credits rather than per-token USD pricing, so its bundled catalog rows use zero USD cost and the config example omits `cost`.
Token Plan charges against a fixed subscription's Credits rather than per-token
USD pricing, so its catalog rows use zero USD cost and the config example omits
`cost`.
<AccordionGroup>
<Accordion title="Auto-injection behavior">
The `xiaomi` provider is auto-enabled when `XIAOMI_API_KEY` is set in your environment or an auth profile exists. `xiaomi-token-plan` needs a regional base URL, so the supported path is the bundled Token Plan onboarding choice or an explicit `models.providers.xiaomi-token-plan` config block.
The `xiaomi` provider is auto-enabled when `XIAOMI_API_KEY` is set in your environment or an auth profile exists. `xiaomi-token-plan` needs a regional base URL, so the supported path is the Token Plan onboarding choice or an explicit `models.providers.xiaomi-token-plan` config block.
</Accordion>
<Accordion title="Model details">
+16
View File
@@ -0,0 +1,16 @@
# OpenClaw Xiaomi Provider
Official OpenClaw provider plugin for Xiaomi MiMo pay-as-you-go and Token Plan
models, usage tracking, and text-to-speech.
Install from OpenClaw:
```bash
openclaw plugins install @openclaw/xiaomi-provider
openclaw gateway restart
```
Configure `XIAOMI_API_KEY` for `xiaomi/*` models and speech, or
`XIAOMI_TOKEN_PLAN_API_KEY` for `xiaomi-token-plan/*` models. See
https://docs.openclaw.ai/providers/xiaomi for regional Token Plan setup and
the full model and speech configuration.
+1 -1
View File
@@ -364,7 +364,7 @@ function createTokenPlanAuthMethod(region: XiaomiTokenPlanRegion): ProviderAuthM
export default definePluginEntry({
id: XIAOMI_PROVIDER_ID,
name: "Xiaomi Provider",
description: "Bundled Xiaomi provider plugin",
description: "Xiaomi provider plugin",
register(api) {
api.registerProvider({
id: XIAOMI_PROVIDER_ID,
+23 -3
View File
@@ -1,8 +1,11 @@
{
"name": "@openclaw/xiaomi-provider",
"version": "2026.7.2",
"private": true,
"description": "OpenClaw Xiaomi provider plugin",
"description": "OpenClaw Xiaomi provider plugin.",
"repository": {
"type": "git",
"url": "https://github.com/openclaw/openclaw"
},
"type": "module",
"devDependencies": {
"@openclaw/plugin-sdk": "workspace:*"
@@ -10,6 +13,23 @@
"openclaw": {
"extensions": [
"./index.ts"
]
],
"install": {
"clawhubSpec": "clawhub:@openclaw/xiaomi-provider",
"npmSpec": "@openclaw/xiaomi-provider",
"defaultChoice": "npm",
"minHostVersion": ">=2026.7.2"
},
"compat": {
"pluginApi": ">=2026.7.2"
},
"build": {
"openclawVersion": "2026.7.2",
"bundledDist": false
},
"release": {
"publishToClawHub": true,
"publishToNpm": true
}
}
}
+1
View File
@@ -320,6 +320,7 @@
"!dist/extensions/voyage/**",
"!dist/extensions/vydra/**",
"!dist/extensions/whatsapp/**",
"!dist/extensions/xiaomi/**",
"!dist/extensions/zai/**",
"!dist/extensions/zalo/**",
"!dist/extensions/zalouser/**",
@@ -1588,6 +1588,138 @@
}
}
},
{
"name": "@openclaw/xiaomi-provider",
"description": "OpenClaw Xiaomi provider plugin.",
"source": "official",
"kind": "provider",
"openclaw": {
"plugin": {
"id": "xiaomi",
"label": "Xiaomi"
},
"providerEndpoints": [
{
"endpointClass": "xiaomi-native",
"hosts": [
"api.xiaomimimo.com",
"token-plan-ams.xiaomimimo.com",
"token-plan-cn.xiaomimimo.com",
"token-plan-sgp.xiaomimimo.com"
]
}
],
"providers": [
{
"id": "xiaomi",
"name": "Xiaomi",
"docs": "/providers/xiaomi",
"categories": [
"cloud",
"llm"
],
"envVars": [
"XIAOMI_API_KEY"
],
"authChoices": [
{
"method": "api-key",
"choiceId": "xiaomi-api-key",
"choiceLabel": "Xiaomi API key (Pay-as-you-go)",
"choiceHint": "Endpoint: api.xiaomimimo.com/v1",
"groupId": "xiaomi",
"groupLabel": "Xiaomi",
"groupHint": "Pay-as-you-go / Token Plan",
"optionKey": "xiaomiApiKey",
"cliFlag": "--xiaomi-api-key",
"cliOption": "--xiaomi-api-key <key>",
"cliDescription": "Xiaomi MiMo pay-as-you-go API key",
"onboardingScopes": [
"text-inference"
]
}
]
},
{
"id": "xiaomi-token-plan",
"name": "Xiaomi Token Plan",
"docs": "/providers/xiaomi",
"categories": [
"cloud",
"llm"
],
"envVars": [
"XIAOMI_TOKEN_PLAN_API_KEY"
],
"authChoices": [
{
"method": "token-plan-ams",
"choiceId": "xiaomi-token-plan-ams",
"choiceLabel": "Xiaomi Token Plan (Europe)",
"choiceHint": "Endpoint preset: token-plan-ams.xiaomimimo.com/v1",
"groupId": "xiaomi",
"groupLabel": "Xiaomi",
"groupHint": "Pay-as-you-go / Token Plan",
"optionKey": "xiaomiTokenPlanApiKey",
"cliFlag": "--xiaomi-token-plan-api-key",
"cliOption": "--xiaomi-token-plan-api-key <key>",
"cliDescription": "Xiaomi MiMo Token Plan API key",
"onboardingScopes": [
"text-inference"
]
},
{
"method": "token-plan-cn",
"choiceId": "xiaomi-token-plan-cn",
"choiceLabel": "Xiaomi Token Plan (China)",
"choiceHint": "Endpoint preset: token-plan-cn.xiaomimimo.com/v1",
"groupId": "xiaomi",
"groupLabel": "Xiaomi",
"groupHint": "Pay-as-you-go / Token Plan",
"optionKey": "xiaomiTokenPlanApiKey",
"cliFlag": "--xiaomi-token-plan-api-key",
"cliOption": "--xiaomi-token-plan-api-key <key>",
"cliDescription": "Xiaomi MiMo Token Plan API key",
"onboardingScopes": [
"text-inference"
]
},
{
"method": "token-plan-sgp",
"choiceId": "xiaomi-token-plan-sgp",
"choiceLabel": "Xiaomi Token Plan (Singapore)",
"choiceHint": "Endpoint preset: token-plan-sgp.xiaomimimo.com/v1",
"groupId": "xiaomi",
"groupLabel": "Xiaomi",
"groupHint": "Pay-as-you-go / Token Plan",
"optionKey": "xiaomiTokenPlanApiKey",
"cliFlag": "--xiaomi-token-plan-api-key",
"cliOption": "--xiaomi-token-plan-api-key <key>",
"cliDescription": "Xiaomi MiMo Token Plan API key",
"onboardingScopes": [
"text-inference"
]
}
]
}
],
"contracts": {
"speechProviders": [
"xiaomi"
],
"usageProviders": [
"xiaomi",
"xiaomi-token-plan"
]
},
"install": {
"clawhubSpec": "clawhub:@openclaw/xiaomi-provider",
"npmSpec": "@openclaw/xiaomi-provider",
"defaultChoice": "npm",
"minHostVersion": ">=2026.7.2"
}
}
},
{
"name": "@openclaw/zai-provider",
"description": "OpenClaw Z.AI provider plugin",
+1
View File
@@ -171,6 +171,7 @@ describe("listPersistedBundledPluginLocationBridges", () => {
["volcengine", "@openclaw/volcengine-provider", true],
["voyage", "@openclaw/voyage-provider", true],
["vydra", "@openclaw/vydra-provider", true],
["xiaomi", "@openclaw/xiaomi-provider", true],
["zoom-meetings", "@openclaw/zoom-meetings", true],
] as const)(
"externalizes the shipped bundled %s plugin using official install metadata",
+2 -2
View File
@@ -1,6 +1,6 @@
// Manual facade. Keep loader boundary explicit.
import type { ModelProviderConfig, OpenClawConfig } from "../config/types.js";
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-loader.js";
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
type FacadeModule = {
applyXiaomiConfig: (cfg: OpenClawConfig) => OpenClawConfig;
@@ -27,7 +27,7 @@ export const applyXiaomiProviderConfig: FacadeModule["applyXiaomiProviderConfig"
/** Build the Xiaomi model provider entry used by setup/config helpers. */
export const buildXiaomiProvider: FacadeModule["buildXiaomiProvider"] = ((...args) =>
loadFacadeModule()["buildXiaomiProvider"](...args)) as FacadeModule["buildXiaomiProvider"];
/** Default Xiaomi model id advertised by the bundled provider facade. */
/** Default Xiaomi model id advertised by the provider facade. */
export const XIAOMI_DEFAULT_MODEL_ID: FacadeModule["XIAOMI_DEFAULT_MODEL_ID"] =
loadFacadeModule()["XIAOMI_DEFAULT_MODEL_ID"];
/** Default Xiaomi provider/model reference written by setup flows. */
@@ -79,6 +79,7 @@ const packageManifestContractTests: PackageManifestContractParams[] = [
pluginLocalRuntimeDeps: ["audio-decode", "baileys"],
minHostVersionBaseline: "2026.3.22",
},
{ pluginId: "xiaomi", minHostVersionBaseline: "2026.7.2" },
{ pluginId: "zalo", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "zalouser", minHostVersionBaseline: "2026.3.22" },
];
@@ -1240,6 +1240,8 @@ describe("plugin-sdk subpath exports", () => {
expectSourceOmitsSnippet("google-model-id", "./google.js");
expectSourceOmitsSnippet("google-model-id", "./facade-runtime.js");
expectSourceOmitsSnippet("google-model-id", "../../extensions/");
expectSourceMentions("xiaomi", ["./facade-runtime.js"]);
expectSourceOmitsSnippet("xiaomi", "./facade-loader.js");
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "./xai.js");
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "./facade-runtime.js");
expectRepoSourceOmitsSnippet("extensions/xai/model-id.ts", "../../extensions/");
@@ -2065,6 +2065,47 @@ describe("official external plugin catalog", () => {
expect(manifest?.contracts?.speechProviders).toEqual(["volcengine"]);
});
it("lists Xiaomi's model, speech, and usage surfaces as one official external provider", () => {
const xiaomi = expectCatalogEntry("xiaomi");
const manifest = getOfficialExternalPluginCatalogManifest(xiaomi);
expect(resolveOfficialExternalPluginId(xiaomi)).toBe("xiaomi");
expect(getOfficialExternalPluginCatalogEntry("xiaomi-token-plan")).toBe(xiaomi);
expect(resolveOfficialExternalPluginInstall(xiaomi)).toEqual({
clawhubSpec: "clawhub:@openclaw/xiaomi-provider",
npmSpec: "@openclaw/xiaomi-provider",
defaultChoice: "npm",
minHostVersion: ">=2026.7.2",
});
expect(manifest?.providers?.map((provider) => provider.id)).toEqual([
"xiaomi",
"xiaomi-token-plan",
]);
expect(manifest?.providers?.[0]?.authChoices?.map((choice) => choice.choiceId)).toEqual([
"xiaomi-api-key",
]);
expect(manifest?.providers?.[1]?.authChoices?.map((choice) => choice.choiceId)).toEqual([
"xiaomi-token-plan-ams",
"xiaomi-token-plan-cn",
"xiaomi-token-plan-sgp",
]);
expect(manifest?.contracts).toMatchObject({
speechProviders: ["xiaomi"],
usageProviders: ["xiaomi", "xiaomi-token-plan"],
});
expect(manifest?.providerEndpoints).toEqual([
{
endpointClass: "xiaomi-native",
hosts: [
"api.xiaomimimo.com",
"token-plan-ams.xiaomimimo.com",
"token-plan-cn.xiaomimimo.com",
"token-plan-sgp.xiaomimimo.com",
],
},
]);
});
it.each([
["teams-meetings", "@openclaw/teams-meetings", "teams_meetings", "teams"],
["zoom-meetings", "@openclaw/zoom-meetings", "zoom_meetings", "zoom"],
@@ -2117,9 +2158,9 @@ describe("official external plugin catalog", () => {
expect(
resolveOfficialExternalProviderContractPluginIds({
contract: "speechProviders",
providerIds: new Set(["gradium", "inworld"]),
providerIds: new Set(["gradium", "inworld", "xiaomi"]),
}),
).toEqual(["gradium", "inworld"]);
).toEqual(["gradium", "inworld", "xiaomi"]);
expect(
resolveOfficialExternalProviderContractPluginIds({
contract: "webFetchProviders",
@@ -2188,6 +2229,8 @@ describe("official external plugin catalog", () => {
VENICE_API_KEY: "venice-key",
AI_GATEWAY_API_KEY: "gateway-key",
VOYAGE_API_KEY: "voyage-key",
XIAOMI_API_KEY: "xiaomi-key",
XIAOMI_TOKEN_PLAN_API_KEY: "xiaomi-token-plan-key",
ZAI_API_KEY: "zai-key",
}),
).toEqual([
@@ -2211,6 +2254,7 @@ describe("official external plugin catalog", () => {
"venice",
"vercel-ai-gateway",
"voyage",
"xiaomi",
"zai",
]);
expect(resolveOfficialExternalProviderPluginIdsForEnv({ GROQ_API_KEY: " " })).toEqual([]);
@@ -133,6 +133,7 @@ describe("official external provider endpoint catalog mirror", () => {
expect(endpointClasses).toContain("modelstudio-native");
expect(endpointClasses).toContain("moonshot-native");
expect(endpointClasses).toContain("meta-native");
expect(endpointClasses).toContain("xiaomi-native");
expect(endpointClasses).toContain("zai-native");
});
});
@@ -339,10 +339,10 @@ describe("bundled plugin build entries", () => {
}
});
it("excludes externalized Cohere and Meta providers from bundled artifacts", () => {
it("excludes externalized Cohere, Meta, and Xiaomi providers from bundled artifacts", () => {
const artifacts = listBundledPluginPackArtifacts();
for (const pluginId of ["cohere", "meta"]) {
for (const pluginId of ["cohere", "meta", "xiaomi"]) {
expect(artifacts).not.toContain(`dist/extensions/${pluginId}/index.js`);
expect(artifacts).not.toContain(`dist/extensions/${pluginId}/openclaw.plugin.json`);
expect(artifacts).not.toContain(`dist/extensions/${pluginId}/package.json`);