feat(providers): add MiMoCode free-tier provider with bootstrap JWT auth (#3659)

Integrated into release/v3.8.22 — page.tsx conflict resolved + NoAuthAccountCard re-applied to ProviderDetailPageClient in review. MiMoCode endpoint validated live.
This commit is contained in:
PizzaV
2026-06-11 16:45:10 +02:00
committed by GitHub
parent 337f16ca6b
commit 5a5d2ee5a4
8 changed files with 727 additions and 2 deletions

View File

@@ -343,6 +343,9 @@ const CHAT_OPENAI_COMPAT_MODELS: Record<string, RegistryModel[]> = {
{ id: "mimo-v2-omni", name: "MiMo-V2-Omni", contextLength: 262144, maxOutputTokens: 131072 },
{ id: "mimo-v2-flash", name: "MiMo-V2-Flash", contextLength: 262144, maxOutputTokens: 65536 },
],
mimocode: [
{ id: "mimo-auto", name: "MiMo Auto", contextLength: 1000000, maxOutputTokens: 128000 },
],
gitlawb: [
{ id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", contextLength: 1048576, maxOutputTokens: 131072 },
{ id: "mimo-v2.5", name: "MiMo-V2.5", contextLength: 1048576, maxOutputTokens: 131072 },
@@ -4067,6 +4070,17 @@ const _REGISTRY_EAGER: Record<string, RegistryEntry> = {
models: CHAT_OPENAI_COMPAT_MODELS["xiaomi-mimo"],
},
mimocode: {
id: "mimocode",
alias: "mcode",
format: "openai",
executor: "mimocode",
baseUrl: "https://api.xiaomimimo.com",
chatPath: "/api/free-ai/openai/chat",
authType: "none",
models: CHAT_OPENAI_COMPAT_MODELS["mimocode"],
},
gitlawb: {
id: "gitlawb",
alias: "glb",

View File

@@ -51,6 +51,7 @@ import { KimiExecutor } from "./kimi.ts"
import { TheOldLlmExecutor } from "./theoldllm.ts";
import { ChipotleExecutor } from "./chipotle.ts";
import { LMArenaExecutor } from "./lmarena.ts";
import { MimocodeExecutor } from "./mimocode.ts";
const executors = {
antigravity: new AntigravityExecutor(),
@@ -146,6 +147,8 @@ const executors = {
pepper: new ChipotleExecutor(), // Alias
lmarena: new LMArenaExecutor(),
lma: new LMArenaExecutor(), // Alias
mimocode: new MimocodeExecutor(),
mcode: new MimocodeExecutor(), // Alias
};
const defaultCache = new Map();
@@ -205,3 +208,4 @@ export { QwenWebExecutor } from "./qwen-web.ts";
export { TheOldLlmExecutor } from "./theoldllm.ts";
export { ChipotleExecutor } from "./chipotle.ts";
export { LMArenaExecutor } from "./lmarena.ts";
export { MimocodeExecutor } from "./mimocode.ts";

View File

@@ -0,0 +1,328 @@
/**
* MiMoCode Executor — Free-tier Xiaomi MiMo models via bootstrap JWT auth.
*
* Implements the auth flow from the official MiMo-Code repository:
* https://github.com/XiaomiMiMo/MiMo-Code/blob/main/packages/opencode/src/plugin/mimo-free.ts
*
* 1. Generate device fingerprint from hostname + OS + arch + CPU + username
* 2. POST /api/free-ai/bootstrap with fingerprint → JWT
* 3. Use JWT as Bearer token for chat requests
* 4. Custom endpoint: /api/free-ai/openai/chat (not /v1/chat/completions)
* 5. Custom header: X-Mimo-Source: mimocode-cli-free
*
* Only the "mimo-auto" model is supported (1M context, 128K output).
* Supports multiple accounts: N fingerprints → N JWTs → round-robin with cooldown.
* On 429, account enters cooldown (exponential backoff). On 401/403, JWT is re-bootstrapped.
*/
import * as crypto from "node:crypto";
import * as os from "node:os";
import { BaseExecutor, type ExecuteInput, type ProviderCredentials } from "./base.ts";
const BOOTSTRAP_PATH = "/api/free-ai/bootstrap";
const CHAT_PATH = "/api/free-ai/openai/chat";
const JWT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
const BOOTSTRAP_TIMEOUT_MS = 15_000;
const COOLDOWN_BASE_MS = 5_000;
const COOLDOWN_MAX_MS = 60_000;
const MIMO_SOURCE = "mimocode-cli-free";
const USER_AGENTS = [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
];
// ── Account State ──────────────────────────────────────────────────────────
interface AccountState {
fingerprint: string;
jwt: string;
expiresAt: number;
cooldownUntil: number;
consecutiveFails: number;
}
function parseJwtExp(jwt: string): number {
try {
const parts = jwt.split(".");
if (parts.length < 2) return Date.now() + 50 * 60 * 1000;
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
return (payload.exp ?? Math.floor(Date.now() / 1000) + 3000) * 1000;
} catch {
return Date.now() + 50 * 60 * 1000;
}
}
function isAccountReady(account: AccountState): boolean {
if (account.cooldownUntil > Date.now()) return false;
if (account.jwt && account.expiresAt - Date.now() > JWT_REFRESH_BUFFER_MS) return true;
return false;
}
// ── Fingerprint Generation ─────────────────────────────────────────────────
function getCpuModel(): string {
try {
const cpus = os.cpus();
if (cpus.length > 0 && cpus[0].model) return cpus[0].model.trim();
} catch { /* ignore */ }
return "unknown-cpu";
}
export function generateFingerprint(seed?: string): string {
if (seed) return crypto.createHash("sha256").update(seed).digest("hex");
const hostname = os.hostname();
const platform = os.platform();
const arch = os.arch();
const cpu = getCpuModel();
let username = "unknown-user";
try {
username = os.userInfo().username;
} catch { /* ignore */ }
return crypto.createHash("sha256").update(`${hostname}|${platform}|${arch}|${cpu}|${username}`).digest("hex");
}
// ── Bootstrap ──────────────────────────────────────────────────────────────
const bootstrapInflight = new Map<string, Promise<{ jwt: string; expiresAt: number }>>();
async function bootstrapJwt(
baseUrl: string,
fingerprint: string,
signal?: AbortSignal | null,
): Promise<{ jwt: string; expiresAt: number }> {
const existing = bootstrapInflight.get(fingerprint);
if (existing) return existing;
const url = `${baseUrl}${BOOTSTRAP_PATH}`;
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), BOOTSTRAP_TIMEOUT_MS);
const onSignal = signal ? () => controller.abort(signal.reason) : null;
if (signal && onSignal) signal.addEventListener("abort", onSignal, { once: true });
const promise = (async () => {
try {
const resp = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ client: fingerprint }),
signal: controller.signal,
});
if (!resp.ok) {
const body = await resp.text().catch(() => "");
throw new Error(`Bootstrap failed: ${resp.status} ${body.slice(0, 200)}`);
}
const data = (await resp.json()) as { jwt?: string };
if (!data.jwt) throw new Error("Bootstrap response missing jwt field");
return { jwt: data.jwt, expiresAt: parseJwtExp(data.jwt) };
} finally {
clearTimeout(timer);
if (signal && onSignal) signal.removeEventListener("abort", onSignal);
bootstrapInflight.delete(fingerprint);
}
})();
bootstrapInflight.set(fingerprint, promise);
return promise;
}
// ── Model Rewriting ────────────────────────────────────────────────────────
function rewriteModelName(model: string): string {
const idx = model.lastIndexOf("/");
return idx >= 0 ? model.slice(idx + 1) : model;
}
// ── Executor ───────────────────────────────────────────────────────────────
export class MimocodeExecutor extends BaseExecutor {
private accounts: AccountState[] = [];
private nextAccountIdx = 0;
private baseUrl: string;
private static encoder = new TextEncoder();
constructor() {
super("mimocode", { format: "openai" });
this.baseUrl = this.getBaseUrls()[0] || "https://api.xiaomimimo.com";
this.accounts.push({ fingerprint: generateFingerprint(), jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 });
}
private syncAccountsFromCredentials(credentials: ProviderCredentials): void {
const fingerprints = credentials?.providerSpecificData?.fingerprints;
if (!Array.isArray(fingerprints)) return;
const existing = new Set(this.accounts.map((a) => a.fingerprint));
for (const fp of fingerprints) {
if (typeof fp === "string" && !existing.has(fp)) {
this.accounts.push({ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 });
existing.add(fp);
}
}
}
private async getJwtForAccount(account: AccountState, signal?: AbortSignal | null): Promise<string> {
if (isAccountReady(account)) return account.jwt;
const result = await bootstrapJwt(this.baseUrl, account.fingerprint, signal);
account.jwt = result.jwt;
account.expiresAt = result.expiresAt;
return account.jwt;
}
private pickAccount(): AccountState {
for (let i = 0; i < this.accounts.length; i++) {
const idx = (this.nextAccountIdx + i) % this.accounts.length;
const acct = this.accounts[idx];
if (isAccountReady(acct)) {
this.nextAccountIdx = (idx + 1) % this.accounts.length;
return acct;
}
}
const fallbackIdx = this.nextAccountIdx % this.accounts.length;
this.nextAccountIdx = (this.nextAccountIdx + 1) % this.accounts.length;
return this.accounts[fallbackIdx];
}
private markCooldown(account: AccountState): void {
account.consecutiveFails++;
const backoff = Math.min(COOLDOWN_BASE_MS * Math.pow(2, account.consecutiveFails - 1), COOLDOWN_MAX_MS);
account.cooldownUntil = Date.now() + backoff + Math.random() * 1000;
}
private markSuccess(account: AccountState): void {
account.consecutiveFails = 0;
}
buildUrl(_model: string, _stream: boolean, _urlIndex = 0, _credentials?: ProviderCredentials | null): string {
return `${this.baseUrl.replace(/\/$/, "")}${CHAT_PATH}`;
}
buildHeaders(
_credentials: ProviderCredentials,
stream = true,
_clientHeaders?: Record<string, string> | null,
_model?: string,
): Record<string, string> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
"X-Mimo-Source": MIMO_SOURCE,
"User-Agent": USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
};
if (stream) headers["Accept"] = "text/event-stream, application/json";
return headers;
}
transformRequest(model: string, body: unknown, _stream: boolean, _credentials?: ProviderCredentials | null): unknown {
if (typeof body === "object" && body !== null) {
return { ...(body as Record<string, unknown>), model: rewriteModelName(model) };
}
return body;
}
async testConnection(
_credentials: ProviderCredentials,
_signal?: AbortSignal | null,
log?: ExecuteInput["log"],
): Promise<boolean> {
try {
const account = this.accounts[0];
const jwt = await this.getJwtForAccount(account, _signal);
const resp = await fetch(this.buildUrl("mimo-auto", false), {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${jwt}`, "X-Mimo-Source": MIMO_SOURCE },
body: JSON.stringify({ model: "mimo-auto", messages: [{ role: "user", content: "ping" }], stream: false }),
signal: _signal ?? undefined,
});
return resp.status === 200;
} catch {
log?.warn?.("MIMOCODE", "testConnection network error");
return false;
}
}
async execute(input: ExecuteInput): Promise<{
response: Response;
url: string;
headers: Record<string, string>;
transformedBody: unknown;
}> {
const { model, stream, body, signal, log } = input;
const encoder = MimocodeExecutor.encoder;
if (signal?.aborted) {
return {
response: new Response(encoder.encode(JSON.stringify({
error: { message: "Request aborted", type: "abort", code: "ABORTED" },
})), { status: 499, headers: { "Content-Type": "application/json" } }),
url: this.buildUrl(model, stream),
headers: this.buildHeaders(input.credentials, stream),
transformedBody: body,
};
}
const url = this.buildUrl(model, stream);
const reqBody = this.transformRequest(model, body, stream, input.credentials);
this.syncAccountsFromCredentials(input.credentials);
// Try each account, skip cooldown ones
for (let attempt = 0; attempt < this.accounts.length; attempt++) {
const account = this.pickAccount();
try {
const jwt = await this.getJwtForAccount(account, signal);
const headers = this.buildHeaders(input.credentials, stream);
headers["Authorization"] = `Bearer ${jwt}`;
let resp = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(reqBody),
signal: signal ?? undefined,
});
// On auth failure, re-bootstrap this account and retry once
if (resp.status === 401 || resp.status === 403) {
log?.warn?.("MIMOCODE", `Auth failed (${resp.status}) on account ${account.fingerprint.slice(0, 8)}`);
account.jwt = "";
account.expiresAt = 0;
account.consecutiveFails = 0;
const freshJwt = await this.getJwtForAccount(account, signal);
headers["Authorization"] = `Bearer ${freshJwt}`;
resp = await fetch(url, { method: "POST", headers, body: JSON.stringify(reqBody), signal: signal ?? undefined });
}
if (resp.status === 429) {
this.markCooldown(account);
log?.warn?.("MIMOCODE", `Rate limited on account ${account.fingerprint.slice(0, 8)}, trying next…`);
continue;
}
this.markSuccess(account);
const respHeaders: Record<string, string> = {};
resp.headers.forEach((v, k) => { respHeaders[k] = v; });
return { response: resp as unknown as Response, url, headers: respHeaders, transformedBody: reqBody };
} catch (err) {
this.markCooldown(account);
if (attempt === this.accounts.length - 1) {
const msg = err instanceof Error ? err.message : String(err);
log?.error?.("MIMOCODE", `Executor error: ${msg}`);
return {
response: new Response(encoder.encode(JSON.stringify({
error: { message: msg, type: "upstream_error", code: "EXECUTOR_ERROR" },
})), { status: 502, headers: { "Content-Type": "application/json" } }),
url, headers: this.buildHeaders(input.credentials, stream), transformedBody: body,
};
}
}
}
return {
response: new Response(encoder.encode(JSON.stringify({
error: { message: "All accounts exhausted", type: "upstream_error", code: "NO_ACCOUNTS" },
})), { status: 502, headers: { "Content-Type": "application/json" } }),
url, headers: this.buildHeaders(input.credentials, stream), transformedBody: body,
};
}
}
export default MimocodeExecutor;

View File

@@ -33,6 +33,7 @@ import {
Select,
ProxyConfigModal,
NoAuthProviderCard,
NoAuthAccountCard,
} from "@/shared/components";
import {
LOCAL_PROVIDERS,
@@ -4133,7 +4134,24 @@ export default function ProviderDetailPageClient() {
)}
{/* Connections */}
{!isUpstreamProxyProvider && isFreeNoAuth && <NoAuthProviderCard />}
{!isUpstreamProxyProvider && isFreeNoAuth && providerId === "mimocode" && (
<NoAuthAccountCard
providerId={providerId}
providerName="MiMoCode"
generateAccountId={() => crypto.randomUUID().replace(/-/g, "")}
/>
)}
{!isUpstreamProxyProvider && isFreeNoAuth && providerId === "opencode" && (
<NoAuthAccountCard
providerId={providerId}
providerName="OpenCode"
generateAccountId={() => crypto.randomUUID().replace(/-/g, "")}
/>
)}
{!isUpstreamProxyProvider &&
isFreeNoAuth &&
providerId !== "mimocode" &&
providerId !== "opencode" && <NoAuthProviderCard />}
{!isUpstreamProxyProvider && !isFreeNoAuth && (
<Card>
<div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">

View File

@@ -0,0 +1,170 @@
"use client";
import { useState, useEffect, useCallback } from "react";
import Card from "./Card";
import Button from "./Button";
interface NoAuthAccountCardProps {
providerId: string;
/** Display name for the provider (e.g. "MiMoCode", "OpenCode") */
providerName: string;
/** Generates a unique account identifier (fingerprint, session token, etc.) */
generateAccountId: () => string;
/** Key in providerSpecificData where account IDs are stored (default: "fingerprints") */
dataKey?: string;
/** Custom description text */
description?: string;
/** Custom "add" button label */
addLabel?: string;
}
interface Connection {
id: string;
provider: string;
apiKey?: string;
providerSpecificData?: Record<string, string[]>;
isActive?: boolean;
}
export default function NoAuthAccountCard({
providerId,
providerName,
generateAccountId,
dataKey = "fingerprints",
description = "Ready to use — no signup needed. Add accounts for rate-limit rotation.",
addLabel = "Add Account",
}: NoAuthAccountCardProps) {
const [connections, setConnections] = useState<Connection[]>([]);
const [loading, setLoading] = useState(true);
const [adding, setAdding] = useState(false);
const fetchConnections = useCallback(async () => {
try {
const res = await fetch("/api/providers");
if (res.ok) {
const data = await res.json();
const filtered = (data.connections || []).filter(
(c: Connection) => c.provider === providerId
);
setConnections(filtered);
}
} catch (err) {
console.error("Failed to fetch connections:", err);
} finally {
setLoading(false);
}
}, [providerId]);
useEffect(() => {
void fetchConnections();
}, [fetchConnections]);
const allAccountIds = connections.flatMap(
(c) => c.providerSpecificData?.[dataKey] || []
);
const handleAddAccount = async () => {
setAdding(true);
try {
const accountId = generateAccountId();
if (connections.length === 0) {
const res = await fetch("/api/providers", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
provider: providerId,
name: `${providerName} Account 1`,
providerSpecificData: { [dataKey]: [accountId] },
}),
});
if (!res.ok) throw new Error("Failed to create connection");
} else {
const conn = connections[0];
const updated = [...allAccountIds, accountId];
const res = await fetch(`/api/providers/${conn.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
providerSpecificData: { [dataKey]: updated },
}),
});
if (!res.ok) throw new Error("Failed to update connection");
}
await fetchConnections();
} catch (err) {
console.error("Failed to add account:", err);
} finally {
setAdding(false);
}
};
const handleRemoveAccount = async (accountId: string) => {
if (connections.length === 0) return;
const conn = connections[0];
const updated = allAccountIds.filter((id) => id !== accountId);
try {
const res = await fetch(`/api/providers/${conn.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
providerSpecificData: { [dataKey]: updated },
}),
});
if (res.ok) await fetchConnections();
} catch (err) {
console.error("Failed to remove account:", err);
}
};
return (
<Card>
<div className="flex items-center gap-3 mb-3">
<div className="inline-flex shrink-0 items-center justify-center w-10 h-10 rounded-full bg-green-500/10 text-green-500">
<span className="material-symbols-outlined text-[20px]">lock_open</span>
</div>
<div className="flex-1">
<p className="text-sm font-medium">No authentication required</p>
<p className="text-xs text-text-muted">{description}</p>
</div>
</div>
<div className="border-t border-border pt-3 mt-3">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">
Accounts ({loading ? "..." : allAccountIds.length})
</span>
<Button size="sm" icon="add" onClick={handleAddAccount} disabled={adding}>
{adding ? "Adding..." : addLabel}
</Button>
</div>
{!loading && allAccountIds.length === 0 && (
<p className="text-xs text-text-muted py-2">
Using auto-generated account. Click &quot;{addLabel}&quot; for rate-limit rotation.
</p>
)}
{!loading && allAccountIds.length > 0 && (
<div className="space-y-1">
{allAccountIds.map((id, i) => (
<div
key={id}
className="flex items-center justify-between rounded-md bg-bg-secondary px-3 py-1.5 text-xs"
>
<span className="font-mono text-text-muted">
Account {i + 1}: {id.slice(0, 12)}...
</span>
<button
onClick={() => handleRemoveAccount(id)}
className="text-red-500 hover:text-red-400 text-xs"
>
Remove
</button>
</div>
))}
</div>
)}
</div>
</Card>
);
}

View File

@@ -35,6 +35,7 @@ export { default as FilterBar } from "./FilterBar";
export { default as ColumnToggle } from "./ColumnToggle";
export { default as DataTable } from "./DataTable";
export { default as NoAuthProviderCard } from "./NoAuthProviderCard";
export { default as NoAuthAccountCard } from "./NoAuthAccountCard";
export { default as CollapsibleSection } from "./CollapsibleSection";
export { default as InfoTooltip } from "./InfoTooltip";
export { default as PresetSlider } from "./PresetSlider";

View File

@@ -106,9 +106,28 @@ export const NOAUTH_PROVIDERS = {
freeNote: "Free video generation — VEO 3.1, Seedance. 6 requests/hour.",
authHint: "No auth required. Rate limited to 6 requests/hour per IP.",
},
mimocode: {
id: "mimocode",
alias: "mcode",
name: "MiMoCode (Free)",
icon: "devices",
color: "#FF6B35",
textIcon: "MC",
website: "https://mimo.mi.com",
noAuth: true,
hasFree: true,
serviceKinds: ["llm"],
freeNote:
"Free — Xiaomi MiMo models via bootstrap JWT auth. No API key required. Supports streaming.",
authHint:
"No API key required. The executor auto-generates JWT tokens via device fingerprint bootstrap.",
notice: {
text: "MiMoCode uses Xiaomi's public free AI endpoint with bootstrap-based JWT authentication. No signup needed. Rate limits apply.",
},
},
};
export const FREE_APIKEY_PROVIDER_IDS = new Set(["qoder"]);
export const FREE_APIKEY_PROVIDER_IDS = new Set(["qoder", "mimocode", "opencode"]);
export function supportsApiKeyOnFreeProvider(providerId: unknown): boolean {
return typeof providerId === "string" && FREE_APIKEY_PROVIDER_IDS.has(providerId);
@@ -2853,6 +2872,8 @@ export function providerAllowsOptionalApiKey(providerId: unknown): boolean {
providerId === "huggingchat" ||
providerId === "gitlawb" ||
providerId === "gitlawb-gmi" ||
providerId === "mimocode" ||
providerId === "opencode" ||
isLocalProvider(providerId) ||
isSelfHostedChatProvider(providerId) ||
isOpenAICompatibleProvider(providerId) ||

View File

@@ -0,0 +1,169 @@
import { describe, it } from "node:test";
import assert from "node:assert";
import { MimocodeExecutor, generateFingerprint } from "../../open-sse/executors/mimocode.ts";
const executor = new MimocodeExecutor();
describe("MimocodeExecutor", () => {
it("generateFingerprint returns a 64-char hex string", () => {
const fp = generateFingerprint();
assert.match(fp, /^[0-9a-f]{64}$/);
});
it("generateFingerprint is deterministic", () => {
assert.strictEqual(generateFingerprint(), generateFingerprint());
});
it("generateFingerprint with seed is deterministic", () => {
assert.strictEqual(generateFingerprint("seed-a"), generateFingerprint("seed-a"));
});
it("generateFingerprint with different seeds differs", () => {
assert.notStrictEqual(generateFingerprint("seed-a"), generateFingerprint("seed-b"));
});
it("buildUrl returns the free-ai chat endpoint", () => {
const url = executor.buildUrl("mimo-auto", false);
assert.ok(url.includes("/api/free-ai/openai/chat"));
assert.ok(url.startsWith("https://"));
});
it("buildHeaders includes X-Mimo-Source and Content-Type", () => {
const headers = (executor as any).buildHeaders({}, true);
assert.strictEqual(headers["Content-Type"], "application/json");
assert.strictEqual(headers["X-Mimo-Source"], "mimocode-cli-free");
});
it("buildHeaders includes Accept for streaming", () => {
const headers = (executor as any).buildHeaders({}, true);
assert.ok(headers["Accept"]?.includes("text/event-stream"));
});
it("buildHeaders omits Accept for non-streaming", () => {
const headers = (executor as any).buildHeaders({}, false);
assert.ok(!headers["Accept"]?.includes("text/event-stream"));
});
it("transformRequest strips model prefix", () => {
const result = (executor as any).transformRequest(
"mcode/mimo-auto",
{ model: "mcode/mimo-auto", messages: [{ role: "user", content: "hi" }] },
false,
);
assert.strictEqual(result.model, "mimo-auto");
});
it("transformRequest passes model through when no prefix", () => {
const result = (executor as any).transformRequest(
"mimo-auto",
{ model: "mimo-auto", messages: [{ role: "user", content: "hi" }] },
false,
);
assert.strictEqual(result.model, "mimo-auto");
});
it("returns 499 on pre-aborted signal", async () => {
const controller = new AbortController();
controller.abort(new Error("cancelled"));
const result = await executor.execute({
model: "mimo-auto",
body: { messages: [{ role: "user", content: "hi" }], stream: false },
stream: false,
signal: controller.signal,
credentials: {},
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
});
assert.strictEqual((result as any).response.status, 499);
});
it("is registered in executor index", async () => {
const { getExecutor } = await import("../../open-sse/executors/index.ts");
const exec = getExecutor("mimocode");
assert.ok(exec instanceof MimocodeExecutor);
});
it("mcode alias works", async () => {
const { getExecutor } = await import("../../open-sse/executors/index.ts");
const exec = getExecutor("mcode");
assert.ok(exec instanceof MimocodeExecutor);
});
});
describe("mimocode multi-account", () => {
it("executor has at least one account", () => {
const accounts = (executor as any).accounts;
assert.ok(Array.isArray(accounts));
assert.ok(accounts.length >= 1);
});
it("each account has required fields", () => {
const accounts = (executor as any).accounts;
for (const acct of accounts) {
assert.ok(typeof acct.fingerprint === "string");
assert.ok(typeof acct.jwt === "string");
assert.ok(typeof acct.expiresAt === "number");
assert.ok(typeof acct.cooldownUntil === "number");
assert.ok(typeof acct.consecutiveFails === "number");
}
});
it("pickAccount returns an account", () => {
const acct = (executor as any).pickAccount();
assert.ok(acct);
assert.ok(typeof acct.fingerprint === "string");
});
it("markCooldown increases consecutiveFails and sets cooldownUntil", () => {
const acct = (executor as any).accounts[0];
const before = acct.consecutiveFails;
(executor as any).markCooldown(acct);
assert.strictEqual(acct.consecutiveFails, before + 1);
assert.ok(acct.cooldownUntil > Date.now());
});
it("markSuccess resets consecutiveFails", () => {
const acct = (executor as any).accounts[0];
acct.consecutiveFails = 5;
(executor as any).markSuccess(acct);
assert.strictEqual(acct.consecutiveFails, 0);
});
});
describe("mimocode provider registration", () => {
it("provider is registered in NOAUTH_PROVIDERS", async () => {
const { NOAUTH_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const provider = (NOAUTH_PROVIDERS as Record<string, any>)["mimocode"];
assert.ok(provider);
assert.strictEqual(provider.id, "mimocode");
assert.strictEqual(provider.alias, "mcode");
assert.strictEqual(provider.noAuth, true);
assert.strictEqual(provider.hasFree, true);
});
it("provider has correct service kinds", async () => {
const { NOAUTH_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const provider = (NOAUTH_PROVIDERS as Record<string, any>)["mimocode"];
assert.ok(provider.serviceKinds?.includes("llm"));
});
});
describe("mimocode providerRegistry entry", () => {
it("registry entry exists with correct executor", async () => {
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
const entry = getRegistryEntry("mimocode");
assert.ok(entry);
assert.strictEqual(entry.executor, "mimocode");
assert.strictEqual(entry.format, "openai");
assert.strictEqual(entry.authType, "none");
});
it("registry entry has mimo-auto model", async () => {
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
const entry = getRegistryEntry("mimocode");
const models = entry.models as Array<{ id: string }>;
const mimoAuto = models.find((m) => m.id === "mimo-auto");
assert.ok(mimoAuto);
});
});