Skip to content

fix(minimax): preserve M3 adaptive thinking on Anthropic routes - #66694

Open
bbasketballer75 wants to merge 3 commits into
NousResearch:mainfrom
bbasketballer75:fix/minimax-anthropic-thinking
Open

fix(minimax): preserve M3 adaptive thinking on Anthropic routes#66694
bbasketballer75 wants to merge 3 commits into
NousResearch:mainfrom
bbasketballer75:fix/minimax-anthropic-thinking

Conversation

@bbasketballer75

@bbasketballer75 bbasketballer75 commented Jul 18, 2026

Copy link
Copy Markdown

Summary

Fix MiniMax-M3 reasoning on MiniMax's Anthropic-compatible global and China endpoints without changing Claude, Kimi, M2.x, or non-MiniMax behavior.

The adapter now uses MiniMax's documented M3 wire contract only when both the endpoint and canonical model slug match:

  • enabled at any Hermes effort (low through ultra): thinking={"type":"adaptive"}
  • disabled: thinking={"type":"disabled"}
  • unset: omit thinking

It never sends M3 budget_tokens, output_config.effort, display, or a forced temperature.

Contract reference: MiniMax Anthropic SDK documentation documents M3 as default-off, adaptive as enabled, disabled as explicitly off, and requires preserving complete thinking/text/tool-use responses across tool turns.

Additional fixes

  • Propagates the actual Anthropic client base URL through auxiliary/MoA calls.
  • Preserves ordered thinking/text/tool-use blocks across intact tool turns.
  • Drops invalidated thinking blocks after orphan-tool cleanup without leaking internal flags.
  • Treats Hermes max and ultra as the same provider-level adaptive mode, since MiniMax exposes no depth tiers.

Verification

Tested candidate base: 2ebeede00

430 focused provider/adapter/replay/Kimi tests passed
ruff: passed (4 changed Python files)
compileall: passed
git diff --check: passed

Coverage includes endpoint/model gates, unset/disabled/enabled effort matrices, max/ultra, response normalization and replay, auxiliary URL propagation, orphan recovery, Kimi, Claude, M2.x, and non-MiniMax endpoints.

Scope

This replaces the earlier default-on/model-only proposal. It does not add an ineffective /anthropic branch to MiniMaxProfile, and it preserves MiniMax's default-off behavior when Hermes reasoning is unset.

Copilot AI review requested due to automatic review settings July 18, 2026 03:27

Copilot AI 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.

Pull request overview

This PR updates the Hermes codebase to ensure MiniMax-M3 “thinking” controls are emitted on the Anthropic-compatible MiniMax route (not just the OpenAI-compatible /v1 route), so configured reasoning settings actually take effect for default MiniMax providers. It also includes additional changes to local command execution and file write error reporting.

Changes:

  • Extend the MiniMax provider profile to emit thinking controls for https://api.minimax.io/anthropic (and keep reasoning_split only for /v1).
  • Add a direct-exec path for standalone powershell/pwsh invocations to avoid bash -c mangling.
  • Improve write_file error messages by detecting MSYS/Git-Bash spawn failures and appending targeted remediation guidance.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
