Skip to content

fix(agent): scope DeepSeek and MiMo reasoning echo to host, not model name - #27886

Closed
EloquentBrush0x wants to merge 1 commit into
NousResearch:mainfrom
EloquentBrush0x:fix/deepseek-mimo-host-driven-reasoning-detection
Closed

EloquentBrush0x wants to merge 1 commit into
NousResearch:mainfrom
EloquentBrush0x:fix/deepseek-mimo-host-driven-reasoning-detection

Conversation

@EloquentBrush0x

Copy link
Copy Markdown
Contributor

Problem

_needs_deepseek_tool_reasoning triggered on "deepseek" in model and _needs_mimo_tool_reasoning triggered on "mimo" in model. Both substring checks fire for any re-exported model whose name contains the substring — including OpenRouter routes like deepseek/deepseek-v3 or xiaomi/mimo-v2.5-pro.

When triggered, Hermes injects reasoning_content into every assistant message before sending it to the API. OpenRouter (and other aggregators) do not understand this field and reject the request:

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

This breaks every tool-call turn for users running DeepSeek or MiMo models through OpenRouter or any other aggregator.

Root Cause

# BEFORE — substring fires for OpenRouter re-exports
def _needs_deepseek_tool_reasoning(self) -> bool:
    model = (self.model or "").lower()
    return (
        provider == "deepseek"
        or "deepseek" in model          # ← false positive on openrouter
        or base_url_host_matches(...)
    )

Fix

Remove the model-name substring checks. Provider identity and base-URL host matching already cover all official API paths:

# AFTER — host-driven only
def _needs_deepseek_tool_reasoning(self) -> bool:
    return (
        provider == "deepseek"
        or base_url_host_matches(self.base_url, "api.deepseek.com")
    )

Same fix applied to _needs_mimo_tool_reasoning.

Parity

Commit 532b209f0 applied the identical correction to _needs_kimi_tool_reasoning with the explicit note:

"Detection is host-driven, not model-name-driven: aggregators like OpenRouter that re-export Kimi/Moonshot models speak their own protocol and reject reasoning_content echoes."

DeepSeek and MiMo were left behind. This PR brings them to the same standard.

Tests

  • test_model_substring replaced with test_openrouter_deepseek_model_not_detected — asserts the bug case now returns False
  • All existing 35 tests continue to pass (36/36)

Checklist

  • Root cause identified and fixed (2 functions)
  • Parity with _needs_kimi_tool_reasoning (commit 532b209f0)
  • No new dependencies
  • Stale test updated to match correct behavior
  • Full test suite passes (36/36)

… name

`_needs_deepseek_tool_reasoning` matched on `"deepseek" in model` and
`_needs_mimo_tool_reasoning` matched on `"mimo" in model`. Both checks
fire for any re-exported model whose name contains the substring —
including OpenRouter routes like `deepseek/deepseek-v3` — causing Hermes
to inject `reasoning_content` into every assistant message. OpenRouter
(and other aggregators) reject that field with HTTP 400 on replay.

Fix mirrors commit 532b209 which applied the same correction to
`_needs_kimi_tool_reasoning`: remove the model-name substring check and
rely only on provider identity and base-URL host matching, both of which
scope detection to requests that actually target the official API.

Official DeepSeek (`provider == "deepseek"` or `api.deepseek.com` host)
and official MiMo (`provider == "xiaomi"` or `xiaomimimo.com` host)
continue to receive the echo; aggregator re-exports do not.
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/deepseek DeepSeek API provider/openrouter OpenRouter aggregator provider/xiaomi Xiaomi MiLM labels May 18, 2026
@teknium1

teknium1 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the focused fix — the premise checks out on current main.

Problems

  • The code change covers both DeepSeek and MiMo, but the regression tests only cover the DeepSeek/OpenRouter false positive. Current main still has the sibling MiMo substring trigger at run_agent.py:4919, and rg -n "xiaomi|mimo|openrouter.*mimo" tests/run_agent/test_deepseek_reasoning_content_echo.py run_agent.py -S did not find a MiMo/OpenRouter test case.

