// Xiaomi plugin entrypoint registers its OpenClaw integration. import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; import type { OpenClawConfig, ProviderAuthContext, ProviderAuthMethod, ProviderAuthMethodNonInteractiveContext, ProviderCatalogContext, ProviderAuthResult, ProviderRuntimeModel, } from "openclaw/plugin-sdk/plugin-entry"; import { applyAuthProfileConfig, buildApiKeyCredential, ensureApiKeyFromOptionEnvOrPrompt, normalizeApiKeyInput, normalizeOptionalSecretInput, type SecretInput, upsertAuthProfileWithLock, validateApiKeyInput, } from "openclaw/plugin-sdk/provider-auth-api-key"; import { applyModelCompatPatch, buildProviderReplayFamilyHooks, } from "openclaw/plugin-sdk/provider-model-shared"; import { PROVIDER_LABELS } from "openclaw/plugin-sdk/provider-usage"; import { applyXiaomiConfig, applyXiaomiTokenPlanConfig, XIAOMI_DEFAULT_MODEL_REF, XIAOMI_TOKEN_PLAN_DEFAULT_MODEL_REF, } from "./onboard.js"; import { buildXiaomiProvider, buildXiaomiTokenPlanProvider, XIAOMI_PROVIDER_ID, XIAOMI_TOKEN_PLAN_PROVIDER_ID, type XiaomiTokenPlanRegion, } from "./provider-catalog.js"; import { buildXiaomiSpeechProvider } from "./speech-provider.js"; import { createMiMoThinkingWrapper } from "./stream.js"; import { resolveMiMoThinkingProfile } from "./thinking.js"; type UpsertAuthProfileParams = Parameters[0]; const PAYG_FLAG_NAME = "--xiaomi-api-key"; const PAYG_OPTION_KEY = "xiaomiApiKey"; const PAYG_ENV_VAR = "XIAOMI_API_KEY"; const TOKEN_PLAN_FLAG_NAME = "--xiaomi-token-plan-api-key"; const TOKEN_PLAN_OPTION_KEY = "xiaomiTokenPlanApiKey"; const TOKEN_PLAN_ENV_VAR = "XIAOMI_TOKEN_PLAN_API_KEY"; const XIAOMI_WIZARD_GROUP = { groupId: "xiaomi", groupLabel: "Xiaomi", groupHint: "Pay-as-you-go / Token Plan", }; const XIAOMI_PROVIDER_HOOKS = { ...buildProviderReplayFamilyHooks({ family: "openai-compatible", dropReasoningFromHistory: false, }), normalizeResolvedModel: ({ model }: { model: ProviderRuntimeModel }) => applyModelCompatPatch(model, { omitEmptyArrayItems: true }), wrapStreamFn: (ctx: { streamFn?: Parameters[0]; thinkingLevel?: Parameters[1]; }) => createMiMoThinkingWrapper(ctx.streamFn, ctx.thinkingLevel), resolveThinkingProfile: ({ modelId }: { modelId: string }) => resolveMiMoThinkingProfile(modelId), isModernModelRef: ({ modelId }: { modelId: string }) => Boolean(resolveMiMoThinkingProfile(modelId)), }; function trimConfiguredBaseUrl( ctx: ProviderCatalogContext, providerId: string, ): string | undefined { const configuredProvider = ctx.config.models?.providers?.[providerId]; const baseUrl = typeof configuredProvider?.baseUrl === "string" ? configuredProvider.baseUrl.trim() : ""; return baseUrl || undefined; } function hasConfiguredProviderEntry(ctx: ProviderCatalogContext, providerId: string): boolean { const configuredProvider = ctx.config.models?.providers?.[providerId]; return Boolean(configuredProvider && typeof configuredProvider === "object"); } function resolveXiaomiCatalog(params: { ctx: ProviderCatalogContext; providerId: string; buildProvider: () => ReturnType; requireConfiguredProvider?: boolean; requireBaseUrl?: boolean; }) { const apiKey = params.ctx.resolveProviderApiKey(params.providerId).apiKey; if (!apiKey) { return null; } if ( params.requireConfiguredProvider === true && !hasConfiguredProviderEntry(params.ctx, params.providerId) ) { return null; } const explicitBaseUrl = trimConfiguredBaseUrl(params.ctx, params.providerId); if (params.requireBaseUrl === true && !explicitBaseUrl) { return null; } return { provider: { ...params.buildProvider(), ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}), apiKey, }, }; } async function upsertAuthProfileWithLockOrThrow(params: UpsertAuthProfileParams): Promise { const updated = await upsertAuthProfileWithLock(params); if (!updated) { throw new Error( "Failed to update auth profile store; the auth store lock may be busy. Wait a moment and retry.", ); } } function buildXiaomiKeyMismatchMessage(params: { actualKey: string; expectedKind: "payg" | "token-plan"; }): string | undefined { const normalized = params.actualKey.trim().toLowerCase(); const expectedPrefix = params.expectedKind === "payg" ? "sk-" : "tp-"; const kindLabel = params.expectedKind === "payg" ? "pay-as-you-go" : "Token Plan"; if (normalized.startsWith(expectedPrefix)) { return undefined; } if (params.expectedKind === "payg" && normalized.startsWith("tp-")) { return ( "This looks like a Xiaomi MiMo Token Plan key (tp-...). " + "Re-run onboarding with one of: --auth-choice xiaomi-token-plan-cn, " + "--auth-choice xiaomi-token-plan-sgp, or --auth-choice xiaomi-token-plan-ams." ); } if (params.expectedKind === "token-plan" && normalized.startsWith("sk-")) { return ( "This looks like a Xiaomi MiMo pay-as-you-go key (sk-...). " + `Re-run onboarding with --auth-choice xiaomi-api-key or pass ${PAYG_FLAG_NAME}.` ); } return ( `Xiaomi MiMo ${kindLabel} keys must start with "${expectedPrefix}". ` + "The entered key does not match the expected format." ); } function assertCompatibleXiaomiKey(params: { actualKey: string; expectedKind: "payg" | "token-plan"; }): void { const message = buildXiaomiKeyMismatchMessage(params); if (message) { throw new Error(message); } } function resolveProfileId(providerId: string): string { return `${providerId}:default`; } async function runXiaomiApiKeyAuth( ctx: ProviderAuthContext, params: { providerId: string; optionKey: string; envVar: string; promptMessage: string; expectedKind: "payg" | "token-plan"; defaultModel: string; applyConfig: (cfg: OpenClawConfig) => OpenClawConfig; }, ): Promise { let capturedSecretInput: SecretInput | undefined; let capturedCredential = false; let capturedMode: "plaintext" | "ref" | undefined; const profileId = resolveProfileId(params.providerId); const apiKey = await ensureApiKeyFromOptionEnvOrPrompt({ token: normalizeOptionalSecretInput(ctx.opts?.[params.optionKey]) ?? normalizeOptionalSecretInput(ctx.opts?.token), tokenProvider: normalizeOptionalSecretInput(ctx.opts?.[params.optionKey]) ? params.providerId : normalizeOptionalSecretInput(ctx.opts?.tokenProvider), secretInputMode: ctx.allowSecretRefPrompt === false ? (ctx.secretInputMode ?? "plaintext") : ctx.secretInputMode, config: ctx.config, env: ctx.env, expectedProviders: [params.providerId], provider: params.providerId, envLabel: params.envVar, promptMessage: params.promptMessage, normalize: normalizeApiKeyInput, validate: validateApiKeyInput, prompter: ctx.prompter, setCredential: async (key, mode) => { capturedSecretInput = key; capturedCredential = true; capturedMode = mode; }, }); assertCompatibleXiaomiKey({ actualKey: apiKey, expectedKind: params.expectedKind, }); if (!capturedCredential) { throw new Error(`Missing Xiaomi API key for provider "${params.providerId}".`); } const credentialInput = capturedSecretInput ?? ""; return { profiles: [ { profileId, credential: buildApiKeyCredential( params.providerId, credentialInput, undefined, capturedMode ? { secretInputMode: capturedMode } : undefined, ), }, ], configPatch: params.applyConfig(ctx.config), defaultModel: params.defaultModel, }; } async function runXiaomiApiKeyAuthNonInteractive( ctx: ProviderAuthMethodNonInteractiveContext, params: { providerId: string; optionKey: string; flagName: `--${string}`; envVar: string; expectedKind: "payg" | "token-plan"; applyConfig: (cfg: OpenClawConfig) => OpenClawConfig; }, ) { const resolved = await ctx.resolveApiKey({ provider: params.providerId, flagValue: normalizeOptionalSecretInput(ctx.opts[params.optionKey]), flagName: params.flagName, envVar: params.envVar, }); if (!resolved) { return null; } assertCompatibleXiaomiKey({ actualKey: resolved.key, expectedKind: params.expectedKind, }); const profileId = resolveProfileId(params.providerId); if (resolved.source !== "profile") { const credential = ctx.toApiKeyCredential({ provider: params.providerId, resolved, }); if (!credential) { return null; } await upsertAuthProfileWithLockOrThrow({ profileId, credential, agentDir: ctx.agentDir, }); } const next = applyAuthProfileConfig(ctx.config, { profileId, provider: params.providerId, mode: "api_key", }); return params.applyConfig(next); } function createPaygAuthMethod(): ProviderAuthMethod { return { id: "api-key", label: "Xiaomi API key (Pay-as-you-go)", hint: "Endpoint: api.xiaomimimo.com/v1", kind: "api_key", wizard: { choiceId: "xiaomi-api-key", choiceLabel: "Xiaomi API key (Pay-as-you-go)", choiceHint: "Endpoint: api.xiaomimimo.com/v1", ...XIAOMI_WIZARD_GROUP, }, run: async (ctx) => await runXiaomiApiKeyAuth(ctx, { providerId: XIAOMI_PROVIDER_ID, optionKey: PAYG_OPTION_KEY, envVar: PAYG_ENV_VAR, promptMessage: "Enter Xiaomi MiMo API key (pay-as-you-go, sk-...)", expectedKind: "payg", defaultModel: XIAOMI_DEFAULT_MODEL_REF, applyConfig: applyXiaomiConfig, }), runNonInteractive: async (ctx) => await runXiaomiApiKeyAuthNonInteractive(ctx, { providerId: XIAOMI_PROVIDER_ID, optionKey: PAYG_OPTION_KEY, flagName: PAYG_FLAG_NAME, envVar: PAYG_ENV_VAR, expectedKind: "payg", applyConfig: applyXiaomiConfig, }), }; } function createTokenPlanAuthMethod(region: XiaomiTokenPlanRegion): ProviderAuthMethod { const regionLabel = region === "ams" ? "Europe" : region === "cn" ? "China" : "Singapore"; const choiceId = `xiaomi-token-plan-${region}`; const choiceLabel = `Xiaomi Token Plan (${regionLabel})`; const choiceHint = `Endpoint preset: token-plan-${region}.xiaomimimo.com/v1`; return { id: `token-plan-${region}`, label: choiceLabel, hint: choiceHint, kind: "api_key", wizard: { choiceId, choiceLabel, choiceHint, ...XIAOMI_WIZARD_GROUP, }, run: async (ctx) => await runXiaomiApiKeyAuth(ctx, { providerId: XIAOMI_TOKEN_PLAN_PROVIDER_ID, optionKey: TOKEN_PLAN_OPTION_KEY, envVar: TOKEN_PLAN_ENV_VAR, promptMessage: `Enter Xiaomi MiMo Token Plan API key (tp-...) for ${regionLabel}`, expectedKind: "token-plan", defaultModel: XIAOMI_TOKEN_PLAN_DEFAULT_MODEL_REF, applyConfig: (cfg) => applyXiaomiTokenPlanConfig(cfg, region), }), runNonInteractive: async (ctx) => await runXiaomiApiKeyAuthNonInteractive(ctx, { providerId: XIAOMI_TOKEN_PLAN_PROVIDER_ID, optionKey: TOKEN_PLAN_OPTION_KEY, flagName: TOKEN_PLAN_FLAG_NAME, envVar: TOKEN_PLAN_ENV_VAR, expectedKind: "token-plan", applyConfig: (cfg) => applyXiaomiTokenPlanConfig(cfg, region), }), }; } export default definePluginEntry({ id: XIAOMI_PROVIDER_ID, name: "Xiaomi Provider", description: "Bundled Xiaomi provider plugin", register(api) { api.registerProvider({ id: XIAOMI_PROVIDER_ID, label: "Xiaomi", docsPath: "/providers/xiaomi", envVars: [PAYG_ENV_VAR], auth: [createPaygAuthMethod()], catalog: { order: "simple", run: async (ctx) => resolveXiaomiCatalog({ ctx, providerId: XIAOMI_PROVIDER_ID, buildProvider: buildXiaomiProvider, }), }, ...XIAOMI_PROVIDER_HOOKS, resolveUsageAuth: async (ctx) => { const apiKey = ctx.resolveApiKeyFromConfigAndStore({ providerIds: [XIAOMI_PROVIDER_ID], envDirect: [ctx.env.XIAOMI_API_KEY], }); return apiKey ? { token: apiKey } : null; }, fetchUsageSnapshot: async () => ({ provider: XIAOMI_PROVIDER_ID, displayName: PROVIDER_LABELS.xiaomi, windows: [], }), }); api.registerProvider({ id: XIAOMI_TOKEN_PLAN_PROVIDER_ID, label: "Xiaomi Token Plan", docsPath: "/providers/xiaomi", envVars: [TOKEN_PLAN_ENV_VAR], auth: [ createTokenPlanAuthMethod("ams"), createTokenPlanAuthMethod("cn"), createTokenPlanAuthMethod("sgp"), ], catalog: { order: "simple", run: async (ctx) => resolveXiaomiCatalog({ ctx, providerId: XIAOMI_TOKEN_PLAN_PROVIDER_ID, buildProvider: buildXiaomiTokenPlanProvider, requireConfiguredProvider: true, requireBaseUrl: true, }), }, ...XIAOMI_PROVIDER_HOOKS, resolveUsageAuth: async (ctx) => { const apiKey = ctx.resolveApiKeyFromConfigAndStore({ providerIds: [XIAOMI_TOKEN_PLAN_PROVIDER_ID], envDirect: [ctx.env.XIAOMI_TOKEN_PLAN_API_KEY], }); return apiKey ? { token: apiKey } : null; }, fetchUsageSnapshot: async () => ({ provider: XIAOMI_TOKEN_PLAN_PROVIDER_ID, displayName: "Xiaomi MiMo Token Plan", windows: [], }), }); api.registerSpeechProvider(buildXiaomiSpeechProvider()); }, });