plugins/model-providers/minimax/__init__.py Emit MiniMax-M3 thinking controls on both /v1 and /anthropic MiniMax routes, keeping reasoning_split only for /v1.
tools/environments/local.py Add _direct_interpreter_argv() and route standalone PowerShell/pwsh calls around bash -c parsing.
tools/file_operations.py Enhance write_file failure handling to surface MSYS/Git-Bash ASLR remediation when detected.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/environments/local.py Outdated
Comment on lines +619 to +627
# Interpreters that, when they are the ENTIRE command (not mixed with any
# other bash construct), get invoked directly instead of through
# `bash -c`. See _direct_interpreter_argv() for why.
_DIRECT_INTERPRETER_EXES = {
"powershell": "powershell.exe",
"powershell.exe": "powershell.exe",
"pwsh": "pwsh.exe",
"pwsh.exe": "pwsh.exe",
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

No longer applies to the current head. The replacement implementation changes only the Anthropic adapter, auxiliary URL propagation, and their focused tests; tools/environments/local.py is not in this PR.

Comment on lines 58 to 74
is_m3 = _is_minimax_m3(model)
is_oai = _is_minimax_global_openai_base_url(base_url)
is_ant = _is_minimax_global_anthropic_base_url(base_url)

if not is_m3 or (not is_oai and not is_ant):
return {}, {}

extra_body: dict[str, Any] = {"reasoning_split": True}
extra_body: dict[str, Any] = {}

if is_oai:
extra_body["reasoning_split"] = True

if isinstance(reasoning_config, dict) and reasoning_config.get("enabled") is False:
extra_body["thinking"] = {"type": "disabled"}
return extra_body, {}

if reasoning_config is not None:
elif reasoning_config is not None:
extra_body["thinking"] = {"type": "adaptive"}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Superseded by the current head. The standard anthropic_messages transport is handled in build_anthropic_kwargs rather than MiniMaxProfile.extra_body, with explicit adaptive, disabled, and unset coverage in tests/agent/test_minimax_provider.py.

Comment on lines 48 to 57
"""Emit M3 reasoning controls for api.minimax.io (both /v1 and /anthropic).

MiniMax-M3's /v1 endpoint keeps thinking inline unless ``reasoning_split``
is sent, so always request the split format on that route. The /anthropic
endpoint returns thinking as native ``thinking`` content blocks already, so
no split flag is needed there. ``thinking`` controls the M3 mode; Hermes'
effort levels are not a MiniMax depth knob here — they only select
adaptive vs disabled. On /anthropic, omitting ``thinking`` causes M3 to
default to OFF (per MiniMax docs), which is the bug this branch fixes.
"""

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Resolved by replacing the earlier branch contents. The current PR no longer contains the unrelated terminal or file-operation changes; its four files are limited to the Anthropic adapter, auxiliary base-URL propagation, and tests.

@bbasketballer75
bbasketballer75 force-pushed the fix/minimax-anthropic-thinking branch from 450c44c to 5ba1429 Compare July 18, 2026 03:44
@bbasketballer75 bbasketballer75 changed the title fix(minimax-provider): emit thinking controls on Anthropic-compatible route fix(minimax): enable M3 thinking on both /v1 and /anthropic routes Jul 18, 2026
@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 comp/plugins Plugin system and bundled plugins provider/minimax MiniMax (Anthropic transport) needs-decision Awaiting maintainer decision before any implementation labels Jul 18, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to open #42560: this branch includes its default-on agent behavior and adds a separate MiniMaxProfile change for explicitly configured reasoning on /anthropic. Please consider splitting or consolidating the overlapping hunk.

@bbasketballer75
bbasketballer75 force-pushed the fix/minimax-anthropic-thinking branch 2 times, most recently from 450c44c to 8267f85 Compare July 18, 2026 05:12
@bbasketballer75

Copy link
Copy Markdown
Author

Responding to the triage bot's earlier ask to split this PR:

Keeping both commits in one PR is intentional, not accidental. A short rationale:

What MiniMaxProfile.build_api_kwargs_extras (provider plugin) does

Emits thinking: {type: adaptive} in extra_body for the /v1 (chat completions) transport. This is the path that runs when a request is shaped via the OpenAI-compatible SDK's chat_completions endpoint.

What build_anthropic_kwargs (anthropic adapter) does

Same thinking control, but emitted through the anthropic-specific kwargs path that runs when a request is shaped via the Anthropic-compatible SDK's /anthropic endpoint.

Why both commits in one PR

The M3 reasoning control is a single behavior unit that must land identically on both transports. If only one commit lands and the other doesn't, the install regresses to mixed-state: one transport path thinks, the other doesn't — exactly the kind of partial fix that's hard to debug later.

Concrete failure mode if split: if someone merges the provider-plugin commit (1622118ee) on its own but not the anthropic-adapter commit (1b47a6c01), then:

  • /v1 requests run with thinking=adaptive
  • /anthropic requests run with no thinking field ✗

Live traffic on this install routes through /anthropic (the Anthropic-compatible SDK is the primary transport for M3). Splitting would leave /anthropic shipping without thinking, which is the broken state the PR is fixing.

Triage-bot's related work

kapelame's #42560 (referenced earlier) is the same change from a different contributor, also kept as a single PR. The pattern matches: this kind of "both transports" fix needs to land together.

If the maintainer still wants a split for atomicity reasons (easier to revert one side), happy to do it — but I'd want to keep the two PRs linked and merge them in the same release, ideally same day.

@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 tracing the request-shaping paths. The adapter premise is still present on current main: agent/anthropic_adapter.py:2652-2669 routes non-Claude models, including M3, to manual thinking.type=enabled.

Problems

  • The added _supports_adaptive_thinking() M3 branch is model-only. It applies adaptive thinking to an M3-named model on any Anthropic-compatible host, despite the PR’s stated wrong-host pass-through requirement.
  • agent/transports/anthropic.py:63-78 directly invokes build_anthropic_kwargs; it does not call MiniMaxProfile.build_api_kwargs_extras. The provider /anthropic hunk therefore does not affect the standard route.
  • The diff has no tests, and current tests/plugins/model_providers/test_minimax_profile.py:190-212 asserts the opposite profile behavior for /anthropic.

Suggested changes

  • Endpoint-gate the adapter behavior with the existing MiniMax Anthropic endpoint recognition, remove the ineffective profile /anthropic branch, and add adapter-level regression coverage for endpoint/model/disable cases.

Automated hermes-sweeper review.

Comment thread agent/anthropic_adapter.py Outdated
models (minimax, qwen3, …) return False so they keep the manual path.
models (qwen3, GLM, …) return False so they keep the manual path;
MiniMax M3 is the documented exception because the M3 Anthropic endpoint
accepts ``thinking.type=adaptive`` (and silently ignores the manual

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.

_supports_adaptive_thinking() has no base_url, so this makes every Anthropic-compatible endpoint using an M3-named model receive MiniMax-specific adaptive fields. Please gate this behavior at the build_anthropic_kwargs() call site with the recognized MiniMax Anthropic endpoint; the PR body’s wrong-host case otherwise cannot pass.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in 0bf25c750. Adaptive M3 controls now require both a canonical M3 slug and a recognized MiniMax global/China Anthropic endpoint. Wrong-host and wrong-model negative cases are included in the focused matrix.

@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 18, 2026
@Silronin

Copy link
Copy Markdown

I have an independently tested implementation that addresses the sweeper feedback above and the stateful replay path that becomes relevant once M3 returns structured thinking blocks.

Comparison branch: main...Silronin:fix/minimax-m3-anthropic-thinking

Commit: 3c680ea, rebased onto current main (f4df260f26c93f15694698869f3ea8e965eea301). No separate PR has been opened yet so we can coordinate here first.

The branch follows the sweeper's requested shape:

  • Applies the special case in build_anthropic_kwargs() only when both are true:
    • the endpoint is a recognized MiniMax Anthropic endpoint (api.minimax.io/anthropic or api.minimaxi.com/anthropic), and
    • the model is a canonical M3 slug (MiniMax-M3 / minimax/minimax-m3).
  • Does not add an /anthropic branch to MiniMaxProfile.build_api_kwargs_extras, because the standard anthropic_messages transport does not consume that profile hook.
  • Emits MiniMax's documented M3 contract only:
    • reasoning on: thinking={"type":"adaptive"}
    • reasoning off: thinking={"type":"disabled"}
    • no Claude-style budget_tokens, output_config, or forced temperature=1.
  • Threads the actual Anthropic SDK client's base_url through _AnthropicCompletionsAdapter, so the endpoint gate also works for auxiliary / MoA calls (including httpx.URL + trailing slash).
  • Preserves the exact thinking / text / tool_use sequence across intact tool-call turns. If orphan cleanup mutates the turn, it drops the now-invalid thinking block while preserving surviving text/tool blocks and removes the internal _thinking_signature_invalidated flag before the request reaches the wire.

Regression coverage includes:

  • endpoint + model + explicit-disable cases;
  • non-MiniMax endpoint and non-canonical M3 slug negative cases;
  • M2.x staying on the existing manual thinking contract;
  • raw Anthropic SDK response -> normalization -> persisted assistant message -> next-request replay;
  • intact tool replay plus partial/all-orphan recovery;
  • auxiliary base_url string, httpx.URL, None, M2.x, and wrong-endpoint cases;
  • Codex -> MiniMax fallback history and redacted_thinking handling;
  • Kimi and existing Anthropic behavior as non-regressions.

Validation on current main:

604 focused tests passed
ruff: PASS
compileall: PASS
git diff --check: PASS

Live MiniMax CN /anthropic verification from the candidate worktree:

wire thinking = {"type":"adaptive"}
response block types = ["thinking", "text"]

A live two-turn tool probe also returned thinking + tool_use, replayed the complete assistant block sequence, then returned thinking + text after the tool result.

Happy for you to cherry-pick/adapt any part of this into #66694, or for a maintainer to indicate that a separate replacement PR would be preferable. I wanted to coordinate first rather than open a competing PR without notice.

@bbasketballer75

Copy link
Copy Markdown
Author

Thanks @Silronin! Your rebased branch Silronin:fix/minimax-m3-anthropic-thinking looks great and addresses @teknium1's review feedback cleanly. I am merging your commits into this PR branch now so we have a single unified fix for M3 thinking on both transports.

@bbasketballer75
bbasketballer75 force-pushed the fix/minimax-anthropic-thinking branch from 8267f85 to 3c680ea Compare July 23, 2026 03:03
@alt-glitch alt-glitch removed comp/plugins Plugin system and bundled plugins needs-decision Awaiting maintainer decision before any implementation sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 23, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Correction: the prior overlap concern was corrected on the current head, which now carries the endpoint/model-gated Anthropic contract and replay coverage. CI and maintainer confirmation are still pending.

@bbasketballer75

Copy link
Copy Markdown
Author

Updated PR with @Silronin's rebased fix (3c680ea). It endpoint-gates the adaptive thinking contract specifically to canonical M3 slugs on MiniMax Anthropic endpoints, includes full response normalization/replay preservation, and adds full regression test coverage.

@bbasketballer75
bbasketballer75 force-pushed the fix/minimax-anthropic-thinking branch from 3c680ea to dc63a08 Compare July 23, 2026 04:12
@bbasketballer75 bbasketballer75 changed the title fix(minimax): enable M3 thinking on both /v1 and /anthropic routes fix(minimax): preserve M3 adaptive thinking on Anthropic routes Jul 23, 2026
@bbasketballer75
bbasketballer75 force-pushed the fix/minimax-anthropic-thinking branch from dc63a08 to 8dd00ee Compare July 29, 2026 05:01
@bbasketballer75

Copy link
Copy Markdown
Author

Comment for #66694

@teknium1 @alt-glitch — re-review requested. Significant updates since the last look:

  1. Rebased onto current origin/main (95d3031) — the prior rebase had a conflict in agent/auxiliary_client.py (upstream changed base_url resolution for Portal routing). Resolved by taking upstream's self._base_url form since the comment explains it covers both Portal and the public_url relaxation this PR introduces.

  2. Endpoint-gated the adaptive thinking contract_is_minimax_anthropic_endpoint(base_url) now must be true in addition to the canonical _is_minimax_m3(model) check. Non-MiniMax Anthropic-compatible routes (Claude, Nous Portal, Kimi) fall through to the existing manual-thinking branch.

  3. Full response normalization + replay preservation — handles the new stateful content blocks correctly across multi-turn tool calls.

  4. Comprehensive regression teststests/agent/test_minimax_provider.py +91/-2 with parametrized cases for endpoint + model slug combinations.

  5. Both @Silronin's rebased fix and the original MiniMaxProfile.build_api_kwargs_extras provider-plugin change are in — they handle different layers (adapter kwargs vs provider profile defaults), so both belong.

PR is now MERGEABLE, +664/-1278 (the deletions are upstream code that this PR replaces for the MiniMax routes specifically). Thanks for the previous round of feedback.

bbasketballer75 added a commit to bbasketballer75/hermes-agent that referenced this pull request Jul 29, 2026
…3 reasoning controls

Extends the `MiniMaxProfile.build_api_kwargs_extras` provider plugin to
recognize MiniMax's Anthropic-compatible `/anthropic` endpoint at
`api.minimax.io/anthropic`, in addition to the existing
`api.minimax.io/v1` OpenAI-compatible route.

## Why this is separate from NousResearch#66694

NousResearch#66694 (`fix(minimax): preserve M3 adaptive thinking on Anthropic routes`)
covers the Anthropic adapter layer — the request kwargs that go out as
Anthropic `thinking: {"type": "adaptive"}` on the `auxiliary_client`
adapter path. That's correct and stays open.

This PR covers the provider plugin layer — the `extra_body` that goes out
on the OpenAI-compatible request shape that MiniMax's `/anthropic` endpoint
also accepts. Different code path, different kwargs structure.

## The bug

On the `/anthropic` endpoint, omitting `thinking` causes MiniMax-M3 to
default to OFF (per MiniMax docs). Previously, the provider plugin only
matched `/v1`, so requests to `/anthropic` got an empty extra_body and M3
returned thinking as disabled.

## The fix

Add `_is_minimax_global_anthropic_base_url()` helper that matches
`api.minimax.io/anthropic`. Update `build_api_kwargs_extras` to:
- Accept both `/v1` and `/anthropic` (the existing `/v1` condition becomes
  an OR with the new `/anthropic` condition).
- Send `reasoning_split=True` only on `/v1` (the `/anthropic` endpoint
  already returns thinking as native content blocks, no split flag
  needed).
- Send `thinking: {type: adaptive}` (or `disabled` if reasoning is
  explicitly disabled) on both routes.

## Out of scope

The `/anthropic` route also requires stateful replay preservation across
multi-turn tool calls, which is the focus of the Anthropic adapter work in
NousResearch#66694. The provider plugin here only handles the request-shape kwargs.
bookerwei and others added 2 commits July 29, 2026 14:44
Enable MiniMax-M3 on https://api.minimaxi.com/anthropic (and the global
MiniMax endpoint) to use the official adaptive thinking contract
(thinking={"type":"adaptive"} or {"type":"disabled"}) instead of the
Anthropic-style enabled + budget_tokens form. M2.x and any non-canonical
M3 slug fall through to the existing manual thinking branch.

Fixes the regression where MiniMax-M3 thinking and the model response
were indistinguishable on the /anthropic route (the upstream MiniMax
profile only adapted the /v1 path).

- Endpoint + canonical-slug gate: _is_minimax_anthropic_endpoint() AND
  _is_minimax_m3() prevent over-matching (vendor/minimax-m3-preview,
  minimax-m3-128k) and false-positive matches on non-MiniMax
  Anthropic-compatible endpoints (Azure, Foundry, Palantir).
- AnthropicCompletionsAdapter forwards the underlying SDK clients
  base_url so the auxiliary/MoA call path reaches the same gate.
- _manage_thinking_signatures preserves the full thinking/text/tool_use
  sequence for intact turns and drops the now-invalid thinking blocks on
  orphan-mutated turns without leaking the internal
  _thinking_signature_invalidated flag onto the wire.
- New regression tests cover: canonical-slug exact match (positive +
  negative), raw SDK response -> normalize_response -> persist ->
  round-trip, Codex->MiniMax fallback with reasoning_content history,
  redacted_thinking preservation, M3 orphan-then-text tool_use fixture,
  orphan flag cleanup across merged assistant turns, M3 on non-MiniMax
  endpoints (manual), M2.x on MiniMax endpoints (manual), and the
  auxiliary adapters _client.base_url=None fallback.

Validated on latest origin/main (f4df260)
with 604 focused tests passing and a live MiniMax CN /anthropic smoke
returning distinct thinking and text blocks under the adaptive contract.
@bbasketballer75
bbasketballer75 force-pushed the fix/minimax-anthropic-thinking branch from 8dd00ee to 7ad7e49 Compare July 29, 2026 18:44
@bbasketballer75

Copy link
Copy Markdown
Author

Rebased onto current origin/main (c3ffe27).

The prior rebase base in my last comment (95d303138) is 221 commits behind now — the prior rebase was correct at the time but the upstream head has moved ~3.5 days of work in. This is a clean rebase onto upstream/main (no conflict resolution needed); both @Silronin's endpoint-gated adaptive-thinking contract (now on commit 7ad7e49) and the test coverage in test_minimax_provider.py / test_auxiliary_client.py are preserved unchanged. agent/auxiliary_client.py was on its way to its current shape anyway.

Re-review still welcome. No new behavioral changes in this push.

@alt-glitch alt-glitch added needs-decision Awaiting maintainer decision before any implementation and removed needs-decision Awaiting maintainer decision before any implementation labels Jul 29, 2026
…herry-pick

The cherry-picked commit's own diff (2bd9721) showed it deleting large
unrelated chunks of auxiliary_client.py -- the entire forward-progress-hook
mechanism for streamed auxiliary calls, among other things. That's not an
intentional part of the MiniMax fix; it means the upstream contributor's
branch was based on a much older auxiliary_client.py than current main, and
the 3-way cherry-pick merge silently reverted real, unrelated upstream
progress instead of just adding the MiniMax-specific base_url threading.

Restored auxiliary_client.py and its test file to the pre-cherry-pick
(current-main) state. The anthropic_adapter.py half of the fix is untouched
-- it's clean, fully tested, and covers the actual bug (M3 thinking not
working on the /anthropic route). The auxiliary/MoA call path not sharing
the same endpoint gate is a narrower, secondary gap; bringing that in
properly needs the PR itself rebased on GitHub against current upstream,
not a local hand-reconciliation of a stale branch.
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 type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants