-
-
Notifications
You must be signed in to change notification settings - Fork 982
feat: add MiniMax as native AI provider #414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| { | ||
| "_README": { | ||
| "description": "Model metadata for MiniMax API access.", | ||
| "documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md", | ||
| "usage": "Models listed here are exposed directly through the MiniMax provider. Aliases are case-insensitive.", | ||
| "field_notes": "Matches providers/shared/model_capabilities.py.", | ||
| "field_descriptions": { | ||
| "model_name": "The model identifier (e.g., 'MiniMax-M2.5', 'MiniMax-M2')", | ||
| "aliases": "Array of short names users can type instead of the full model name", | ||
| "context_window": "Total number of tokens the model can process (input + output combined)", | ||
| "max_output_tokens": "Maximum number of tokens the model can generate in a single response", | ||
| "supports_extended_thinking": "Whether the model supports extended reasoning tokens (MiniMax uses reasoning_split instead)", | ||
| "supports_json_mode": "Whether the model can guarantee valid JSON output", | ||
| "supports_function_calling": "Whether the model supports function/tool calling", | ||
| "supports_images": "Whether the model can process images/visual input", | ||
| "supports_temperature": "Whether the model accepts temperature parameter in API calls", | ||
| "description": "Human-readable description of the model", | ||
| "intelligence_score": "1-20 human rating used as the primary signal for auto-mode model ordering" | ||
| } | ||
| }, | ||
| "models": [ | ||
| { | ||
| "model_name": "MiniMax-M2.5", | ||
| "friendly_name": "MiniMax (M2.5)", | ||
| "aliases": [ | ||
| "m2.5", | ||
| "minimax", | ||
| "minimax-m2.5" | ||
| ], | ||
| "intelligence_score": 16, | ||
| "description": "MiniMax M2.5 (196K context) - Frontier reasoning model with tool calling", | ||
| "context_window": 196608, | ||
| "max_output_tokens": 196608, | ||
| "supports_extended_thinking": false, | ||
| "supports_system_prompts": true, | ||
| "supports_streaming": true, | ||
| "supports_function_calling": true, | ||
| "supports_json_mode": true, | ||
| "supports_images": false, | ||
| "supports_temperature": true | ||
| }, | ||
| { | ||
| "model_name": "MiniMax-M2.5-highspeed", | ||
| "friendly_name": "MiniMax (M2.5 Highspeed)", | ||
| "aliases": [ | ||
| "m2.5-fast", | ||
| "m2.5-highspeed", | ||
| "minimax-m2.5-fast" | ||
| ], | ||
| "intelligence_score": 15, | ||
| "description": "MiniMax M2.5 Highspeed (204K context) - Fast reasoning model", | ||
| "context_window": 204800, | ||
| "max_output_tokens": 100000, | ||
| "supports_extended_thinking": false, | ||
| "supports_system_prompts": true, | ||
| "supports_streaming": true, | ||
| "supports_function_calling": true, | ||
| "supports_json_mode": true, | ||
| "supports_images": false, | ||
| "supports_temperature": true | ||
| }, | ||
| { | ||
| "model_name": "MiniMax-M2.1", | ||
| "friendly_name": "MiniMax (M2.1)", | ||
| "aliases": [ | ||
| "m2.1", | ||
| "minimax-m2.1" | ||
| ], | ||
| "intelligence_score": 15, | ||
| "description": "MiniMax M2.1 (204K context) - Advanced reasoning model with tool calling", | ||
| "context_window": 204800, | ||
| "max_output_tokens": 100000, | ||
| "supports_extended_thinking": false, | ||
| "supports_system_prompts": true, | ||
| "supports_streaming": true, | ||
| "supports_function_calling": true, | ||
| "supports_json_mode": true, | ||
| "supports_images": false, | ||
| "supports_temperature": true | ||
| }, | ||
| { | ||
| "model_name": "MiniMax-M2.1-highspeed", | ||
| "friendly_name": "MiniMax (M2.1 Highspeed)", | ||
| "aliases": [ | ||
| "m2.1-fast", | ||
| "m2.1-highspeed", | ||
| "minimax-m2.1-fast" | ||
| ], | ||
| "intelligence_score": 14, | ||
| "description": "MiniMax M2.1 Highspeed (204K context) - Fast reasoning model", | ||
| "context_window": 204800, | ||
| "max_output_tokens": 100000, | ||
| "supports_extended_thinking": false, | ||
| "supports_system_prompts": true, | ||
| "supports_streaming": true, | ||
| "supports_function_calling": true, | ||
| "supports_json_mode": true, | ||
| "supports_images": false, | ||
| "supports_temperature": true | ||
| }, | ||
| { | ||
| "model_name": "MiniMax-M2", | ||
| "friendly_name": "MiniMax (M2)", | ||
| "aliases": [ | ||
| "m2", | ||
| "minimax-m2" | ||
| ], | ||
| "intelligence_score": 13, | ||
| "description": "MiniMax M2 (204K context) - Capable reasoning model with tool calling", | ||
| "context_window": 204800, | ||
| "max_output_tokens": 100000, | ||
| "supports_extended_thinking": false, | ||
| "supports_system_prompts": true, | ||
| "supports_streaming": true, | ||
| "supports_function_calling": true, | ||
| "supports_json_mode": true, | ||
| "supports_images": false, | ||
| "supports_temperature": true | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| """MiniMax model provider implementation.""" | ||
|
|
||
| import logging | ||
| from typing import TYPE_CHECKING, ClassVar, Optional | ||
|
|
||
| if TYPE_CHECKING: | ||
| from tools.models import ToolModelCategory | ||
|
|
||
| from .openai_compatible import OpenAICompatibleProvider | ||
| from .registries.minimax import MiniMaxModelRegistry | ||
| from .registry_provider_mixin import RegistryBackedProviderMixin | ||
| from .shared import ModelCapabilities, ProviderType | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class MiniMaxModelProvider(RegistryBackedProviderMixin, OpenAICompatibleProvider): | ||
| """Integration for MiniMax models exposed over an OpenAI-style API. | ||
|
|
||
| Publishes capability metadata for the officially supported deployments and | ||
| maps tool-category preferences to the appropriate MiniMax model. | ||
| """ | ||
|
|
||
| FRIENDLY_NAME = "MiniMax" | ||
|
|
||
| REGISTRY_CLASS = MiniMaxModelRegistry | ||
| MODEL_CAPABILITIES: ClassVar[dict[str, ModelCapabilities]] = {} | ||
|
|
||
| # Canonical model identifiers used for category routing. | ||
| PRIMARY_MODEL = "MiniMax-M2.5" | ||
| FAST_MODEL = "MiniMax-M2.5-highspeed" | ||
|
|
||
| def __init__(self, api_key: str, **kwargs): | ||
| """Initialize MiniMax provider with API key.""" | ||
| # Set MiniMax base URL | ||
| kwargs.setdefault("base_url", "https://api.minimax.io/v1") | ||
| self._ensure_registry() | ||
| super().__init__(api_key, **kwargs) | ||
| self._invalidate_capability_cache() | ||
|
|
||
| def get_provider_type(self) -> ProviderType: | ||
| """Get the provider type.""" | ||
| return ProviderType.MINIMAX | ||
|
|
||
| def get_preferred_model(self, category: "ToolModelCategory", allowed_models: list[str]) -> Optional[str]: | ||
| """Get MiniMax's preferred model for a given category from allowed models. | ||
|
|
||
| Args: | ||
| category: The tool category requiring a model | ||
| allowed_models: Pre-filtered list of models allowed by restrictions | ||
|
|
||
| Returns: | ||
| Preferred model name or None | ||
| """ | ||
| from tools.models import ToolModelCategory | ||
|
|
||
| if not allowed_models: | ||
| return None | ||
|
|
||
| if category == ToolModelCategory.EXTENDED_REASONING: | ||
| # Prefer M2.5 for advanced reasoning tasks | ||
| if self.PRIMARY_MODEL in allowed_models: | ||
| return self.PRIMARY_MODEL | ||
| if self.FAST_MODEL in allowed_models: | ||
| return self.FAST_MODEL | ||
| return allowed_models[0] | ||
|
|
||
| elif category == ToolModelCategory.FAST_RESPONSE: | ||
| # Prefer M2.5-highspeed for speed | ||
| if self.FAST_MODEL in allowed_models: | ||
| return self.FAST_MODEL | ||
| if self.PRIMARY_MODEL in allowed_models: | ||
| return self.PRIMARY_MODEL | ||
| return allowed_models[0] | ||
|
|
||
| else: # BALANCED or default | ||
| # Prefer M2.5 for balanced use | ||
| if self.PRIMARY_MODEL in allowed_models: | ||
| return self.PRIMARY_MODEL | ||
| if self.FAST_MODEL in allowed_models: | ||
| return self.FAST_MODEL | ||
| return allowed_models[0] | ||
|
|
||
|
|
||
| # Load registry data at import time | ||
| MiniMaxModelProvider._ensure_registry() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| """Registry loader for MiniMax model capabilities.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from ..shared import ProviderType | ||
| from .base import CapabilityModelRegistry | ||
|
|
||
|
|
||
| class MiniMaxModelRegistry(CapabilityModelRegistry): | ||
| """Capability registry backed by ``conf/minimax_models.json``.""" | ||
|
|
||
| def __init__(self, config_path: str | None = None) -> None: | ||
| super().__init__( | ||
| env_var_name="MINIMAX_MODELS_CONFIG_PATH", | ||
| default_filename="minimax_models.json", | ||
| provider=ProviderType.MINIMAX, | ||
| friendly_prefix="MiniMax ({model})", | ||
| config_path=config_path, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,7 @@ class ModelProviderRegistry: | |
| ProviderType.OPENAI, # Direct OpenAI access | ||
| ProviderType.AZURE, # Azure-hosted OpenAI deployments | ||
| ProviderType.XAI, # Direct X.AI GROK access | ||
| ProviderType.MINIMAX, # Direct MiniMax access | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By adding Useful? React with 👍 / 👎. |
||
| ProviderType.DIAL, # DIAL unified API access | ||
| ProviderType.CUSTOM, # Local/self-hosted models | ||
| ProviderType.OPENROUTER, # Catch-all for cloud models | ||
|
|
@@ -336,6 +337,7 @@ def _get_api_key_for_provider(cls, provider_type: ProviderType) -> Optional[str] | |
| ProviderType.OPENAI: "OPENAI_API_KEY", | ||
| ProviderType.AZURE: "AZURE_OPENAI_API_KEY", | ||
| ProviderType.XAI: "XAI_API_KEY", | ||
| ProviderType.MINIMAX: "MINIMAX_API_KEY", | ||
| ProviderType.OPENROUTER: "OPENROUTER_API_KEY", | ||
| ProviderType.CUSTOM: "CUSTOM_API_KEY", # Can be empty for providers that don't need auth | ||
| ProviderType.DIAL: "DIAL_API_KEY", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for selecting a preferred model is a bit repetitive across the different categories. The
EXTENDED_REASONINGandBALANCEDcategories have identical logic, and theFAST_RESPONSEcategory just swaps the preference order. You can simplify this by defining the preference order in a list and then iterating through it to make the code more concise and maintainable.