NousResearch/hermes-agent

Minimax M3 model support and aux model alignment

Cluster 36196. Data as of

Nothing open on GitHub. Fix merged in #39024 on 4 Jun 2026. Check it covers your case.

The short answer

0open issues
0open PRs
3items grouped
Known?
Yes. 3 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #39024. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
Nothing open on GitHub.

These items concern adding support for the MinimaxM3 model and fixing the default auxiliary model to align with the M3 frontier for minimax and minimax-cn providers. Multiple fix attempts address the same alignment issue.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #39024 fix(minimax): align default_aux_model with M3 frontier (salvage #37664)

    merged to main

    files: agent/auxiliary_client.py, plugins/model-providers/minimax/__init__.py, tests/agent/test_minimax_provider.py, tests/hermes_cli/test_api_key_providers.py, tests/plugins/model_providers/test_minimax_profile.py

    Show the diff
    • agent/auxiliary_client.py
      @@ -265,9 +265,6 @@ def _get_aux_model_for_provider(provider_id: str) -> str:
           "stepfun": "step-3.5-flash",
           "kimi-coding-cn": "kimi-k2-turbo-preview",
           "gmi": "google/gemini-3.1-flash-lite-preview",
      -    "minimax": "MiniMax-M2.7",
      -    "minimax-oauth": "MiniMax-M2.7-highspeed",
      -    "minimax-cn": "MiniMax-M2.7",
           "anthropic": "claude-haiku-4-5-20251001",
           "opencode-zen": "gemini-3-flash",
           "opencode-go": "glm-5",
    • plugins/model-providers/minimax/__init__.py
      @@ -14,7 +14,7 @@
           env_vars=("MINIMAX_API_KEY",),
           base_url="https://api.minimax.io/anthropic",
           auth_type="api_key",
      -    default_aux_model="MiniMax-M2.7",
      +    default_aux_model="MiniMax-M3",
       )
       
       minimax_cn = ProviderProfile(
      @@ -24,7 +24,7 @@
           env_vars=("MINIMAX_CN_API_KEY",),
           base_url="https://api.minimaxi.com/anthropic",
           auth_type="api_key",
      -    default_aux_model="MiniMax-M2.7",
      +    default_aux_model="MiniMax-M3",
       )
       
       minimax_oauth = ProviderProfile(
      @@ -37,7 +37,7 @@
           env_vars=(),  # OAuth — tokens in auth.json, not env
           base_url="https://api.minimax.io/anthropic",
           auth_type="oauth_external",
      -    default_aux_model="MiniMax-M2.7-highspeed",
      +    default_aux_model="MiniMax-M2.7",
       )
       
       register_provider(minimax)
    • tests/agent/test_minimax_provider.py
      @@ -141,14 +141,37 @@ def test_thinking_still_works_for_claude(self):
       
       
       class TestMinimaxAuxModel:
      -    """Verify auxiliary model is standard (not highspeed) — now reads from profiles."""
      +    """Verify auxiliary model is the current frontier standard (not highspeed).
      +
      +    As of M3's release (2026-06-01) the minimax / minimax-cn provider
      +    profiles advertise ``MiniMax-M3`` as their ``default_aux_model`` (the
      +    same model users see in ``_PROVIDER_MODELS["minimax"]`` and in the
      +    user-facing ``model.default`` for a Token-Plan install).  The OAuth
      +    / Coding Plan path sticks with M2.7 because M3 is not on that
      +    tier — see ``test_minimax_profile.py`` for the per-provider split.
      +
      +    The historical concern this class guards is the #4082 / #6082
      +    regression: the highspeed variant costs 2x with no model-quality
      +    benefit, so we still assert that no aux choice contains the substring
      +    ``"highspeed"``.
      +    """
       
           def test_minimax_aux_is_standard(self):
      +        # Import model_tools to trigger plugin discovery so the
      +        # ProviderProfile objects are registered in the providers
      +        # registry before _get_aux_model_for_provider() is called.
      +        # Without this, profile-based resolution can be order-dependent
      +        # or fail outright in isolation (the minimax-* entries are
      +        # no longer in _API_KEY_PROVIDER_AUX_MODELS_FALLBACK after the
      +        # minimax-M3 default-aux-model cleanup, so the profile is
      +        # the only path to a non-empty aux value).
      +        import model_tools  # noqa: F401
               from agent.auxiliary_client import _get_aux_model_for_provider
      -        assert _get_aux_model_for_provider("minimax") == "MiniMax-M2.7"
      -        assert _get_aux_model_for_provider("minimax-cn") == "MiniMax-M2.7"
      +        assert _get_aux_model_for_provider("minimax") == "MiniMax-M3"
      +        assert _get_aux_model_for_provider("minimax-cn") == "MiniMax-M3"
       
           def test_minimax_aux_not_highspeed(self):
      +        import model_tools  # noqa: F401
               from agent.auxiliary_client import _get_aux_model_for_provider
               assert "highspeed" not in _get_aux_model_for_provider("minimax")
               assert "highspeed" not in _get_aux_model_for_provider("minimax-cn")
    • tests/hermes_cli/test_api_key_providers.py
      @@ -1279,6 +1279,20 @@ def test_minimax_oauth_has_models(self):
               assert len(models) >= 1
       
           def test_minimax_oauth_aux_model_registered(self):
      -        from agent.auxiliary_client import _API_KEY_PROVIDER_AUX_MODELS
      -        assert "minimax-oauth" in _API_KEY_PROVIDER_AUX_MODELS
      -        assert _API_KEY_PROVIDER_AUX_MODELS["minimax-oauth"]  # non-empty
      +        # Aux model for the minimax-oauth provider now lives on the
      +        # ProviderProfile (plugins/model-providers/minimax/__init__.py),
      +        # not the legacy _API_KEY_PROVIDER_AUX_MODELS dict in
      +        # agent/auxiliary_client.py. The profile layer is the source
      +        # of truth; _get_aux_model_for_provider() reads from it first
      +        # and only falls back to the dict when no profile is registered.
      +        import model_tools  # noqa: F401  -- triggers plugin discovery
      +        import providers
      +
      +        profile = providers.get_provider_profile("minimax-oauth")
      +        assert profile is not None, "minimax-oauth provider profile must be registered"
      +        assert profile.default_aux_model, (
      +            "minimax-oauth profile must advertise a non-empty default_aux_model "
      +            "so the auxiliary client (compression / vision / session-search) "
      +            "doesn't fire the 'No auxiliary LLM provider configured' warning "
      +            "for every minimax-oauth session."
      +        )
    • tests/plugins/model_providers/test_minimax_profile.py
      @@ -0,0 +1,120 @@
      +"""Unit tests for the MiniMax provider profile.
      +
      +Three MiniMax provider profiles (`minimax` direct API, `minimax-cn` China direct
      +API, `minimax-oauth` browser OAuth) all advertise a `default_aux_model` on
      +their `ProviderProfile`. The previous M2.7 / M2.7-highspeed values were
      +stale relative to the current frontier model (M3, released 2026-06-01) and
      +inconsistent with the `_PROVIDER_MODELS["minimax"]` catalog top entry in
      +`hermes_cli/models.py`.
      +
      +This file pins the new defaults so the choice is reviewable and any future
      +revert shows up in a failing test rather than silent behavior drift.
      +
      +Refs:
      +  - Issue #36196: M3 support request
      +  - PR #36205 (closed unmerged): Csrayz's M3 + 1M context work
      +  - PR #36212 (open): adds M3 to `_PROVIDER_MODELS["minimax"]` catalog
      +  - PR #6082: M2.7-highspeed → M2.7 for aux model (half-price fix)
      +  - Commit 773a0faca: same profile-layer fix pattern for `deepseek`
      +"""
      +
      +from __future__ import annotations
      +
      +import pytest
      +
      +
      [redacted:email](params=["minimax", "minimax-cn", "minimax-oauth"])
      +def minimax_profile(request):
      +    """Resolve each registered MiniMax profile.
      +
      +    Going through ``providers.get_provider_profile`` keeps the test honest —
      +    if someone later replaces the registered class with a plain
      +    ``ProviderProfile``, every assertion below collapses.
      +    """
      +    import model_tools  # noqa: F401  -- triggers plugin discovery
      +    import providers
      +
      +    profile = providers.get_provider_profile(request.param)
      +    assert profile is not None, f"{request.param} provider profile must be registered"
      +    return profile, request.param
      +
      +
      +class TestMinimaxAuxModelM3:
      +    """MiniMax profile aux model is the new frontier M3, not the stale M2.7.
      +
      +    The catalog top entry is ``MiniMax-M3`` in
      +    ``hermes_cli.models._PROVIDER_MODELS['minimax']`` and the
      +    user-facing ``model.default`` for a Token-Plan install is M3,
      +    so pinning the aux default to the same model keeps the runtime
      +    consistent (same auth, same billing pool, same rate limits, no
      +    surprise 2x-cost highspeed variant). M3 was released 2026-06-01
      +    — picking it as the aux default matches the forward-looking
      +    catalog order rather than the pre-M3 era.
      +    """
      +
      +    @pytest.mark.parametrize(
      +        "provider_id,expected",
      +        [
      +            ("minimax", "MiniMax-M3"),
      +            ("minimax-cn", "MiniMax-M3"),
      +            # minimax-oauth sticks with M2.7: the OAuth / Coding Plan
      +            # tier historically used -highspeed (PR #6082 collapsed that
      +            # to plain M2.7 to avoid the 2x TPS surcharge). M3 is not on
      +            # the OAuth/Coding Plan tier per platform docs as of this PR,
      +            # so the safe choice is the cheapest generally-available
      +            # M2.7 — matching PR #6082's intent.
      +            ("minimax-oauth", "MiniMax-M2.7"),
      +        ],
      +    )
      +    def test_profile_advertises_expected_aux_model(
      +        self, provider_id, expected
      +    ):
      +        import model_tools  # noqa: F401
      +        import providers
      +
      +        profile = providers.get_provider_profile(provider_id)
      +        assert profile is not None
      +        assert profile.default_aux_model == expected, (
      +            f"{provider_id} default_aux_model drifted to "
      +            f"{profile.default_aux_model!r}, expected {expected!r}"
      +        )
      +
      +    def test_consumer_api_returns_non_empty_for_each_provider(self, minimax_profile):
      +        from agent.auxiliary_client import _get_aux_model_for_provider
      +
      +        profile, provider_id = minimax_profile
      +        resolved = _get_aux_model_for_provider(provider_id)
      +        assert resolved != "", (
      +            f"_get_aux_model_for_provider({provider_id!r}) returned empty — "
      +            "the 'No auxiliary LLM provider configured' warning will fire on "
      +            f"every {provider_id} session even though the profile advertises "
      +            f"default_aux_model={profile.default_aux_model!r}"
      +        )
      +        assert resolved == profile.default_aux_model, (
      +            f"_get_aux_model_for_provider({provider_id!r}) returned "
      +            f"{resolved!r} but profile advertises {profile.default_aux_model!r} "
      +            "— the consumer API and the profile have drifted out of sync"
      +        )
      +
      +
      +class TestMinimaxAuxModelNotHighspeed:
      +    """Regression guard against re-introducing the M2.7-highspeed aux default.
      +
      +    PR #6082 collapsed the highspeed aux choice to plain M2.7 because the
      +    highspeed variant costs 2x with no real benefit for compression / vision /
      +    session-search aux tasks. None of the three MiniMax profiles should
      +    silently re-introduce that 2x-cost path.
      +    """
      +
      +    @pytest.mark.parametrize("provider_id", ["minimax", "minimax-cn", "minimax-oauth"])
      +    def test_default_aux_model_is_not_highspeed(self, provider_id):
      +        import model_tools  # noqa: F401
      +        import providers
      +
      +        profile = providers.get_provider_profile(provider_id)
      +        assert profile is not None
      +        assert "highspeed" not in profile.default_aux_model.lower(), (
      +            f"{provider_id} default_aux_model={profile.default_aux_model!r} "
      +            "is a -highspeed variant — that costs 2x for the same model and "
      +            "broke #4082 the first time. Revert to plain M2.7 or M3."
      +        )

1 PR closed without merging

From the close comments: merged via another change 1

  • #37664 fix(minimax): align default_aux_model with M3 frontier on minimax + minimax-cn · merged via another change → 3d1d0a4, b531b5d, fa8e2f9, #39024
Closed issues · 1
  • Closed#36196[Feature]: MinimaxM3 model support
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Merged PRs
#39024
Closed issues
1
Attempts
1 PR closed without merging
Fix link checked
4 Jun 2026

For your agent

The same facts, typed.