From 1432266694d48210ef76f1cfd6e3d92cbb70ad5a Mon Sep 17 00:00:00 2001 From: PR Bot Date: Wed, 18 Mar 2026 16:33:04 +0800 Subject: [PATCH 1/4] feat: upgrade MiniMax default model to M2.7 - Add MiniMax-M2.7 and MiniMax-M2.7-highspeed to supported models list - Update docstring to list M2.7 models before M2.5 - Update README/README_CHS model references - Add unit tests for M2.7 and M2.7-highspeed models - Keep all previous models as alternatives --- README.md | 2 +- README_CHS.md | 2 +- sources/llm_provider.py | 6 ++++-- tests/test_minimax_provider.py | 36 ++++++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index aa874a5..751fbd9 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ provider_server_address = # Typically ignored or can be left blank when is_local | Hugging Face | `huggingface` | No | Use models from Hugging Face Inference API. | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) | | TogetherAI | `togetherAI` | No | Use various open-source models via TogetherAI API.| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) | | OpenRouter | `openrouter` | No | Use OpenRouter Models| [https://openrouter.ai/](https://openrouter.ai/) | -| MiniMax | `minimax` | No | Use MiniMax M2.5 series models (e.g., MiniMax-M2.5).| [platform.minimax.io](https://platform.minimax.io/user-center/basic-information) | +| MiniMax | `minimax` | No | Use MiniMax models (e.g., MiniMax-M2.7, MiniMax-M2.5).| [platform.minimax.io](https://platform.minimax.io/user-center/basic-information) | *Note:* * We advise against using `gpt-4o` or other OpenAI models for complex web browsing and task planning as current prompt optimizations are geared towards models like Deepseek. diff --git a/README_CHS.md b/README_CHS.md index d505131..d37c3af 100644 --- a/README_CHS.md +++ b/README_CHS.md @@ -230,7 +230,7 @@ provider_server_address = # 当 is_local = False 时,对于大多数 API 通 | Hugging Face | `huggingface` | 否 | 使用 Hugging Face Inference API 中的模型。 | [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) | | TogetherAI | `togetherAI` | 否 | 通过 TogetherAI API 使用各种开源模型。| [api.together.ai/settings/api-keys](https://api.together.ai/settings/api-keys) | | OpenRouter | `openrouter` | No | 通过 OpenRouter 使用各种开源模型| [https://openrouter.ai/](https://openrouter.ai/) | -| MiniMax | `minimax` | 否 | 使用 MiniMax 的 M2.5 系列模型(如 MiniMax-M2.5)。 | [platform.minimax.io](https://platform.minimax.io/user-center/basic-information) | +| MiniMax | `minimax` | 否 | 使用 MiniMax 模型(如 MiniMax-M2.7、MiniMax-M2.5)。 | [platform.minimax.io](https://platform.minimax.io/user-center/basic-information) | *注意:* * 我们不建议将 `gpt-4o` 或其他 OpenAI 模型用于复杂的网页浏览和任务规划,因为当前的提示优化针对 Deepseek 等模型。 diff --git a/sources/llm_provider.py b/sources/llm_provider.py index a77dc14..790965d 100644 --- a/sources/llm_provider.py +++ b/sources/llm_provider.py @@ -416,11 +416,13 @@ class Provider: def minimax_fn(self, history, verbose=False): """ Use MiniMax API to generate text via OpenAI-compatible interface. - + Supported models: + - 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 model (~60 tps), 204,800 context window - MiniMax-M2.5-highspeed: Same performance, faster (~100 tps) - + Note: temperature must be in range (0.0, 1.0], default is 1.0 """ load_dotenv() diff --git a/tests/test_minimax_provider.py b/tests/test_minimax_provider.py index 15453c3..0b7a041 100644 --- a/tests/test_minimax_provider.py +++ b/tests/test_minimax_provider.py @@ -155,6 +155,42 @@ class TestMiniMaxProvider(unittest.TestCase): class TestMiniMaxProviderModels(unittest.TestCase): """Test cases for MiniMax provider model configurations.""" + @patch('sources.llm_provider.OpenAI') + @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-key'}) + def test_minimax_m27_model(self, mock_openai_class): + """Test MiniMax-M2.7 model.""" + mock_client = MagicMock() + mock_openai_class.return_value = mock_client + mock_response = MagicMock() + mock_response.choices = [MagicMock(message=MagicMock(content="Response"))] + mock_client.chat.completions.create.return_value = mock_response + + with patch.object(Provider, 'get_api_key', return_value='test-key'): + provider = Provider("minimax", "MiniMax-M2.7", is_local=False) + history = [{"role": "user", "content": "Hello"}] + provider.minimax_fn(history) + + call_kwargs = mock_client.chat.completions.create.call_args[1] + self.assertEqual(call_kwargs['model'], "MiniMax-M2.7") + + @patch('sources.llm_provider.OpenAI') + @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-key'}) + def test_minimax_m27_highspeed_model(self, mock_openai_class): + """Test MiniMax-M2.7-highspeed model.""" + mock_client = MagicMock() + mock_openai_class.return_value = mock_client + mock_response = MagicMock() + mock_response.choices = [MagicMock(message=MagicMock(content="Response"))] + mock_client.chat.completions.create.return_value = mock_response + + with patch.object(Provider, 'get_api_key', return_value='test-key'): + provider = Provider("minimax", "MiniMax-M2.7-highspeed", is_local=False) + history = [{"role": "user", "content": "Hello"}] + provider.minimax_fn(history) + + call_kwargs = mock_client.chat.completions.create.call_args[1] + self.assertEqual(call_kwargs['model'], "MiniMax-M2.7-highspeed") + @patch('sources.llm_provider.OpenAI') @patch.dict(os.environ, {'MINIMAX_API_KEY': 'test-key'}) def test_minimax_m25_model(self, mock_openai_class): From 7cde1549b23c8e527f8c11258e8d6a74c6072936 Mon Sep 17 00:00:00 2001 From: Octopus Date: Thu, 2 Apr 2026 16:52:06 +0800 Subject: [PATCH 2/4] fix: initialize answer variable and reset stop flag in PlannerAgent.process (fixes #359) --- sources/agents/planner_agent.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sources/agents/planner_agent.py b/sources/agents/planner_agent.py index ff6cba4..720908c 100644 --- a/sources/agents/planner_agent.py +++ b/sources/agents/planner_agent.py @@ -264,6 +264,8 @@ class PlannerAgent(Agent): agents_tasks = [] required_infos = None agents_work_result = dict() + answer = "" + self.stop = False self.status_message = "Making a plan..." agents_tasks = await self.make_plan(goal) From d1ecb15703c2b4e47d53f03e16aae51869fa3914 Mon Sep 17 00:00:00 2001 From: Octopus Date: Fri, 3 Apr 2026 10:51:23 +0800 Subject: [PATCH 3/4] fix: add max retry limit to PlannerAgent.make_plan to prevent infinite loop (fixes #367) --- sources/agents/planner_agent.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sources/agents/planner_agent.py b/sources/agents/planner_agent.py index ff6cba4..ada8c07 100644 --- a/sources/agents/planner_agent.py +++ b/sources/agents/planner_agent.py @@ -147,17 +147,23 @@ class PlannerAgent(Agent): pretty_print(f"{task['agent']} -> {task['task']}", color="info") pretty_print("▔▗ E N D ▖▔", color="status") - async def make_plan(self, prompt: str) -> str: + async def make_plan(self, prompt: str, max_retries: int = 4) -> str: """ Asks the LLM to make a plan. Args: prompt (str): The prompt to be sent to the LLM. + max_retries (int): Maximum number of retries before giving up. Returns: str: The plan made by the LLM. """ ok = False answer = None + retries = 0 while not ok: + if retries >= max_retries: + pretty_print(f"Failed to make a plan after {max_retries} attempts. Giving up.", color="failure") + self.logger.warning(f"make_plan exceeded max retries ({max_retries}).") + return [] animate_thinking("Thinking...", color="status") self.memory.push('user', prompt) answer, reasoning = await self.llm_request() @@ -168,6 +174,7 @@ class PlannerAgent(Agent): self.show_plan(agents_tasks, answer) prompt = f"Failed to parse the tasks. Please write down your task followed by a json plan within ```json. Do not ask for clarification.\n" pretty_print("Failed to make plan. Retrying...", color="warning") + retries += 1 continue self.show_plan(agents_tasks, answer) ok = True From 872d01f8e555c3f10ad27454b0fe2024788f1f3f Mon Sep 17 00:00:00 2001 From: Octopus Date: Sat, 4 Apr 2026 11:23:41 +0800 Subject: [PATCH 4/4] fix: return HTTP 500 instead of calling sys.exit(1) on query errors Previously, any unhandled exception during query processing caused the entire backend server to exit via sys.exit(1), making the frontend show 'System offline. Deploy backend first.' until the container was restarted. Also, is_generating was never reset to False on exception, permanently blocking all subsequent queries with 429 responses. - Replace sys.exit(1) with a proper HTTP 500 error response - Move is_generating = False to the finally block so it always resets Fixes #382 --- api.py | 5 ++++- sources/agents/planner_agent.py | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/api.py b/api.py index 288e108..56d3154 100755 --- a/api.py +++ b/api.py @@ -278,8 +278,11 @@ async def process_query(request: QueryRequest): return JSONResponse(status_code=200, content=query_resp.jsonify()) except Exception as e: logger.error(f"An error occurred: {str(e)}") - sys.exit(1) + query_resp.answer = f"An error occurred: {str(e)}" + query_resp.reasoning = f"Error: {str(e)}" + return JSONResponse(status_code=500, content=query_resp.jsonify()) finally: + is_generating = False logger.info("Processing finished") if config.getboolean('MAIN', 'save_session'): interaction.save_session() diff --git a/sources/agents/planner_agent.py b/sources/agents/planner_agent.py index 720908c..ff6cba4 100644 --- a/sources/agents/planner_agent.py +++ b/sources/agents/planner_agent.py @@ -264,8 +264,6 @@ class PlannerAgent(Agent): agents_tasks = [] required_infos = None agents_work_result = dict() - answer = "" - self.stop = False self.status_message = "Making a plan..." agents_tasks = await self.make_plan(goal)