Skip to content

feat: add MiniMax model and endpoint support#166

Open
octo-patch wants to merge 3 commits into
Mirrowel:mainfrom
octo-patch:octo/20260716-provider-add-recvoNp7gtQzMB
Open

feat: add MiniMax model and endpoint support#166
octo-patch wants to merge 3 commits into
Mirrowel:mainfrom
octo-patch:octo/20260716-provider-add-recvoNp7gtQzMB

Conversation

@octo-patch

@octo-patch octo-patch commented Jul 16, 2026

Copy link
Copy Markdown

Description

Adds MiniMax provider routing with built-in MiniMax-M3 and MiniMax-M2.7 model metadata, fallback model discovery, regional endpoint selection, and protocol-aware base routing. Updates environment examples and documentation, and adds native model metadata and cost coverage.

The secondary compatibility base configuration remains at /anthropic; a request capture verifies that the protocol request uses /v1/messages.

Compatibility

Existing user-defined model definitions remain supported, and models discovered from the provider API are appended without replacing the built-in entries.

Testing Done

  • python3 -m compileall -q src tests
  • PYTHONPATH=src .venv/bin/python -c "from rotator_library.providers import PROVIDER_PLUGINS; assert \"minimax\" in PROVIDER_PLUGINS"
  • PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -v

@octo-patch
octo-patch requested a review from Mirrowel as a code owner July 16, 2026 06:46
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added MiniMax as a supported provider, including MiniMax-M3 and MiniMax-M2.7.
    • Enabled model discovery with native model metadata (context, modalities, thinking modes) and tier-based pricing.
    • Added environment-driven region/protocol selection for OpenAI- and Anthropic-compatible MiniMax endpoints, plus optional per-deployment base URL overrides.
  • Documentation
    • Updated README and documentation with MiniMax routes, environment variable examples, and “MiniMax Endpoint Selection” requirements (including Anthropic base URL formatting).
  • Tests
    • Added integration tests covering provider routing, endpoint generation, override behavior, and tier-based cost calculation.

Walkthrough

Adds MiniMax region and protocol configuration, native metadata for two models, provider discovery and request routing, UI/environment wiring, documentation, and automated tests for endpoint selection and Anthropic-compatible requests.

Changes

MiniMax integration

Layer / File(s) Summary
MiniMax endpoint and model definitions
src/rotator_library/minimax_config.py, src/rotator_library/provider_config.py, .env.example, DOCUMENTATION.md, README.md
Defines supported regions, protocols, endpoint overrides, model metadata, environment configuration, provider UI fields, and MiniMax documentation.
Native MiniMax model registry
src/rotator_library/model_info_service.py
Builds native MiniMax catalog records, supports exact lookup, exposes structured metadata, and calculates tier-based costs.
Provider routing and validation
src/rotator_library/providers/minimax_provider.py, tests/test_minimax_provider.py
Adds model discovery, fallback models, protocol-specific request transformation, Bearer authentication, and integration tests.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: mirrowel, mirrowel, mirrowel

Poem

I’m a rabbit with endpoints to hop,
Through global and CN paths I won’t stop.
Models bloom in the registry bright,
Anthropic messages travel just right.
MiniMax carrots—configured tonight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: MiniMax model and endpoint support.
Description check ✅ Passed It includes Description and Testing Done with useful details; the template's Checklist section is missing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mirrobot-agent

Copy link
Copy Markdown
Contributor

Starting my review of the MiniMax provider addition. I'll dig into the new endpoint routing, model metadata integration, and provider plugin to make sure everything aligns with the existing patterns. Back shortly with a bundled review.

@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds MiniMax model and endpoint support. The main changes are:

  • Built-in metadata and tiered pricing for MiniMax-M3 and MiniMax-M2.7.
  • Regional OpenAI- and Anthropic-compatible endpoint routing.
  • Provider model discovery with built-in fallbacks.
  • Configuration examples, documentation, and provider tests.

Confidence Score: 5/5

This looks safe to merge.

  • The native MiniMax record now wins when an external catalog contains the same model identifier.
  • Refresh, cache, and combined-model paths preserve the native metadata.

Important Files Changed

Filename Overview
src/rotator_library/model_info_service.py Adds native MiniMax metadata, explicit lookup precedence, capability fields, and tiered cost calculation.
src/rotator_library/minimax_config.py Defines MiniMax models, pricing, regions, protocols, and endpoint resolution.
src/rotator_library/providers/minimax_provider.py Adds MiniMax model discovery and protocol-aware request routing.
src/rotator_library/provider_config.py Registers MiniMax settings and preserves endpoints selected by provider hooks.
tests/test_minimax_provider.py Covers model discovery, endpoint selection, request routing, native metadata, and long-context pricing.

