Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions src/autogluon/assistant/configs/minimax.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# MiniMax Configuration

per_execution_timeout: 86400

# Data Perception
max_file_group_size_to_show: 5
num_example_files_to_show: 1

max_chars_per_file: 768
num_tutorial_retrievals: 30
max_num_tutorials: 5
max_user_input_length: 2048
max_error_message_length: 2048
max_tutorial_length: 32768
configure_env: false
condense_tutorials: True
use_tutorial_summary: True
continuous_improvement: False
optimize_system_resources: False
cleanup_unused_env: True
enable_meta_prompting: False

llm: &default_llm
provider: minimax
model: MiniMax-M3
# Regional route: global_en (api.minimax.io) or cn_zh (api.minimaxi.com)
region: global_en
# Compatibility route: openai or anthropic
api: openai
max_tokens: 65535
proxy_url: null
temperature: 0.1
top_p: 0.9
verbose: True
multi_turn: False
template: null
add_coding_format_instruction: false
apply_meta_prompting: False

# Ensure all agent types inherit the MiniMax LLM config
python_coder:
<<: *default_llm # Merge llm_config
multi_turn: True
apply_meta_prompting: True

bash_coder:
<<: *default_llm # Merge llm_config
multi_turn: True

executer:
<<: *default_llm # Merge llm_config
max_stdout_length: 8192
max_stderr_length: 2048

meta_prompting:
<<: *default_llm # Merge llm_config
multi_turn: False

reader:
<<: *default_llm # Merge llm_config
details: False

error_analyzer:
<<: *default_llm # Merge llm_config

retriever:
<<: *default_llm # Merge llm_config

reranker:
<<: *default_llm # Merge llm_config
temperature: 0.
top_p: 1.

description_file_retriever:
<<: *default_llm # Merge llm_config
temperature: 0.
top_p: 1.

task_descriptor:
<<: *default_llm # Merge llm_config
max_description_files_length_to_show: 1024
max_description_files_length_for_summarization: 16384
apply_meta_prompting: True

tool_selector:
<<: *default_llm # Merge llm_config
temperature: 0.
top_p: 1.
9 changes: 8 additions & 1 deletion src/autogluon/assistant/llm/llm_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .azure_openai_chat import AssistantAzureChatOpenAI, create_azure_openai_chat, get_azure_models
from .base_chat import GlobalTokenTracker
from .bedrock_chat import AssistantChatBedrock, create_bedrock_chat, get_bedrock_models
from .minimax_chat import AssistantChatMiniMax, AssistantChatMiniMaxAnthropic, create_minimax_chat, get_minimax_models
from .openai_chat import AssistantChatOpenAI, create_openai_chat, get_openai_models
from .sagemaker_chat import SagemakerEndpointChat, create_sagemaker_chat, get_sagemaker_endpoints

Expand All @@ -34,12 +35,14 @@ def get_valid_models(cls, provider):
return get_anthropic_models()
elif provider == "sagemaker":
return get_sagemaker_endpoints()
elif provider == "minimax":
return get_minimax_models()
else:
raise ValueError(f"Unsupported provider: {provider}")

@classmethod
def get_valid_providers(cls):
return ["azure", "openai", "bedrock", "anthropic", "sagemaker"]
return ["azure", "openai", "bedrock", "anthropic", "sagemaker", "minimax"]

