fix(agent): preserve reasoning_content for Xiaomi MiMo thinking mode (#24443)#24603
Open
NilsR0711 wants to merge 2 commits into
Open
fix(agent): preserve reasoning_content for Xiaomi MiMo thinking mode (#24443)#24603NilsR0711 wants to merge 2 commits into
NilsR0711 wants to merge 2 commits into
Conversation
…ousResearch#24443) MiMo's OpenAI-compatible API requires reasoning_content on every prior assistant message in thinking mode. Without it, the next replay fails with HTTP 400 ("The reasoning_content in the thinking mode must be passed back to the API."). Hermes already implements the echo-back pattern for DeepSeek V4 and Kimi / Moonshot thinking; MiMo was simply not enrolled, so three failure modes coexisted: 1. Tool-call turns where the SDK did not surface reasoning_content as a top-level attribute persisted without the field; the next request omitted it. 2. Cross-provider history (session opened under another provider, then /model-switched to MiMo) was not run through the leak guard, so prior reasoning was either dropped or echoed unsafely. 3. Legacy sessions with reasoning_content="" pinned at creation time replayed verbatim instead of being upgraded to " ". Add _needs_mimo_tool_reasoning() and OR it into the existing _needs_thinking_reasoning_pad() gate. Detection covers four signals: provider == "xiaomi", xiaomimimo.com host, and the catalog/bare model naming conventions (xiaomi/mimo-..., mimo-..., vendor/mimo-...). All four existing tiers in _copy_reasoning_content_for_api and the build-time pad branch in _build_assistant_message activate automatically once the gate fires. DeepSeek / Kimi behaviour is untouched. Tests: 38 hermetic cases mirroring tests/run_agent/test_deepseek_ reasoning_content_echo.py — detection signals (positive + negative lookalike guards for MiniMax / Mistral / Microsoft Phi-4), pad-gate regression, _copy_reasoning_content_for_api tiers 1-4 under MiMo, _build_assistant_message tool-call pad. 100 tests pass across the new file and the pre-existing DeepSeek/Kimi echo suites; ruff clean. Platforms: hermetic, no platform dependency.
Collaborator
… path (NousResearch#24443) Extend the Xiaomi MiMo thinking-mode fix to agent/anthropic_adapter.py so sessions using the Anthropic Messages protocol (xiaomimimo.com or xiaomi/ / mimo- model slugs routed through Anthropic-compatible gateways) also get reasoning_content round-tripped on replayed tool-call turns. - _model_name_is_xiaomi_mimo: catalog (xiaomi/), bare (mimo-) and third-party namespaced (/mimo-) slot shapes. Narrow on purpose - does not accept mimo_ / xiaomi-mimo- (no published catalog uses those) so lookalikes (MiniMax, Mistral, Phi-4, mimowave) are not misdetected. - _is_xiaomi_mimo_anthropic_endpoint: ORed into _preserve_unsigned_thinking alongside Kimi / DeepSeek. - 37 new tests in tests/agent/test_mimo_anthropic_thinking.py covering positives, negative guards against lookalike families, unsigned-block preservation across non-latest assistant turns, signed-block stripping, cache_control stripping, and MiniMax regression guard. Refs NousResearch#24443. Companion fix to run_agent.py (already on this branch).
4 tasks
Author
|
@alt-glitch — acknowledging the duplicate triage (#24603 / #24605 / #24465 all enroll MiMo into Before close, I want to flag three additions in this branch that are not covered by either #24465 or #24605 and that I think are worth folding into the canonical fix before it merges. Posted the detail on #24465 (#24465 (comment)); summary:
If the maintainers prefer, I can:
Let me know which path works best. All test artifacts (101/101 green locally) are reproducible from this branch. |
This was referenced May 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Enrol Xiaomi MiMo into the
reasoning_contentecho-back enforcement set on both the OpenAI-compatible path (run_agent.py) and the Anthropic-Messages path (agent/anthropic_adapter.py) so multi-turn MiMo conversations stop failing with HTTP 400.Why
MiMo's OpenAI-compatible API requires
reasoning_contenton every prior assistant message in thinking mode (see MiMo docs). Without it, the next replay returns:Hermes already ships the echo-back pattern for DeepSeek V4 thinking and Kimi / Moonshot thinking on both protocol paths; MiMo was simply not in either enforcement gate. That double omission produced four failure modes:
reasoning_content— when MiMo streams reasoning via deltas only, the assembledChatCompletionMessagehas no top-level attribute, so the build-time pad never fired. Persisted history then lacked the field and the next request 400'd./model-switched to MiMo bypassed the tier-2 leak guard, so prior chain-of-thought either leaked or was dropped.reasoning_content=""sessions (pre-fix: use non-empty reasoning_content placeholder for DeepSeek V4 Pro thinking mode #17341) replayed the empty string verbatim instead of upgrading it to" ".xiaomimimo.com, OpenRoutermimo-slots, private proxies) had no carve-out: unsigned thinking blocks synthesised fromreasoning_contentwere stripped along with signed Anthropic blocks, and the next replay 400'd.Fixes #24443.
How
run_agent.py(OpenAI-compatible path)_needs_mimo_tool_reasoning(), modelled on_needs_kimi_tool_reasoning(). Detection covers four signals:provider == "xiaomi"(Hermes-internal id fromhermes_cli/auth.py)base_urlhost matchesxiaomimimo.comxiaomi/(catalog form)mimo-or contains/mimo-(bare + third-party catalog form)_needs_thinking_reasoning_pad()ORs the new detector in. All four existing tiers of_copy_reasoning_content_for_apiand the tool-call pad branch in_build_assistant_messageactivate for MiMo automatically.agent/anthropic_adapter.py(Anthropic-Messages path)_model_name_is_xiaomi_mimo()covering three slot shapes: catalogxiaomi/, baremimo-, and embedded/mimo-for namespaced third-party slots (e.g.openrouter/mimo-v2.5-pro). Intentionally narrow — does not acceptmimo_/xiaomi-mimo-(no published catalog uses those) so lookalikes are not misdetected._is_xiaomi_mimo_anthropic_endpoint(), ORed into_preserve_unsigned_thinkingalongside_is_kimi_family_endpointand_is_deepseek_anthropic_endpoint. MiMo now uses the same strip-signed / keep-unsigned policy as Kimi/codingand DeepSeek/anthropic.DeepSeek / Kimi / Anthropic-native / MiniMax behaviour is untouched — the three detectors are OR-combined and mutually exclusive in practice. No schema or state migration.
A known gap is documented in the new docstring: sessions routed through a proxy or institutional gateway with a custom hostname AND no Hermes provider id set will not auto-detect; users in that configuration should set
provider: xiaomiexplicitly.How to test
pytest tests/run_agent/test_mimo_reasoning_content_echo.py \ tests/run_agent/test_deepseek_reasoning_content_echo.py \ tests/agent/test_mimo_anthropic_thinking.py \ tests/agent/test_deepseek_anthropic_thinking.py \ tests/agent/test_kimi_coding_anthropic_thinking.py -qrun_agent.pysuite38 hermetic tests in
tests/run_agent/test_mimo_reasoning_content_echo.pymirroring the DeepSeek echo suite:_needs_mimo_tool_reasoning): all four positive signals, case-insensitive provider id, third-party catalog form, plus negative guards for lookalike model names (MiniMax, Mistral, Microsoft Phi-4,mimowavesubstring)._needs_thinking_reasoning_padflips on under MiMo and remains off for unrelated providers; pre-existing DeepSeek / Kimi paths unaffected._copy_reasoning_content_for_api: all four tiers exercised under MiMo (tool-call pad,""→" "upgrade, explicit content preserved,reasoningfield promoted, cross-provider leak guard injects" ")._build_assistant_message:reasoning→reasoning_contentbackfill,model_extrapreservation, tool-call pad with no rawreasoning_content, parametrised matrix covering attr-none / attr-absent / base-url / catalog / negative-non-mimo cases, streamed-reasoning promotion over pad, creation-time pad boundary for text-only turns.agent/anthropic_adapter.pysuite37 hermetic tests in
tests/agent/test_mimo_anthropic_thinking.pymirroring the DeepSeek/Kimi Anthropic-path suites:_model_name_is_xiaomi_mimo): catalog / bare //mimo-shapes; case-insensitive; whitespace-tolerant.mimowave,phi-4-mimo-style,mimo_v2,xiaomi-mimo-v2, empty/non-string inputs — all must NOT match._is_xiaomi_mimo_anthropic_endpoint): host-only, model-only, neither-signal cases.convert_messages_to_anthropic: unsigned thinking blocks preserved on tool-call replay (parametrised over four detection routes); preservation across non-latest assistant turns; signed Anthropic blocks stripped;cache_controlstripped from thinking blocks; MiniMax regression guard (a too-liberal MiMo matcher would break MiniMax — explicit negative test).Result: 101 tests pass across the new file and the pre-existing DeepSeek / Kimi / MiMo echo suites, 0 regressions.
ruff check agent/anthropic_adapter.py tests/agent/test_mimo_anthropic_thinking.py run_agent.py tests/run_agent/test_mimo_reasoning_content_echo.pyclean.Platforms tested
Hermetic test suite — no platform-specific code paths.