From ca28ab8a0ab48e9336ba6614e70c30cbd4456393 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:08:52 +0530 Subject: [PATCH 01/13] Add: transformation file for minmax anthropic endpoint --- .../llms/minimax/messages/transformation.py | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 litellm/llms/minimax/messages/transformation.py diff --git a/litellm/llms/minimax/messages/transformation.py b/litellm/llms/minimax/messages/transformation.py new file mode 100644 index 00000000000..27d28f02d83 --- /dev/null +++ b/litellm/llms/minimax/messages/transformation.py @@ -0,0 +1,81 @@ +""" +MiniMax Anthropic transformation config - extends AnthropicConfig for MiniMax's Anthropic-compatible API +""" +from typing import Optional + +import litellm +from litellm.llms.anthropic.experimental_pass_through.messages.transformation import ( + AnthropicMessagesConfig, +) +from litellm.secret_managers.main import get_secret_str + + +class MinimaxMessagesConfig(AnthropicMessagesConfig): + """ + MiniMax Anthropic configuration that extends AnthropicConfig. + MiniMax provides an Anthropic-compatible API at: + - International: https://api.minimax.io/anthropic + - China: https://api.minimaxi.com/anthropic + + Supported models: + - MiniMax-M2.1 + - MiniMax-M2.1-lightning + - MiniMax-M2 + """ + + @property + def custom_llm_provider(self) -> Optional[str]: + return "minimax" + + @staticmethod + def get_api_key(api_key: Optional[str] = None) -> Optional[str]: + """ + Get MiniMax API key from environment or parameters. + """ + return ( + api_key + or get_secret_str("MINIMAX_API_KEY") + or litellm.api_key + ) + + @staticmethod + def get_api_base( + api_base: Optional[str] = None, + ) -> str: + """ + Get MiniMax API base URL. + Defaults to international endpoint: https://api.minimax.io/anthropic + For China, set to: https://api.minimaxi.com/anthropic + """ + return ( + api_base + or get_secret_str("MINIMAX_API_BASE") + or "https://api.minimax.io/anthropic/v1/messages" + ) + + def get_complete_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: dict, + litellm_params: dict, + stream: Optional[bool] = None, + ) -> str: + """ + Get the complete URL for MiniMax API. + Override to ensure we use MiniMax's endpoint, not Anthropic's. + """ + # Get the base URL (either provided or default MiniMax endpoint) + base_url = self.get_api_base(api_base=api_base) + + # If the base URL already includes the full path, return it + if base_url.endswith("/v1/messages"): + return base_url + + # Otherwise append the messages endpoint + if base_url.endswith("/"): + return f"{base_url}v1/messages" + else: + return f"{base_url}/v1/messages" + From 4bae4d00f5cf0fc480218040d358987e97058783 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:09:35 +0530 Subject: [PATCH 02/13] Add: transformation file for minmax anthropic endpoint --- litellm/litellm_core_utils/get_llm_provider_logic.py | 5 ++++- litellm/types/utils.py | 1 + litellm/utils.py | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/get_llm_provider_logic.py b/litellm/litellm_core_utils/get_llm_provider_logic.py index a23fce891b9..a707bdedad3 100644 --- a/litellm/litellm_core_utils/get_llm_provider_logic.py +++ b/litellm/litellm_core_utils/get_llm_provider_logic.py @@ -4,8 +4,8 @@ import httpx import litellm from litellm.constants import REPLICATE_MODEL_NAME_WITH_ID_LENGTH -from litellm.secret_managers.main import get_secret, get_secret_str from litellm.llms.openai_like.json_loader import JSONProviderRegistry +from litellm.secret_managers.main import get_secret, get_secret_str from ..types.router import LiteLLM_Params @@ -267,6 +267,9 @@ def get_llm_provider( # noqa: PLR0915 elif endpoint == "api.moonshot.ai/v1": custom_llm_provider = "moonshot" dynamic_api_key = get_secret_str("MOONSHOT_API_KEY") + elif endpoint == "api.minimax.io/anthropic" or endpoint == "api.minimaxi.com/anthropic": + custom_llm_provider = "minimax" + dynamic_api_key = get_secret_str("MINIMAX_API_KEY") elif endpoint == "platform.publicai.co/v1": custom_llm_provider = "publicai" dynamic_api_key = get_secret_str("PUBLICAI_API_KEY") diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 3416459bc28..47d9ece5e37 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -3014,6 +3014,7 @@ class LlmProviders(str, Enum): AMAZON_NOVA = "amazon_nova" A2A_AGENT = "a2a_agent" LANGGRAPH = "langgraph" + MINIMAX = "minimax" # Create a set of all provider values for quick lookup diff --git a/litellm/utils.py b/litellm/utils.py index 805fbafcfce..c0e4dd8c052 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -7501,6 +7501,12 @@ class ProviderConfigManager: ) return AzureAnthropicMessagesConfig() + elif litellm.LlmProviders.MINIMAX == provider: + from litellm.llms.minimax.messages.transformation import ( + MinimaxMessagesConfig, + ) + + return MinimaxMessagesConfig() return None @staticmethod From 743960ad0a95b98f0da2642ce35184014f84e87a Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:10:06 +0530 Subject: [PATCH 03/13] Add pricing for minmax models in model map --- ...odel_prices_and_context_window_backup.json | 42 +++++++++++++++++++ model_prices_and_context_window.json | 42 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index f4b42d1fd6e..9a938164f3d 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -19580,6 +19580,48 @@ "output_cost_per_token": 1.2e-06, "supports_system_messages": true }, + "minimax/MiniMax-M2.1": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3.75e-07, + "litellm_provider": "minimax", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_prompt_caching": true, + "supports_system_messages": true, + "max_input_tokens": 1000000, + "max_output_tokens": 8192 + }, + "minimax/MiniMax-M2.1-lightning": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 2.4e-06, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3.75e-07, + "litellm_provider": "minimax", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_prompt_caching": true, + "supports_system_messages": true, + "max_input_tokens": 1000000, + "max_output_tokens": 8192 + }, + "minimax/MiniMax-M2": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3.75e-07, + "litellm_provider": "minimax", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_prompt_caching": true, + "supports_system_messages": true, + "max_input_tokens": 200000, + "max_output_tokens": 8192 + }, "mistral.magistral-small-2509": { "input_cost_per_token": 5e-07, "litellm_provider": "bedrock_converse", diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index f4b42d1fd6e..9a938164f3d 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -19580,6 +19580,48 @@ "output_cost_per_token": 1.2e-06, "supports_system_messages": true }, + "minimax/MiniMax-M2.1": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3.75e-07, + "litellm_provider": "minimax", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_prompt_caching": true, + "supports_system_messages": true, + "max_input_tokens": 1000000, + "max_output_tokens": 8192 + }, + "minimax/MiniMax-M2.1-lightning": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 2.4e-06, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3.75e-07, + "litellm_provider": "minimax", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_prompt_caching": true, + "supports_system_messages": true, + "max_input_tokens": 1000000, + "max_output_tokens": 8192 + }, + "minimax/MiniMax-M2": { + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 3e-08, + "cache_creation_input_token_cost": 3.75e-07, + "litellm_provider": "minimax", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_prompt_caching": true, + "supports_system_messages": true, + "max_input_tokens": 200000, + "max_output_tokens": 8192 + }, "mistral.magistral-small-2509": { "input_cost_per_token": 5e-07, "litellm_provider": "bedrock_converse", From 2f9042c9748ae6d3976d4e48bc46b6d59aba8cd6 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:10:36 +0530 Subject: [PATCH 04/13] Add tests related to minmax doc --- tests/test_litellm/llms/minimax/__init__.py | 2 + .../llms/minimax/messages/__init__.py | 2 + .../minimax/messages/test_transformation.py | 147 ++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 tests/test_litellm/llms/minimax/__init__.py create mode 100644 tests/test_litellm/llms/minimax/messages/__init__.py create mode 100644 tests/test_litellm/llms/minimax/messages/test_transformation.py diff --git a/tests/test_litellm/llms/minimax/__init__.py b/tests/test_litellm/llms/minimax/__init__.py new file mode 100644 index 00000000000..19c644e5d98 --- /dev/null +++ b/tests/test_litellm/llms/minimax/__init__.py @@ -0,0 +1,2 @@ +# MiniMax tests + diff --git a/tests/test_litellm/llms/minimax/messages/__init__.py b/tests/test_litellm/llms/minimax/messages/__init__.py new file mode 100644 index 00000000000..8672b141150 --- /dev/null +++ b/tests/test_litellm/llms/minimax/messages/__init__.py @@ -0,0 +1,2 @@ +# MiniMax messages tests + diff --git a/tests/test_litellm/llms/minimax/messages/test_transformation.py b/tests/test_litellm/llms/minimax/messages/test_transformation.py new file mode 100644 index 00000000000..bbb30b652af --- /dev/null +++ b/tests/test_litellm/llms/minimax/messages/test_transformation.py @@ -0,0 +1,147 @@ +""" +Test MiniMax Anthropic-compatible API support +""" +import os +import sys +from unittest.mock import MagicMock, patch + +import pytest + +sys.path.insert( + 0, os.path.abspath("../") +) # Adds the parent directory to the system path + +import litellm +from litellm import completion +from litellm.llms.minimax.messages.transformation import MinimaxMessagesConfig + + +def test_minimax_anthropic_config(): + """Test that MinimaxMessagesConfig is properly configured""" + config = MinimaxMessagesConfig() + + # Test custom_llm_provider + assert config.custom_llm_provider == "minimax" + + # Test get_api_base default + api_base = config.get_api_base() + assert api_base == "https://api.minimax.io/anthropic/v1/messages" + + # Test get_api_base with custom value + custom_base = config.get_api_base(api_base="https://api.minimaxi.com/anthropic/v1/messages") + assert custom_base == "https://api.minimaxi.com/anthropic/v1/messages" + + +def test_minimax_provider_routing(): + """Test that minimax provider is properly routed""" + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + # Test with minimax/ prefix + model, provider, api_key, api_base = get_llm_provider( + model="minimax/MiniMax-M2.1", + api_base="https://api.minimax.io/anthropic/v1/messages" + ) + assert provider == "minimax" + assert model == "MiniMax-M2.1" + + +def test_minimax_provider_config_manager(): + """Test that ProviderConfigManager returns MinimaxMessagesConfig""" + from litellm.types.utils import LlmProviders + from litellm.utils import ProviderConfigManager + + config = ProviderConfigManager.get_provider_anthropic_messages_config( + model="MiniMax-M2.1", + provider=LlmProviders.MINIMAX + ) + + assert config is not None + assert isinstance(config, MinimaxMessagesConfig) + assert config.custom_llm_provider == "minimax" + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_completion_basic(): + """Test basic completion with MiniMax Anthropic-compatible API""" + response = completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Hello, how are you?"}], + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/anthropic/v1/messages" + ) + + assert response is not None + assert hasattr(response, "choices") + assert len(response.choices) > 0 + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_completion_with_thinking(): + """Test completion with thinking parameter (MiniMax M2.1 feature)""" + response = completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Solve this problem: 2+2=?"}], + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/anthropic/v1/messages", + thinking={"type": "enabled", "budget_tokens": 1000} + ) + + assert response is not None + # Check if thinking content is present in response + for choice in response.choices: + if hasattr(choice.message, "content"): + # MiniMax returns thinking blocks similar to Anthropic + assert choice.message.content is not None + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_completion_with_tools(): + """Test completion with tool calling (function calling)""" + tools = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get the current weather in a location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + } + }, + "required": ["location"], + }, + }, + } + ] + + response = completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "What's the weather in San Francisco?"}], + tools=tools, + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/anthropic/v1/messages" + ) + + assert response is not None + assert hasattr(response, "choices") + + +if __name__ == "__main__": + # Run basic tests that don't require API key + print("Testing MiniMax Anthropic Config...") + test_minimax_anthropic_config() + print("✓ Config test passed") + + print("\nTesting MiniMax Provider Routing...") + test_minimax_provider_routing() + print("✓ Routing test passed") + + print("\nTesting MiniMax Provider Config Manager...") + test_minimax_provider_config_manager() + print("✓ Provider config manager test passed") + + print("\n✅ All basic tests passed!") + From 403875256c603dc71755829d8b20c0d56f54d435 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:11:26 +0530 Subject: [PATCH 05/13] Add minmax documentation --- docs/my-website/docs/providers/minmax.md | 192 +++++++++++++++++++++++ docs/my-website/sidebars.js | 1 + 2 files changed, 193 insertions(+) create mode 100644 docs/my-website/docs/providers/minmax.md diff --git a/docs/my-website/docs/providers/minmax.md b/docs/my-website/docs/providers/minmax.md new file mode 100644 index 00000000000..0e8f18d2505 --- /dev/null +++ b/docs/my-website/docs/providers/minmax.md @@ -0,0 +1,192 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# MiniMax - v1/messages + +## Overview + +Litellm provides anthropic specs compatible support for minmax + +## Supported Models + +MiniMax offers three models through their Anthropic-compatible API: + +| Model | Description | Input Cost | Output Cost | Prompt Caching Read | Prompt Caching Write | +|-------|-------------|------------|-------------|---------------------|----------------------| +| **MiniMax-M2.1** | Powerful Multi-Language Programming with Enhanced Programming Experience (~60 tps) | $0.3/M tokens | $1.2/M tokens | $0.03/M tokens | $0.375/M tokens | +| **MiniMax-M2.1-lightning** | Faster and More Agile (~100 tps) | $0.3/M tokens | $2.4/M tokens | $0.03/M tokens | $0.375/M tokens | +| **MiniMax-M2** | Agentic capabilities, Advanced reasoning | $0.3/M tokens | $1.2/M tokens | $0.03/M tokens | $0.375/M tokens | + + +## Usage Examples + +### Basic Chat Completion + +```python +import litellm + +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Hello, how are you?"}], + api_key="your-minimax-api-key", + api_base="https://api.minimax.io/anthropic/v1/messages" +) + +print(response.choices[0].message.content) +``` + +### Using Environment Variables + +```bash +export MINIMAX_API_KEY="your-minimax-api-key" +export MINIMAX_API_BASE="https://api.minimax.io/anthropic/v1/messages" +``` + +```python +import litellm + +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Hello!"}] +) +``` + +### With Thinking (M2.1 Feature) + +```python +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Solve: 2+2=?"}], + thinking={"type": "enabled", "budget_tokens": 1000}, + api_key="your-minimax-api-key" +) + +# Access thinking content +for block in response.choices[0].message.content: + if hasattr(block, 'type') and block.type == 'thinking': + print(f"Thinking: {block.thinking}") +``` + +### With Tool Calling + +```python +tools = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get current weather", + "parameters": { + "type": "object", + "properties": { + "location": {"type": "string"} + }, + "required": ["location"] + } + } + } +] + +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "What's the weather in SF?"}], + tools=tools, + api_key="your-minimax-api-key" +) +``` + +### Streaming + +```python +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Tell me a story"}], + stream=True, + api_key="your-minimax-api-key" +) + +for chunk in response: + if chunk.choices[0].delta.content: + print(chunk.choices[0].delta.content, end="") +``` + +## Usage with LiteLLM Proxy + +You can use MiniMax models with the Anthropic SDK by routing through LiteLLM Proxy: + +| Step | Description | +|------|-------------| +| **1. Start LiteLLM Proxy** | Configure proxy with MiniMax models in `config.yaml` | +| **2. Set Environment Variables** | Point Anthropic SDK to proxy endpoint | +| **3. Use Anthropic SDK** | Call MiniMax models using native Anthropic SDK | + +### Step 1: Configure LiteLLM Proxy + +Create a `config.yaml`: + +```yaml +model_list: + - model_name: minimax/MiniMax-M2.1 + litellm_params: + model: minimax/MiniMax-M2.1 + api_key: os.environ/MINIMAX_API_KEY + api_base: https://api.minimax.io/anthropic/v1/messages +``` + +Start the proxy: + +```bash +litellm --config config.yaml +``` + +### Step 2: Use with Anthropic SDK + +```python +import os +os.environ["ANTHROPIC_BASE_URL"] = "http://localhost:4000" +os.environ["ANTHROPIC_API_KEY"] = "sk-1234" # Your LiteLLM proxy key + +import anthropic + +client = anthropic.Anthropic() + +message = client.messages.create( + model="minimax/MiniMax-M2.1", + max_tokens=1000, + system="You are a helpful assistant.", + messages=[ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Hi, how are you?" + } + ] + } + ] +) + +for block in message.content: + if block.type == "thinking": + print(f"Thinking:\n{block.thinking}\n") + elif block.type == "text": + print(f"Text:\n{block.text}\n") +``` +## Cost Calculation + +Cost calculation works automatically using the pricing information in `model_prices_and_context_window.json`. + +Example: +```python +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Hello!"}], + api_key="your-minimax-api-key" +) + +# Access cost information +print(f"Cost: ${response._hidden_params.get('response_cost', 0)}") +``` + + diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index b6b8fe1223d..9801c764acc 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -722,6 +722,7 @@ const sidebars = { "providers/meta_llama", "providers/milvus_vector_stores", "providers/mistral", + "providers/minimax", "providers/moonshot", "providers/morph", "providers/nebius", From 0174c56c907c722879842b869de936832ff65fa4 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:23:27 +0530 Subject: [PATCH 06/13] Fix: documentation for litellm sdk --- docs/my-website/docs/providers/minmax.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/docs/my-website/docs/providers/minmax.md b/docs/my-website/docs/providers/minmax.md index 0e8f18d2505..7019b8a59f5 100644 --- a/docs/my-website/docs/providers/minmax.md +++ b/docs/my-website/docs/providers/minmax.md @@ -25,7 +25,7 @@ MiniMax offers three models through their Anthropic-compatible API: ```python import litellm -response = litellm.completion( +response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", messages=[{"role": "user", "content": "Hello, how are you?"}], api_key="your-minimax-api-key", @@ -45,7 +45,7 @@ export MINIMAX_API_BASE="https://api.minimax.io/anthropic/v1/messages" ```python import litellm -response = litellm.completion( +response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", messages=[{"role": "user", "content": "Hello!"}] ) @@ -54,7 +54,7 @@ response = litellm.completion( ### With Thinking (M2.1 Feature) ```python -response = litellm.completion( +response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", messages=[{"role": "user", "content": "Solve: 2+2=?"}], thinking={"type": "enabled", "budget_tokens": 1000}, @@ -87,7 +87,7 @@ tools = [ } ] -response = litellm.completion( +response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", messages=[{"role": "user", "content": "What's the weather in SF?"}], tools=tools, @@ -95,20 +95,7 @@ response = litellm.completion( ) ``` -### Streaming -```python -response = litellm.completion( - model="minimax/MiniMax-M2.1", - messages=[{"role": "user", "content": "Tell me a story"}], - stream=True, - api_key="your-minimax-api-key" -) - -for chunk in response: - if chunk.choices[0].delta.content: - print(chunk.choices[0].delta.content, end="") -``` ## Usage with LiteLLM Proxy From af8483b37ebd08e8765fefe055fa12330a038479 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 16:27:35 +0530 Subject: [PATCH 07/13] Fix: documentation for litellm sdk --- docs/my-website/docs/providers/minmax.md | 9 +++-- ...odel_prices_and_context_window_backup.json | 40 +++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/docs/my-website/docs/providers/minmax.md b/docs/my-website/docs/providers/minmax.md index 7019b8a59f5..3c7db7a9b48 100644 --- a/docs/my-website/docs/providers/minmax.md +++ b/docs/my-website/docs/providers/minmax.md @@ -29,7 +29,8 @@ response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", messages=[{"role": "user", "content": "Hello, how are you?"}], api_key="your-minimax-api-key", - api_base="https://api.minimax.io/anthropic/v1/messages" + api_base="https://api.minimax.io/anthropic/v1/messages", + max_tokens=1000 ) print(response.choices[0].message.content) @@ -47,7 +48,8 @@ import litellm response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", - messages=[{"role": "user", "content": "Hello!"}] + messages=[{"role": "user", "content": "Hello!"}], + max_tokens=1000 ) ``` @@ -91,7 +93,8 @@ response = litellm.anthropic.messages.acreate( model="minimax/MiniMax-M2.1", messages=[{"role": "user", "content": "What's the weather in SF?"}], tools=tools, - api_key="your-minimax-api-key" + api_key="your-minimax-api-key", + max_tokens=1000 ) ``` diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index e123ba00081..3fe1b4f6a9e 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -1357,6 +1357,20 @@ "litellm_provider": "azure", "mode": "chat" }, + "azure_ai/gpt-oss-120b": { + "input_cost_per_token": 1.5e-7, + "output_cost_per_token": 6e-7, + "litellm_provider": "azure_ai", + "max_input_tokens": 131072, + "max_output_tokens": 131072, + "max_tokens": 131072, + "mode": "chat", + "source": "https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_tool_choice": true + }, "azure/eu/gpt-4o-2024-08-06": { "deprecation_date": "2026-02-27", "cache_read_input_token_cost": 1.375e-06, @@ -3707,6 +3721,32 @@ "/v1/images/generations" ] }, + "azure/gpt-image-1.5": { + "cache_read_input_image_token_cost": 2e-06, + "cache_read_input_token_cost": 1.25e-06, + "input_cost_per_token": 5e-06, + "input_cost_per_image_token": 8e-06, + "litellm_provider": "azure", + "mode": "image_generation", + "output_cost_per_image_token": 3.2e-05, + "supported_endpoints": [ + "/v1/images/generations", + "/v1/images/edits" + ] + }, + "azure/gpt-image-1.5-2025-12-16": { + "cache_read_input_image_token_cost": 2e-06, + "cache_read_input_token_cost": 1.25e-06, + "input_cost_per_token": 5e-06, + "input_cost_per_image_token": 8e-06, + "litellm_provider": "azure", + "mode": "image_generation", + "output_cost_per_image_token": 3.2e-05, + "supported_endpoints": [ + "/v1/images/generations", + "/v1/images/edits" + ] + }, "azure/low/1024-x-1024/gpt-image-1-mini": { "input_cost_per_pixel": 2.0751953125e-09, "litellm_provider": "azure", From 38cf66df012dbf225b115bc52b1d94e8b6eb901c Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 17:07:21 +0530 Subject: [PATCH 08/13] Add: chat completion transformation for minmax --- litellm/llms/minimax/chat/__init__.py | 4 + litellm/llms/minimax/chat/transformation.py | 83 +++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 litellm/llms/minimax/chat/__init__.py create mode 100644 litellm/llms/minimax/chat/transformation.py diff --git a/litellm/llms/minimax/chat/__init__.py b/litellm/llms/minimax/chat/__init__.py new file mode 100644 index 00000000000..45bcfd03b49 --- /dev/null +++ b/litellm/llms/minimax/chat/__init__.py @@ -0,0 +1,4 @@ +""" +MiniMax OpenAI-compatible chat API +""" + diff --git a/litellm/llms/minimax/chat/transformation.py b/litellm/llms/minimax/chat/transformation.py new file mode 100644 index 00000000000..ed80ff8aed1 --- /dev/null +++ b/litellm/llms/minimax/chat/transformation.py @@ -0,0 +1,83 @@ +""" +MiniMax OpenAI transformation config - extends OpenAI chat config for MiniMax's OpenAI-compatible API +""" +from typing import Optional + +import litellm +from litellm.llms.openai.chat.gpt_transformation import OpenAIGPTConfig +from litellm.secret_managers.main import get_secret_str + + +class MinimaxChatConfig(OpenAIGPTConfig): + """ + MiniMax OpenAI configuration that extends OpenAIGPTConfig. + MiniMax provides an OpenAI-compatible API at: + - International: https://api.minimax.io/v1 + - China: https://api.minimaxi.com/v1 + + Supported models: + - MiniMax-M2.1 + - MiniMax-M2.1-lightning + - MiniMax-M2 + """ + + @staticmethod + def get_api_key(api_key: Optional[str] = None) -> Optional[str]: + """ + Get MiniMax API key from environment or parameters. + """ + return ( + api_key + or get_secret_str("MINIMAX_API_KEY") + or litellm.api_key + ) + + @staticmethod + def get_api_base( + api_base: Optional[str] = None, + ) -> str: + """ + Get MiniMax API base URL. + Defaults to international endpoint: https://api.minimax.io/v1 + For China, set to: https://api.minimaxi.com/v1 + """ + return ( + api_base + or get_secret_str("MINIMAX_API_BASE") + or "https://api.minimax.io/v1" + ) + + def get_complete_url( + self, + api_base: Optional[str], + api_key: Optional[str], + model: str, + optional_params: dict, + litellm_params: dict, + stream: Optional[bool] = None, + ) -> str: + """ + Get the complete URL for MiniMax OpenAI API. + Override to ensure we use MiniMax's endpoint. + """ + # Get the base URL (either provided or default MiniMax endpoint) + base_url = self.get_api_base(api_base=api_base) + + # Ensure it ends with /chat/completions + if base_url.endswith("/chat/completions"): + return base_url + elif base_url.endswith("/v1"): + return f"{base_url}/chat/completions" + elif base_url.endswith("/"): + return f"{base_url}v1/chat/completions" + else: + return f"{base_url}/v1/chat/completions" + + def get_supported_openai_params(self, model: str) -> list: + """ + Get supported OpenAI parameters for MiniMax. + Adds reasoning_split to the list of supported params. + """ + base_params = super().get_supported_openai_params(model=model) + return base_params + ["reasoning_split"] + From b1b8d19d97127a3f238b105a78be0c32e7612d5f Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 17:08:44 +0530 Subject: [PATCH 09/13] Add: chat completion transformation for minmax --- litellm/__init__.py | 1 + litellm/_lazy_imports.py | 9 +++++ .../get_llm_provider_logic.py | 3 ++ litellm/main.py | 38 ++++++++++++++++++- litellm/utils.py | 2 + 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/litellm/__init__.py b/litellm/__init__.py index b20b3c5f8e1..dfcee0e2d3c 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -1482,6 +1482,7 @@ if TYPE_CHECKING: from .llms.bytez.chat.transformation import BytezChatConfig as BytezChatConfig from .llms.compactifai.chat.transformation import CompactifAIChatConfig as CompactifAIChatConfig from .llms.empower.chat.transformation import EmpowerChatConfig as EmpowerChatConfig + from .llms.minimax.chat.transformation import MinimaxChatConfig as MinimaxChatConfig from .llms.aiohttp_openai.chat.transformation import AiohttpOpenAIChatConfig as AiohttpOpenAIChatConfig from .llms.huggingface.chat.transformation import HuggingFaceChatConfig as HuggingFaceChatConfig from .llms.huggingface.embedding.transformation import HuggingFaceEmbeddingConfig as HuggingFaceEmbeddingConfig diff --git a/litellm/_lazy_imports.py b/litellm/_lazy_imports.py index 6f96f9f8ff3..044fad924ac 100644 --- a/litellm/_lazy_imports.py +++ b/litellm/_lazy_imports.py @@ -165,6 +165,7 @@ LLM_CONFIG_NAMES = ( "BytezChatConfig", "CompactifAIChatConfig", "EmpowerChatConfig", + "MinimaxChatConfig", "AiohttpOpenAIChatConfig", "HuggingFaceChatConfig", "HuggingFaceEmbeddingConfig", @@ -750,6 +751,14 @@ def _lazy_import_llm_configs(name: str) -> Any: # noqa: PLR0915 _globals["EmpowerChatConfig"] = _EmpowerChatConfig return _EmpowerChatConfig + if name == "MinimaxChatConfig": + from .llms.minimax.chat.transformation import ( + MinimaxChatConfig as _MinimaxChatConfig, + ) + + _globals["MinimaxChatConfig"] = _MinimaxChatConfig + return _MinimaxChatConfig + if name == "AiohttpOpenAIChatConfig": from .llms.aiohttp_openai.chat.transformation import ( AiohttpOpenAIChatConfig as _AiohttpOpenAIChatConfig, diff --git a/litellm/litellm_core_utils/get_llm_provider_logic.py b/litellm/litellm_core_utils/get_llm_provider_logic.py index 3b0a3a5e1a5..164e2a73e65 100644 --- a/litellm/litellm_core_utils/get_llm_provider_logic.py +++ b/litellm/litellm_core_utils/get_llm_provider_logic.py @@ -270,6 +270,9 @@ def get_llm_provider( # noqa: PLR0915 elif endpoint == "api.minimax.io/anthropic" or endpoint == "api.minimaxi.com/anthropic": custom_llm_provider = "minimax" dynamic_api_key = get_secret_str("MINIMAX_API_KEY") + elif endpoint == "api.minimax.io/v1" or endpoint == "api.minimaxi.com/v1": + custom_llm_provider = "minimax" + dynamic_api_key = get_secret_str("MINIMAX_API_KEY") elif endpoint == "platform.publicai.co/v1": custom_llm_provider = "publicai" dynamic_api_key = get_secret_str("PUBLICAI_API_KEY") diff --git a/litellm/main.py b/litellm/main.py index 60fe3eb2dec..fe2c2f333fc 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -68,7 +68,6 @@ from litellm.constants import ( DEFAULT_MOCK_RESPONSE_PROMPT_TOKEN_COUNT, ) from litellm.exceptions import LiteLLMUnknownProvider -from litellm.llms.openai_like.json_loader import JSONProviderRegistry from litellm.integrations.custom_logger import CustomLogger from litellm.litellm_core_utils.asyncify import run_async_function from litellm.litellm_core_utils.audio_utils.utils import ( @@ -98,6 +97,7 @@ from litellm.llms.base_llm.base_model_iterator import ( from litellm.llms.bedrock.common_utils import BedrockModelInfo from litellm.llms.cohere.common_utils import CohereModelInfo from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler +from litellm.llms.openai_like.json_loader import JSONProviderRegistry from litellm.llms.vertex_ai.common_utils import ( VertexAIModelRoute, get_vertex_ai_model_route, @@ -2247,6 +2247,42 @@ def completion( # type: ignore # noqa: PLR0915 logging.post_call( input=messages, api_key=api_key, original_response=response ) + elif custom_llm_provider == "minimax": + api_key = ( + api_key + or get_secret_str("MINIMAX_API_KEY") + or litellm.api_key + ) + + api_base = ( + api_base + or litellm.api_base + or get_secret_str("MINIMAX_API_BASE") + or "https://api.minimax.io/v1" + ) + + response = base_llm_http_handler.completion( + model=model, + messages=messages, + api_base=api_base, + custom_llm_provider=custom_llm_provider, + model_response=model_response, + encoding=_get_encoding(), + logging_obj=logging, + optional_params=optional_params, + timeout=timeout, + litellm_params=litellm_params, + shared_session=shared_session, + acompletion=acompletion, + stream=stream, + api_key=api_key, + headers=headers, + client=client, + provider_config=provider_config, + ) + logging.post_call( + input=messages, api_key=api_key, original_response=response + ) elif ( model in litellm.open_ai_chat_completion_models or custom_llm_provider == "custom_openai" diff --git a/litellm/utils.py b/litellm/utils.py index c0e4dd8c052..d073c7866c2 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -7224,6 +7224,8 @@ class ProviderConfigManager: return litellm.IBMWatsonXAIConfig() elif litellm.LlmProviders.EMPOWER == provider: return litellm.EmpowerChatConfig() + elif litellm.LlmProviders.MINIMAX == provider: + return litellm.MinimaxChatConfig() elif litellm.LlmProviders.GITHUB == provider: return litellm.GithubChatConfig() elif litellm.LlmProviders.COMPACTIFAI == provider: From 26c039614648ee278c96c06cf7ecda55dc4c3550 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 17:10:06 +0530 Subject: [PATCH 10/13] Add documentation for chat compeltion minmax --- docs/my-website/docs/providers/minmax.md | 201 +++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/docs/my-website/docs/providers/minmax.md b/docs/my-website/docs/providers/minmax.md index 3c7db7a9b48..b76f1271589 100644 --- a/docs/my-website/docs/providers/minmax.md +++ b/docs/my-website/docs/providers/minmax.md @@ -163,6 +163,207 @@ for block in message.content: elif block.type == "text": print(f"Text:\n{block.text}\n") ``` + +# MiniMax - v1/chat/completions + +## Usage with LiteLLM SDK + +You can use MiniMax's OpenAI-compatible API directly with LiteLLM: + +### Basic Chat Completion + +```python +import litellm + +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello, how are you?"} + ], + api_key="your-minimax-api-key", + api_base="https://api.minimax.io/v1" +) + +print(response.choices[0].message.content) +``` + +### Using Environment Variables + +```bash +export MINIMAX_API_KEY="your-minimax-api-key" +export MINIMAX_API_BASE="https://api.minimax.io/v1" +``` + +```python +import litellm + +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Hello!"}] +) +``` + +### With Reasoning Split + +```python +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Solve: 2+2=?"} + ], + extra_body={"reasoning_split": True}, + api_key="your-minimax-api-key", + api_base="https://api.minimax.io/v1" +) + +# Access reasoning details if available +if hasattr(response.choices[0].message, 'reasoning_details'): + print(f"Thinking: {response.choices[0].message.reasoning_details}") +print(f"Response: {response.choices[0].message.content}") +``` + +### With Tool Calling + +```python +tools = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get current weather", + "parameters": { + "type": "object", + "properties": { + "location": {"type": "string"} + }, + "required": ["location"] + } + } + } +] + +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "What's the weather in SF?"}], + tools=tools, + api_key="your-minimax-api-key", + api_base="https://api.minimax.io/v1" +) +``` + +### Streaming + +```python +response = litellm.completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Tell me a story"}], + stream=True, + api_key="your-minimax-api-key", + api_base="https://api.minimax.io/v1" +) + +for chunk in response: + if chunk.choices[0].delta.content: + print(chunk.choices[0].delta.content, end="") +``` + + +## Usage with OpenAI SDK via LiteLLM Proxy + +You can also use MiniMax models with the OpenAI SDK by routing through LiteLLM Proxy: + +| Step | Description | +|------|-------------| +| **1. Start LiteLLM Proxy** | Configure proxy with MiniMax models in `config.yaml` | +| **2. Set Environment Variables** | Point OpenAI SDK to proxy endpoint | +| **3. Use OpenAI SDK** | Call MiniMax models using native OpenAI SDK | + +### Step 1: Configure LiteLLM Proxy + +Create a `config.yaml`: + +```yaml +model_list: + - model_name: minimax/MiniMax-M2.1 + litellm_params: + model: minimax/MiniMax-M2.1 + api_key: os.environ/MINIMAX_API_KEY + api_base: https://api.minimax.io/v1 +``` + +Start the proxy: + +```bash +litellm --config config.yaml +``` + +### Step 2: Use with OpenAI SDK + +```python +import os +os.environ["OPENAI_BASE_URL"] = "http://localhost:4000" +os.environ["OPENAI_API_KEY"] = "sk-1234" # Your LiteLLM proxy key + +from openai import OpenAI + +client = OpenAI() + +response = client.chat.completions.create( + model="minimax/MiniMax-M2.1", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hi, how are you?"}, + ], + # Set reasoning_split=True to separate thinking content + extra_body={"reasoning_split": True}, +) + +# Access thinking and response +if hasattr(response.choices[0].message, 'reasoning_details'): + print(f"Thinking:\n{response.choices[0].message.reasoning_details[0]['text']}\n") +print(f"Text:\n{response.choices[0].message.content}\n") +``` + +### Streaming with OpenAI SDK + +```python +from openai import OpenAI + +client = OpenAI() + +stream = client.chat.completions.create( + model="minimax/MiniMax-M2.1", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + extra_body={"reasoning_split": True}, + stream=True, +) + +reasoning_buffer = "" +text_buffer = "" + +for chunk in stream: + if hasattr(chunk.choices[0].delta, "reasoning_details") and chunk.choices[0].delta.reasoning_details: + for detail in chunk.choices[0].delta.reasoning_details: + if "text" in detail: + reasoning_text = detail["text"] + new_reasoning = reasoning_text[len(reasoning_buffer):] + if new_reasoning: + print(new_reasoning, end="", flush=True) + reasoning_buffer = reasoning_text + + if chunk.choices[0].delta.content: + content_text = chunk.choices[0].delta.content + new_text = content_text[len(text_buffer):] if text_buffer else content_text + if new_text: + print(new_text, end="", flush=True) + text_buffer = content_text +``` + ## Cost Calculation Cost calculation works automatically using the pricing information in `model_prices_and_context_window.json`. From 4e77dc67d231b6693d4de254f5f0b6c80a471d0f Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 17:10:46 +0530 Subject: [PATCH 11/13] Add tests for chat completion minmax --- .../llms/minimax/chat/__init__.py | 2 + .../llms/minimax/chat/test_transformation.py | 225 ++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 tests/test_litellm/llms/minimax/chat/__init__.py create mode 100644 tests/test_litellm/llms/minimax/chat/test_transformation.py diff --git a/tests/test_litellm/llms/minimax/chat/__init__.py b/tests/test_litellm/llms/minimax/chat/__init__.py new file mode 100644 index 00000000000..6c63920b3ea --- /dev/null +++ b/tests/test_litellm/llms/minimax/chat/__init__.py @@ -0,0 +1,2 @@ +# MiniMax chat tests + diff --git a/tests/test_litellm/llms/minimax/chat/test_transformation.py b/tests/test_litellm/llms/minimax/chat/test_transformation.py new file mode 100644 index 00000000000..aa7105077a0 --- /dev/null +++ b/tests/test_litellm/llms/minimax/chat/test_transformation.py @@ -0,0 +1,225 @@ +""" +Test MiniMax OpenAI-compatible API support +""" +import os +import sys +from unittest.mock import MagicMock, patch + +import pytest + +sys.path.insert( + 0, os.path.abspath("../") +) # Adds the parent directory to the system path + +import litellm +from litellm import completion +from litellm.llms.minimax.chat.transformation import MinimaxChatConfig + + +def test_minimax_chat_config(): + """Test that MinimaxChatConfig is properly configured""" + config = MinimaxChatConfig() + + # Test get_api_base default + api_base = config.get_api_base() + assert api_base == "https://api.minimax.io/v1" + + # Test get_api_base with custom value + custom_base = config.get_api_base(api_base="https://api.minimaxi.com/v1") + assert custom_base == "https://api.minimaxi.com/v1" + + # Test get_complete_url + complete_url = config.get_complete_url( + api_base="https://api.minimax.io/v1", + api_key=None, + model="MiniMax-M2.1", + optional_params={}, + litellm_params={}, + stream=False + ) + assert complete_url == "https://api.minimax.io/v1/chat/completions" + + +def test_minimax_chat_config_url_variations(): + """Test URL handling with different base URL formats""" + config = MinimaxChatConfig() + + # Test with /v1 ending + url1 = config.get_complete_url( + api_base="https://api.minimax.io/v1", + api_key=None, + model="MiniMax-M2.1", + optional_params={}, + litellm_params={}, + ) + assert url1 == "https://api.minimax.io/v1/chat/completions" + + # Test with trailing slash + url2 = config.get_complete_url( + api_base="https://api.minimax.io/", + api_key=None, + model="MiniMax-M2.1", + optional_params={}, + litellm_params={}, + ) + assert url2 == "https://api.minimax.io/v1/chat/completions" + + # Test without trailing slash + url3 = config.get_complete_url( + api_base="https://api.minimax.io", + api_key=None, + model="MiniMax-M2.1", + optional_params={}, + litellm_params={}, + ) + assert url3 == "https://api.minimax.io/v1/chat/completions" + + # Test with full path already + url4 = config.get_complete_url( + api_base="https://api.minimax.io/v1/chat/completions", + api_key=None, + model="MiniMax-M2.1", + optional_params={}, + litellm_params={}, + ) + assert url4 == "https://api.minimax.io/v1/chat/completions" + + +def test_minimax_provider_routing(): + """Test that minimax provider is properly routed""" + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + # Test with minimax/ prefix + model, provider, api_key, api_base = get_llm_provider( + model="minimax/MiniMax-M2.1", + api_base="https://api.minimax.io/v1" + ) + assert provider == "minimax" + assert model == "MiniMax-M2.1" + + +def test_minimax_provider_config_manager(): + """Test that ProviderConfigManager returns MinimaxChatConfig""" + from litellm.types.utils import LlmProviders + from litellm.utils import ProviderConfigManager + + config = ProviderConfigManager.get_provider_chat_config( + model="MiniMax-M2.1", + provider=LlmProviders.MINIMAX + ) + + assert config is not None + assert isinstance(config, MinimaxChatConfig) + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_chat_completion_basic(): + """Test basic chat completion with MiniMax OpenAI-compatible API""" + response = completion( + model="minimax/MiniMax-M2.1", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello, how are you?"} + ], + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/v1" + ) + + assert response is not None + assert hasattr(response, "choices") + assert len(response.choices) > 0 + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_chat_completion_with_reasoning_split(): + """Test completion with reasoning_split parameter (MiniMax M2.1 feature)""" + response = completion( + model="minimax/MiniMax-M2.1", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Solve this problem: 2+2=?"} + ], + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/v1", + extra_body={"reasoning_split": True} + ) + + assert response is not None + # Check if reasoning_details is present in response + if hasattr(response.choices[0].message, "reasoning_details"): + assert response.choices[0].message.reasoning_details is not None + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_chat_completion_with_tools(): + """Test completion with tool calling (function calling)""" + tools = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get the current weather in a location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + } + }, + "required": ["location"], + }, + }, + } + ] + + response = completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "What's the weather in San Francisco?"}], + tools=tools, + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/v1" + ) + + assert response is not None + assert hasattr(response, "choices") + + +@pytest.mark.skip(reason="Requires actual MiniMax API key") +def test_minimax_chat_completion_streaming(): + """Test streaming completion""" + response = completion( + model="minimax/MiniMax-M2.1", + messages=[{"role": "user", "content": "Count to 5"}], + stream=True, + api_key=os.getenv("MINIMAX_API_KEY"), + api_base="https://api.minimax.io/v1" + ) + + chunks = [] + for chunk in response: + chunks.append(chunk) + + assert len(chunks) > 0 + + +if __name__ == "__main__": + # Run basic tests that don't require API key + print("Testing MiniMax Chat Config...") + test_minimax_chat_config() + print("✓ Config test passed") + + print("\nTesting MiniMax Chat Config URL Variations...") + test_minimax_chat_config_url_variations() + print("✓ URL variations test passed") + + print("\nTesting MiniMax Provider Routing...") + test_minimax_provider_routing() + print("✓ Routing test passed") + + print("\nTesting MiniMax Provider Config Manager...") + test_minimax_provider_config_manager() + print("✓ Provider config manager test passed") + + print("\n✅ All basic tests passed!") + From e18cfc0cf6908014956c5f9f5dcc2fbc2a585042 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 21:42:51 +0530 Subject: [PATCH 12/13] corrected provider name --- docs/my-website/docs/providers/{minmax.md => minimax.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/my-website/docs/providers/{minmax.md => minimax.md} (100%) diff --git a/docs/my-website/docs/providers/minmax.md b/docs/my-website/docs/providers/minimax.md similarity index 100% rename from docs/my-website/docs/providers/minmax.md rename to docs/my-website/docs/providers/minimax.md From a2240775c4a813cf2f4eac23000341f87344d48c Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 23 Dec 2025 21:46:34 +0530 Subject: [PATCH 13/13] correct doc --- docs/my-website/docs/providers/minimax.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/my-website/docs/providers/minimax.md b/docs/my-website/docs/providers/minimax.md index b76f1271589..250c5159a3d 100644 --- a/docs/my-website/docs/providers/minimax.md +++ b/docs/my-website/docs/providers/minimax.md @@ -1,6 +1,8 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +# MiniMax + # MiniMax - v1/messages ## Overview