|
60 | 60 | "kimi-k2.6", |
61 | 61 | "k2.6-code-preview", |
62 | 62 | }) |
| 63 | +_NULL_REASONING_DISABLE_MARKERS = frozenset({"mimo", "xiaomi", "xiaomimimo"}) |
| 64 | +_NULL_REASONING_DISABLE_PREFIXES = ("mimo-", "mimo_", "mimo.") |
63 | 65 | _OPENAI_COMPAT_REQUEST_TIMEOUT_S = 120.0 |
64 | 66 |
|
65 | 67 | # Maps ProviderSpec.thinking_style → extra_body builder. |
@@ -91,6 +93,29 @@ def _is_kimi_thinking_model(model_name: str) -> bool: |
91 | 93 | return False |
92 | 94 |
|
93 | 95 |
|
| 96 | +def _model_looks_like_null_reasoning_route(model_name: str) -> bool: |
| 97 | + """Return True for model ids that are known to disable reasoning via null. |
| 98 | +
|
| 99 | + Gateway models usually arrive as publisher/model slugs. Match whole path |
| 100 | + parts or known MiMo prefixes instead of arbitrary substrings so unrelated |
| 101 | + names like "mimosa-pro" do not receive Xiaomi-specific payloads. |
| 102 | + """ |
| 103 | + parts = tuple(part for part in model_name.lower().replace(":", "/").split("/") if part) |
| 104 | + for part in parts: |
| 105 | + if part in _NULL_REASONING_DISABLE_MARKERS: |
| 106 | + return True |
| 107 | + if part.startswith(_NULL_REASONING_DISABLE_PREFIXES): |
| 108 | + return True |
| 109 | + return False |
| 110 | + |
| 111 | + |
| 112 | +def _needs_null_reasoning_disable(spec: ProviderSpec | None, model_name: str) -> bool: |
| 113 | + """Return True for OpenAI-compatible routes that disable thinking via JSON null.""" |
| 114 | + if spec and spec.reasoning_disable_style == "reasoning_effort_null": |
| 115 | + return True |
| 116 | + return _model_looks_like_null_reasoning_route(model_name) |
| 117 | + |
| 118 | + |
94 | 119 | def _openai_compat_timeout_s() -> float: |
95 | 120 | """Return the bounded request timeout used for OpenAI-compatible providers.""" |
96 | 121 | return _float_env("NANOBOT_OPENAI_COMPAT_TIMEOUT_S", _OPENAI_COMPAT_REQUEST_TIMEOUT_S) |
@@ -585,6 +610,12 @@ def _build_kwargs( |
585 | 610 |
|
586 | 611 | if wire_effort and semantic_effort != "none": |
587 | 612 | kwargs["reasoning_effort"] = wire_effort |
| 613 | + elif semantic_effort == "none" and _needs_null_reasoning_disable(spec, model_name): |
| 614 | + # Some OpenAI-compatible thinking models, notably Xiaomi MiMo |
| 615 | + # directly and through routers, require an explicit JSON null to |
| 616 | + # override the provider/model default. Put it in extra_body so the |
| 617 | + # OpenAI SDK cannot treat a top-level None as an omitted argument. |
| 618 | + kwargs.setdefault("extra_body", {})["reasoning_effort"] = None |
588 | 619 |
|
589 | 620 | # Provider-specific thinking parameters. |
590 | 621 | # Only sent when reasoning_effort is explicitly configured so that |
|
0 commit comments