Repository navigation
fix(providers): wire MiMo thinking control on gateway providers (#3845) - #3851
Conversation
…S#3845) The xiaomi_mimo ProviderSpec carries thinking_style="thinking_type", but gateway providers (OpenRouter etc.) route MiMo under their own spec which has no thinking_style. As a result, `reasoning_effort="none"` was silently ignored: `{"thinking": {"type": "disabled"}}` was never injected and responses still contained reasoning_content. Mirror the Kimi pattern that already handles the same problem: add an explicit _MIMO_THINKING_MODELS allowlist (mimo-v2.5-pro, mimo-v2.5, mimo-v2-pro, mimo-v2-omni — per Xiaomi docs), an _is_mimo_thinking_model helper that strips publisher prefixes ("xiaomi/mimo-v2.5-pro" matches), and a sibling branch in _build_kwargs that injects the thinking payload by model name. mimo-v2-flash is intentionally excluded — it has no thinking mode. Also include MiMo in the explicit_thinking predicate so the reasoning_content backfill (HKUDS#3554, HKUDS#3584) covers the gateway path consistently with the direct path. Tests cover the gateway disable/enable signals, bare-slug fallback, flash exclusion, and a non-MiMo sanity check.
|
I don't know why... It seems the logic to disable thinking is in effect, and I don't have time to delve deeper into the nanobot code right now, but I have a vague guess—is there a similar situation requiring fallingangel@fallingangel-vps~nanob.txt The vim command between the two runs was switching the provider from openrouter to xiaomiMimo — everything else stayed the same. |
|
@ClearPlume Thanks, you are right: extra_body.thinking is MiMo's upstream shape and OpenRouter strips it and uses its own reasoning field, so the disable signal never reached the model. Follow-up in #3867, it also injects extra_body.reasoning = {effort: "none"} (by OR documentation) when routing Kimi/MiMo through OR. Both fields go out so direct paths unchanged, OR now honors the setting. Would appreciate a verification against your setup once it's merged. |
Follow-up to #3851: that PR added `extra_body.thinking={type: disabled}` for MiMo via OpenRouter, but OR doesn't forward provider-specific thinking shapes to upstream — it strips unknown extra_body fields and uses its own unified `reasoning` parameter. So MiMo via OR kept thinking despite the injection (reproduced by @ClearPlume on #3851 with identical kwargs but provider switched from openrouter → xiaomi_mimo). For known thinking-capable models (Kimi, MiMo) routed via the openrouter spec, also inject `extra_body.reasoning = {effort: <effort>}` in OR's documented enum ("none"|"minimal"|"low"|"medium"|"high"|"xhigh"). OR translates this to the upstream model's native shape. Existing tests updated to expect both fields on the OR path. The direct xiaomi_mimo and moonshot paths are unchanged (the new branch is gated on spec.name == "openrouter"). Flash and non-MiMo models on OR continue to receive no injection.
Follow-up to HKUDS#3851: that PR added `extra_body.thinking={type: disabled}` for MiMo via OpenRouter, but OR doesn't forward provider-specific thinking shapes to upstream — it strips unknown extra_body fields and uses its own unified `reasoning` parameter. So MiMo via OR kept thinking despite the injection (reproduced by @ClearPlume on HKUDS#3851 with identical kwargs but provider switched from openrouter → xiaomi_mimo). For known thinking-capable models (Kimi, MiMo) routed via the openrouter spec, also inject `extra_body.reasoning = {effort: <effort>}` in OR's documented enum ("none"|"minimal"|"low"|"medium"|"high"|"xhigh"). OR translates this to the upstream model's native shape. Existing tests updated to expect both fields on the OR path. The direct xiaomi_mimo and moonshot paths are unchanged (the new branch is gated on spec.name == "openrouter"). Flash and non-MiMo models on OR continue to receive no injection.
Follow-up to HKUDS#3851: that PR added `extra_body.thinking={type: disabled}` for MiMo via OpenRouter, but OR doesn't forward provider-specific thinking shapes to upstream — it strips unknown extra_body fields and uses its own unified `reasoning` parameter. So MiMo via OR kept thinking despite the injection (reproduced by @ClearPlume on HKUDS#3851 with identical kwargs but provider switched from openrouter → xiaomi_mimo). For known thinking-capable models (Kimi, MiMo) routed via the openrouter spec, also inject `extra_body.reasoning = {effort: <effort>}` in OR's documented enum ("none"|"minimal"|"low"|"medium"|"high"|"xhigh"). OR translates this to the upstream model's native shape. Existing tests updated to expect both fields on the OR path. The direct xiaomi_mimo and moonshot paths are unchanged (the new branch is gated on spec.name == "openrouter"). Flash and non-MiMo models on OR continue to receive no injection.
Summary
{"thinking": {"type": "disabled"}}) is driven byProviderSpec.thinking_style, which only the dedicatedxiaomi_mimospec carries. When users route MiMo through a gateway (OpenRouter, etc.), the active spec has nothinking_style, soreasoning_effort="none"is silently dropped and the response still containsreasoning_content._MIMO_THINKING_MODELSallowlist +_is_mimo_thinking_model()helper (strips publisher prefix, soxiaomi/mimo-v2.5-promatches) + sibling injection branch in_build_kwargs.tests/providers/test_xiaomi_mimo_thinking.py(per Xiaomi docs):mimo-v2.5-pro,mimo-v2.5,mimo-v2-pro,mimo-v2-omni.mimo-v2-flashis intentionally excluded — it has no thinking mode.explicit_thinkingpredicate so thereasoning_content=""backfill (DeepSeek-V4 reasoning_content error still reproducible on v0.1.5.post3 with WebUI + exec tool on Windows #3554, [Fixed] DeepSeek API 'reasoning_content' error - Root cause identified and Patch provided #3584) covers the gateway path consistently with the direct path.Why an explicit allowlist (not a substring rule)
It matches Kimi's approach, keeps
mimo-v2-flashout without special-casing, and the canonical model list was already enumerated in the existing test docstring — no new policy decision needed.Test plan
pytest tests/providers/test_xiaomi_mimo_thinking.py -v— 11 passed (6 existing + 5 new)pytest tests/providers/ -q— 408 passed, no regressions in adjacent paths (Kimi, DeepSeek, DashScope)ruff check nanobot/providers/openai_compat_provider.py tests/providers/test_xiaomi_mimo_thinking.py— cleanmimo-v2-flashexclusion, non-MiMo non-Kimi sanityNotes for reviewers
xiaomi_mimorequests of allowlisted models (spec-driven + model-name). They write the same payload, so the dict update is an idempotent no-op — no behavior change on the direct path._is_mimo_thinking_model(currently it injects formimo-v2-flashtoo) is left as a follow-up if desired.