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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user