Files
2026-07-13 13:39:12 +08:00

55 lines
2.8 KiB
TypeScript

type JsonRecord = Record<string, unknown>;
function asRecord(value: unknown): JsonRecord | null {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : null;
}
/**
* Normalize chain-of-thought control to Xiaomi MiMo's native request shape.
*
* MiMo controls thinking ONLY via a top-level `thinking: { type: "enabled" | "disabled" }`
* object (mimo.mi.com .../usage-guide/text-generation/deep-thinking). It does NOT
* understand OpenAI's `reasoning_effort` / `reasoning`, and its request validator is
* strict ("400 Param Incorrect"). OmniRoute's OpenAI path otherwise carries reasoning
* intent as `reasoning_effort`, and the claude→openai translator may leave a
* Claude-shaped `thinking:{type, budget_tokens}` — forwarding either verbatim means the
* client's on/off choice is silently dropped AND unknown keys (`budget_tokens`,
* `reasoning_effort`) ride along as extra params the validator can reject.
*
* This returns a NEW object only when it changes the body:
* - an existing `thinking` object → reduced to just `{type}`; `"disabled"` stays
* disabled, anything else (`enabled` / `adaptive` / unknown) becomes `"enabled"`.
* This strips `budget_tokens` / `keep` / … that MiMo does not accept.
* - `reasoning_effort` / `reasoning` → removed (MiMo's unknown params).
*
* It deliberately does NOT synthesize `thinking:{type:"enabled"}` from a bare
* `reasoning_effort`: `mimo-v2-omni` is documented as non-thinking, so forcing thinking
* on from an effort hint could turn a silently-ignored param into a hard error. Clients
* enable thinking by sending MiMo's `thinking:{type:"enabled"}` (or relying on the
* per-model default) and disable it with `thinking:{type:"disabled"}` — both now reach
* MiMo cleanly. When neither a thinking object nor `reasoning_effort` / `reasoning` is
* present, the body is returned untouched so MiMo keeps its documented per-model default.
*
* Scope: the native `xiaomi-mimo` provider only (callers gate on provider id). This is a
* separate concern from the OpenRouter/native reasoning_effort tier mapping in
* `sanitizeReasoningEffortForProvider` (base.ts), which runs later and becomes a no-op
* here once `reasoning_effort` has been removed.
*/
export function normalizeMimoThinking<T extends Record<string, unknown>>(body: T): T {
const record = asRecord(body);
if (!record) return body;
const thinking = asRecord(record.thinking);
const hasReasoningEffort = record.reasoning_effort !== undefined;
const hasReasoning = record.reasoning !== undefined;
if (!thinking && !hasReasoningEffort && !hasReasoning) return body;
const next: JsonRecord = { ...record };
if (thinking) {
next.thinking = { type: thinking.type === "disabled" ? "disabled" : "enabled" };
}
delete next.reasoning_effort;
delete next.reasoning;
return next as T;
}