Skip to content

fix(agent): preserve reasoning_content on Xiaomi MiMo thinking endpoints - #24737

Open
xx9090950 wants to merge 1 commit into
NousResearch:mainfrom
xx9090950:fix/xiaomi-anthropic-thinking-reasoning-content
Open

fix(agent): preserve reasoning_content on Xiaomi MiMo thinking endpoints#24737
xx9090950 wants to merge 1 commit into
NousResearch:mainfrom
xx9090950:fix/xiaomi-anthropic-thinking-reasoning-content

Conversation

@xx9090950

Copy link
Copy Markdown

What does this PR do?

Xiaomi MiMo (mimo-v2.5-pro, mimo-v2.5, …) is a DeepSeek-derived thinking-capable model family. Both its OpenAI-compatible api.xiaomimimo.com/v1 endpoint and its Anthropic-compatible token-plan-*.xiaomimimo.com/anthropic endpoint enforce the same reasoning_content echo-back contract as DeepSeek and Kimi: when a persisted session replays an assistant tool-call turn that was recorded without reasoning_content, Xiaomi rejects the next request with HTTP 400:

The reasoning_content in the thinking mode must be passed back to the API.

But the existing guards only matched DeepSeek and Kimi:

  • _preserve_unsigned_thinking (agent/anthropic_adapter.py) drops reasoning_content-derived thinking blocks for any non-whitelisted third-party /anthropic endpoint, so Xiaomi history loses its thinking blocks on replay.
  • _needs_thinking_reasoning_pad (run_agent.py) doesn't pad/preserve reasoning_content on tool-call turns for Xiaomi, so even new turns are persisted without the field.

This PR adds Xiaomi to both whitelists, mirroring the DeepSeek policy verbatim. Same strip-signed / keep-unsigned policy, same three detection signals, same regression test layout — Xiaomi-shaped scenarios were just missing from the whitelist.

Related Issue

Fixes an unfiled bug; reproduction is straightforward (see How to Test). Happy to file a tracking issue if maintainers prefer one.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • agent/anthropic_adapter.py
    • Add _is_xiaomi_anthropic_endpoint(base_url) — pinned to the /anthropic path (host match xiaomimimo.com covers token-plan-{cn,sgp,ams,…} regional subdomains). The OpenAI-compatible /v1 base URL never reaches this adapter, so detection fails closed there.
    • Add _is_xiaomi_anthropic_endpoint(base_url) to the _preserve_unsigned_thinking whitelist in convert_messages_to_anthropic, alongside _is_kimi_family_endpoint and _is_deepseek_anthropic_endpoint.
  • run_agent.py
    • Add _needs_xiaomi_tool_reasoning() — three detection signals matching the DeepSeek shape: provider == "xiaomi", model starts with mimo-, or host matches xiaomimimo.com (covers both /v1 and /anthropic transports).
    • Wire it into _needs_thinking_reasoning_pad().
  • tests/agent/test_xiaomi_anthropic_thinking.py — new: unsigned thinking block survival on /anthropic, signed-block stripping, OpenAI-base fail-closed, substring false-positive guard. (10 tests)
  • tests/run_agent/test_xiaomi_reasoning_content_echo.py — new: detection signals, replay padding, build-time pinning, cross-provider history guard, parametrized pad scenarios. (22 tests)

How to Test

Reproduce the bug (before this fix)

# cli-config.yaml
model:
  default: mimo-v2.5-pro
  provider: xiaomi
  base_url: https://token-plan-cn.xiaomimimo.com/anthropic
  api_mode: anthropic_messages

Run any multi-turn session that uses terminal or another tool (a cron job that fetches a URL is a good reproducer). On the second tool-call turn, the upstream call fails with:

RuntimeError: Error code: 400 - {'error': {'code': '400', 'message': 'Param Incorrect',
  'param': 'The reasoning_content in the thinking mode must be passed back to the API.',
  'type': ''}}

Verify the fix

  1. pytest tests/agent/test_xiaomi_anthropic_thinking.py tests/run_agent/test_xiaomi_reasoning_content_echo.py -q — 32 new tests pass.
  2. pytest tests/run_agent/test_deepseek_reasoning_content_echo.py tests/agent/test_deepseek_anthropic_thinking.py tests/agent/test_kimi_coding_anthropic_thinking.py tests/hermes_cli/test_xiaomi_provider.py -q — 114 existing tests still pass (no regression on DeepSeek / Kimi / xiaomi provider).
  3. Rerun the cron job / multi-turn session against token-plan-cn.xiaomimimo.com/anthropic — the next tool-call turn now carries the synthesised thinking block on replay and the 400 disappears.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(agent): …)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix (no unrelated commits)
  • I've run the relevant test suites locally — see How to Test above (1462 tests pass; two pre-existing failures on maintest_switch_model_preserves_config_context_length and test_interrupt_child_during_api_call — are unrelated to this change and reproduce on a clean checkout)
  • I've added tests for my changes — 32 new tests covering both the detection helpers and the conversion path
  • I've tested on my platform: macOS 15 (Darwin 25.2.0), Python 3.11.14

