fix(providers): wire MiMo thinking control on gateway providers (#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 (#3554, #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.
This commit is contained in:
olgagaga
2026-05-16 20:46:34 +08:00
committed by Xubin Ren
parent 8a819dda1e
commit 0ca0fe2221
2 changed files with 124 additions and 1 deletions
@@ -31,6 +31,12 @@ def _mimo_spec():
return specs["xiaomi_mimo"]
def _openrouter_spec():
"""Return the registered OpenRouter ProviderSpec (no thinking_style)."""
specs = {s.name: s for s in PROVIDERS}
return specs["openrouter"]
def _mimo_provider() -> OpenAICompatProvider:
return OpenAICompatProvider(
api_key="test-key",
@@ -39,6 +45,15 @@ def _mimo_provider() -> OpenAICompatProvider:
)
def _openrouter_provider(default_model: str) -> OpenAICompatProvider:
"""Provider configured as OpenRouter (gateway, no thinking_style on spec)."""
return OpenAICompatProvider(
api_key="sk-or-test",
default_model=default_model,
spec=_openrouter_spec(),
)
def _simple_messages() -> list[dict[str, Any]]:
return [{"role": "user", "content": "hello"}]
@@ -119,3 +134,69 @@ def test_mimo_reasoning_effort_unset_preserves_provider_default():
)
assert "reasoning_effort" not in kwargs
assert "extra_body" not in kwargs
# ---------------------------------------------------------------------------
# Gateway path: MiMo routed through OpenRouter (no spec.thinking_style)
# ---------------------------------------------------------------------------
def test_mimo_via_openrouter_reasoning_effort_none_disables_thinking():
"""OpenRouter routes MiMo as "xiaomi/mimo-v2.5-pro"; the openrouter spec
has no thinking_style, so the disable signal must come from the
model-name path (#3845)."""
provider = _openrouter_provider("xiaomi/mimo-v2.5-pro")
kwargs = provider._build_kwargs(
messages=_simple_messages(),
tools=None, model=None, max_tokens=100,
temperature=0.7, reasoning_effort="none", tool_choice=None,
)
assert "reasoning_effort" not in kwargs
assert kwargs["extra_body"] == {"thinking": {"type": "disabled"}}
def test_mimo_via_openrouter_reasoning_effort_medium_enables_thinking():
"""Same as the direct path: any non-none/minimal effort enables thinking."""
provider = _openrouter_provider("xiaomi/mimo-v2.5-pro")
kwargs = provider._build_kwargs(
messages=_simple_messages(),
tools=None, model=None, max_tokens=100,
temperature=0.7, reasoning_effort="medium", tool_choice=None,
)
assert kwargs.get("reasoning_effort") == "medium"
assert kwargs["extra_body"] == {"thinking": {"type": "enabled"}}
def test_mimo_via_openrouter_bare_slug_also_matches():
"""Bare "mimo-v2.5-pro" (no publisher prefix) must also match the
allowlist, since gateways sometimes accept either form."""
provider = _openrouter_provider("mimo-v2.5-pro")
kwargs = provider._build_kwargs(
messages=_simple_messages(),
tools=None, model=None, max_tokens=100,
temperature=0.7, reasoning_effort="none", tool_choice=None,
)
assert kwargs["extra_body"] == {"thinking": {"type": "disabled"}}
def test_mimo_flash_via_openrouter_does_not_inject_thinking():
"""mimo-v2-flash has no thinking mode per Xiaomi docs; the allowlist
excludes it, so no thinking field should be injected on the gateway path."""
provider = _openrouter_provider("xiaomi/mimo-v2-flash")
kwargs = provider._build_kwargs(
messages=_simple_messages(),
tools=None, model=None, max_tokens=100,
temperature=0.7, reasoning_effort="none", tool_choice=None,
)
assert "extra_body" not in kwargs
def test_non_mimo_model_via_openrouter_unaffected():
"""Sanity: a non-MiMo, non-Kimi model through OpenRouter is untouched."""
provider = _openrouter_provider("openai/gpt-4o")
kwargs = provider._build_kwargs(
messages=_simple_messages(),
tools=None, model=None, max_tokens=100,
temperature=0.7, reasoning_effort="none", tool_choice=None,
)
assert "extra_body" not in kwargs