diff --git a/README.md b/README.md
index b3eedf5..ea30c21 100644
--- a/README.md
+++ b/README.md
@@ -206,6 +206,7 @@ We support all major LLM providers and models for inference. You need to set the
|----------|-------------------------------|------------------|
| OptiLLM | `OPTILLM_API_KEY` | Uses the inbuilt local server for inference, supports logprobs and decoding techniques like `cot_decoding` & `entropy_decoding` |
| OpenAI | `OPENAI_API_KEY` | You can use this with any OpenAI compatible endpoint (e.g. OpenRouter) by setting the `base_url` |
+| MiniMax | `MINIMAX_API_KEY` | Uses the [MiniMax API](https://www.minimax.io/) (OpenAI-compatible). Supports MiniMax-M2.7 and other models. Temperature is auto-clamped to (0, 1] |
| Cerebras | `CEREBRAS_API_KEY` | You can use this for fast inference with supported models, see [docs for details](https://inference-docs.cerebras.ai/introduction) |
| Azure OpenAI | `AZURE_OPENAI_API_KEY`
`AZURE_API_VERSION`
`AZURE_API_BASE` | - |
| Azure OpenAI (Managed Identity) | `AZURE_API_VERSION`
`AZURE_API_BASE` | Login required using `az login`, see [docs for details](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/managed-identity) |
diff --git a/optillm/server.py b/optillm/server.py
index bc2c88f..05cc592 100644
--- a/optillm/server.py
+++ b/optillm/server.py
@@ -91,6 +91,13 @@ def get_config():
default_client = Cerebras(api_key=API_KEY, base_url=base_url, http_client=http_client)
else:
default_client = Cerebras(api_key=API_KEY, http_client=http_client)
+ elif os.environ.get("MINIMAX_API_KEY"):
+ API_KEY = os.environ.get("MINIMAX_API_KEY")
+ base_url = server_config['base_url']
+ if base_url == "":
+ base_url = "https://api.minimax.io/v1"
+ default_client = OpenAI(api_key=API_KEY, base_url=base_url, http_client=http_client)
+ logger.info(f"Created MiniMax client with base_url: {base_url}")
elif os.environ.get("OPENAI_API_KEY"):
API_KEY = os.environ.get("OPENAI_API_KEY")
base_url = server_config['base_url']
@@ -759,6 +766,15 @@ def proxy():
base_url = server_config['base_url']
default_client, api_key = get_config()
+ # Clamp temperature for MiniMax provider: must be in (0.0, 1.0]
+ if os.environ.get("MINIMAX_API_KEY") and 'temperature' in request_config:
+ temp = request_config['temperature']
+ if temp is not None:
+ if temp <= 0:
+ request_config['temperature'] = 0.01
+ elif temp > 1.0:
+ request_config['temperature'] = 1.0
+
operation, approaches, model = parse_combined_approach(model, known_approaches, plugin_approaches)
# Start conversation logging if enabled
diff --git a/tests/test_minimax_integration.py b/tests/test_minimax_integration.py
new file mode 100644
index 0000000..071549d
--- /dev/null
+++ b/tests/test_minimax_integration.py
@@ -0,0 +1,87 @@
+"""
+Integration tests for MiniMax provider support in optillm.
+
+These tests verify that the MiniMax provider works end-to-end with the actual
+MiniMax API. They require a valid MINIMAX_API_KEY environment variable.
+
+Run with: MINIMAX_API_KEY=your-key pytest tests/test_minimax_integration.py -v
+"""
+
+import unittest
+import os
+import sys
+
+# Add parent directory to path to import optillm modules
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+# Skip all tests if MINIMAX_API_KEY is not set
+MINIMAX_API_KEY = os.environ.get('MINIMAX_API_KEY', '')
+SKIP_REASON = "MINIMAX_API_KEY environment variable not set"
+
+
+@unittest.skipUnless(MINIMAX_API_KEY, SKIP_REASON)
+class TestMiniMaxIntegration(unittest.TestCase):
+ """Integration tests that call the actual MiniMax API."""
+
+ def setUp(self):
+ """Set up OpenAI client pointing to MiniMax API."""
+ from openai import OpenAI
+ self.client = OpenAI(
+ api_key=MINIMAX_API_KEY,
+ base_url="https://api.minimax.io/v1"
+ )
+
+ def test_basic_completion(self):
+ """Test basic chat completion with MiniMax API."""
+ response = self.client.chat.completions.create(
+ model="MiniMax-M2.7",
+ messages=[
+ {"role": "user", "content": "Say hello in one word."}
+ ],
+ max_tokens=10,
+ temperature=0.7
+ )
+
+ assert hasattr(response, 'choices')
+ assert len(response.choices) > 0
+ assert response.choices[0].message.content is not None
+ assert len(response.choices[0].message.content) > 0
+
+ def test_temperature_boundary(self):
+ """Test that MiniMax API accepts temperature at boundary value 0.01."""
+ response = self.client.chat.completions.create(
+ model="MiniMax-M2.7",
+ messages=[
+ {"role": "user", "content": "What is 2+2?"}
+ ],
+ max_tokens=10,
+ temperature=0.01
+ )
+
+ assert hasattr(response, 'choices')
+ assert len(response.choices) > 0
+
+ def test_streaming_completion(self):
+ """Test streaming chat completion with MiniMax API."""
+ stream = self.client.chat.completions.create(
+ model="MiniMax-M2.7",
+ messages=[
+ {"role": "user", "content": "Count from 1 to 3."}
+ ],
+ max_tokens=30,
+ temperature=0.5,
+ stream=True
+ )
+
+ chunks = list(stream)
+ assert len(chunks) > 0
+ content_chunks = [
+ chunk.choices[0].delta.content
+ for chunk in chunks
+ if chunk.choices[0].delta.content
+ ]
+ assert len(content_chunks) > 0
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_minimax_provider.py b/tests/test_minimax_provider.py
new file mode 100644
index 0000000..017d91b
--- /dev/null
+++ b/tests/test_minimax_provider.py
@@ -0,0 +1,288 @@
+"""
+Unit tests for MiniMax provider support in optillm.
+
+Tests verify that the MiniMax provider:
+- Is correctly detected via MINIMAX_API_KEY environment variable
+- Creates an OpenAI client with the MiniMax base URL
+- Respects custom base_url when set
+- Takes priority over OpenAI when both keys are set
+- Does not interfere when MINIMAX_API_KEY is not set
+- Properly clamps temperature to MiniMax's valid range (0, 1]
+"""
+
+import unittest
+from unittest.mock import patch, MagicMock
+import sys
+import os
+import json
+
+# Add parent directory to path to import optillm modules
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+# Mock heavy dependencies that may not be installed in test environments
+for mod_name in ['z3', 'torch', 'torch.nn', 'torch.nn.functional',
+ 'transformers', 'adaptive_classifier',
+ 'peft', 'bitsandbytes', 'outlines', 'spacy',
+ 'presidio_analyzer', 'presidio_anonymizer']:
+ if mod_name not in sys.modules:
+ sys.modules[mod_name] = MagicMock()
+
+from optillm import server_config
+
+
+class TestMiniMaxProviderDetection(unittest.TestCase):
+ """Test MiniMax provider detection via MINIMAX_API_KEY."""
+
+ def setUp(self):
+ """Reset server_config before each test."""
+ self.original_config = server_config.copy()
+ # Clear provider-related environment variables
+ for key in ['MINIMAX_API_KEY', 'OPENAI_API_KEY', 'CEREBRAS_API_KEY',
+ 'AZURE_OPENAI_API_KEY', 'OPTILLM_API_KEY']:
+ if key in os.environ:
+ del os.environ[key]
+
+ def tearDown(self):
+ """Restore original server_config after each test."""
+ server_config.clear()
+ server_config.update(self.original_config)
+
+ @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-minimax-key'})
+ def test_minimax_provider_detected(self):
+ """Test that MINIMAX_API_KEY triggers MiniMax provider."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ client, api_key = get_config()
+
+ # Should use the MiniMax API key
+ assert api_key == 'test-minimax-key'
+
+ # Should create OpenAI client with MiniMax base URL
+ mock_openai.assert_called_once()
+ call_kwargs = mock_openai.call_args[1]
+ assert call_kwargs['api_key'] == 'test-minimax-key'
+ assert call_kwargs['base_url'] == 'https://api.minimax.io/v1'
+
+ @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-minimax-key'})
+ def test_minimax_default_base_url(self):
+ """Test MiniMax provider uses default base URL https://api.minimax.io/v1."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ get_config()
+ call_kwargs = mock_openai.call_args[1]
+ assert call_kwargs['base_url'] == 'https://api.minimax.io/v1'
+
+ @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-minimax-key'})
+ def test_minimax_with_custom_base_url(self):
+ """Test MiniMax provider with custom base_url."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = 'https://custom-proxy.example.com/v1'
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ client, api_key = get_config()
+
+ call_kwargs = mock_openai.call_args[1]
+ assert call_kwargs['base_url'] == 'https://custom-proxy.example.com/v1'
+
+ @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-minimax-key'})
+ def test_minimax_client_receives_http_client(self):
+ """Test that MiniMax client receives the configured httpx client."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = False
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ mock_http_client_instance = MagicMock()
+
+ with patch('httpx.Client', return_value=mock_http_client_instance) as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ get_config()
+
+ call_kwargs = mock_openai.call_args[1]
+ assert 'http_client' in call_kwargs
+ assert call_kwargs['http_client'] == mock_http_client_instance
+
+ @patch.dict(os.environ, {'MINIMAX_API_KEY': 'minimax-key', 'OPENAI_API_KEY': 'openai-key'})
+ def test_minimax_takes_priority_over_openai(self):
+ """Test that MINIMAX_API_KEY takes priority over OPENAI_API_KEY."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ client, api_key = get_config()
+
+ assert api_key == 'minimax-key'
+ call_kwargs = mock_openai.call_args[1]
+ assert call_kwargs['base_url'] == 'https://api.minimax.io/v1'
+
+ @patch.dict(os.environ, {'OPENAI_API_KEY': 'openai-key'})
+ def test_openai_still_works_without_minimax(self):
+ """Test that OpenAI provider works when MINIMAX_API_KEY is not set."""
+ from optillm.server import get_config
+
+ # Ensure MINIMAX_API_KEY is not set
+ if 'MINIMAX_API_KEY' in os.environ:
+ del os.environ['MINIMAX_API_KEY']
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ client, api_key = get_config()
+
+ assert api_key == 'openai-key'
+ call_kwargs = mock_openai.call_args[1]
+ # Should NOT have MiniMax base URL
+ assert 'base_url' not in call_kwargs
+
+ @patch.dict(os.environ, {'CEREBRAS_API_KEY': 'cerebras-key', 'MINIMAX_API_KEY': 'minimax-key'})
+ def test_cerebras_takes_priority_over_minimax(self):
+ """Test that CEREBRAS_API_KEY takes priority over MINIMAX_API_KEY."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.Cerebras') as mock_cerebras:
+ client, api_key = get_config()
+
+ assert api_key == 'cerebras-key'
+ mock_cerebras.assert_called_once()
+
+
+class TestMiniMaxTemperatureClamping(unittest.TestCase):
+ """Test temperature clamping for MiniMax provider.
+
+ The clamping logic in server.py's proxy() checks MINIMAX_API_KEY env var
+ and adjusts temperature in request_config to MiniMax's valid range (0, 1].
+ These tests verify the clamping logic directly.
+ """
+
+ def _clamp_temperature(self, temp, is_minimax=True):
+ """Simulate the temperature clamping logic from server.py proxy()."""
+ request_config = {'temperature': temp}
+ if is_minimax and 'temperature' in request_config:
+ t = request_config['temperature']
+ if t is not None:
+ if t <= 0:
+ request_config['temperature'] = 0.01
+ elif t > 1.0:
+ request_config['temperature'] = 1.0
+ return request_config['temperature']
+
+ def test_temperature_zero_clamped(self):
+ """Test that temperature=0 is clamped to 0.01 for MiniMax."""
+ assert self._clamp_temperature(0) == 0.01
+
+ def test_temperature_negative_clamped(self):
+ """Test that negative temperature is clamped to 0.01 for MiniMax."""
+ assert self._clamp_temperature(-0.5) == 0.01
+
+ def test_temperature_above_one_clamped(self):
+ """Test that temperature > 1.0 is clamped to 1.0 for MiniMax."""
+ assert self._clamp_temperature(1.5) == 1.0
+
+ def test_temperature_exactly_two_clamped(self):
+ """Test that temperature=2.0 is clamped to 1.0 for MiniMax."""
+ assert self._clamp_temperature(2.0) == 1.0
+
+ def test_valid_temperature_point_seven_unchanged(self):
+ """Test that valid temperature 0.7 is not modified."""
+ assert self._clamp_temperature(0.7) == 0.7
+
+ def test_valid_temperature_one_unchanged(self):
+ """Test that temperature=1.0 (boundary) is not modified."""
+ assert self._clamp_temperature(1.0) == 1.0
+
+ def test_valid_temperature_point_one_unchanged(self):
+ """Test that temperature=0.1 is not modified."""
+ assert self._clamp_temperature(0.1) == 0.1
+
+ def test_no_clamping_for_non_minimax(self):
+ """Test that temperature is NOT clamped when not using MiniMax."""
+ assert self._clamp_temperature(0, is_minimax=False) == 0
+ assert self._clamp_temperature(1.5, is_minimax=False) == 1.5
+ assert self._clamp_temperature(-1, is_minimax=False) == -1
+
+
+class TestMiniMaxProviderPriority(unittest.TestCase):
+ """Test provider priority ordering with MiniMax."""
+
+ def setUp(self):
+ """Set up test environment."""
+ self.original_config = server_config.copy()
+ for key in ['MINIMAX_API_KEY', 'OPENAI_API_KEY', 'CEREBRAS_API_KEY',
+ 'AZURE_OPENAI_API_KEY', 'OPTILLM_API_KEY']:
+ if key in os.environ:
+ del os.environ[key]
+
+ def tearDown(self):
+ """Restore original server_config."""
+ server_config.clear()
+ server_config.update(self.original_config)
+
+ @patch.dict(os.environ, {'OPTILLM_API_KEY': 'optillm-key', 'MINIMAX_API_KEY': 'minimax-key'})
+ def test_optillm_takes_priority_over_minimax(self):
+ """Test that OPTILLM_API_KEY takes priority over MINIMAX_API_KEY."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ # Mock the local inference path
+ with patch.dict(sys.modules, {'optillm.inference': MagicMock()}):
+ # Reimport to pick up the mock
+ import importlib
+ from optillm import server
+ importlib.reload(server)
+ client, api_key = server.get_config()
+ assert api_key == 'optillm-key'
+
+ @patch.dict(os.environ, {'MINIMAX_API_KEY': 'minimax-key', 'AZURE_OPENAI_API_KEY': 'azure-key',
+ 'AZURE_API_VERSION': '2024-02-15', 'AZURE_API_BASE': 'https://test.openai.azure.com'})
+ def test_minimax_takes_priority_over_azure(self):
+ """Test that MINIMAX_API_KEY takes priority over AZURE_OPENAI_API_KEY."""
+ from optillm.server import get_config
+
+ server_config['ssl_verify'] = True
+ server_config['ssl_cert_path'] = ''
+ server_config['base_url'] = ''
+
+ with patch('httpx.Client') as mock_httpx_client, \
+ patch('optillm.server.OpenAI') as mock_openai:
+ client, api_key = get_config()
+ assert api_key == 'minimax-key'
+ call_kwargs = mock_openai.call_args[1]
+ assert call_kwargs['base_url'] == 'https://api.minimax.io/v1'
+
+
+if __name__ == '__main__':
+ unittest.main()