Skip to content

feat(minimax): add minimax-oauth-openai provider for M3 prompt caching - #54012

Open
nickjohnsonrob wants to merge 2 commits into
NousResearch:mainfrom
nickjohnsonrob:feat/minimax-oauth-openai-profile
Open

feat(minimax): add minimax-oauth-openai provider for M3 prompt caching#54012
nickjohnsonrob wants to merge 2 commits into
NousResearch:mainfrom
nickjohnsonrob:feat/minimax-oauth-openai-profile

Conversation

@nickjohnsonrob

Copy link
Copy Markdown

Problem

MiniMax's Anthropic-compatible endpoint at https://api.minimax.io/anthropic silently ignores cache_control hints, so MiniMax-M3 sessions never receive cache_read discounting on MiniMax's 5-hour Token Plan Plus quota. MiniMax's OpenAI-compatible endpoint at https://api.minimax.io/v1 honors prompt caching natively — same model, same OAuth, same auth.json slot, just a different transport + base URL.

The upstream pi-mono community 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-openai that:

  • Reuses existing MiniMax OAuth credentials — same client_id, same scope, same auth.json.providers.minimax-oauth slot. Users who have already run hermes model → MiniMax (OAuth) get the new provider for free; no re-auth.
  • Routes to /v1/chat/completions — the OpenAI-compatible endpoint that honors prompt caching.
  • Inherits the M3 reasoning controlsreasoning_split: true + thinking: {type: adaptive} are emitted on the new profile via the existing MiniMaxProfile.build_api_kwargs_extras subclass hook (no duplication).

Existing minimax-oauth (Anthropic-compat) is completely unchanged. Users who don't switch see no difference.

Files

File Change
plugins/model-providers/minimax/__init__.py New minimax_oauth_openai profile (22 lines)
hermes_cli/auth.py New PROVIDER_REGISTRY["minimax-oauth-openai"] entry + MINIMAX_OAUTH_GLOBAL_INFERENCE_OPENAI constant (17 lines)
hermes_cli/runtime_provider.py Extend existing MiniMax OAuth credential branch to cover both provider names, switching api_mode per name (7 lines)
agent/auxiliary_client.py New _resolve_minimax_oauth_for_aux + _build_minimax_oauth_openai_aux_client helpers + dispatch branch in resolve_provider_client + aliases in _PROVIDER_ALIASES (103 lines)

Test coverage

  • tests/agent/test_auxiliary_client_minimax_oauth_openai.py — this file already exists in main (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 plain OpenAI client on https://api.minimax.io/v1
    • resolve_provider_client("minimax-oauth-openai", ...) dispatches to the new helper
    • _ANTHROPIC_COMPAT_PROVIDERS does NOT contain minimax-oauth-openai
  • tests/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-340 hard-codes api_mode="anthropic_messages" for provider == "minimax-oauth" before the configured-mode check at line 404-405. So model.api_mode: chat_completions in config.yaml is silently ignored for the existing minimax-oauth provider. 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:

hermes chat -q "Reply OK" -m MiniMax-M3
→ POST https://api.minimax.io/anthropic/v1/messages
→ token usage: prompt=42,819, completion=38, cache_read=0   ← no caching

After this PR, switching model.provider: minimax-oauth-openai:

hermes chat -q "Reply OK" -m MiniMax-M3
→ POST https://api.minimax.io/v1/chat/completions
→ token usage: prompt=42,819, completion=38, cache_read=~33,000  ← prefix cached

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).

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).
@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins provider/minimax MiniMax (Anthropic transport) P3 Low — cosmetic, nice to have labels Jun 28, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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: New MINIMAX_OAUTH_GLOBAL_INFERENCE_OPENAI constant and ProviderConfig entry with shares_auth_with linking to the existing minimax-oauth provider.
  • runtime_provider.py: Handles the new provider in the resolution chain with proper api_mode and base_url routing.

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 tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 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 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 from api_key at agent/agent_init.py:921-940. Please provide equivalent refresh/retry handling for the new transport.
  • hermes_cli/models.py:1092-1106 excludes oauth_external profiles from automatic picker insertion. Since this profile is oauth_external, the PR needs explicit picker/setup integration; otherwise hermes model cannot 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()

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.

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",

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.

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.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 15, 2026

@GottZ GottZ left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 /anthropic rewrite, but the added not url.endswith("/anthropic/v1") check is redundant when the same condition already requires url.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 distinct minimax-oauth-openai profile, 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, the oauth_external profile 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.

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 comp/cli CLI entry point, hermes_cli/, setup wizard comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have provider/minimax MiniMax (Anthropic transport) sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants