From c760d7cc68548aa7a2322f5feb674cf3970262f3 Mon Sep 17 00:00:00 2001 From: PR Bot Date: Fri, 13 Mar 2026 21:21:00 +0800 Subject: [PATCH 1/2] feat: add MiniMax LLM provider support Add MiniMax as a supported LLM provider alongside OpenAI and Anthropic. MiniMax models (MiniMax-M2.5, MiniMax-M2.5-highspeed) are accessed via their OpenAI-compatible API with automatic temperature clamping to satisfy MiniMax's (0.0, 1.0] constraint. Changes: - Add MiniMax model detection and ChatOpenAI configuration in AI class - Load MINIMAX_API_KEY from environment/.env files - Add is_minimax_model() helper for token usage tracking - Add unit tests for MiniMax model creation, temperature constraint, and missing API key validation - Update README with MiniMax setup instructions and model details --- README.md | 20 +++++++++- gpt_engineer/applications/cli/main.py | 7 ++++ gpt_engineer/core/ai.py | 20 ++++++++++ gpt_engineer/core/token_usage.py | 11 ++++++ tests/core/test_ai.py | 54 +++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 172210af7f..e99604df99 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Choose **one** of: - Add your OPENAI_API_KEY in .env - Custom model: - See [docs](https://gpt-engineer.readthedocs.io/en/latest/open_models.html), supports local model, azure, etc. +- For MiniMax models: `export MINIMAX_API_KEY=[your api key]` Check the [Windows README](./WINDOWS_README.md) for Windows usage. @@ -102,7 +103,24 @@ E.g. `gpte projects/example-vision gpt-4-vision-preview --prompt_file prompt/tex ### Open source, local and alternative models -By default, gpt-engineer supports OpenAI Models via the OpenAI API or Azure OpenAI API, as well as Anthropic models. +By default, gpt-engineer supports OpenAI Models via the OpenAI API or Azure OpenAI API, as well as Anthropic models and [MiniMax](https://platform.minimax.io) models. + +#### MiniMax Models + +To use MiniMax models, set the `MINIMAX_API_KEY` environment variable and pass a MiniMax model name: + +```bash +export MINIMAX_API_KEY=your-minimax-api-key +gpte my-project -m MiniMax-M2.5 +``` + +Supported MiniMax models: +| Model | Description | +|-------|-------------| +| `MiniMax-M2.5` | Peak Performance. Ultimate Value. 204K context window. | +| `MiniMax-M2.5-highspeed` | Same performance, faster and more agile. 204K context window. | + +You can also set a custom API base URL via `MINIMAX_API_BASE` (defaults to `https://api.minimax.io/v1`). For users in China, set it to `https://api.minimaxi.com/v1`. With a little extra setup, you can also run with open source models like WizardCoder. See the [documentation](https://gpt-engineer.readthedocs.io/en/latest/open_models.html) for example instructions. diff --git a/gpt_engineer/applications/cli/main.py b/gpt_engineer/applications/cli/main.py index 5a0c4135b7..2df5d9b2af 100644 --- a/gpt_engineer/applications/cli/main.py +++ b/gpt_engineer/applications/cli/main.py @@ -89,6 +89,11 @@ def load_env_if_needed(): if os.getenv("ANTHROPIC_API_KEY") is None: load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env")) + if os.getenv("MINIMAX_API_KEY") is None: + load_dotenv() + if os.getenv("MINIMAX_API_KEY") is None: + load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env")) + def concatenate_paths(base_path, sub_path): # Compute the relative path from base_path to sub_path @@ -551,6 +556,8 @@ def main( if ai.token_usage_log.is_openai_model(): print("Total api cost: $ ", ai.token_usage_log.usage_cost()) + elif ai.token_usage_log.is_minimax_model(): + print("Total tokens used: ", ai.token_usage_log.total_tokens()) elif os.getenv("LOCAL_MODEL"): print("Total api cost: $ 0.0 since we are using local LLM.") else: diff --git a/gpt_engineer/core/ai.py b/gpt_engineer/core/ai.py index ae86f63364..c3e1a8fef6 100644 --- a/gpt_engineer/core/ai.py +++ b/gpt_engineer/core/ai.py @@ -362,6 +362,26 @@ def _create_chat_model(self) -> BaseChatModel: streaming=self.streaming, max_tokens_to_sample=4096, ) + elif "minimax" in self.model_name.lower(): + # MiniMax requires temperature in (0.0, 1.0], zero is not accepted + minimax_temperature = max(self.temperature, 0.01) + minimax_api_key = os.getenv("MINIMAX_API_KEY") + if not minimax_api_key: + raise ValueError( + "MINIMAX_API_KEY environment variable is required for MiniMax models. " + "Get your API key at https://platform.minimax.io" + ) + minimax_base_url = os.getenv( + "MINIMAX_API_BASE", "https://api.minimax.io/v1" + ) + return ChatOpenAI( + model=self.model_name, + temperature=minimax_temperature, + streaming=self.streaming, + callbacks=[StreamingStdOutCallbackHandler()], + openai_api_key=minimax_api_key, + openai_api_base=minimax_base_url, + ) elif self.vision: return ChatOpenAI( model=self.model_name, diff --git a/gpt_engineer/core/token_usage.py b/gpt_engineer/core/token_usage.py index b10fec9033..5c38dd58ed 100644 --- a/gpt_engineer/core/token_usage.py +++ b/gpt_engineer/core/token_usage.py @@ -259,6 +259,17 @@ def is_openai_model(self) -> bool: """ return "gpt" in self.model_name.lower() + def is_minimax_model(self) -> bool: + """ + Check if the model is a MiniMax model. + + Returns + ------- + bool + True if the model is a MiniMax model, False otherwise. + """ + return "minimax" in self.model_name.lower() + def total_tokens(self) -> int: """ Return the total number of tokens used in the conversation. diff --git a/tests/core/test_ai.py b/tests/core/test_ai.py index 44eaeb6321..a0d3278f61 100644 --- a/tests/core/test_ai.py +++ b/tests/core/test_ai.py @@ -1,3 +1,7 @@ +import os + +from unittest.mock import patch + from langchain.chat_models.base import BaseChatModel from langchain_community.chat_models.fake import FakeListChatModel @@ -51,3 +55,53 @@ def test_token_logging(monkeypatch): # assert assert usageCostAfterStart > 0 assert usageCostAfterNext > usageCostAfterStart + + +def test_minimax_model_creation(monkeypatch): + monkeypatch.setattr(AI, "_create_chat_model", mock_create_chat_model) + + ai = AI("MiniMax-M2.5") + + # act + response_messages = ai.start("system prompt", "user prompt", step_name="step name") + + # assert + assert response_messages[-1].content == "response1" + assert ai.token_usage_log.is_minimax_model() + assert not ai.token_usage_log.is_openai_model() + + +def test_minimax_temperature_constraint(): + """Test that MiniMax temperature is clamped to avoid zero.""" + ai_instance = AI.__new__(AI) + ai_instance.temperature = 0.0 + ai_instance.model_name = "MiniMax-M2.5" + ai_instance.azure_endpoint = None + ai_instance.streaming = True + ai_instance.vision = False + + with patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key"}): + with patch("gpt_engineer.core.ai.ChatOpenAI") as mock_chat: + mock_chat.return_value = FakeListChatModel(responses=["response"]) + ai_instance._create_chat_model() + # Verify temperature was clamped above 0 + call_kwargs = mock_chat.call_args[1] + assert call_kwargs["temperature"] >= 0.01 + + +def test_minimax_missing_api_key(): + """Test that MiniMax raises error when API key is missing.""" + ai_instance = AI.__new__(AI) + ai_instance.temperature = 0.1 + ai_instance.model_name = "MiniMax-M2.5" + ai_instance.azure_endpoint = None + ai_instance.streaming = True + ai_instance.vision = False + + with patch.dict(os.environ, {}, clear=True): + os.environ.pop("MINIMAX_API_KEY", None) + try: + ai_instance._create_chat_model() + assert False, "Should have raised ValueError" + except ValueError as e: + assert "MINIMAX_API_KEY" in str(e) From 7ed9f7c3f95ae7848a2b662d894b85fb67d5e646 Mon Sep 17 00:00:00 2001 From: PR Bot Date: Wed, 18 Mar 2026 17:42:40 +0800 Subject: [PATCH 2/2] feat: upgrade MiniMax default model to M2.7 - Add MiniMax-M2.7 and MiniMax-M2.7-highspeed to model list - Set MiniMax-M2.7 as default model in README example - Keep all previous models (M2.5, M2.5-highspeed) as alternatives - Update related unit tests to use M2.7 --- README.md | 4 +++- tests/core/test_ai.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e99604df99..a7624cc2ae 100644 --- a/README.md +++ b/README.md @@ -111,12 +111,14 @@ To use MiniMax models, set the `MINIMAX_API_KEY` environment variable and pass a ```bash export MINIMAX_API_KEY=your-minimax-api-key -gpte my-project -m MiniMax-M2.5 +gpte my-project -m MiniMax-M2.7 ``` Supported MiniMax models: | Model | Description | |-------|-------------| +| `MiniMax-M2.7` | Latest flagship model with enhanced reasoning and coding. | +| `MiniMax-M2.7-highspeed` | High-speed version of M2.7 for low-latency scenarios. | | `MiniMax-M2.5` | Peak Performance. Ultimate Value. 204K context window. | | `MiniMax-M2.5-highspeed` | Same performance, faster and more agile. 204K context window. | diff --git a/tests/core/test_ai.py b/tests/core/test_ai.py index a0d3278f61..65a03da32a 100644 --- a/tests/core/test_ai.py +++ b/tests/core/test_ai.py @@ -60,7 +60,7 @@ def test_token_logging(monkeypatch): def test_minimax_model_creation(monkeypatch): monkeypatch.setattr(AI, "_create_chat_model", mock_create_chat_model) - ai = AI("MiniMax-M2.5") + ai = AI("MiniMax-M2.7") # act response_messages = ai.start("system prompt", "user prompt", step_name="step name") @@ -75,7 +75,7 @@ def test_minimax_temperature_constraint(): """Test that MiniMax temperature is clamped to avoid zero.""" ai_instance = AI.__new__(AI) ai_instance.temperature = 0.0 - ai_instance.model_name = "MiniMax-M2.5" + ai_instance.model_name = "MiniMax-M2.7" ai_instance.azure_endpoint = None ai_instance.streaming = True ai_instance.vision = False @@ -93,7 +93,7 @@ def test_minimax_missing_api_key(): """Test that MiniMax raises error when API key is missing.""" ai_instance = AI.__new__(AI) ai_instance.temperature = 0.1 - ai_instance.model_name = "MiniMax-M2.5" + ai_instance.model_name = "MiniMax-M2.7" ai_instance.azure_endpoint = None ai_instance.streaming = True ai_instance.vision = False