101 lines
3.3 KiB
Python
101 lines
3.3 KiB
Python
"""
|
||
Provider preset system for ViMax chat model configuration.
|
||
|
||
Supports auto-detection and resolution of LLM provider settings,
|
||
allowing users to specify a provider name (e.g., ``minimax``) instead
|
||
of manually configuring base_url and model details.
|
||
"""
|
||
|
||
import os
|
||
import logging
|
||
from typing import Dict, Any, Optional
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Provider presets
|
||
# ---------------------------------------------------------------------------
|
||
|
||
PROVIDER_PRESETS: Dict[str, Dict[str, Any]] = {
|
||
"minimax": {
|
||
"base_url": "https://api.minimax.io/v1",
|
||
"env_key": "MINIMAX_API_KEY",
|
||
"default_model": "MiniMax-M3",
|
||
"models": [
|
||
"MiniMax-M3",
|
||
"MiniMax-M2.7",
|
||
"MiniMax-M2.7-highspeed",
|
||
],
|
||
"temperature_range": (0.0, 1.0),
|
||
},
|
||
}
|
||
|
||
|
||
def resolve_chat_model_config(init_args: Dict[str, Any]) -> Dict[str, Any]:
|
||
"""Resolve provider presets and return final ``init_chat_model`` kwargs.
|
||
|
||
If ``model_provider`` matches a known preset (e.g. ``minimax``), the
|
||
returned dict will have:
|
||
|
||
* ``model_provider`` rewritten to ``"openai"`` (OpenAI-compatible API)
|
||
* ``base_url`` filled in from the preset when not already set
|
||
* ``api_key`` sourced from the environment when not already set
|
||
* ``model`` defaulted to the preset's default model when not already set
|
||
* ``temperature`` clamped to the provider's supported range
|
||
|
||
For unknown providers the dict is returned unchanged.
|
||
"""
|
||
args = dict(init_args) # shallow copy
|
||
provider = args.get("model_provider", "openai")
|
||
|
||
preset = PROVIDER_PRESETS.get(provider)
|
||
if preset is None:
|
||
return args
|
||
|
||
# base_url
|
||
if not args.get("base_url"):
|
||
args["base_url"] = preset["base_url"]
|
||
|
||
# api_key – fall back to env var
|
||
if not args.get("api_key"):
|
||
env_key = preset.get("env_key", "")
|
||
env_val = os.environ.get(env_key, "")
|
||
if env_val:
|
||
args["api_key"] = env_val
|
||
logger.info("Using %s API key from environment variable %s", provider, env_key)
|
||
|
||
# default model
|
||
if not args.get("model"):
|
||
args["model"] = preset["default_model"]
|
||
logger.info("Defaulting to model %s for provider %s", args["model"], provider)
|
||
|
||
# temperature clamping
|
||
temp_range = preset.get("temperature_range")
|
||
if temp_range and "temperature" in args and args["temperature"] is not None:
|
||
lo, hi = temp_range
|
||
original = args["temperature"]
|
||
args["temperature"] = max(lo, min(hi, original))
|
||
if args["temperature"] != original:
|
||
logger.warning(
|
||
"Clamped temperature %.2f -> %.2f for provider %s",
|
||
original, args["temperature"], provider,
|
||
)
|
||
|
||
# rewrite to openai-compatible provider for LangChain
|
||
args["model_provider"] = "openai"
|
||
|
||
return args
|
||
|
||
|
||
def detect_provider_from_env() -> Optional[str]:
|
||
"""Return the name of a provider whose API key is found in the environment.
|
||
|
||
Checks ``PROVIDER_PRESETS`` in definition order and returns the first
|
||
match, or ``None`` if no key is set.
|
||
"""
|
||
for name, preset in PROVIDER_PRESETS.items():
|
||
env_key = preset.get("env_key", "")
|
||
if env_key and os.environ.get(env_key):
|
||
return name
|
||
return None
|