Reviews (3): Last reviewed commit: "docs: use ASCII MiniMax model notation" | Re-trigger Greptile

Comment thread src/rotator_library/model_info_service.py

@mirrobot-agent mirrobot-agent Bot 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.

Overall Assessment

Solid, well-structured addition. The region/protocol endpoint selection is cleanly factored into minimax_config.py, the provider plugin follows the existing transform_request hook contract, and the native model catalog integrates nicely with the existing _native_store/priority machinery in model_info_service.py. Tests cover fallback model merging, native metadata, endpoint resolution, and an end-to-end Anthropic capture verifying /anthropic/v1/messages. Good use of graceful degradation in get_models (returns defaults on discovery failure rather than []).

Architectural Feedback

The main concern is the interaction between this provider's transform_request and the framework's convert_for_litellm step (see inline). Rewriting the model to openai/… / anthropic/… is an elegant way to reuse LiteLLM's adapters, but it also re-exposes MiniMax to those providers' _API_BASE overrides. Worth a guard so MiniMax routing can't be silently clobbered in multi-provider setups.

Key Suggestions

  • Guard the post-hook convert_for_litellm so it won't overwrite a provider hook's api_base/custom_llm_provider (silent misrouting risk).
  • Move/replace the Anthropic base-URL ValueError validation — it's swallowed by the hook wrapper, so it currently provides no user protection.
  • Resolve the MINIMAX_ANTHROPIC_BASE_URL documentation asymmetry.

Questions for the Author

  • Are has_tools/has_functions = False intentional for MiniMax-M3 given its documented tool-calling support?

This review was generated by an AI assistant.

Comment on lines +81 to +83
kwargs["model"] = f"{protocol}/{model_name}"
kwargs["api_base"] = get_minimax_endpoint(protocol=protocol)
kwargs["custom_llm_provider"] = protocol

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.

