diff --git a/README.md b/README.md
index 8f5997c6..653e2464 100644
--- a/README.md
+++ b/README.md
@@ -230,8 +230,9 @@ export STRIX_REASONING_EFFORT="high" # control thinking effort (default: high,
- [OpenAI GPT-5.4](https://openai.com/api/) — `openai/gpt-5.4`
- [Anthropic Claude Sonnet 4.6](https://claude.com/platform/api) — `anthropic/claude-sonnet-4-6`
- [Google Gemini 3 Pro Preview](https://cloud.google.com/vertex-ai) — `vertex_ai/gemini-3-pro-preview`
+- [MiniMax-M2.7](https://platform.minimax.io) — `openai/MiniMax-M2.7` (set `LLM_API_BASE=https://api.minimax.io/v1`)
-See the [LLM Providers documentation](https://docs.strix.ai/llm-providers/overview) for all supported providers including Vertex AI, Bedrock, Azure, and local models.
+See the [LLM Providers documentation](https://docs.strix.ai/llm-providers/overview) for all supported providers including Vertex AI, Bedrock, Azure, MiniMax, and local models.
## Enterprise
diff --git a/docs/llm-providers/minimax.mdx b/docs/llm-providers/minimax.mdx
new file mode 100644
index 00000000..80ee39be
--- /dev/null
+++ b/docs/llm-providers/minimax.mdx
@@ -0,0 +1,43 @@
+---
+title: "MiniMax"
+description: "Configure Strix with MiniMax models"
+---
+
+[MiniMax](https://www.minimax.io) provides powerful large language models with up to 1M token context windows through an OpenAI-compatible API.
+
+## Setup
+
+```bash
+export STRIX_LLM="openai/MiniMax-M2.7"
+export LLM_API_KEY="your-minimax-api-key"
+export LLM_API_BASE="https://api.minimax.io/v1"
+```
+
+Or use the shorthand with automatic base URL detection:
+
+```bash
+export STRIX_LLM="openai/MiniMax-M2.7"
+export MINIMAX_API_KEY="your-minimax-api-key"
+```
+
+## Available Models
+
+| Model | Configuration | Context Window |
+|-------|---------------|----------------|
+| MiniMax-M2.7 | `openai/MiniMax-M2.7` | 1M tokens |
+| MiniMax-M2.7-highspeed | `openai/MiniMax-M2.7-highspeed` | 1M tokens |
+
+**MiniMax-M2.7** is the latest flagship model with strong reasoning and coding capabilities.
+**MiniMax-M2.7-highspeed** offers faster inference with slightly reduced quality.
+
+## Get API Key
+
+1. Go to [platform.minimax.io](https://platform.minimax.io)
+2. Sign up or sign in
+3. Navigate to API Keys and create a new key
+
+## Notes
+
+- MiniMax API is fully OpenAI-compatible, so it works via the `openai/` LiteLLM prefix
+- Temperature range: 0.0 to 1.0 (inclusive)
+- When `MINIMAX_API_KEY` is set and the model name contains "minimax", the API key and base URL are auto-detected
diff --git a/docs/llm-providers/overview.mdx b/docs/llm-providers/overview.mdx
index 8c0d5002..14314896 100644
--- a/docs/llm-providers/overview.mdx
+++ b/docs/llm-providers/overview.mdx
@@ -14,6 +14,7 @@ Set your model and API key:
| GPT-5.4 | OpenAI | `openai/gpt-5.4` |
| Claude Sonnet 4.6 | Anthropic | `anthropic/claude-sonnet-4-6` |
| Gemini 3 Pro | Google Vertex | `vertex_ai/gemini-3-pro-preview` |
+| MiniMax-M2.7 | MiniMax | `openai/MiniMax-M2.7` |
```bash
export STRIX_LLM="openai/gpt-5.4"
@@ -52,6 +53,9 @@ See the [Local Models guide](/llm-providers/local) for setup instructions and re
GPT-5.4 via Azure.
+
+ MiniMax-M2.7 models with 1M context.
+
Llama 4, Mistral, and self-hosted models.
diff --git a/strix/config/config.py b/strix/config/config.py
index 782101dd..953a761f 100644
--- a/strix/config/config.py
+++ b/strix/config/config.py
@@ -212,4 +212,17 @@ def resolve_llm_config() -> tuple[str | None, str | None, str | None]:
or Config.get("ollama_api_base")
)
+ # Auto-detect MiniMax provider: use MINIMAX_API_KEY and set base URL
+ if _is_minimax_model(model):
+ if not api_key:
+ api_key = os.getenv("MINIMAX_API_KEY")
+ if not api_base:
+ api_base = "https://api.minimax.io/v1"
+
return model, api_key, api_base
+
+
+def _is_minimax_model(model: str) -> bool:
+ """Check if the model name refers to a MiniMax model."""
+ lower = model.lower()
+ return "minimax" in lower
diff --git a/strix/llm/utils.py b/strix/llm/utils.py
index 9771854f..547ee0ea 100644
--- a/strix/llm/utils.py
+++ b/strix/llm/utils.py
@@ -41,6 +41,8 @@ STRIX_MODEL_MAP: dict[str, str] = {
"gemini-3-flash-preview": "gemini/gemini-3-flash-preview",
"glm-5": "openrouter/z-ai/glm-5",
"glm-4.7": "openrouter/z-ai/glm-4.7",
+ "minimax-m2.7": "openai/MiniMax-M2.7",
+ "minimax-m2.7-highspeed": "openai/MiniMax-M2.7-highspeed",
}
diff --git a/tests/llm/test_minimax.py b/tests/llm/test_minimax.py
new file mode 100644
index 00000000..55bc9f87
--- /dev/null
+++ b/tests/llm/test_minimax.py
@@ -0,0 +1,167 @@
+"""Tests for MiniMax model integration."""
+
+import os
+
+import pytest
+
+from strix.config.config import Config, _is_minimax_model, resolve_llm_config
+from strix.llm.config import LLMConfig
+from strix.llm.utils import STRIX_MODEL_MAP, resolve_strix_model
+
+
+class TestMiniMaxModelMap:
+ """Tests for MiniMax entries in STRIX_MODEL_MAP."""
+
+ def test_minimax_m27_in_model_map(self):
+ assert "minimax-m2.7" in STRIX_MODEL_MAP
+ assert STRIX_MODEL_MAP["minimax-m2.7"] == "openai/MiniMax-M2.7"
+
+ def test_minimax_m27_highspeed_in_model_map(self):
+ assert "minimax-m2.7-highspeed" in STRIX_MODEL_MAP
+ assert STRIX_MODEL_MAP["minimax-m2.7-highspeed"] == "openai/MiniMax-M2.7-highspeed"
+
+
+class TestMiniMaxModelResolution:
+ """Tests for resolving strix/ MiniMax models."""
+
+ def test_resolve_strix_minimax_m27(self):
+ api_model, canonical = resolve_strix_model("strix/minimax-m2.7")
+ assert api_model == "openai/minimax-m2.7"
+ assert canonical == "openai/MiniMax-M2.7"
+
+ def test_resolve_strix_minimax_m27_highspeed(self):
+ api_model, canonical = resolve_strix_model("strix/minimax-m2.7-highspeed")
+ assert api_model == "openai/minimax-m2.7-highspeed"
+ assert canonical == "openai/MiniMax-M2.7-highspeed"
+
+ def test_resolve_direct_minimax_model_passthrough(self):
+ api_model, canonical = resolve_strix_model("openai/MiniMax-M2.7")
+ assert api_model == "openai/MiniMax-M2.7"
+ assert canonical == "openai/MiniMax-M2.7"
+
+
+class TestIsMiniMaxModel:
+ """Tests for MiniMax model detection."""
+
+ def test_detects_minimax_openai_prefix(self):
+ assert _is_minimax_model("openai/MiniMax-M2.7")
+
+ def test_detects_minimax_case_insensitive(self):
+ assert _is_minimax_model("openai/minimax-m2.7")
+
+ def test_detects_minimax_strix_prefix(self):
+ assert _is_minimax_model("strix/minimax-m2.7")
+
+ def test_non_minimax_model(self):
+ assert not _is_minimax_model("openai/gpt-5.4")
+
+ def test_non_minimax_anthropic(self):
+ assert not _is_minimax_model("anthropic/claude-sonnet-4-6")
+
+
+class TestMiniMaxConfigResolution:
+ """Tests for MiniMax auto-detection in resolve_llm_config."""
+
+ def test_auto_detect_minimax_api_key(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "openai/MiniMax-M2.7")
+ monkeypatch.setenv("MINIMAX_API_KEY", "test-minimax-key")
+ monkeypatch.delenv("LLM_API_KEY", raising=False)
+ monkeypatch.delenv("LLM_API_BASE", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ model, api_key, api_base = resolve_llm_config()
+
+ assert model == "openai/MiniMax-M2.7"
+ assert api_key == "test-minimax-key"
+ assert api_base == "https://api.minimax.io/v1"
+
+ def test_llm_api_key_takes_precedence_over_minimax_key(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "openai/MiniMax-M2.7")
+ monkeypatch.setenv("LLM_API_KEY", "llm-key-takes-precedence")
+ monkeypatch.setenv("MINIMAX_API_KEY", "minimax-key")
+ monkeypatch.delenv("LLM_API_BASE", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ model, api_key, api_base = resolve_llm_config()
+
+ assert api_key == "llm-key-takes-precedence"
+ assert api_base == "https://api.minimax.io/v1"
+
+ def test_custom_api_base_takes_precedence(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "openai/MiniMax-M2.7")
+ monkeypatch.setenv("MINIMAX_API_KEY", "test-key")
+ monkeypatch.setenv("LLM_API_BASE", "https://custom-proxy.com/v1")
+ monkeypatch.delenv("LLM_API_KEY", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ model, api_key, api_base = resolve_llm_config()
+
+ assert api_base == "https://custom-proxy.com/v1"
+
+ def test_no_minimax_key_no_auto_detect(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "openai/gpt-5.4")
+ monkeypatch.delenv("LLM_API_KEY", raising=False)
+ monkeypatch.delenv("MINIMAX_API_KEY", raising=False)
+ monkeypatch.delenv("LLM_API_BASE", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ model, api_key, api_base = resolve_llm_config()
+
+ assert model == "openai/gpt-5.4"
+ assert api_key is None
+ assert api_base is None
+
+ def test_minimax_auto_base_url_when_no_base_set(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "openai/MiniMax-M2.7-highspeed")
+ monkeypatch.setenv("LLM_API_KEY", "some-key")
+ monkeypatch.delenv("LLM_API_BASE", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ model, api_key, api_base = resolve_llm_config()
+
+ assert api_base == "https://api.minimax.io/v1"
+
+
+class TestMiniMaxLLMConfig:
+ """Tests for LLMConfig with MiniMax models."""
+
+ def test_llm_config_minimax_direct(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "openai/MiniMax-M2.7")
+ monkeypatch.setenv("LLM_API_KEY", "test-key")
+ monkeypatch.delenv("LLM_API_BASE", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ config = LLMConfig()
+
+ assert config.model_name == "openai/MiniMax-M2.7"
+ assert config.litellm_model == "openai/MiniMax-M2.7"
+ assert config.api_key == "test-key"
+ assert config.api_base == "https://api.minimax.io/v1"
+
+ def test_llm_config_minimax_strix_shortcut(self, monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setenv("STRIX_LLM", "strix/minimax-m2.7")
+ monkeypatch.setenv("MINIMAX_API_KEY", "minimax-key")
+ monkeypatch.delenv("LLM_API_KEY", raising=False)
+ monkeypatch.delenv("LLM_API_BASE", raising=False)
+ monkeypatch.delenv("OPENAI_API_BASE", raising=False)
+ monkeypatch.delenv("LITELLM_BASE_URL", raising=False)
+ monkeypatch.delenv("OLLAMA_API_BASE", raising=False)
+
+ config = LLMConfig()
+
+ assert config.model_name == "strix/minimax-m2.7"
+ assert config.litellm_model == "openai/minimax-m2.7"
+ assert config.canonical_model == "openai/MiniMax-M2.7"
+ assert config.api_key == "minimax-key"
diff --git a/tests/llm/test_minimax_integration.py b/tests/llm/test_minimax_integration.py
new file mode 100644
index 00000000..eb9da2c0
--- /dev/null
+++ b/tests/llm/test_minimax_integration.py
@@ -0,0 +1,78 @@
+"""Integration tests for MiniMax provider.
+
+These tests verify end-to-end MiniMax integration by making real API calls.
+They require MINIMAX_API_KEY to be set in the environment.
+"""
+
+import os
+
+import pytest
+
+from strix.llm.config import LLMConfig
+from strix.llm.llm import LLM
+
+
+pytestmark = pytest.mark.skipif(
+ not os.environ.get("MINIMAX_API_KEY"),
+ reason="MINIMAX_API_KEY not set",
+)
+
+
+@pytest.fixture()
+def minimax_llm(monkeypatch: pytest.MonkeyPatch) -> LLM:
+ """Create an LLM instance configured for MiniMax."""
+ monkeypatch.setenv("STRIX_LLM", "openai/MiniMax-M2.7")
+ monkeypatch.setenv("LLM_API_KEY", os.environ.get("MINIMAX_API_KEY", ""))
+ monkeypatch.setenv("LLM_API_BASE", "https://api.minimax.io/v1")
+ monkeypatch.setenv("STRIX_TELEMETRY", "0")
+ config = LLMConfig()
+ return LLM(config, agent_name=None)
+
+
+@pytest.mark.asyncio()
+async def test_minimax_basic_completion(minimax_llm: LLM):
+ """Test that MiniMax can complete a simple prompt."""
+ messages = [{"role": "user", "content": "Reply with exactly: hello"}]
+ responses = []
+ async for response in minimax_llm.generate(messages):
+ responses.append(response)
+
+ assert len(responses) > 0
+ final = responses[-1]
+ assert final.content
+ assert "hello" in final.content.lower()
+
+
+@pytest.mark.asyncio()
+async def test_minimax_streaming(minimax_llm: LLM):
+ """Test that MiniMax streaming produces incremental responses."""
+ messages = [{"role": "user", "content": "Count from 1 to 3, one number per line."}]
+ responses = []
+ async for response in minimax_llm.generate(messages):
+ responses.append(response)
+
+ # Streaming should produce multiple intermediate responses
+ assert len(responses) >= 2
+ final = responses[-1]
+ assert "1" in final.content
+ assert "2" in final.content
+ assert "3" in final.content
+
+
+@pytest.mark.asyncio()
+async def test_minimax_config_auto_detection():
+ """Test that MINIMAX_API_KEY auto-detection works end-to-end."""
+ api_key = os.environ.get("MINIMAX_API_KEY", "")
+ orig_llm_key = os.environ.pop("LLM_API_KEY", None)
+ orig_llm_base = os.environ.pop("LLM_API_BASE", None)
+ os.environ["STRIX_LLM"] = "openai/MiniMax-M2.7"
+
+ try:
+ config = LLMConfig()
+ assert config.api_key == api_key
+ assert config.api_base == "https://api.minimax.io/v1"
+ finally:
+ if orig_llm_key is not None:
+ os.environ["LLM_API_KEY"] = orig_llm_key
+ if orig_llm_base is not None:
+ os.environ["LLM_API_BASE"] = orig_llm_base