Documentation & Housekeeping

  • I've updated relevant documentation — docstrings on the new helpers explain the contract; no user-facing docs needed
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A (no new config keys)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A (no architectural change)
  • I've considered cross-platform impact — change is pure Python string/dict handling; no I/O, no platform-specific code
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A (tool surface unchanged)

Xiaomi MiMo (mimo-v2.5-pro, mimo-v2.5, ...) is a DeepSeek-derived
thinking-capable model family. Both its OpenAI-compatible
``api.xiaomimimo.com/v1`` endpoint and its Anthropic-compatible
``token-plan-*.xiaomimimo.com/anthropic`` endpoint enforce the same
reasoning_content echo-back contract as DeepSeek and Kimi: when a
persisted session replays an assistant tool-call turn that was recorded
without reasoning_content, Xiaomi rejects the next request with HTTP
400::

    The reasoning_content in the thinking mode must be passed back
    to the API.

But the existing guards only matched DeepSeek and Kimi:

- ``_preserve_unsigned_thinking`` (agent/anthropic_adapter.py) — drops
  reasoning_content-derived thinking blocks for any non-whitelisted
  third-party /anthropic endpoint, so Xiaomi history loses its thinking
  blocks on replay.
- ``_needs_thinking_reasoning_pad`` (run_agent.py) — doesn't pad/preserve
  reasoning_content on tool-call turns for Xiaomi, so even new turns
  are persisted without the field.

Add Xiaomi to both whitelists, mirroring the DeepSeek policy:

- ``_is_xiaomi_anthropic_endpoint`` — pinned to the ``/anthropic`` path
  (host match ``xiaomimimo.com`` covers ``token-plan-{cn,sgp,ams,...}``
  regional subdomains). The OpenAI-compatible ``/v1`` base URL never
  reaches this adapter, so detection fails closed there.
- ``_needs_xiaomi_tool_reasoning`` — three detection signals matching
  the DeepSeek shape: ``provider == "xiaomi"``, model starts with
  ``mimo-``, or host matches ``xiaomimimo.com`` (covers both /v1 and
  /anthropic transports).

Coverage:

- ``tests/agent/test_xiaomi_anthropic_thinking.py`` — unsigned thinking
  block survival, signed-block stripping, OpenAI-base fail-closed,
  substring false-positive guard.
- ``tests/run_agent/test_xiaomi_reasoning_content_echo.py`` — detection
  signals, replay padding, build-time pinning, cross-provider history
  guard, parametrized pad scenarios.

Tested on macOS Darwin 25.2.0, Python 3.11.14; 32 new tests pass,
existing DeepSeek/Kimi/xiaomi-provider suites (82 tests) unchanged.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/xiaomi Xiaomi MiLM labels May 13, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #24465 (earliest open PR for Xiaomi MiMo reasoning_content replay support). Also competes with #24603, #24605, #24726, #24747.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused Xiaomi replay coverage. The Anthropic conversion issue is still present on current main: agent/anthropic_adapter.py:2275-2278 preserves unsigned thinking only for Kimi and DeepSeek, while the third-party branch at agent/anthropic_adapter.py:2302-2309 strips Xiaomi's blocks.

Problems

  • The run_agent.py part is stale. Current main already invokes _needs_mimo_tool_reasoning() from _needs_thinking_reasoning_pad() at run_agent.py:5478-5484 and implements the current detector at run_agent.py:5521-5535. The PR's _needs_xiaomi_tool_reasoning() hunk would duplicate superseded logic.

Suggested changes

  • Salvage the Anthropic adapter allowlist and the Xiaomi /anthropic regression coverage; omit the run_agent.py hunk and retain current main's detector.

Automated hermes-sweeper review.

Comment thread run_agent.py
return (
self._needs_deepseek_tool_reasoning()
or self._needs_kimi_tool_reasoning()
or self._needs_xiaomi_tool_reasoning()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current main already wires _needs_mimo_tool_reasoning() into this gate (run_agent.py:5478-5484) and has the current detector at run_agent.py:5521-5535. Please omit this stale duplicate hunk when salvaging the remaining Anthropic-adapter fix.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have provider/xiaomi Xiaomi MiLM sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants