Skip to content

fix(auxiliary): route minimax-oauth provider through dedicated helper - #36779

Open
VIPKaiser wants to merge 1 commit into
NousResearch:mainfrom
VIPKaiser:fix/minimax-oauth-auxiliary-routing
Open

fix(auxiliary): route minimax-oauth provider through dedicated helper#36779
VIPKaiser wants to merge 1 commit into
NousResearch:mainfrom
VIPKaiser:fix/minimax-oauth-auxiliary-routing

Conversation

@VIPKaiser

Copy link
Copy Markdown

Problem

Users with MiniMax OAuth authentication (configured via hermes model -> MiniMax (OAuth)) cannot use it for auxiliary tasks (compression, title_generation, web_extract, etc.). Any auxiliary.<task>.provider: minimax-oauth config in config.yaml produces:

RuntimeError: Provider 'minimax-oauth' is set in config.yaml but no API key
was found. Set the MINIMAX-OAUTH_API_KEY environment variable, or switch
to a different provider with `hermes model`.

This is misleading: the user is correctly authenticated; the failure is in the dispatch.

Root cause

resolve_provider_client() in agent/auxiliary_client.py has early branches for the other OAuth providers:

if provider == "nous": ...
if provider == "openai-codex": ...
if provider == "xai-oauth": ...

…but no branch for minimax-oauth. So requests fall through to the generic pconfig.auth_type in {"oauth_device_code", "oauth_external"} arm, which doesn't list oauth_minimax (the auth_type the MiniMax ProviderConfig uses). It hits the final unhandled auth_type oauth_minimax warning, returns (None, None), and the caller raises the misleading error.

Fix

  1. New helper _build_minimax_oauth_aux_client() — plumbs the MiniMax OAuth token provider callable (build_minimax_oauth_token_provider()) into the OpenAI client so a fresh access token is minted per request (MiniMax issues short-lived tokens, ~15min TTL).
  2. New early branch in resolve_provider_client() — parallel to the nous/openai-codex/xai-oauth branches, routes provider='minimax-oauth' to the new helper.
  3. Defensive elif pconfig.auth_type == 'oauth_minimax' arm — belt-and-braces: if someone refactors out the early branch in the future, the auth_type fallback still works.
  4. OpenAI-compatible base_url rewrite — MiniMax's /anthropic endpoint works over /v1/chat/completions too, so auxiliary tasks can use the bare OpenAI client (matching the existing minimax api-key path).

Tests

8 new test cases in tests/agent/test_auxiliary_client_minimax_oauth.py:

  • test_returns_client_when_logged_in — happy path
  • test_returns_client_with_model_fallback — caller passes no model
  • test_returns_none_when_not_logged_in — clean (None, None) when auth.json has no MiniMax entry
  • test_returns_none_when_creds_resolution_raises — AuthError handled
  • test_dispatches_to_minimax_oauth_helper — confirm early-branch routing
  • test_returns_none_cleanly_when_helper_returns_none — no false-positive error
  • test_oauth_minimax_auth_type_branch_exists — defensive source-grep on the auth_type fallback
  • test_does_not_raise_api_key_error_when_logged_in — regression test for the original misleading error string

All 388 auxiliary/minimax tests pass; the 5 unrelated failures elsewhere in tests/agent/ are pre-existing (verified by running on stashed/clean main).

Live verification

$ python -c "from agent.auxiliary_client import resolve_provider_client, call_llm;               client, model = resolve_provider_client('minimax-oauth', 'MiniMax-M3');               r = call_llm(task='title_generation', messages=[...], max_tokens=200, temperature=0.3)"
client: OpenAI
base_url: https://api.minimax.io/v1/
model: MiniMax-M3
OK, response: ChatCompletion(id='066cb47be319db96ceb0134cb4f5689e', ...)

End-to-end call to MiniMax via the new auxiliary path returns a real ChatCompletion.

Risk

  • auxiliary_client.py is on the hot path for every auxiliary call (compression, web_extract, title_generation, curator, profile_describer, kanban_decomposer, triage_specifier, approval, mcp, skills_hub, vision). The new code is contained to one early branch and one helper function, both gated on provider == 'minimax-oauth'. The defensive auth_type arm only fires for the same provider.
  • The /anthropic/v1 base_url rewrite is wrapped in a try/except so a non-matching base URL silently keeps the original (and would surface the same Anthropic 404 the user might have been seeing before).
  • No new dependencies, no new env vars, no schema changes to auth.json.

Checklist

  • Tested locally with live MiniMax OAuth
  • All existing auxiliary/minimax tests still pass
  • New regression tests cover the original error message
  • Defensive fallback for the auth_type dispatch

