feat(minimax): add minimax-oauth-openai provider for M3 prompt caching - #54012
feat(minimax): add minimax-oauth-openai provider for M3 prompt caching#54012nickjohnsonrob wants to merge 2 commits into
Conversation
MiniMax's Anthropic-compatible endpoint at https://api.minimax.io/anthropic silently ignores cache_control hints, so MiniMax-M3 sessions never get cache_read discounting. MiniMax's OpenAI-compatible endpoint at https://api.minimax.io/v1 honors prompt caching natively. This adds a parallel provider "minimax-oauth-openai" that reuses the existing MiniMax OAuth credentials (same client_id, scope, and auth.json slot) but routes to /v1 with chat_completions transport. Existing "minimax-oauth" is unchanged. * plugins/model-providers/minimax/__init__.py: register a new minimax_oauth_openai profile that subclasses MiniMaxProfile so the M3 reasoning_split + thinking hook is inherited. Aliases "minimax-oai" and "minimax-openai" added to match the upstream test fixture in tests/agent/test_auxiliary_client_minimax_oauth_openai.py. * hermes_cli/auth.py: add PROVIDER_REGISTRY entry "minimax-oauth-openai" sharing MiniMax OAuth's auth_type=oauth_minimax and pointing inference_base_url at /v1. New constant MINIMAX_OAUTH_GLOBAL_INFERENCE_OPENAI exposes the URL. * hermes_cli/runtime_provider.py: extend the existing resolve_minimax_oauth_runtime_credentials branch to cover both provider names, selecting api_mode=chat_completions for minimax-oauth-openai and api_mode=anthropic_messages for minimax-oauth. * agent/auxiliary_client.py: add _resolve_minimax_oauth_for_aux() and _build_minimax_oauth_openai_aux_client() mirroring the xai-oauth pattern, plus dispatch in resolve_provider_client. Adds "minimax-oai" / "minimax-openai" / "minimax_oauth_openai" aliases in _PROVIDER_ALIASES so aux routing matches the bundled profile. Without this, compression/title-generation/summarization for users on minimax-oauth-openai silently falls through to the OAuth-unhandled tail and re-routes to whatever Step-2 fallback the user has configured. Tests: 113 MiniMax-related + 132 runtime_provider resolution tests all pass; the 12-case auxiliary-client suite in tests/agent/test_auxiliary_client_minimax_oauth_openai.py (which upstream already committed but never landed the implementation for) goes from 12 failed / 0 passed to 12 passed / 0 failed. Refs the upstream pi-mono fix at rwese/pi-minimax-m3-caching-fix.
The runtime resolver pulls base_url from resolve_minimax_oauth_runtime_credentials, which reads auth.json.inference_base_url (Anthropic-compatible). For the new minimax-oauth-openai provider, explicitly substitute the /v1 URL from the ProviderConfig so the base URL matches the chat_completions transport — otherwise /chat/completions requests hit /anthropic and 404. Verified locally: hermes chat -q OK routes to POST https://api.minimax.io/v1/chat/completions and the response includes cached_tokens=1501 on the first turn (cache fills as the conversation prefix grows).
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment
Clean implementation of a new minimax-oauth-openai provider that routes through the OpenAI-compatible endpoint (/v1) instead of the Anthropic-compatible one, enabling prompt caching for MiniMax-M3.
Key changes:
auxiliary_client.py: Provider alias mappings, OAuth resolution helper, and auxiliary client builder. Well-documented with clear rationale for the base URL substitution.auth.py: NewMINIMAX_OAUTH_GLOBAL_INFERENCE_OPENAIconstant andProviderConfigentry withshares_auth_withlinking to the existingminimax-oauthprovider.runtime_provider.py: Handles the new provider in the resolution chain with properapi_modeandbase_urlrouting.
Assessment:
- Provider config is well-structured with proper auth sharing
- Auxiliary client properly falls through to Step-2 when credentials missing
- Error handling is appropriate (warning + None return)
- No security concerns
- Docs and config examples updated
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Hardens Windows cron Telegram alerts by fixing subprocess encoding and adding a urllib fallback. The cron scheduler now forces UTF-8 encoding (encoding='utf-8', errors='replace') and sets PYTHONIOENCODING=utf-8 / PYTHONUTF8=1 for child processes. For text-only Telegram sends, a urllib-based sendMessage fallback is added so cron alerts are not dropped by python-telegram-bot HTTPX timeouts. Tests cover Unicode stdout decoding and the urllib fallback path.
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for wiring the OAuth credential reuse and the /v1 transport direction. The requested provider is still absent on current main: hermes_cli/runtime_provider.py:1840-1852 only resolves minimax-oauth as anthropic_messages.
Problems
- The new chat-completions path retains a static OAuth token. Current MiniMax refresh wiring is limited to the Anthropic branch in
agent/agent_init.py:793-829; the regular OpenAI branch constructs client kwargs directly fromapi_keyatagent/agent_init.py:921-940. Please provide equivalent refresh/retry handling for the new transport. hermes_cli/models.py:1092-1106excludesoauth_externalprofiles from automatic picker insertion. Since this profile isoauth_external, the PR needs explicit picker/setup integration; otherwisehermes modelcannot select it.- The stated auxiliary-client test file is absent from current main, and this PR adds no tests.
Suggested changes
- Add refresh-safe OpenAI OAuth handling and focused regression coverage.
- Wire the new option into the MiniMax picker/setup flow and update the MiniMax OAuth documentation.
This is an automated hermes-sweeper review.
| pconfig = PROVIDER_REGISTRY.get(provider) | ||
| if pconfig and pconfig.auth_type == "oauth_minimax": | ||
| from hermes_cli.auth import resolve_minimax_oauth_runtime_credentials | ||
| creds = resolve_minimax_oauth_runtime_credentials() |
There was a problem hiding this comment.
This selects the OpenAI transport but still uses the static token returned by resolve_minimax_oauth_runtime_credentials(). The existing MiniMax per-request refresh hook is limited to the Anthropic client path (agent/agent_init.py:805-829); please add equivalent refresh or bounded 401-retry handling before exposing long-lived OpenAI sessions.
| description="MiniMax via OAuth routed to /v1 — prompt caching enabled", | ||
| signup_url="https://api.minimax.io/", | ||
| env_vars=(), # OAuth — tokens in auth.json, not env | ||
| base_url="https://api.minimax.io/v1", |
There was a problem hiding this comment.
Profiles with oauth_external are skipped by the automatic CANONICAL_PROVIDERS extension (hermes_cli/models.py:1092-1106). Please add the explicit MiniMax picker/setup wiring so users can select this provider through hermes model while reusing the existing OAuth credential slot.
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Four PRs address related but distinct MiniMax endpoint and M3 behavior: #17401 and #22830 target auxiliary endpoint routing, #54012 adds a separate OAuth OpenAI-compatible transport for prompt caching, and #66694 fixes M3 thinking and replay semantics on the existing Anthropic-compatible transport.
Related pull requests
- #17401 [closed]
related— (+10/-1) — closed, ineffective historical fix: it targets the auxiliary/anthropicrewrite, but the addednot url.endswith("/anthropic/v1")check is redundant when the same condition already requiresurl.endswith("/anthropic"), so the diff does not change routing behavior; it remains relevant as an earlier report of the same auxiliary endpoint-selection cause and was closed awaiting an upstream fix. - #22830 [closed]
related— (+8/-8) — closed, superseded by main: it globally changes MiniMax provider bases to/v1, conflating the OpenAI auxiliary route with the main Anthropic Messages route and risking structured tool-calling behavior; the contributor review documents that main instead applies the scoped auxiliary rewrite with tests, making this broader replacement unnecessary. - #54012
related— (+157/-4) — keep open, changes required: the diff adds a distinctminimax-oauth-openaiprofile, shares MiniMax OAuth credentials, and routes runtime and auxiliary traffic to/v1, directly addressing M3 prompt caching without changing the existing Anthropic provider. The contributor keep_open review remains blocking because the regular OpenAI execution path still lacks refresh-safe OAuth handling, theoauth_externalprofile is not integrated into the picker/setup path, and the PR adds no focused regression tests. - #66694
related— (+566/-19) — keep open as a separate fix: the current diff endpoint- and model-gates MiniMax-M3 adaptive thinking on global/CN Anthropic routes, propagates the auxiliary base URL, preserves valid replay blocks, and adds focused positive and negative coverage. It addresses the earlier contributor keep_open findings on wrong-host gating, ineffective transport integration, and missing tests, but CI and maintainer confirmation are still pending.
Duplicates
#17401 and #22830 overlap on the auxiliary MiniMax endpoint-routing cause, but they are not equivalent implementations: #17401 is behaviorally ineffective, while #22830 applies an overbroad global replacement. #54012 and #66694 are complementary transport-specific changes, not duplicates.
Suggested consolidation
Do not merge #54012 yet: retain it as the consolidation target for the OAuth /v1 prompt-caching provider, but first satisfy the contributor keep_open review with refresh-safe OpenAI OAuth execution, picker/setup integration, and focused tests. Keep #66694 separate for the Anthropic M3 thinking/replay contract pending CI and maintainer confirmation; #17401 and #22830 can remain closed as ineffective or superseded historical overlaps, with no additional duplicate closure needed.
Cross-PR triage: Reviewed 4 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 46 kB of PR diffs, 9 kB of issue/PR text, 9 kB of discussion (19 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
Problem
MiniMax's Anthropic-compatible endpoint at
https://api.minimax.io/anthropicsilently ignorescache_controlhints, soMiniMax-M3sessions never receivecache_readdiscounting on MiniMax's 5-hour Token Plan Plus quota. MiniMax's OpenAI-compatible endpoint athttps://api.minimax.io/v1honors prompt caching natively — same model, same OAuth, sameauth.jsonslot, just a different transport + base URL.The upstream
pi-monocommunity already published a fix for this (rwese/pi-minimax-m3-caching-fix) that flips the base URL and the transport. This PR brings that fix to Hermes.What this adds
A new parallel provider
minimax-oauth-openaithat:client_id, samescope, sameauth.json.providers.minimax-oauthslot. Users who have already runhermes model→ MiniMax (OAuth) get the new provider for free; no re-auth./v1/chat/completions— the OpenAI-compatible endpoint that honors prompt caching.reasoning_split: true+thinking: {type: adaptive}are emitted on the new profile via the existingMiniMaxProfile.build_api_kwargs_extrassubclass hook (no duplication).Existing
minimax-oauth(Anthropic-compat) is completely unchanged. Users who don't switch see no difference.Files
plugins/model-providers/minimax/__init__.pyminimax_oauth_openaiprofile (22 lines)hermes_cli/auth.pyPROVIDER_REGISTRY["minimax-oauth-openai"]entry +MINIMAX_OAUTH_GLOBAL_INFERENCE_OPENAIconstant (17 lines)hermes_cli/runtime_provider.pyapi_modeper name (7 lines)agent/auxiliary_client.py_resolve_minimax_oauth_for_aux+_build_minimax_oauth_openai_aux_clienthelpers + dispatch branch inresolve_provider_client+ aliases in_PROVIDER_ALIASES(103 lines)Test coverage
tests/agent/test_auxiliary_client_minimax_oauth_openai.py— this file already exists inmain(committed upstream) but was failing 100% because the implementation was missing. With this PR it goes from 12 failed / 0 passed → 12 passed / 0 failed. The test file documents the public API contract:_normalize_aux_provider("minimax-oai") == "minimax-oauth-openai"_normalize_aux_provider("minimax-openai") == "minimax-oauth-openai"_normalize_aux_provider("minimax-oauth-openai") == "minimax-oauth-openai"_normalize_aux_provider("minimax-oauth") == "minimax-oauth"(no alias hijack)_build_minimax_oauth_openai_aux_client("MiniMax-M3")returns a plainOpenAIclient onhttps://api.minimax.io/v1resolve_provider_client("minimax-oauth-openai", ...)dispatches to the new helper_ANTHROPIC_COMPAT_PROVIDERSdoes NOT containminimax-oauth-openaitests/test_minimax_oauth.py+tests/plugins/model_providers/test_minimax_profile.py+tests/agent/test_minimax_*.py— 113 MiniMax-related tests all pass (no regression).tests/hermes_cli/test_runtime_provider_resolution.py— 132 runtime provider tests pass (no regression).Why not just change
config.yaml model.api_mode?runtime_provider.py:333-340hard-codesapi_mode="anthropic_messages"forprovider == "minimax-oauth"before the configured-mode check at line 404-405. Somodel.api_mode: chat_completionsin config.yaml is silently ignored for the existingminimax-oauthprovider. Adding a separate provider name is the minimal-surface-area way to expose the OpenAI-compat transport without forking the credential flow.Reproduction (before/after)
Before this PR, on a MiniMax OAuth session:
After this PR, switching
model.provider: minimax-oauth-openai:Quota burn on a 1-hour coding session: ~5x lower after the switch, matching the upstream pi-mono fix's reported behavior.
Refs: rwese/pi-minimax-m3-caching-fix (the pi-mono fix this PR mirrors for Hermes).