@classmethod
def get_chat_model(cls, config: DictConfig, session_name: str) -> Union[
Expand All @@ -48,6 +51,8 @@ def get_chat_model(cls, config: DictConfig, session_name: str) -> Union[
AssistantChatBedrock,
AssistantChatAnthropic,
SagemakerEndpointChat,
AssistantChatMiniMax,
AssistantChatMiniMaxAnthropic,
]:
"""Get a configured chat model instance using LangGraph patterns."""
provider = config.provider
Expand Down Expand Up @@ -75,5 +80,7 @@ def get_chat_model(cls, config: DictConfig, session_name: str) -> Union[
return create_bedrock_chat(config, session_name)
elif provider == "sagemaker":
return create_sagemaker_chat(config, session_name)
elif provider == "minimax":
return create_minimax_chat(config, session_name)
else:
raise ValueError(f"Unsupported provider: {provider}")
134 changes: 134 additions & 0 deletions src/autogluon/assistant/llm/minimax_chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import logging
import os
from typing import Any, Dict, List, Union

from langchain_anthropic import ChatAnthropic
from langchain_openai import ChatOpenAI
from openai import OpenAI

from .base_chat import BaseAssistantChat

logger = logging.getLogger(__name__)

# Regional routes exposed by MiniMax. Each region serves both an
# OpenAI-compatible endpoint and an Anthropic-compatible endpoint.
MINIMAX_REGIONAL_ENDPOINTS = {
"global_en": {
"openai_base_url": "https://api.minimax.io/v1",
"anthropic_base_url": "https://api.minimax.io/anthropic",
},
"cn_zh": {
"openai_base_url": "https://api.minimaxi.com/v1",
"anthropic_base_url": "https://api.minimaxi.com/anthropic",
},
}

DEFAULT_MINIMAX_REGION = "global_en"

# Supported compatibility routes.
MINIMAX_APIS = ("openai", "anthropic")
DEFAULT_MINIMAX_API = "openai"

# Current MiniMax chat models, used as a fallback when live discovery is unavailable.
MINIMAX_MODELS = ["MiniMax-M3", "MiniMax-M2.7"]
DEFAULT_MINIMAX_MODEL = "MiniMax-M3"


class AssistantChatMiniMax(ChatOpenAI, BaseAssistantChat):
"""MiniMax chat model over the OpenAI-compatible route with LangGraph support."""

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.initialize_conversation(self)

def describe(self) -> Dict[str, Any]:
base_desc = super().describe()
return {**base_desc, "model": self.model_name, "base_url": self.openai_api_base}


class AssistantChatMiniMaxAnthropic(ChatAnthropic, BaseAssistantChat):
"""MiniMax chat model over the Anthropic-compatible route with LangGraph support."""

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.initialize_conversation(self)

def describe(self) -> Dict[str, Any]:
base_desc = super().describe()
return {**base_desc, "model": self.model}


def _resolve_region(region: str) -> Dict[str, str]:
if region not in MINIMAX_REGIONAL_ENDPOINTS:
raise ValueError(
f"Invalid MiniMax region: {region}. Must be one of {list(MINIMAX_REGIONAL_ENDPOINTS)}"
)
return MINIMAX_REGIONAL_ENDPOINTS[region]


def get_minimax_models(region: str = DEFAULT_MINIMAX_REGION) -> List[str]:
"""Get available MiniMax models via the OpenAI-compatible route with a static fallback."""
endpoints = _resolve_region(region)
try:
client = OpenAI(api_key=os.environ.get("MINIMAX_API_KEY"), base_url=endpoints["openai_base_url"])
models = client.models.list()
discovered = [model.id for model in models.data if model.id.startswith("MiniMax")]
if discovered:
return discovered
except Exception as e:
logger.warning(f"Failed to fetch MiniMax models: {e}")
return list(MINIMAX_MODELS)


def create_minimax_chat(config, session_name: str) -> Union[AssistantChatMiniMax, AssistantChatMiniMaxAnthropic]:
"""Create a MiniMax chat model instance for the selected regional and compatibility route."""
model = config.model

if "MINIMAX_API_KEY" not in os.environ:
raise ValueError("MiniMax API key not found in environment")

region = getattr(config, "region", DEFAULT_MINIMAX_REGION)
endpoints = _resolve_region(region)

api = getattr(config, "api", DEFAULT_MINIMAX_API)
if api not in MINIMAX_APIS:
raise ValueError(f"Invalid MiniMax api: {api}. Must be one of {list(MINIMAX_APIS)}")

api_key = os.environ["MINIMAX_API_KEY"]
logger.info(f"Using MiniMax model: {model} ({api} route, region {region}) for session: {session_name}")

if api == "anthropic":
kwargs = {
"model": model,
"anthropic_api_key": api_key,
"anthropic_api_url": endpoints["anthropic_base_url"],
"session_name": session_name,
"max_tokens": config.max_tokens,
}

if hasattr(config, "temperature"):
kwargs["temperature"] = config.temperature

if hasattr(config, "verbose"):
kwargs["verbose"] = config.verbose

if hasattr(config, "thinking") and hasattr(config.thinking, "enabled"):
kwargs["thinking"] = config.thinking

return AssistantChatMiniMaxAnthropic(**kwargs)

kwargs = {
"model_name": model,
"openai_api_key": api_key,
"openai_api_base": endpoints["openai_base_url"],
"session_name": session_name,
"max_tokens": config.max_tokens,
}

if hasattr(config, "temperature"):
kwargs["temperature"] = config.temperature

if hasattr(config, "verbose"):
kwargs["verbose"] = config.verbose

return AssistantChatMiniMax(**kwargs)
Empty file added tests/unittests/llm/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions tests/unittests/llm/test_minimax_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest

# These imports pull in optional heavy runtime dependencies; skip the whole
# module when they are unavailable so the suite still collects cleanly.
pytest.importorskip("langchain_openai")
pytest.importorskip("langchain_anthropic")
pytest.importorskip("langchain_aws")
pytest.importorskip("langgraph")


def test_minimax_is_registered_provider():
from autogluon.assistant.llm.llm_factory import ChatLLMFactory

assert "minimax" in ChatLLMFactory.get_valid_providers()


def test_minimax_regional_endpoints():
from autogluon.assistant.llm.minimax_chat import MINIMAX_REGIONAL_ENDPOINTS

assert set(MINIMAX_REGIONAL_ENDPOINTS) == {"global_en", "cn_zh"}
assert MINIMAX_REGIONAL_ENDPOINTS["global_en"]["openai_base_url"] == "https://api.minimax.io/v1"
assert MINIMAX_REGIONAL_ENDPOINTS["global_en"]["anthropic_base_url"] == "https://api.minimax.io/anthropic"
assert MINIMAX_REGIONAL_ENDPOINTS["cn_zh"]["openai_base_url"] == "https://api.minimaxi.com/v1"
assert MINIMAX_REGIONAL_ENDPOINTS["cn_zh"]["anthropic_base_url"] == "https://api.minimaxi.com/anthropic"


def test_minimax_models_include_current_releases():
from autogluon.assistant.llm.minimax_chat import DEFAULT_MINIMAX_MODEL, MINIMAX_MODELS

assert DEFAULT_MINIMAX_MODEL == "MiniMax-M3"
assert "MiniMax-M3" in MINIMAX_MODELS
assert "MiniMax-M2.7" in MINIMAX_MODELS
Loading