resolve_provider_client() had early branches for the nous, openai-codex,
and xai-oauth OAuth providers, but no branch for minimax-oauth. When a
user configured auxiliary.<task>.provider = minimax-oauth (as is
recommended for MiniMax OAuth subscribers), the call fell through to the
generic auth_type dispatch, which only handles oauth_device_code /
oauth_external — not the oauth_minimax auth_type that MiniMax uses. The
fallback logged an unhandled-auth-type warning and returned (None, None),
which the caller then translated into the misleading:

    RuntimeError: Provider 'minimax-oauth' is set in config.yaml but no
    API key was found. Set the MINIMAX-OAUTH_API_KEY environment variable,
    or switch to a different provider with `hermes model`.

…even though the user was correctly authenticated.

This commit:

1. Adds a _build_minimax_oauth_aux_client() helper that pulls a fresh
   access token from build_minimax_oauth_token_provider() on every
   request (MiniMax issues short-lived tokens, ~15min TTL, so a static
   string captured at client construction would expire mid-session).
2. Adds an early branch in resolve_provider_client() that routes
   provider='minimax-oauth' through the new helper — parallel to the
   existing nous / openai-codex / xai-oauth branches.
3. Adds a defensive elif pconfig.auth_type == 'oauth_minimax' arm in
   the generic dispatch as belt-and-braces protection against future
   refactors that might remove the early branch.
4. Rewrites the Anthropic-Messages base URL to the OpenAI-compatible
   /v1/chat/completions path so auxiliary tasks can use the bare OpenAI
   client (the main agent path uses the Anthropic transport, but
   auxiliaries work fine over the OpenAI route and that's what the
   existing minimax config.yaml examples show).

Tests:
  tests/agent/test_auxiliary_client_minimax_oauth.py — 8 cases covering
  the happy path, not-logged-in, callable-token refresh, and regression
  on the misleading 'no API key' error message.

Live verification:
  resolve_provider_client('minimax-oauth', 'MiniMax-M3') now returns a
  working OpenAI client (base_url=https://api.minimax.io/v1/), and a
  call_llm() round-trip with the same prompt the title_generator uses
  produces a real ChatCompletion response.
@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 provider/minimax MiniMax (Anthropic transport) labels Jun 1, 2026

@mxnstrexgl mxnstrexgl 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.

🤖 Automated PR Review

Security Scan

  • ✓ No hardcoded secrets, injection sinks, unsafe deserialization, or dependency red flags found by this automated scan.

Code Quality

  • ✓ No blocking code-quality issues found by this automated scan.

Summary

Status: APPROVE — security findings: 0, quality suggestions: 0.

Automated review; raw diff content intentionally omitted.

@sweetcornna

Copy link
Copy Markdown
Contributor

I verified this branch locally while triaging #38685. Focused checks pass in an isolated worktree:

python -m pytest tests/agent/test_auxiliary_client_minimax_oauth.py -q
# 8 passed

python -m ruff check agent/auxiliary_client.py tests/agent/test_auxiliary_client_minimax_oauth.py
# All checks passed

git diff --check origin/main...HEAD
# passed

This PR looks like the existing fix coverage for #38685 / #21521 from the focused regression angle. GitHub currently reports no checks on the branch, but the local focused verification is clean.

@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 isolating a real auxiliary-routing gap. Current main still registers minimax-oauth as oauth_minimax (hermes_cli/auth.py:301-310), while resolve_provider_client() only routes oauth_device_code and oauth_external (agent/auxiliary_client.py:5106-5119).

Problems

  • The proposed raw OpenAI /v1 route bypasses the current MiniMax OAuth transport path. The provider declares anthropic_messages (plugins/model-providers/minimax/__init__.py:82-92), and the callable credential is designed for build_anthropic_client()'s per-request bearer hook (hermes_cli/auth.py:7779-7823, agent/anthropic_adapter.py:745-751).
  • The source-inspection regression test is implementation-coupled rather than proving the authenticated client and transport behavior.

Suggested changes

  • Port the route onto current agent/auxiliary_client.py, using resolve_minimax_oauth_runtime_credentials(as_token_provider=True) plus build_anthropic_client() and AnthropicAuxiliaryClient.
  • Replace the source-grep assertion with a mocked behavioral routing/transport test.

This is an automated hermes-sweeper review.

Comment thread agent/auxiliary_client.py
# ``hermes model -> MiniMax (OAuth)``.
if provider == "minimax-oauth":
client, default = _build_minimax_oauth_aux_client(model)
if client is None:

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.

Please preserve the current MiniMax OAuth transport rather than returning a raw OpenAI /v1 client here. Current main declares this provider anthropic_messages and uses build_anthropic_client() to install the callable credential as a per-request bearer hook (hermes_cli/auth.py:7779-7823; agent/anthropic_adapter.py:745-751). Build and return the Anthropic auxiliary adapter from that established path instead.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data 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 13, 2026
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 P3 Low — cosmetic, nice to have provider/minimax MiniMax (Anthropic transport) sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants