Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
# --- Chutes ---
#CHUTES_API_KEY_1="YOUR_CHUTES_API_KEY"

# --- MiniMax ---
#MINIMAX_API_KEY_1="YOUR_MINIMAX_API_KEY"

# ------------------------------------------------------------------------------
# | [OAUTH] Provider OAuth 2.0 Credentials |
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -86,6 +89,20 @@
# cannot automatically determine your Google Cloud Project ID.
#GEMINI_CLI_PROJECT_ID=""

# --- MiniMax Endpoint Selection ---
# Select the upstream region and compatibility protocol used for MiniMax calls.
# Supported regions: global_en, cn_zh
# Supported protocols: openai, anthropic
#MINIMAX_API_REGION="global_en"
#MINIMAX_API_PROTOCOL="openai"
#
# Anthropic-compatible base URLs must end with /anthropic. The client adapter
# appends /v1/messages when sending a Messages API request.
#MINIMAX_GLOBAL_OPENAI_BASE_URL="https://api.minimax.io/v1"
#MINIMAX_GLOBAL_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic"
#MINIMAX_CN_OPENAI_BASE_URL="https://api.minimaxi.com/v1"
#MINIMAX_CN_ANTHROPIC_BASE_URL="https://api.minimaxi.com/anthropic"

# --- Model Ignore Lists ---
# Specify a comma-separated list of model names to exclude from a provider's
# available models. This is useful for filtering out models you don't want to use.
Expand Down
27 changes: 25 additions & 2 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -1145,7 +1145,31 @@ TIMEOUT_POOL=120

The library handles provider idiosyncrasies through specialized "Provider" classes in `src/rotator_library/providers/`.

### 3.1. Gemini CLI (`gemini_cli_provider.py`)
### 3.1. MiniMax (`minimax_provider.py`)

The MiniMax provider exposes the built-in `MiniMax-M3` and `MiniMax-M2.7`
models while preserving additional models returned by the provider's model
discovery endpoint. Native model metadata includes context limits, pricing,
input modalities, tool use, interleaved thinking, and tiered pricing for the
`/v1/models` and cost APIs.

Configure the upstream region and protocol with these environment variables:

```env
MINIMAX_API_REGION="global_en" # or cn_zh
MINIMAX_API_PROTOCOL="openai" # or anthropic

MINIMAX_GLOBAL_OPENAI_BASE_URL="https://api.minimax.io/v1"
MINIMAX_GLOBAL_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic"
MINIMAX_CN_OPENAI_BASE_URL="https://api.minimaxi.com/v1"
MINIMAX_CN_ANTHROPIC_BASE_URL="https://api.minimaxi.com/anthropic"
```

Anthropic-compatible base URLs must end with `/anthropic`. The adapter passes
that base to the compatibility client, which appends `/v1/messages` for the
Messages API request.

### 3.2. Gemini CLI (`gemini_cli_provider.py`)

The `GeminiCliProvider` is the most complex implementation, mimicking the Google Cloud Code extension.

Expand Down Expand Up @@ -1492,4 +1516,3 @@ The GUI modifies the same environment variables that the `RotatingClient` reads:
3. **Proxy applies rules** → `get_available_models()` filters based on rules

**Note**: The proxy must be restarted to pick up rule changes made via the GUI (or use the Launcher TUI's reload functionality if available).

22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ openai/gpt-4o ← OpenAI API
anthropic/claude-3-5-sonnet ← Anthropic API
openrouter/anthropic/claude-3-opus ← OpenRouter
gemini_cli/gemini-2.5-pro ← Gemini CLI (OAuth)
minimax/MiniMax-M3 (MiniMax OpenAI-compatible route)
minimax/MiniMax-M2.7 (MiniMax OpenAI-compatible route)
```

### Usage Examples
Expand Down Expand Up @@ -278,6 +280,7 @@ GEMINI_API_KEY_1="your-gemini-key"
GEMINI_API_KEY_2="another-gemini-key"
OPENAI_API_KEY_1="your-openai-key"
ANTHROPIC_API_KEY_1="your-anthropic-key"
MINIMAX_API_KEY_1="your-minimax-key"
```

> Copy `.env.example` to `.env` as a starting point.
Expand Down Expand Up @@ -454,6 +457,25 @@ The proxy includes a powerful text-based UI for configuration and management.
| `IGNORE_MODELS_<PROVIDER>` | Blacklist (comma-separated, supports `*`) | `IGNORE_MODELS_OPENAI=*-preview*` |
| `WHITELIST_MODELS_<PROVIDER>` | Whitelist (overrides blacklist) | `WHITELIST_MODELS_GEMINI=gemini-2.5-pro` |

### MiniMax Endpoint Selection

MiniMax supports both configured regions and both compatibility protocols. Set
the region and protocol in `.env`; the provider plugin then routes requests
through the selected base URL.

```env
MINIMAX_API_REGION="global_en" # or cn_zh
MINIMAX_API_PROTOCOL="openai" # or anthropic

MINIMAX_GLOBAL_OPENAI_BASE_URL="https://api.minimax.io/v1"
MINIMAX_GLOBAL_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic"
MINIMAX_CN_OPENAI_BASE_URL="https://api.minimaxi.com/v1"
MINIMAX_CN_ANTHROPIC_BASE_URL="https://api.minimaxi.com/anthropic"
```

Anthropic-compatible base URLs must end with `/anthropic`. The adapter uses
the provider's `/v1/messages` request path without exposing a derived base URL.

### Advanced Features

| Variable | Description |
Expand Down
148 changes: 148 additions & 0 deletions src/rotator_library/minimax_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# SPDX-License-Identifier: LGPL-3.0-only
# Copyright (c) 2026 Mirrowel

"""MiniMax endpoint and model configuration."""

from __future__ import annotations

import os
import logging
from typing import Any, Dict, Optional


lib_logger = logging.getLogger("rotator_library")


GLOBAL_EN = "global_en"
CN_ZH = "cn_zh"
OPENAI_PROTOCOL = "openai"
ANTHROPIC_PROTOCOL = "anthropic"

MINIMAX_ENDPOINTS: Dict[str, Dict[str, str]] = {
GLOBAL_EN: {
OPENAI_PROTOCOL: "https://api.minimax.io/v1",
ANTHROPIC_PROTOCOL: "https://api.minimax.io/anthropic",
},
CN_ZH: {
OPENAI_PROTOCOL: "https://api.minimaxi.com/v1",
ANTHROPIC_PROTOCOL: "https://api.minimaxi.com/anthropic",
},
}

MINIMAX_MODEL_DEFINITIONS: Dict[str, Dict[str, Any]] = {
"MiniMax-M3": {
"context_window": 1_000_000,
"pricing_usd_per_million_tokens": {
"input": 0.3,
"output": 1.2,
"cache_read": 0.06,
"cache_write": None,
},
"pricing_tiers_usd_per_million_tokens": [
{
"service_tier": "standard",
"input_tokens_lte": 512_000,
"input": 0.3,
"output": 1.2,
"cache_read": 0.06,
"cache_write": None,
},
{
"service_tier": "standard",
"input_tokens_gt": 512_000,
"input": 0.6,
"output": 2.4,
"cache_read": 0.12,
"cache_write": None,
},
{
"service_tier": "priority",
"input_tokens_lte": 512_000,
"input": 0.45,
"output": 1.8,
"cache_read": 0.09,
"cache_write": None,
},
{
"service_tier": "priority",
"input_tokens_gt": 512_000,
"input": 0.9,
"output": 3.6,
"cache_read": 0.18,
"cache_write": None,
},
],
"input_modalities": ["text", "image", "video"],
"thinking": ["adaptive", "disabled"],
"interleaved": True,
},
"MiniMax-M2.7": {
"context_window": 204_800,
"pricing_usd_per_million_tokens": {
"input": 0.3,
"output": 1.2,
"cache_read": 0.06,
"cache_write": 0.375,
},
"input_modalities": ["text"],
"thinking": ["always_on"],
},
}

MINIMAX_DEFAULT_MODELS = tuple(MINIMAX_MODEL_DEFINITIONS)

_REGION_ENV_VARS = {
GLOBAL_EN: {
OPENAI_PROTOCOL: "MINIMAX_GLOBAL_OPENAI_BASE_URL",
ANTHROPIC_PROTOCOL: "MINIMAX_GLOBAL_ANTHROPIC_BASE_URL",
},
CN_ZH: {
OPENAI_PROTOCOL: "MINIMAX_CN_OPENAI_BASE_URL",
ANTHROPIC_PROTOCOL: "MINIMAX_CN_ANTHROPIC_BASE_URL",
},
}


def get_minimax_region() -> str:
"""Return the configured endpoint region, defaulting to the global service."""
region = os.getenv("MINIMAX_API_REGION", GLOBAL_EN).strip().lower()
return region if region in MINIMAX_ENDPOINTS else GLOBAL_EN


def get_minimax_protocol() -> str:
"""Return the configured upstream protocol."""
protocol = os.getenv("MINIMAX_API_PROTOCOL", OPENAI_PROTOCOL).strip().lower()
return (
protocol
if protocol in (OPENAI_PROTOCOL, ANTHROPIC_PROTOCOL)
else OPENAI_PROTOCOL
)


def get_minimax_endpoint(
region: Optional[str] = None,
protocol: Optional[str] = None,
) -> str:
"""Resolve a user-configured or default MiniMax endpoint."""
selected_region = region or get_minimax_region()
selected_protocol = protocol or get_minimax_protocol()

if selected_region not in MINIMAX_ENDPOINTS:
selected_region = GLOBAL_EN
if selected_protocol not in (OPENAI_PROTOCOL, ANTHROPIC_PROTOCOL):
selected_protocol = OPENAI_PROTOCOL

env_var = _REGION_ENV_VARS[selected_region][selected_protocol]
override = os.getenv(env_var, "").strip()
if not override:
if selected_protocol == OPENAI_PROTOCOL:
override = os.getenv("MINIMAX_API_BASE", "").strip()

endpoint = override or MINIMAX_ENDPOINTS[selected_region][selected_protocol]
endpoint = endpoint.rstrip("/")
if selected_protocol == ANTHROPIC_PROTOCOL and not endpoint.endswith("/anthropic"):
lib_logger.warning(
"Invalid MiniMax Anthropic base URL; using the selected default endpoint"
)
endpoint = MINIMAX_ENDPOINTS[selected_region][selected_protocol]
return endpoint
Loading