From d224d425f902e843c88cef57ec1ee749cbb73694 Mon Sep 17 00:00:00 2001 From: Declan Murphy <278305138+declan-murphy-bf@users.noreply.github.com> Date: Sun, 31 May 2026 05:22:29 +0800 Subject: [PATCH 1/4] feat: add MiniMax chat backend module Port qwen_backend.py pattern to minimax_backend.py as a new OpenAI-compatible urllib-based backend. Includes: - BASE_URL defaulting to https://api.minimax.chat/v1 - API_KEY, TIMEOUT_SECONDS, MAX_TOKENS, TEMPERATURE env vars - ENABLE_THINKING support (MiniMax thinking mode) - configure_minimax_chat() runtime configurator - chat_target() and chat_target_messages() functions - TokenTracker integration and get_token_summary() - set_target_deployment() support - Default model: MiniMax/MiniMax-Text-01 --- skillopt/model/minimax_backend.py | 277 ++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 skillopt/model/minimax_backend.py diff --git a/skillopt/model/minimax_backend.py b/skillopt/model/minimax_backend.py new file mode 100644 index 0000000..64daf71 --- /dev/null +++ b/skillopt/model/minimax_backend.py @@ -0,0 +1,277 @@ +"""OpenAI-compatible MiniMax chat backend for the target path.""" +from __future__ import annotations + +import json +import os +import threading +import time +import urllib.error +import urllib.request +from typing import Any + +from skillopt.model.common import ( + CompatAssistantMessage, + CompatToolCall, + CompatToolFunction, + TokenTracker, + default_model_for_backend, +) + +BASE_URL = os.environ.get("MINIMAX_BASE_URL", "https://api.minimax.chat/v1") +API_KEY = os.environ.get("MINIMAX_API_KEY", "") +TIMEOUT_SECONDS = float(os.environ.get("MINIMAX_TIMEOUT_SECONDS", "300") or 300) +MAX_TOKENS = int(os.environ.get("MINIMAX_MAX_TOKENS", "8000") or 8000) +TEMPERATURE: float | None = None +_raw_temperature = os.environ.get("MINIMAX_TEMPERATURE", "0.7").strip() +if _raw_temperature: + TEMPERATURE = float(_raw_temperature) +ENABLE_THINKING = os.environ.get("MINIMAX_ENABLE_THINKING", "false").strip().lower() in { + "1", + "true", + "yes", + "on", +} + +TARGET_DEPLOYMENT = os.environ.get( + "TARGET_DEPLOYMENT", + default_model_for_backend("minimax_chat"), +) + +_config_lock = threading.Lock() +tracker = TokenTracker() + + +def _chat_url() -> str: + base = BASE_URL.rstrip("/") + if base.endswith("/chat/completions"): + return base + return f"{base}/chat/completions" + + +def _json_safe(value: Any) -> Any: + if value is None or isinstance(value, (str, int, float, bool)): + return value + if isinstance(value, list): + return [_json_safe(item) for item in value] + if isinstance(value, dict): + return {str(key): _json_safe(val) for key, val in value.items()} + model_dump = getattr(value, "model_dump", None) + if callable(model_dump): + try: + return model_dump(mode="json") + except TypeError: + return model_dump() + return str(value) + + +def _usage_from_payload(payload: dict[str, Any]) -> dict[str, int]: + usage = payload.get("usage") or {} + prompt_tokens = int(usage.get("prompt_tokens") or usage.get("input_tokens") or 0) + completion_tokens = int(usage.get("completion_tokens") or usage.get("output_tokens") or 0) + total_tokens = int(usage.get("total_tokens") or (prompt_tokens + completion_tokens)) + return { + "prompt_tokens": prompt_tokens, + "completion_tokens": completion_tokens, + "total_tokens": total_tokens, + } + + +def _compat_message_from_payload(message: dict[str, Any], choice: dict[str, Any]) -> CompatAssistantMessage: + content = message.get("content") or "" + if not isinstance(content, str): + content = json.dumps(content, ensure_ascii=False) + tool_calls: list[CompatToolCall] = [] + for index, tool_call in enumerate(message.get("tool_calls") or [], start=1): + function = tool_call.get("function") or {} + tool_calls.append( + CompatToolCall( + id=str(tool_call.get("id") or f"minimax_tool_{index}"), + type=str(tool_call.get("type") or "function"), + function=CompatToolFunction( + name=str(function.get("name") or ""), + arguments=str(function.get("arguments") or "{}"), + ), + ) + ) + return CompatAssistantMessage( + content=content, + tool_calls=tool_calls, + metadata={ + "finish_reason": choice.get("finish_reason"), + "choice0": _json_safe(choice), + }, + ) + + +def _post_chat_completion(payload: dict[str, Any], timeout: float | None) -> dict[str, Any]: + headers = {"Content-Type": "application/json"} + if API_KEY: + headers["Authorization"] = f"Bearer {API_KEY}" + req = urllib.request.Request( + _chat_url(), + data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), + headers=headers, + method="POST", + ) + try: + with urllib.request.urlopen(req, timeout=timeout or TIMEOUT_SECONDS) as resp: + raw = resp.read().decode("utf-8") + except urllib.error.HTTPError as e: + body = e.read().decode("utf-8", errors="replace") + raise RuntimeError(f"MiniMax chat API returned HTTP {e.code}: {body}") from e + except urllib.error.URLError as e: + raise RuntimeError(f"MiniMax chat API request failed: {e}") from e + try: + return json.loads(raw) + except json.JSONDecodeError as e: + raise RuntimeError(f"MiniMax chat API returned non-JSON response: {raw[:1000]}") from e + + +def _chat_messages_impl( + messages: list[dict[str, Any]], + max_completion_tokens: int, + retries: int, + stage: str, + *, + tools: list[dict[str, Any]] | None = None, + tool_choice: str | dict[str, Any] | None = None, + return_message: bool = False, + deployment: str | None = None, + timeout: float | None = None, +) -> tuple[Any, dict[str, int]]: + payload: dict[str, Any] = { + "model": deployment or TARGET_DEPLOYMENT, + "messages": _json_safe(messages), + "max_tokens": min(max_completion_tokens, MAX_TOKENS), + } + payload["chat_template_kwargs"] = {"enable_thinking": ENABLE_THINKING} + if TEMPERATURE is not None: + payload["temperature"] = TEMPERATURE + if tools: + payload["tools"] = _json_safe(tools) + if tool_choice is not None: + payload["tool_choice"] = _json_safe(tool_choice) + + last_err: Exception | None = None + for attempt in range(retries): + try: + data = _post_chat_completion(payload, timeout) + choices = data.get("choices") or [] + if not choices: + raise RuntimeError(f"MiniMax chat API returned no choices: {data}") + choice0 = choices[0] + message = choice0.get("message") or {} + text = message.get("content") or "" + if not isinstance(text, str): + text = json.dumps(text, ensure_ascii=False) + usage_info = _usage_from_payload(data) + tracker.record(stage, usage_info["prompt_tokens"], usage_info["completion_tokens"]) + if return_message: + return _compat_message_from_payload(message, choice0), usage_info + return text, usage_info + except Exception as e: # noqa: BLE001 + last_err = e + time.sleep(min(2 ** attempt, 30)) + raise RuntimeError(f"MiniMax chat call failed after {retries} retries: {last_err}") + + +def configure_minimax_chat( + *, + base_url: str | None = None, + api_key: str | None = None, + temperature: float | str | None = None, + timeout_seconds: float | str | None = None, + max_tokens: int | str | None = None, + enable_thinking: bool | str | None = None, +) -> None: + global BASE_URL, API_KEY, TEMPERATURE, TIMEOUT_SECONDS, MAX_TOKENS, ENABLE_THINKING + with _config_lock: + if base_url is not None: + BASE_URL = str(base_url).strip() or BASE_URL + os.environ["MINIMAX_BASE_URL"] = BASE_URL + if api_key is not None: + API_KEY = str(api_key).strip() + os.environ["MINIMAX_API_KEY"] = API_KEY + if temperature is not None: + raw = str(temperature).strip() + TEMPERATURE = float(raw) if raw else None + os.environ["MINIMAX_TEMPERATURE"] = raw + if timeout_seconds is not None: + TIMEOUT_SECONDS = float(timeout_seconds) + os.environ["MINIMAX_TIMEOUT_SECONDS"] = str(timeout_seconds) + if max_tokens is not None: + MAX_TOKENS = int(max_tokens) + os.environ["MINIMAX_MAX_TOKENS"] = str(max_tokens) + if enable_thinking is not None: + if isinstance(enable_thinking, str): + ENABLE_THINKING = enable_thinking.strip().lower() in {"1", "true", "yes", "on"} + else: + ENABLE_THINKING = bool(enable_thinking) + os.environ["MINIMAX_ENABLE_THINKING"] = "true" if ENABLE_THINKING else "false" + + +def get_max_tokens() -> int: + return MAX_TOKENS + + +def chat_target( + system: str, + user: str, + max_completion_tokens: int = 16384, + retries: int = 5, + stage: str = "target", + reasoning_effort: str | None = None, + timeout: float | None = None, +) -> tuple[str, dict[str, int]]: + del reasoning_effort + messages = [{"role": "system", "content": system}, {"role": "user", "content": user}] + return _chat_messages_impl( + messages, + max_completion_tokens, + retries, + stage, + timeout=timeout, + ) + + +def chat_target_messages( + messages: list[dict[str, Any]], + max_completion_tokens: int = 16384, + retries: int = 5, + stage: str = "target", + reasoning_effort: str | None = None, + *, + tools: list[dict[str, Any]] | None = None, + tool_choice: str | dict[str, Any] | None = None, + return_message: bool = False, + timeout: float | None = None, +) -> tuple[Any, dict[str, int]]: + del reasoning_effort + return _chat_messages_impl( + messages, + max_completion_tokens, + retries, + stage, + tools=tools, + tool_choice=tool_choice, + return_message=return_message, + timeout=timeout, + ) + + +def get_token_summary() -> dict[str, dict[str, int]]: + return tracker.summary() + + +def reset_token_tracker() -> None: + tracker.reset() + + +def set_reasoning_effort(effort: str | None) -> None: + del effort + + +def set_target_deployment(deployment: str) -> None: + global TARGET_DEPLOYMENT + TARGET_DEPLOYMENT = deployment or default_model_for_backend("minimax_chat") + os.environ["TARGET_DEPLOYMENT"] = TARGET_DEPLOYMENT \ No newline at end of file From 309ea64ff41ab8eee65088180461007be1c0d715 Mon Sep 17 00:00:00 2001 From: Declan Murphy <278305138+declan-murphy-bf@users.noreply.github.com> Date: Sun, 31 May 2026 05:22:33 +0800 Subject: [PATCH 2/4] feat: integrate MiniMax into model router, backend config, and common MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit common.py: - Add minimax_chat → MiniMax/MiniMax-Text-01 to _BACKEND_DEFAULT_MODELS - Add minimax/minimax_chat aliases to _BACKEND_ALIASES backend_config.py: - Add minimax_chat to set_optimizer_backend() valid set - Add minimax_chat to set_target_backend() valid set - Add minimax_chat to is_optimizer_chat_backend() - Add minimax_chat to is_target_chat_backend() __init__.py: - Import minimax_backend as _minimax - Add minimax_chat to set_backend() legacy handler - Add minimax_chat to get_backend_name() reporting - Route chat_target() and chat_target_messages() to _minimax - Update NotImplementedError messages to list minimax_chat - Aggregate _minimax into get_token_summary() - Add _minimax.reset_token_tracker() - Add configure_minimax_chat() delegator - Add _minimax to set_reasoning_effort() and set_target_deployment() --- skillopt/model/__init__.py | 64 +++++++++++++++++++++++++++++++- skillopt/model/backend_config.py | 12 +++--- skillopt/model/common.py | 3 ++ 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/skillopt/model/__init__.py b/skillopt/model/__init__.py index bd33aa1..cbd5358 100644 --- a/skillopt/model/__init__.py +++ b/skillopt/model/__init__.py @@ -6,6 +6,7 @@ from typing import Any from skillopt.model import azure_openai as _openai from skillopt.model import claude_backend as _claude +from skillopt.model import minimax_backend as _minimax from skillopt.model import qwen_backend as _qwen from skillopt.model.backend_config import ( # noqa: F401 configure_claude_code_exec, @@ -50,6 +51,10 @@ def set_backend(name: str | None) -> str: set_optimizer_backend("openai_chat") set_target_backend("qwen_chat") return "qwen_chat" + if normalized in {"minimax", "minimax_chat"}: + set_optimizer_backend("openai_chat") + set_target_backend("minimax_chat") + return "minimax_chat" raise ValueError(f"Unsupported legacy backend: {name!r}") @@ -65,6 +70,8 @@ def get_backend_name() -> str: return "codex" if optimizer == "openai_chat" and target == "qwen_chat": return "qwen_chat" + if optimizer == "openai_chat" and target == "minimax_chat": + return "minimax_chat" return f"{optimizer}+{target}" @@ -124,9 +131,18 @@ def chat_target( stage=stage, reasoning_effort=reasoning_effort, ) + if get_target_backend() == "minimax_chat": + return _minimax.chat_target( + system=system, + user=user, + max_completion_tokens=max_completion_tokens, + retries=retries, + stage=stage, + reasoning_effort=reasoning_effort, + ) if not is_target_chat_backend(): raise NotImplementedError( - "chat_target is only supported with target_backend=openai_chat, claude_chat, or qwen_chat. " + "chat_target is only supported with target_backend=openai_chat, claude_chat, qwen_chat, or minimax_chat. " "Exec backends are handled in environment-specific rollout code." ) return _openai.chat_target( @@ -210,9 +226,20 @@ def chat_target_messages( tool_choice=tool_choice, return_message=return_message, ) + if get_target_backend() == "minimax_chat": + return _minimax.chat_target_messages( + messages=messages, + max_completion_tokens=max_completion_tokens, + retries=retries, + stage=stage, + reasoning_effort=reasoning_effort, + tools=tools, + tool_choice=tool_choice, + return_message=return_message, + ) if not is_target_chat_backend(): raise NotImplementedError( - "chat_target_messages is only supported with target_backend=openai_chat, claude_chat, or qwen_chat. " + "chat_target_messages is only supported with target_backend=openai_chat, claude_chat, qwen_chat, or minimax_chat. " "Exec backends are handled in environment-specific rollout code." ) return _openai.chat_target_messages( @@ -301,6 +328,17 @@ def get_token_summary() -> dict: summary[stage]["prompt_tokens"] += values["prompt_tokens"] summary[stage]["completion_tokens"] += values["completion_tokens"] summary[stage]["total_tokens"] += values["total_tokens"] + minimax_summary = _minimax.get_token_summary() + for stage, values in minimax_summary.items(): + if stage == "_total": + continue + if stage not in summary: + summary[stage] = values + continue + summary[stage]["calls"] += values["calls"] + summary[stage]["prompt_tokens"] += values["prompt_tokens"] + summary[stage]["completion_tokens"] += values["completion_tokens"] + summary[stage]["total_tokens"] += values["total_tokens"] total = { "calls": 0, "prompt_tokens": 0, @@ -322,6 +360,7 @@ def reset_token_tracker() -> None: _openai.reset_token_tracker() _claude.reset_token_tracker() _qwen.reset_token_tracker() + _minimax.reset_token_tracker() def configure_azure_openai( @@ -386,16 +425,37 @@ def configure_qwen_chat( ) +def configure_minimax_chat( + *, + base_url: str | None = None, + api_key: str | None = None, + temperature: float | str | None = None, + timeout_seconds: float | str | None = None, + max_tokens: int | str | None = None, + enable_thinking: bool | str | None = None, +) -> None: + _minimax.configure_minimax_chat( + base_url=base_url, + api_key=api_key, + temperature=temperature, + timeout_seconds=timeout_seconds, + max_tokens=max_tokens, + enable_thinking=enable_thinking, + ) + + def set_reasoning_effort(effort: str | None) -> None: _openai.set_reasoning_effort(effort) _claude.set_reasoning_effort(effort) _qwen.set_reasoning_effort(effort) + _minimax.set_reasoning_effort(effort) def set_target_deployment(deployment: str) -> None: _openai.set_target_deployment(deployment) _claude.set_target_deployment(deployment) _qwen.set_target_deployment(deployment) + _minimax.set_target_deployment(deployment) def set_optimizer_deployment(deployment: str) -> None: diff --git a/skillopt/model/backend_config.py b/skillopt/model/backend_config.py index cf36b7e..2cdc8c3 100644 --- a/skillopt/model/backend_config.py +++ b/skillopt/model/backend_config.py @@ -49,10 +49,10 @@ CLAUDE_CODE_EXEC_MAX_THINKING_TOKENS = max( def set_optimizer_backend(backend: str) -> None: global OPTIMIZER_BACKEND OPTIMIZER_BACKEND = normalize_backend_name(backend or "openai_chat") - if OPTIMIZER_BACKEND not in {"openai_chat", "claude_chat"}: + if OPTIMIZER_BACKEND not in {"openai_chat", "claude_chat", "minimax_chat"}: raise ValueError( f"Unsupported optimizer backend: {OPTIMIZER_BACKEND!r}. " - "Supported values are 'openai_chat' and 'claude_chat'." + "Supported values are 'openai_chat', 'claude_chat', and 'minimax_chat'." ) os.environ["OPTIMIZER_BACKEND"] = OPTIMIZER_BACKEND @@ -64,10 +64,10 @@ def get_optimizer_backend() -> str: def set_target_backend(backend: str) -> None: global TARGET_BACKEND TARGET_BACKEND = normalize_backend_name(backend or "openai_chat") - if TARGET_BACKEND not in {"openai_chat", "claude_chat", "qwen_chat", "codex_exec", "claude_code_exec"}: + if TARGET_BACKEND not in {"openai_chat", "claude_chat", "qwen_chat", "minimax_chat", "codex_exec", "claude_code_exec"}: raise ValueError( f"Unsupported target backend: {TARGET_BACKEND!r}. " - "Supported values are 'openai_chat', 'claude_chat', 'qwen_chat', 'codex_exec', and 'claude_code_exec'." + "Supported values are 'openai_chat', 'claude_chat', 'qwen_chat', 'minimax_chat', 'codex_exec', and 'claude_code_exec'." ) os.environ["TARGET_BACKEND"] = TARGET_BACKEND @@ -81,11 +81,11 @@ def is_target_exec_backend() -> bool: def is_optimizer_chat_backend() -> bool: - return OPTIMIZER_BACKEND in {"openai_chat", "claude_chat"} + return OPTIMIZER_BACKEND in {"openai_chat", "claude_chat", "minimax_chat"} def is_target_chat_backend() -> bool: - return TARGET_BACKEND in {"openai_chat", "claude_chat", "qwen_chat"} + return TARGET_BACKEND in {"openai_chat", "claude_chat", "qwen_chat", "minimax_chat"} def configure_codex_exec( diff --git a/skillopt/model/common.py b/skillopt/model/common.py index ee90e38..c545579 100644 --- a/skillopt/model/common.py +++ b/skillopt/model/common.py @@ -25,6 +25,7 @@ _BACKEND_DEFAULT_MODELS = { "claude_chat": "claude-sonnet-4-6", "claude_code_exec": "claude-sonnet-4-6", "qwen_chat": "Qwen/Qwen3.5-4B", + "minimax_chat": "MiniMax/MiniMax-Text-01", } _BACKEND_ALIASES = { @@ -41,6 +42,8 @@ _BACKEND_ALIASES = { "anthropic": "claude_chat", "qwen": "qwen_chat", "qwen_chat": "qwen_chat", + "minimax": "minimax_chat", + "minimax_chat": "minimax_chat", } From e4201074aa418f05b994370691e0e74def4106ee Mon Sep 17 00:00:00 2001 From: Declan Murphy <278305138+declan-murphy-bf@users.noreply.github.com> Date: Sun, 31 May 2026 05:22:35 +0800 Subject: [PATCH 3/4] docs: add MiniMax config to default.yaml and .env.example default.yaml: - Add minimax_base_url, minimax_api_key, minimax_model, minimax_temperature, minimax_max_tokens, minimax_enable_thinking settings - Add optimizer_minimax_base_url, target_minimax_base_url per-role overrides - Add optimizer_minimax_api_key, target_minimax_api_key per-role overrides .env.example: - Add MINIMAX_BASE_URL, MINIMAX_API_KEY, MINIMAX_MODEL env var docs --- .env.example | 5 +++++ configs/_base_/default.yaml | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/.env.example b/.env.example index f424cda..c68ef76 100644 --- a/.env.example +++ b/.env.example @@ -27,3 +27,8 @@ export AZURE_OPENAI_API_KEY= # ── Qwen Local Model (for qwen_chat backend) ──────────────────────── # export QWEN_CHAT_BASE_URL=http://localhost:8000/v1 # export QWEN_CHAT_MODEL=Qwen/Qwen3.5-4B + +# ── MiniMax (for minimax_chat backend) ────────────────────────────── +# export MINIMAX_BASE_URL=https://api.minimax.chat/v1 +# export MINIMAX_API_KEY=... +# export MINIMAX_MODEL=MiniMax/MiniMax-Text-01 diff --git a/configs/_base_/default.yaml b/configs/_base_/default.yaml index ed8f61d..8ac5985 100644 --- a/configs/_base_/default.yaml +++ b/configs/_base_/default.yaml @@ -44,6 +44,18 @@ model: target_azure_openai_ad_scope: "https://cognitiveservices.azure.com/.default" target_azure_openai_managed_identity_client_id: "" + # MiniMax backend settings (minimax_chat target) + minimax_base_url: "" # https://api.minimax.chat/v1 if blank + minimax_api_key: "" + minimax_model: "MiniMax/MiniMax-Text-01" + minimax_temperature: "0.7" + minimax_max_tokens: "8000" + minimax_enable_thinking: "false" + optimizer_minimax_base_url: "" # per-role override + target_minimax_base_url: "" # per-role override + optimizer_minimax_api_key: "" + target_minimax_api_key: "" + train: num_epochs: 4 train_size: 0 # 0 = derive from dataset split when available From c6da31df4403865282eb643c945e8dedec124a9b Mon Sep 17 00:00:00 2001 From: Declan Murphy <278305138+declan-murphy-bf@users.noreply.github.com> Date: Sun, 31 May 2026 05:27:50 +0800 Subject: [PATCH 4/4] fix: use correct MiniMax endpoint, model name, and add .venv to gitignore --- .env.example | 4 ++-- .gitignore | 1 + configs/_base_/default.yaml | 4 ++-- skillopt/model/common.py | 2 +- skillopt/model/minimax_backend.py | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index c68ef76..7060b86 100644 --- a/.env.example +++ b/.env.example @@ -29,6 +29,6 @@ export AZURE_OPENAI_API_KEY= # export QWEN_CHAT_MODEL=Qwen/Qwen3.5-4B # ── MiniMax (for minimax_chat backend) ────────────────────────────── -# export MINIMAX_BASE_URL=https://api.minimax.chat/v1 +# export MINIMAX_BASE_URL=https://api.minimax.io/v1 # export MINIMAX_API_KEY=... -# export MINIMAX_MODEL=MiniMax/MiniMax-Text-01 +# export MINIMAX_MODEL=MiniMax-M2.7 diff --git a/.gitignore b/.gitignore index 3bc970b..64267de 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ docs/reflact_overview.html docs/render_ablation_paper_tables.py docs/让* .gradio/ +.venv diff --git a/configs/_base_/default.yaml b/configs/_base_/default.yaml index 8ac5985..addfbff 100644 --- a/configs/_base_/default.yaml +++ b/configs/_base_/default.yaml @@ -45,9 +45,9 @@ model: target_azure_openai_managed_identity_client_id: "" # MiniMax backend settings (minimax_chat target) - minimax_base_url: "" # https://api.minimax.chat/v1 if blank + minimax_base_url: "" # https://api.minimax.io/v1 if blank minimax_api_key: "" - minimax_model: "MiniMax/MiniMax-Text-01" + minimax_model: "MiniMax-M2.7" minimax_temperature: "0.7" minimax_max_tokens: "8000" minimax_enable_thinking: "false" diff --git a/skillopt/model/common.py b/skillopt/model/common.py index c545579..80983b5 100644 --- a/skillopt/model/common.py +++ b/skillopt/model/common.py @@ -25,7 +25,7 @@ _BACKEND_DEFAULT_MODELS = { "claude_chat": "claude-sonnet-4-6", "claude_code_exec": "claude-sonnet-4-6", "qwen_chat": "Qwen/Qwen3.5-4B", - "minimax_chat": "MiniMax/MiniMax-Text-01", + "minimax_chat": "MiniMax-M2.7", } _BACKEND_ALIASES = { diff --git a/skillopt/model/minimax_backend.py b/skillopt/model/minimax_backend.py index 64daf71..8c6add9 100644 --- a/skillopt/model/minimax_backend.py +++ b/skillopt/model/minimax_backend.py @@ -17,7 +17,7 @@ from skillopt.model.common import ( default_model_for_backend, ) -BASE_URL = os.environ.get("MINIMAX_BASE_URL", "https://api.minimax.chat/v1") +BASE_URL = os.environ.get("MINIMAX_BASE_URL", "https://api.minimax.io/v1") API_KEY = os.environ.get("MINIMAX_API_KEY", "") TIMEOUT_SECONDS = float(os.environ.get("MINIMAX_TIMEOUT_SECONDS", "300") or 300) MAX_TOKENS = int(os.environ.get("MINIMAX_MAX_TOKENS", "8000") or 8000)