Suggested changes

  • Add a MiMo aggregator regression test alongside the new DeepSeek one, e.g. provider="openrouter", model="xiaomi/mimo-v2.5-pro", base_url="https://openrouter.ai/api/v1", asserting _needs_mimo_tool_reasoning() is False.
  • Keep coverage that official MiMo paths still return True via provider == "xiaomi" or xiaomimimo.com host matching, since the PR intentionally removes only model-name detection.

The patch itself is aligned with the existing Kimi host-driven behavior at run_agent.py:4880-4890, and git apply --check shows it applies mechanically with line offsets. This is an automated hermes-sweeper review.

teknium1 added a commit that referenced this pull request Jun 15, 2026
Salvages the Xiaomi MiMo thinking/replay fixes from #27886/#25379/#26802/#27363 into one provider cluster, with MiMo reasoning replay enabled for native Xiaomi endpoints plus Nous/OpenRouter Xiaomi slugs.

Co-authored-by: EloquentBrush0x <283442588+EloquentBrush0x@users.noreply.github.com>

Co-authored-by: Peterson <pppan2003@gmail.com>

Co-authored-by: Zhao Zhuoran <zhao.zr11@protonmail.com>

Co-authored-by: zccyman <zccyman@users.noreply.github.com>
@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 Jun 29, 2026
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for the careful write-up and the kimi-parity reasoning — the analysis is solid and the fix is clean. But before changing provider behavior I re-verified the premise live against OpenRouter today, and the HTTP 400 is not reproducible.

Current main injects reasoning_content=" " on replay when the model name contains deepseek/mimo (the substring check this PR removes). I ran that exact wire shape against OpenRouter:

Model (bare name fires the substring) Turn 1 tool call Replay with reasoning_content=" " echo
deepseek/deepseek-v4-pro 200 200
deepseek/deepseek-chat-v3.1 200 200 (3-turn chain)
deepseek/deepseek-v4-flash 200 200 (3-turn chain)
xiaomi/mimo-v2.5-pro 200 200
xiaomi/mimo-v2.5 200 200

I also tried every echo shape on deepseek-v4-pro" ", "", real reasoning text, OpenRouter's native reasoning key, and the key absent entirely — all returned 200. OpenRouter normalizes/accepts the field; it does not reject the echo.

The quoted error — "The reasoning_content in the thinking mode must be passed back to the API" — is DeepSeek's own native endpoint complaining that reasoning is missing, which is the opposite of an aggregator rejecting an extra field. So the substring firing on deepseek/... routes through OpenRouter doesn't break tool calls the way described here.

There's also a small regression risk in the change itself: dropping the substring would silently stop the echo for a legitimate custom-provider setup that points a deepseek-named model at api.deepseek.com without setting provider=deepseek — trading a real behavior for a fix to a bug that doesn't reproduce.

Closing as cannot-reproduce. If you can share a request that actually 400s on a current aggregator route (full request body + the responding host), reopen and we'll dig in — the kimi precedent means we'd happily bring deepseek/mimo to parity once there's a reproduction. Appreciate the contribution.

@teknium1 teknium1 closed this Jun 30, 2026
jh1nresh pushed a commit to jh1nresh/hermes-agent that referenced this pull request Aug 26, 2026
Salvages the Xiaomi MiMo thinking/replay fixes from NousResearch#27886/NousResearch#25379/NousResearch#26802/NousResearch#27363 into one provider cluster, with MiMo reasoning replay enabled for native Xiaomi endpoints plus Nous/OpenRouter Xiaomi slugs.

Co-authored-by: EloquentBrush0x <283442588+EloquentBrush0x@users.noreply.github.com>

Co-authored-by: Peterson <pppan2003@gmail.com>

Co-authored-by: Zhao Zhuoran <zhao.zr11@protonmail.com>

Co-authored-by: zccyman <zccyman@users.noreply.github.com>
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 P1 High — major feature broken, no workaround provider/deepseek DeepSeek API provider/openrouter OpenRouter aggregator 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