diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 360b487b6..d6af62210 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -265,9 +265,6 @@ _API_KEY_PROVIDER_AUX_MODELS_FALLBACK: Dict[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", diff --git a/plugins/model-providers/minimax/__init__.py b/plugins/model-providers/minimax/__init__.py index f29eb1aa0..6d77536ac 100644 --- a/plugins/model-providers/minimax/__init__.py +++ b/plugins/model-providers/minimax/__init__.py @@ -14,7 +14,7 @@ minimax = ProviderProfile( 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 @@ minimax_cn = ProviderProfile( 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 @@ minimax_oauth = ProviderProfile( 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) diff --git a/tests/agent/test_minimax_provider.py b/tests/agent/test_minimax_provider.py index 73e8034dd..bed3c1166 100644 --- a/tests/agent/test_minimax_provider.py +++ b/tests/agent/test_minimax_provider.py @@ -141,12 +141,25 @@ class TestMinimaxThinkingSupport: 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): 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): from agent.auxiliary_client import _get_aux_model_for_provider diff --git a/tests/plugins/model_providers/test_minimax_profile.py b/tests/plugins/model_providers/test_minimax_profile.py new file mode 100644 index 000000000..495c125ce --- /dev/null +++ b/tests/plugins/model_providers/test_minimax_profile.py @@ -0,0 +1,119 @@ +"""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 + + +@pytest.fixture(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`` (hermes_cli/models.py:298) 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." + )