Skip to content

fix(anthropic_adapter): preserve thinking content on MiniMax /anthropic endpoint (#75725) - #75748

Open
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/75725-minimax-thinking-replay
Open

fix(anthropic_adapter): preserve thinking content on MiniMax /anthropic endpoint (#75725)#75748
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/75725-minimax-thinking-replay

Conversation

@Tranquil-Flow

@Tranquil-Flow Tranquil-Flow commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What

MiniMax's /anthropic endpoint returns signed thinking blocks but validates signatures against the originating turn context. The generic third-party branch in _manage_thinking_signatures stripped ALL thinking blocks (signed or unsigned), which killed interleaved reasoning on turn 2+ — the wire request carried [tool_use] only, no chain-of-thought context.

MiniMax accepts unsigned thinking blocks on replay and uses them for interleaved reasoning across tool-call turns (verified by the reporter's live API tests). This adds a MiniMax-specific branch that strips the signature (signed → unsigned) while preserving the thinking content. This is distinct from DeepSeek's policy (which strips signed blocks entirely because DeepSeek only replays unsigned blocks synthesised from reasoning_content).

How

New elif _is_minimax_anthropic_endpoint(base_url): branch in _manage_thinking_signatures, placed before the generic _is_third_party strip:

  • thinking blocks: strip signature + cache_control, keep thinking text → block becomes unsigned.
  • redacted_thinking blocks: the opaque data payload is signature-equivalent and MiniMax cannot validate it → replaced with a text placeholder to preserve block position for interleaved reasoning.

Other endpoints (DeepSeek, Kimi, native Anthropic, Nous Portal, generic third-party) are unaffected — the MiniMax branch only matches api.minimax.io/anthropic / api.minimaxi.com/anthropic.

Verification

RED phase — 4 regression tests fail on upstream/main (thinking stripped on MiniMax):

4 failed, 4 passed in 0.17s

GREEN phase — all 8 new tests pass with the fix:

8 passed in 0.19s

Nearby suite — 167 total tests pass (zero failures):

  • tests/agent/test_minimax_anthropic_thinking.py: 8 passed
  • tests/agent/test_nous_portal_anthropic_wire.py: 26 passed (incl. new test_minimax_demotes_signed_thinking_to_unsigned)
  • tests/agent/test_anthropic_adapter.py: 84 passed
  • tests/agent/test_deepseek_anthropic_thinking.py + kimi + minimax provider: 49 passed

Existing test updated: test_other_third_party_gateways_still_strip_thinking was repointed to a generic third-party proxy URL (it previously used the MiniMax URL and asserted all thinking stripped, which is now incorrect since MiniMax has its own carve-out). A new test_minimax_demotes_signed_thinking_to_unsigned test was added in the same Portal test class to verify MiniMax's signed→unsigned demotion.

Closes #75725.


Auto-published by Moonsong via Path B automated pipeline.

@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/minimax MiniMax (Anthropic transport) needs-decision Awaiting maintainer decision before any implementation labels Aug 1, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #24494 and #66694. All address MiniMax Anthropic thinking replay, but the current diffs make distinct signed-block policy choices (strip, unsigned preservation, or M3 verbatim replay); maintainer direction is needed before consolidation.

@teknium1

teknium1 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for tracing the replay path. The current-main premise is real: agent/anthropic_adapter.py:2478-2481 classifies MiniMax as third-party and agent/anthropic_adapter.py:2509-2516 strips its thinking blocks. The proposed branch is placed before that generic strip and uses the existing MiniMax-only endpoint predicate.

Problems

  • The signed-block contract requires consolidation before merge. This PR changes signed MiniMax thinking into unsigned thinking, while open feat(anthropic-adapter): preserve unsigned thinking blocks on MiniMax round-trip #24494 currently specifies preserving unsigned blocks but stripping signed ones. The MEMBER note on this PR explicitly identifies these as competing signed-block policies.
  • agent/anthropic_adapter.py:615-626 recognizes both global and China MiniMax Anthropic endpoints, but the added tests exercise only https://api.minimax.io/anthropic; add coverage for https://api.minimaxi.com/anthropic as well.

Suggested changes

  • Select and document one MiniMax signed-thinking replay policy, then consolidate the overlapping PRs around it.
  • Parameterize the regression cases over both recognized MiniMax endpoint URLs.

Automated hermes-sweeper review.

@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 Aug 1, 2026
@Eklps

Eklps commented Aug 5, 2026

Copy link
Copy Markdown

Thanks for taking the signed-to-unsigned replay direction here. I independently reproduced the current-main replay path and tested a local consolidation patch instead of opening another overlapping PR.

The core policy in this PR is sound: keep the thinking text, remove signature and cache_control, preserve unsigned blocks, and leave Kimi/DeepSeek/Portal behavior unchanged. I found three adjacent hardening issues worth folding into whichever PR maintainers select:

  1. Use one MiniMax endpoint predicate for both endpoint behavior and Bearer auth.

    Separate predicates can disagree:

    https://api.minimax.io:443/anthropic  endpoint=True,  bearer=False
    https://api.minimax.io/anthropicx     endpoint=False, bearer=True
    

    The minimal fix is for _requires_bearer_auth() to call _is_minimax_anthropic_endpoint(base_url). The shared predicate should require HTTPS; exact api.minimax.io or api.minimaxi.com; no userinfo; default/explicit port 443 only; an exact /anthropic path boundary; and no query or fragment (the SDK appends /v1/messages).

  2. Invalidate thinking when consecutive assistant turns are merged.

    _merge_consecutive_roles() can append content to a turn containing thinking/redacted_thinking. That structurally changes the turn the reasoning was computed against. The provider-bound copy should set _thinking_signature_invalidated=True, so _manage_thinking_signatures() drops stale thinking for the mutated turn.

  3. Scope the provider-specific replay policy to the verified model contract.

    The reported contract is MiniMax-M3. Gating on canonical MiniMax-M3 / minimax/minimax-m3 slugs avoids silently changing M2.x or future aliases before their behavior is verified.

The combined local patch passed 189 focused MiniMax/Anthropic/Kimi/DeepSeek/Portal/contributor tests, plus py_compile and git diff --check. Coverage included signed-to-unsigned downgrade, unsigned preservation, unsupported redacted_thinking, orphan/assistant-merge invalidation, explicit :443, lookalike hosts/paths, query/fragment rejection, reasoning-default-off, and cross-provider regressions.

I am intentionally not opening another competing PR. I can provide the small hardening patch or adapt it onto this branch after maintainer direction on consolidation.

…ic endpoint (NousResearch#75725)

MiniMax's /anthropic endpoint returns signed thinking blocks but validates
signatures against the originating turn context.  The generic third-party
branch in _manage_thinking_signatures stripped ALL thinking blocks
(assuming third-party endpoints cannot validate Anthropic-proprietary
signatures), which killed interleaved reasoning on turn 2+ — the wire
request carried [tool_use] only, no chain-of-thought context.

MiniMax accepts unsigned thinking blocks on replay (verified by the
reporter's live API tests).  Add a MiniMax-specific branch that strips the
signature (signed→unsigned) while preserving the thinking content, distinct
from DeepSeek's policy (which strips signed blocks entirely because DeepSeek
only replays unsigned synthesised blocks).
@Tranquil-Flow
Tranquil-Flow force-pushed the fix/75725-minimax-thinking-replay branch from adbe9ac to 9a6564a Compare August 5, 2026 11:15
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 needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have provider/minimax MiniMax (Anthropic transport) 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.

MiniMax-M3 interleaved thinking stops after the first tool-call turn (/anthropic endpoint)

4 participants