From 64dc033164204e67250933bd6cf68edbb772433a Mon Sep 17 00:00:00 2001 From: octo-patch <266937838+octo-patch@users.noreply.github.com> Date: Sun, 15 Mar 2026 13:18:37 +0800 Subject: [PATCH 1/4] Add MiniMax as a supported LLM provider MiniMax offers OpenAI-compatible API with models like MiniMax-M2.5 and MiniMax-M2.5-highspeed (204K context window). This commit adds: - MiniMax provider section in README (setup guide, cost estimation) - Example config file (configs/minimax_config.yaml) - Updated test env to support MiniMax API key validation Co-Authored-By: octo-patch --- README.md | 32 +++++++++++++++- configs/README.md | 3 ++ configs/minimax_config.yaml | 74 +++++++++++++++++++++++++++++++++++++ tests/test_valid_configs.py | 2 +- 4 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 configs/minimax_config.yaml diff --git a/README.md b/README.md index 740909f5e5..f6d11d637d 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ OpenEvolve implements a sophisticated **evolutionary coding pipeline** that goes
Advanced LLM Integration -- **Universal API**: Works with OpenAI, Google, local models, and proxies +- **Universal API**: Works with OpenAI, Google, MiniMax, local models, and proxies - **Intelligent Ensembles**: Weighted combinations with sophisticated fallback - **Test-Time Compute**: Enhanced reasoning through proxy systems (see [OptiLLM setup](#llm-provider-setup)) - **Plugin Ecosystem**: Support for advanced reasoning plugins @@ -281,6 +281,7 @@ docker run --rm -v $(pwd):/app ghcr.io/algorithmicsuperintelligence/openevolve:l - **o3-mini**: ~$0.03-0.12 per iteration (more cost-effective) - **Gemini-2.5-Pro**: ~$0.08-0.30 per iteration - **Gemini-2.5-Flash**: ~$0.01-0.05 per iteration (fastest and cheapest) +- **MiniMax-M2.5**: ~$0.02-0.08 per iteration (204K context, OpenAI-compatible) - **Local models**: Nearly free after setup - **OptiLLM**: Use cheaper models with test-time compute for better results @@ -320,6 +321,33 @@ export OPENAI_API_KEY="your-gemini-api-key"
+
+🧠 MiniMax + +[MiniMax](https://www.minimaxi.com/) offers powerful models with 204K context window via an OpenAI-compatible API: + +```yaml +# config.yaml +llm: + api_base: "https://api.minimax.io/v1" + api_key: "${MINIMAX_API_KEY}" + models: + - name: "MiniMax-M2.5" + weight: 0.6 + - name: "MiniMax-M2.5-highspeed" + weight: 0.4 +``` + +```bash +export MINIMAX_API_KEY="your-minimax-api-key" +``` + +> **Note:** MiniMax requires temperature to be in (0.0, 1.0] — zero is not accepted. The default 0.7 works well. + +See [`configs/minimax_config.yaml`](configs/minimax_config.yaml) for a complete configuration example. + +
+
🏠 Local Models (Ollama/vLLM) @@ -792,7 +820,7 @@ See the [Cost Estimation](#cost-estimation) section in Installation & Setup for **Yes!** OpenEvolve supports any OpenAI-compatible API: -- **Commercial**: OpenAI, Google, Cohere +- **Commercial**: OpenAI, Google, Cohere, MiniMax - **Local**: Ollama, vLLM, LM Studio, text-generation-webui - **Advanced**: OptiLLM for routing and test-time compute diff --git a/configs/README.md b/configs/README.md index 6ce24383c1..40506def76 100644 --- a/configs/README.md +++ b/configs/README.md @@ -12,6 +12,9 @@ The main configuration file containing all available options with sensible defau Use this file as a template for your own configurations. +### `minimax_config.yaml` +A complete configuration for using [MiniMax](https://www.minimaxi.com/) models (MiniMax-M2.5, MiniMax-M2.5-highspeed) with OpenEvolve. MiniMax provides an OpenAI-compatible API with 204K context window support. + ### `island_config_example.yaml` A practical example configuration demonstrating proper island-based evolution setup. Shows: - Recommended island settings for most use cases diff --git a/configs/minimax_config.yaml b/configs/minimax_config.yaml new file mode 100644 index 0000000000..e11c090022 --- /dev/null +++ b/configs/minimax_config.yaml @@ -0,0 +1,74 @@ +# OpenEvolve Configuration for MiniMax +# MiniMax provides OpenAI-compatible API with powerful models like MiniMax-M2.5 +# Get your API key from: https://platform.minimaxi.com/ +# +# Set your API key: +# export MINIMAX_API_KEY="your-minimax-api-key" + +# General settings +max_iterations: 100 +checkpoint_interval: 10 +log_level: "INFO" +random_seed: 42 + +# LLM configuration for MiniMax +llm: + api_base: "https://api.minimax.io/v1" + api_key: "${MINIMAX_API_KEY}" + + # MiniMax models for evolution + models: + - name: "MiniMax-M2.5" + weight: 0.6 + - name: "MiniMax-M2.5-highspeed" + weight: 0.4 + + # MiniMax models for LLM feedback + evaluator_models: + - name: "MiniMax-M2.5-highspeed" + weight: 1.0 + + # Generation parameters + # Note: MiniMax requires temperature to be in (0.0, 1.0] — zero is not accepted + temperature: 0.7 + top_p: 0.95 + max_tokens: 4096 + + # Request parameters + timeout: 120 + retries: 3 + retry_delay: 5 + +# Evolution settings +diff_based_evolution: true +max_code_length: 10000 + +# Prompt configuration +prompt: + system_message: "You are an expert coder helping to improve programs through evolution." + evaluator_system_message: "You are an expert code reviewer." + num_top_programs: 3 + num_diverse_programs: 2 + use_template_stochasticity: true + include_artifacts: true + +# Database configuration +database: + population_size: 1000 + num_islands: 5 + migration_interval: 50 + migration_rate: 0.1 + feature_dimensions: + - "complexity" + - "diversity" + feature_bins: 10 + +# Evaluator configuration +evaluator: + timeout: 300 + cascade_evaluation: true + cascade_thresholds: + - 0.5 + - 0.75 + - 0.9 + parallel_evaluations: 4 diff --git a/tests/test_valid_configs.py b/tests/test_valid_configs.py index ec46bd6a44..92653d703a 100644 --- a/tests/test_valid_configs.py +++ b/tests/test_valid_configs.py @@ -24,7 +24,7 @@ def collect_files(self): config_files.append(os.path.join(root, file)) return config_files - @patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key-for-validation"}) + @patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key-for-validation", "MINIMAX_API_KEY": "test-key-for-validation"}) def test_import_config_files(self): """Attempt to import all config files""" config_files = self.collect_files() From 78e5e6c7647c12e1968eda74d69e78b22200fa32 Mon Sep 17 00:00:00 2001 From: PR Bot Date: Wed, 18 Mar 2026 18:33:44 +0000 Subject: [PATCH 2/4] feat: upgrade MiniMax default model to M2.7 - Update MiniMax-M2.7 and MiniMax-M2.7-highspeed as default models - Update config, README, and docs references - Keep all previous models as alternatives --- README.md | 8 ++++---- configs/README.md | 2 +- configs/minimax_config.yaml | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f6d11d637d..812e52deb8 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ OpenEvolve implements a sophisticated **evolutionary coding pipeline** that goes
Advanced LLM Integration -- **Universal API**: Works with OpenAI, Google, MiniMax, local models, and proxies +- **Universal API**: Works with OpenAI, Google, MiniMax (M2.7), local models, and proxies - **Intelligent Ensembles**: Weighted combinations with sophisticated fallback - **Test-Time Compute**: Enhanced reasoning through proxy systems (see [OptiLLM setup](#llm-provider-setup)) - **Plugin Ecosystem**: Support for advanced reasoning plugins @@ -281,7 +281,7 @@ docker run --rm -v $(pwd):/app ghcr.io/algorithmicsuperintelligence/openevolve:l - **o3-mini**: ~$0.03-0.12 per iteration (more cost-effective) - **Gemini-2.5-Pro**: ~$0.08-0.30 per iteration - **Gemini-2.5-Flash**: ~$0.01-0.05 per iteration (fastest and cheapest) -- **MiniMax-M2.5**: ~$0.02-0.08 per iteration (204K context, OpenAI-compatible) +- **MiniMax-M2.7**: ~$0.02-0.08 per iteration (204K context, OpenAI-compatible) - **Local models**: Nearly free after setup - **OptiLLM**: Use cheaper models with test-time compute for better results @@ -332,9 +332,9 @@ llm: api_base: "https://api.minimax.io/v1" api_key: "${MINIMAX_API_KEY}" models: - - name: "MiniMax-M2.5" + - name: "MiniMax-M2.7" weight: 0.6 - - name: "MiniMax-M2.5-highspeed" + - name: "MiniMax-M2.7-highspeed" weight: 0.4 ``` diff --git a/configs/README.md b/configs/README.md index 40506def76..6e249e5c9a 100644 --- a/configs/README.md +++ b/configs/README.md @@ -13,7 +13,7 @@ The main configuration file containing all available options with sensible defau Use this file as a template for your own configurations. ### `minimax_config.yaml` -A complete configuration for using [MiniMax](https://www.minimaxi.com/) models (MiniMax-M2.5, MiniMax-M2.5-highspeed) with OpenEvolve. MiniMax provides an OpenAI-compatible API with 204K context window support. +A complete configuration for using [MiniMax](https://www.minimaxi.com/) models (MiniMax-M2.7, MiniMax-M2.7-highspeed) with OpenEvolve. MiniMax provides an OpenAI-compatible API with 204K context window support. ### `island_config_example.yaml` A practical example configuration demonstrating proper island-based evolution setup. Shows: diff --git a/configs/minimax_config.yaml b/configs/minimax_config.yaml index e11c090022..38f95da636 100644 --- a/configs/minimax_config.yaml +++ b/configs/minimax_config.yaml @@ -1,5 +1,5 @@ # OpenEvolve Configuration for MiniMax -# MiniMax provides OpenAI-compatible API with powerful models like MiniMax-M2.5 +# MiniMax provides OpenAI-compatible API with powerful models like MiniMax-M2.7 # Get your API key from: https://platform.minimaxi.com/ # # Set your API key: @@ -18,14 +18,14 @@ llm: # MiniMax models for evolution models: - - name: "MiniMax-M2.5" + - name: "MiniMax-M2.7" weight: 0.6 - - name: "MiniMax-M2.5-highspeed" + - name: "MiniMax-M2.7-highspeed" weight: 0.4 # MiniMax models for LLM feedback evaluator_models: - - name: "MiniMax-M2.5-highspeed" + - name: "MiniMax-M2.7-highspeed" weight: 1.0 # Generation parameters From f692811571a5eb3daa840c041fd25d2b0d5434ca Mon Sep 17 00:00:00 2001 From: octo-patch Date: Wed, 3 Jun 2026 02:40:41 +0800 Subject: [PATCH 3/4] feat: upgrade MiniMax default model to M3 - Add MiniMax-M3 to model list and set as default - Keep MiniMax-M2.7 and MiniMax-M2.7-highspeed as alternatives - Update README and configs/README.md with M3 references Co-Authored-By: Octopus --- README.md | 12 +++++++----- configs/README.md | 2 +- configs/minimax_config.yaml | 8 +++++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 812e52deb8..c6f44763de 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ OpenEvolve implements a sophisticated **evolutionary coding pipeline** that goes
Advanced LLM Integration -- **Universal API**: Works with OpenAI, Google, MiniMax (M2.7), local models, and proxies +- **Universal API**: Works with OpenAI, Google, MiniMax (M3), local models, and proxies - **Intelligent Ensembles**: Weighted combinations with sophisticated fallback - **Test-Time Compute**: Enhanced reasoning through proxy systems (see [OptiLLM setup](#llm-provider-setup)) - **Plugin Ecosystem**: Support for advanced reasoning plugins @@ -281,7 +281,7 @@ docker run --rm -v $(pwd):/app ghcr.io/algorithmicsuperintelligence/openevolve:l - **o3-mini**: ~$0.03-0.12 per iteration (more cost-effective) - **Gemini-2.5-Pro**: ~$0.08-0.30 per iteration - **Gemini-2.5-Flash**: ~$0.01-0.05 per iteration (fastest and cheapest) -- **MiniMax-M2.7**: ~$0.02-0.08 per iteration (204K context, OpenAI-compatible) +- **MiniMax-M3**: ~$0.02-0.08 per iteration (512K context, OpenAI-compatible) - **Local models**: Nearly free after setup - **OptiLLM**: Use cheaper models with test-time compute for better results @@ -324,7 +324,7 @@ export OPENAI_API_KEY="your-gemini-api-key"
🧠 MiniMax -[MiniMax](https://www.minimaxi.com/) offers powerful models with 204K context window via an OpenAI-compatible API: +[MiniMax](https://www.minimaxi.com/) offers powerful models with up to 512K context window via an OpenAI-compatible API: ```yaml # config.yaml @@ -332,10 +332,12 @@ llm: api_base: "https://api.minimax.io/v1" api_key: "${MINIMAX_API_KEY}" models: - - name: "MiniMax-M2.7" + - name: "MiniMax-M3" weight: 0.6 + - name: "MiniMax-M2.7" + weight: 0.3 - name: "MiniMax-M2.7-highspeed" - weight: 0.4 + weight: 0.1 ``` ```bash diff --git a/configs/README.md b/configs/README.md index 6e249e5c9a..3f0af1b67c 100644 --- a/configs/README.md +++ b/configs/README.md @@ -13,7 +13,7 @@ The main configuration file containing all available options with sensible defau Use this file as a template for your own configurations. ### `minimax_config.yaml` -A complete configuration for using [MiniMax](https://www.minimaxi.com/) models (MiniMax-M2.7, MiniMax-M2.7-highspeed) with OpenEvolve. MiniMax provides an OpenAI-compatible API with 204K context window support. +A complete configuration for using [MiniMax](https://www.minimaxi.com/) models (MiniMax-M3, MiniMax-M2.7, MiniMax-M2.7-highspeed) with OpenEvolve. MiniMax provides an OpenAI-compatible API with up to 512K context window support. ### `island_config_example.yaml` A practical example configuration demonstrating proper island-based evolution setup. Shows: diff --git a/configs/minimax_config.yaml b/configs/minimax_config.yaml index 38f95da636..a5501971c4 100644 --- a/configs/minimax_config.yaml +++ b/configs/minimax_config.yaml @@ -1,5 +1,5 @@ # OpenEvolve Configuration for MiniMax -# MiniMax provides OpenAI-compatible API with powerful models like MiniMax-M2.7 +# MiniMax provides OpenAI-compatible API with powerful models like MiniMax-M3 # Get your API key from: https://platform.minimaxi.com/ # # Set your API key: @@ -18,10 +18,12 @@ llm: # MiniMax models for evolution models: - - name: "MiniMax-M2.7" + - name: "MiniMax-M3" weight: 0.6 + - name: "MiniMax-M2.7" + weight: 0.3 - name: "MiniMax-M2.7-highspeed" - weight: 0.4 + weight: 0.1 # MiniMax models for LLM feedback evaluator_models: From 679f5cc8685feff2b5c27e37d612589bfaa5fc92 Mon Sep 17 00:00:00 2001 From: octo-patch <266937838+octo-patch@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:28:42 +0800 Subject: [PATCH 4/4] feat: default MiniMax examples to M3.1 Flash --- README.md | 14 ++- configs/README.md | 2 +- configs/minimax_config.yaml | 21 +++-- tests/test_minimax_config.py | 171 +++++++++++++++++++++++++++++++++++ tests/test_valid_configs.py | 10 +- 5 files changed, 197 insertions(+), 21 deletions(-) create mode 100644 tests/test_minimax_config.py diff --git a/README.md b/README.md index a4a5af9b11..1cd35a7ee1 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ docker run --rm -v $(pwd):/app ghcr.io/algorithmicsuperintelligence/openevolve:l - **o3-mini**: ~$0.03-0.12 per iteration (more cost-effective) - **Gemini-2.5-Pro**: ~$0.08-0.30 per iteration - **Gemini-2.5-Flash**: ~$0.01-0.05 per iteration (fastest and cheapest) -- **MiniMax-M3**: ~$0.02-0.08 per iteration (512K context, OpenAI-compatible) +- **MiniMax-M3.1-Flash / MiniMax-M3**: Cost depends on token usage; see [MiniMax pricing](https://platform.minimax.io/docs/pricing/overview). - **Local models**: Nearly free after setup - **OptiLLM**: Use cheaper models with test-time compute for better results @@ -375,7 +375,7 @@ export OPENAI_API_KEY="your-gemini-api-key"
🧠 MiniMax -[MiniMax](https://www.minimaxi.com/) offers powerful models with up to 512K context window via an OpenAI-compatible API: +[MiniMax](https://platform.minimax.io/docs/api-reference/text-openai-api) provides MiniMax-M3.1-Flash and MiniMax-M3 with 1,000,000-token context windows via an OpenAI-compatible API. This configuration selects Flash by default: ```yaml # config.yaml @@ -383,19 +383,17 @@ llm: api_base: "https://api.minimax.io/v1" api_key: "${MINIMAX_API_KEY}" models: + - name: "MiniMax-M3.1-Flash" + weight: 1.0 - name: "MiniMax-M3" - weight: 0.6 - - name: "MiniMax-M2.7" - weight: 0.3 - - name: "MiniMax-M2.7-highspeed" - weight: 0.1 + weight: 0.0 # Increase to include M3 in the ensemble ``` ```bash export MINIMAX_API_KEY="your-minimax-api-key" ``` -> **Note:** MiniMax requires temperature to be in (0.0, 1.0] — zero is not accepted. The default 0.7 works well. +> **Note:** For mainland China, set `api_base` to `https://api.minimaxi.com/v1` with a regional API key. Both models accept temperature in `[0, 2]`. Flash always thinks; optionally set `reasoning_effort` to `low`, `medium`, `high`, `xhigh`, or `max` (the API default). M3 ignores effort. Explicit model IDs in existing configurations are passed through unchanged. See [`configs/minimax_config.yaml`](configs/minimax_config.yaml) for a complete configuration example. diff --git a/configs/README.md b/configs/README.md index cd8bc31e99..6b7dfba1bd 100644 --- a/configs/README.md +++ b/configs/README.md @@ -13,7 +13,7 @@ The main configuration file containing all available options with sensible defau Use this file as a template for your own configurations. ### `minimax_config.yaml` -A complete configuration for using [MiniMax](https://www.minimaxi.com/) models (MiniMax-M3, MiniMax-M2.7, MiniMax-M2.7-highspeed) with OpenEvolve. MiniMax provides an OpenAI-compatible API with up to 512K context window support. +A complete configuration for using [MiniMax](https://platform.minimax.io/docs/api-reference/text-openai-api) models with OpenEvolve. MiniMax-M3.1-Flash is the default for evolution and evaluation; increase MiniMax-M3's weight to include it in the evolution ensemble. Both models provide a 1,000,000-token context window through the OpenAI-compatible API. The configuration documents international and mainland China endpoints. ### `island_config_example.yaml` A practical example configuration demonstrating proper island-based evolution setup. Shows: diff --git a/configs/minimax_config.yaml b/configs/minimax_config.yaml index a5501971c4..b7cb5f68ca 100644 --- a/configs/minimax_config.yaml +++ b/configs/minimax_config.yaml @@ -1,6 +1,6 @@ # OpenEvolve Configuration for MiniMax -# MiniMax provides OpenAI-compatible API with powerful models like MiniMax-M3 -# Get your API key from: https://platform.minimaxi.com/ +# MiniMax-M3.1-Flash is the default; MiniMax-M3 is an optional ensemble member. +# Get your API key from: https://platform.minimax.io/ # # Set your API key: # export MINIMAX_API_KEY="your-minimax-api-key" @@ -14,24 +14,25 @@ random_seed: 42 # LLM configuration for MiniMax llm: api_base: "https://api.minimax.io/v1" + # For mainland China, use https://api.minimaxi.com/v1 with a regional API key. api_key: "${MINIMAX_API_KEY}" - # MiniMax models for evolution + # Flash is selected by default. Increase M3's weight to include it in evolution. models: + - name: "MiniMax-M3.1-Flash" + weight: 1.0 - name: "MiniMax-M3" - weight: 0.6 - - name: "MiniMax-M2.7" - weight: 0.3 - - name: "MiniMax-M2.7-highspeed" - weight: 0.1 + weight: 0.0 # MiniMax models for LLM feedback evaluator_models: - - name: "MiniMax-M2.7-highspeed" + - name: "MiniMax-M3.1-Flash" weight: 1.0 # Generation parameters - # Note: MiniMax requires temperature to be in (0.0, 1.0] — zero is not accepted + # Flash always thinks. Optional reasoning_effort: low, medium, high, xhigh, max. + # Omit reasoning_effort to use the API default (max); M3 ignores this setting. + # Both models accept temperature in [0, 2]. temperature: 0.7 top_p: 0.95 max_tokens: 4096 diff --git a/tests/test_minimax_config.py b/tests/test_minimax_config.py new file mode 100644 index 0000000000..3d0953e032 --- /dev/null +++ b/tests/test_minimax_config.py @@ -0,0 +1,171 @@ +"""Exercise the MiniMax configuration through the real SDK's HTTP boundary.""" + +import json +import os +import unittest +from contextlib import ExitStack +from pathlib import Path +from tempfile import TemporaryDirectory +from unittest.mock import patch + +import openai + +try: + import httpx +except ModuleNotFoundError: + import httpx2 as httpx + +from openevolve.config import Config, load_config +from openevolve.controller import OpenEvolve +from openevolve.llm.ensemble import LLMEnsemble + +CONFIG_PATH = Path(__file__).resolve().parents[1] / "configs" / "minimax_config.yaml" + + +class TestMiniMaxConfig(unittest.IsolatedAsyncioTestCase): + def load_example(self): + with patch.dict(os.environ, {"MINIMAX_API_KEY": "test-key-for-validation"}): + return load_config(str(CONFIG_PATH)) + + async def capture_request(self, models, messages=None, controller_config=None, **kwargs): + requests = [] + + def respond(request): + requests.append(request) + return httpx.Response( + 200, + json={ + "id": "test-completion", + "object": "chat.completion", + "created": 0, + "model": json.loads(request.content)["model"], + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": {"role": "assistant", "content": "result"}, + } + ], + }, + ) + + # Replace only the network transport: config loading, ensemble selection, + # request construction and OpenAI SDK serialization all run normally. + client_class = openai.AsyncOpenAI + + def create_client(**kwargs): + return client_class( + **kwargs, http_client=httpx.AsyncClient(transport=httpx.MockTransport(respond)) + ) + + with ExitStack() as stack: + stack.enter_context( + patch("openevolve.llm.openai.openai.AsyncOpenAI", side_effect=create_client) + ) + if controller_config is not None: + output_dir = stack.enter_context(TemporaryDirectory()) + stack.enter_context(patch.object(OpenEvolve, "_setup_logging")) + example = CONFIG_PATH.parents[1] / "examples" / "function_minimization" + controller = OpenEvolve( + str(example / "initial_program.py"), + str(example / "evaluator.py"), + controller_config, + output_dir=output_dir, + ) + ensemble = ( + controller.llm_evaluator_ensemble + if models is controller_config.llm.evaluator_models + else controller.llm_ensemble + ) + clients = controller.llm_ensemble.models + controller.llm_evaluator_ensemble.models + else: + ensemble = LLMEnsemble(models) + clients = ensemble.models + try: + result = await ensemble.generate_with_context( + "system", messages or [{"role": "user", "content": "improve"}], **kwargs + ) + self.assertEqual(result, "result") + finally: + for model in clients: + await model.client.close() + self.assertEqual(len(requests), 1) + return requests[0], json.loads(requests[0].content) + + async def test_example_defaults_reach_both_regional_endpoints(self): + for base in ("https://api.minimax.io/v1", "https://api.minimaxi.com/v1"): + config = self.load_example() + self.assertEqual( + [model.name for model in config.llm.models], + ["MiniMax-M3.1-Flash", "MiniMax-M3"], + ) + self.assertEqual([model.weight for model in config.llm.models], [1.0, 0.0]) + config.llm.update_model_params({"api_base": base}, overwrite=True) + for models in (config.llm.models, config.llm.evaluator_models): + with self.subTest(base=base, models=models): + request, body = await self.capture_request(models, controller_config=config) + self.assertEqual(body["seed"], config.llm.random_seed) + self.assertIsInstance(body["seed"], int) + self.assertEqual(str(request.url), base + "/chat/completions") + self.assertEqual(body["model"], "MiniMax-M3.1-Flash") + self.assertEqual(body["max_tokens"], 4096) + self.assertEqual(body["temperature"], 0.7) + self.assertEqual(body["top_p"], 0.95) + self.assertFalse(body["stream"]) + for field in ( + "thinking", + "reasoning_effort", + "reasoning_split", + "service_tier", + ): + self.assertNotIn(field, body) + + async def test_flash_effort_reaches_wire(self): + for effort in ("low", "medium", "high", "xhigh", "max"): + with self.subTest(effort=effort): + config = self.load_example() + config.llm.update_model_params({"reasoning_effort": effort}, overwrite=True) + _, body = await self.capture_request(config.llm.models) + self.assertEqual(body["reasoning_effort"], effort) + _, body = await self.capture_request(config.llm.models, reasoning_effort="low") + self.assertEqual(body["reasoning_effort"], "low") + + async def test_m3_can_be_selected_explicitly(self): + config = self.load_example() + config.llm.models[0].weight = 0.0 + config.llm.models[1].weight = 1.0 + _, body = await self.capture_request(config.llm.models) + self.assertEqual(body["model"], "MiniMax-M3") + self.assertNotIn("reasoning_effort", body) + + async def test_saved_legacy_custom_models_and_content_are_preserved(self): + messages = [ + { + "role": "user", + "content": [ + {"type": "text", "text": "describe"}, + {"type": "image_url", "image_url": {"url": "https://example.com/image.png"}}, + {"type": "video_url", "video_url": {"url": "mm_file://fixture"}}, + ], + } + ] + for model in ("MiniMax-M2.7", "MiniMax-M2.7-highspeed", "custom-model"): + for key, value in (("primary_model", model), ("models", [{"name": model}])): + with self.subTest(model=model, key=key): + config = Config.from_dict( + { + "llm": { + "api_base": "https://example.com/v1", + "api_key": "test-key-for-validation", + key: value, + } + } + ) + request, body = await self.capture_request(config.llm.models, messages) + self.assertEqual(str(request.url), "https://example.com/v1/chat/completions") + self.assertEqual(body["model"], model) + self.assertEqual(body["messages"][1:], messages) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_valid_configs.py b/tests/test_valid_configs.py index 92653d703a..d2e65182d5 100644 --- a/tests/test_valid_configs.py +++ b/tests/test_valid_configs.py @@ -2,9 +2,9 @@ Confirming the validity of configuration files in project directories """ +import itertools import os import unittest -import itertools from unittest.mock import MagicMock, patch from openevolve.config import Config, load_config @@ -24,7 +24,13 @@ def collect_files(self): config_files.append(os.path.join(root, file)) return config_files - @patch.dict(os.environ, {"ANTHROPIC_API_KEY": "test-key-for-validation", "MINIMAX_API_KEY": "test-key-for-validation"}) + @patch.dict( + os.environ, + { + "ANTHROPIC_API_KEY": "test-key-for-validation", + "MINIMAX_API_KEY": "test-key-for-validation", + }, + ) def test_import_config_files(self): """Attempt to import all config files""" config_files = self.collect_files()