Routing interaction risk: rewriting the model to openai/<name> or anthropic/<name> makes MiniMax subject to convert_for_litellm, which runs after this hook (transforms.py step 4). That step extracts the provider prefix from kwargs["model"] and, when OPENAI_API_BASE or ANTHROPIC_API_BASE is set, overwrites kwargs["api_base"] with the OpenAI/Anthropic endpoint (provider_config.py:763-768). In a multi-provider deployment where those vars are set, MiniMax requests would be silently misrouted away from the selected MiniMax endpoint, and the current tests never exercise this (they don't set those env vars).

Consider guarding against it, e.g. a sentinel so convert_for_litellm skips when the hook already set api_base/custom_llm_provider, or routing through a MiniMax-scoped provider prefix instead of borrowing openai/anthropic.

Comment thread src/rotator_library/minimax_config.py Outdated
Comment on lines +106 to +107
if selected_protocol == ANTHROPIC_PROTOCOL and not endpoint.endswith("/anthropic"):
raise ValueError("MiniMax Anthropic base URL must end with /anthropic")

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 ValueError is effectively a no-op for users: transform_request runs inside a bare except Exception in transforms.py:114-115 that only logs at debug and continues. So a misconfigured Anthropic base URL never surfaces — instead the request falls through with half-mutated kwargs (model already rewritten to anthropic/... but no api_base/custom_llm_provider), then fails opaquely at the LiteLLM layer.

Consider validating at config/startup time, or having the provider log a warning and fall back to a safe default rather than raising into a swallowed hook.

Comment thread src/rotator_library/minimax_config.py Outdated
Comment on lines +98 to +102
if not override:
if selected_protocol == OPENAI_PROTOCOL:
override = os.getenv("MINIMAX_API_BASE", "").strip()
else:
override = os.getenv("MINIMAX_ANTHROPIC_BASE_URL", "").strip()

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.

MINIMAX_ANTHROPIC_BASE_URL is read here but isn't documented anywhere (.env.example, README.md, DOCUMENTATION.md, or the provider_config.py extra_vars list), unlike its OpenAI counterpart MINIMAX_API_BASE. The naming is also asymmetric (MINIMAX_API_BASE vs MINIMAX_ANTHROPIC_BASE_URL).

Either document both fallback vars consistently, or drop them in favor of the four region/protocol-specific vars that are already documented.

Comment on lines +116 to +117
"has_tools": False,
"has_functions": False,

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.

has_tools/has_functions are hardcoded False for both models and surfaced via the /v1/models capability metadata. MiniMax-M3 (and M2.7) advertise function/tool calling in their public docs — if so, this understates their capabilities to clients querying the proxy. Are these intentionally False, or should at least M3 report tool support?

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/rotator_library/model_info_service.py`:
- Around line 1269-1274: Update the tier matching logic in the standard_tiers
loop to evaluate both optional input_tokens_gt and input_tokens_lte bounds
independently, requiring input_tokens to be greater than the lower bound when
present and less than or equal to the upper bound when present. Remove the
mutually exclusive if/else behavior while preserving open-ended range handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 014ac39d-3e00-4c0e-b6fb-2e1345e483ce

📥 Commits

Reviewing files that changed from the base of the PR and between c951f13 and f39da68.

📒 Files selected for processing (5)
  • DOCUMENTATION.md
  • src/rotator_library/minimax_config.py
  • src/rotator_library/model_info_service.py
  • src/rotator_library/provider_config.py
  • tests/test_minimax_provider.py
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
🪛 Ruff (0.15.21)
src/rotator_library/minimax_config.py

[warning] 10-10: typing.Dict is deprecated, use dict instead

(UP035)

🔇 Additional comments (4)
src/rotator_library/minimax_config.py (1)

144-147: LGTM!

src/rotator_library/provider_config.py (1)

752-756: LGTM!

tests/test_minimax_provider.py (1)

100-132: LGTM!

DOCUMENTATION.md (1)

1153-1154: 📐 Maintainability & Code Quality | 🟡 Minor | 💤 Low value

Correct typographical error.

The phrase "interleaved thinking" appears to be missing a comma, incorrectly blending two distinct capabilities ("interleaved" and "thinking").

📝 Proposed fix
-input modalities, tool use, interleaved thinking, and tiered pricing for the
+input modalities, tool use, interleaved, thinking, and tiered pricing for the
 `/v1/models` and cost APIs.
			> Likely an incorrect or invalid review comment.

Comment on lines +1269 to +1274
for tier in standard_tiers:
if tier.get("input_tokens_lte") is not None:
matches = input_tokens <= tier["input_tokens_lte"]
else:
matches = input_tokens > tier.get("input_tokens_gt", -1)
if matches:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make tier range intersection robust.

If a pricing tier definition ever uses both input_tokens_gt and input_tokens_lte to establish an explicit range, the current if/else logic will only enforce the upper bound (lte) and completely ignore the lower bound. Checking both bounds simultaneously ensures reliable tier resolution for future ranges.

♻️ Proposed refactor
             for tier in standard_tiers:
-                if tier.get("input_tokens_lte") is not None:
-                    matches = input_tokens <= tier["input_tokens_lte"]
-                else:
-                    matches = input_tokens > tier.get("input_tokens_gt", -1)
+                matches = True
+                if tier.get("input_tokens_gt") is not None:
+                    matches &= input_tokens > tier["input_tokens_gt"]
+                if tier.get("input_tokens_lte") is not None:
+                    matches &= input_tokens <= tier["input_tokens_lte"]
                 if matches:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for tier in standard_tiers:
if tier.get("input_tokens_lte") is not None:
matches = input_tokens <= tier["input_tokens_lte"]
else:
matches = input_tokens > tier.get("input_tokens_gt", -1)
if matches:
for tier in standard_tiers:
matches = True
if tier.get("input_tokens_gt") is not None:
matches &= input_tokens > tier["input_tokens_gt"]
if tier.get("input_tokens_lte") is not None:
matches &= input_tokens <= tier["input_tokens_lte"]
if matches:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/rotator_library/model_info_service.py` around lines 1269 - 1274, Update
the tier matching logic in the standard_tiers loop to evaluate both optional
input_tokens_gt and input_tokens_lte bounds independently, requiring
input_tokens to be greater than the lower bound when present and less than or
equal to the upper bound when present. Remove the mutually exclusive if/else
behavior while preserving open-ended range handling.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

283-283: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the environment variable the runtime actually reads.

The README adds MINIMAX_API_KEY_1, but src/rotator_library/litellm_providers.py registers MINIMAX_API_KEY as the runtime key variable. Users following this example may receive authentication failures. Use MINIMAX_API_KEY here or update runtime support for numbered aliases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 283, Update the README environment-variable example to use
MINIMAX_API_KEY, matching the runtime key registered by litellm_providers.py. Do
not introduce numbered aliases unless runtime support is also intentionally
added.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@README.md`:
- Line 283: Update the README environment-variable example to use
MINIMAX_API_KEY, matching the runtime key registered by litellm_providers.py. Do
not introduce numbered aliases unless runtime support is also intentionally
added.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7d74c75-9930-49f5-936f-21fe24c5c4d7

📥 Commits

Reviewing files that changed from the base of the PR and between f39da68 and a2f5faf.

📒 Files selected for processing (1)
  • README.md
📜 Review details
🔇 Additional comments (2)
README.md (2)

108-109: LGTM!


460-478: LGTM!

@Mirrowel

Copy link
Copy Markdown
Owner

@octo-patch PR seems good. only problem is that i am in the middle of experimental rewrite that adds... a lot. Most likely i will merge this PR and any other PRs into that or rewrite them to work on that instead. Main is a bit behind dev, and dev is a lot behind experimental #162 .

@mirrobot-agent

mirrobot-agent Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@Mirrowel, following up on your request to also assess porting effort from main to experimental (at 5499ad1). Posting the findings here as asked. This one is materially more work than #165 — mostly because experimental already added a minimax stub and a new protocol-routing system that overlaps with this PR's approach.

TL;DR

Metric Value
Overall porting effort Medium–High (~1 day)
Architectural conflict Yes — provider uses the old transform_request hook; experimental's direction is the native-protocols system
Pre-existing overlap experimental already has a minimax entry in provider_config.py and registers the provider name
Files needing rework 1–2 (minimax_provider.py, possibly provider_config.py) + manual merge of model_info_service.py

File-by-file

File Porting verdict
minimax_config.py (new) Ports unchanged. Standalone module (env-based region/protocol + model defs), no framework deps.
providers/minimax_provider.py (new) Works as-is, but misaligned with experimental's direction. This is the main rework. The PR uses the old pattern: a transform_request hook that rewrites api_base + custom_llm_provider + has_custom_logic() == False to defer to LiteLLM. experimental introduced a native protocols system (DynamicOpenAICompatibleProvider with get_protocol_name, default_output_protocol, get_native_endpoint, get_native_operation, and anthropic_messages / openai_chat / responses adapters in protocols/). The transform_request hook still functions on experimental (client/transforms.py:163 still calls it via hasattr), so it won't break — but for proper alignment MiniMax should be re-expressed as a config/protocol-driven provider (region + protocol selected via ProviderRuntimeConfig) rather than a runtime request rewrite. That's where most of the day goes.
provider_config.py Direct conflict to merge. experimental already has a minimax entry (with a single MINIMAX_API_BASE extra var). This PR replaces that block with region/protocol config (MINIMAX_API_REGION, MINIMAX_API_PROTOCOL, four *_BASE_URL vars). Manual merge — and if you go the protocol-config route above, much of this may move into config.experimental JSON instead of LITELLM_PROVIDERS. Also: the PR's convert_for_litellm guard (if kwargs.get("api_base") and kwargs.get("custom_llm_provider"): return kwargs) needs reconciling with experimental's convert_for_litellm (provider_config.py:696), which has its own evolved logic.
model_info_service.py Largely additive, but needs a careful manual merge. The PR adds: ModelPricing.tiers, ModelCapabilities.thinking_modes, a _native_store + MINIMAX_MODEL_CATALOG + _build_minimax_model_catalog(), tier-aware compute_cost(), and exposes tiers / thinking_modes in as_api_response(). None of these fields exist on experimental today, so the additions are conceptually clean — but experimental has evolved this file (shifted line offsets, likely overlapping changes around compute_cost / diagnostics / all_raw_models), so it can't be a blind cherry-pick. Worth a close read to confirm experimental doesn't already have a competing pricing-direction in flight.
tests/test_minimax_provider.py Partially ports. It references ProviderTransforms, ProviderConfig, litellm.acompletion, ModelRegistry — all present on experimental. But if MiniMax is reworked onto native protocols, the transform_request/ProviderTransforms tests will need rewriting to exercise the protocol-selection path instead.
DOCUMENTATION.md, README.md, .env.example Additive — carry over. (experimental's .env.example has no MiniMax content at all right now, so the new section applies cleanly.)

Recommendation

  • If porting quickly: you can land it close to as-written (transform_request hook still works on experimental). Cost: a provider-config merge + a manual model_info_service.py integration. ~half a day.
  • If porting "properly": rework minimax_provider.py onto the native-protocols/config layer so region+protocol become declarative ProviderRuntimeConfig rather than a runtime rewrite, and fold the endpoint table into config. That aligns it with where experimental is heading and avoids carrying two parallel mechanisms. ~1 day.
  • The model-metadata additions (tiers, thinking_modes, native catalog) are genuinely additive and worth keeping regardless of which provider approach you pick — those are the highest-value, lowest-conflict parts of this PR.

I'd suggest deciding the provider-routing approach first, since it determines whether the provider_config.py changes stay in LITELLM_PROVIDERS or move to the structured config.

This analysis was generated by an AI assistant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants