diff --git a/.env.example b/.env.example index 8f321e548..aad73c9ad 100644 --- a/.env.example +++ b/.env.example @@ -11,6 +11,15 @@ ZHIPU_CN_API_KEY= MINIMAX_API_KEY= MINIMAX_CN_API_KEY= OPENROUTER_API_KEY= +MISTRAL_API_KEY= +MOONSHOT_API_KEY= +GROQ_API_KEY= +NVIDIA_API_KEY= + +# Optional: a custom OpenAI-compatible endpoint (vLLM, LM Studio, llama.cpp, +# relay). Select provider "openai_compatible" and set the base URL; the key is +# optional (local servers need none). +#OPENAI_COMPATIBLE_API_KEY= # Optional: point at a remote Ollama server. When unset, defaults to # the local instance at http://localhost:11434/v1. Convention follows diff --git a/README.md b/README.md index a84f1027f..20147d101 100644 --- a/README.md +++ b/README.md @@ -225,7 +225,7 @@ from tradingagents.graph.trading_graph import TradingAgentsGraph from tradingagents.default_config import DEFAULT_CONFIG config = DEFAULT_CONFIG.copy() -config["llm_provider"] = "openai" # openai, google, anthropic, xai, deepseek, qwen, qwen-cn, glm, glm-cn, minimax, minimax-cn, openrouter, ollama, azure +config["llm_provider"] = "openai" # e.g. openai, google, anthropic, deepseek, groq, ollama; openai_compatible covers any OpenAI-compatible endpoint (vLLM, LM Studio, llama.cpp, ...) config["deep_think_llm"] = "gpt-5.5" # Model for complex reasoning config["quick_think_llm"] = "gpt-5.4-mini" # Model for quick tasks config["max_debate_rounds"] = 2 diff --git a/cli/utils.py b/cli/utils.py index 6054956ce..3ee2d25c7 100644 --- a/cli/utils.py +++ b/cli/utils.py @@ -311,6 +311,10 @@ def _llm_provider_table() -> list[tuple[str, str, str | None]]: ("GLM", "glm", "https://open.bigmodel.cn/api/paas/v4/"), ("MiniMax", "minimax", "https://api.minimax.io/v1"), ("OpenRouter", "openrouter", "https://openrouter.ai/api/v1"), + ("Mistral", "mistral", "https://api.mistral.ai/v1"), + ("Kimi (Moonshot)", "kimi", "https://api.moonshot.ai/v1"), + ("Groq", "groq", "https://api.groq.com/openai/v1"), + ("NVIDIA NIM", "nvidia", "https://integrate.api.nvidia.com/v1"), ("Azure OpenAI", "azure", None), ("Ollama", "ollama", ollama_url), ("OpenAI-compatible (vLLM, LM Studio, llama.cpp, custom relay)", "openai_compatible", None), diff --git a/tests/test_provider_registry.py b/tests/test_provider_registry.py index 23f36c060..596108a77 100644 --- a/tests/test_provider_registry.py +++ b/tests/test_provider_registry.py @@ -35,6 +35,10 @@ def test_registry_membership(): ("minimax", "https://api.minimax.io/v1", MinimaxChatOpenAI, False), ("minimax-cn", "https://api.minimaxi.com/v1", MinimaxChatOpenAI, False), ("openrouter", "https://openrouter.ai/api/v1", NormalizedChatOpenAI, False), + ("mistral", "https://api.mistral.ai/v1", NormalizedChatOpenAI, False), + ("kimi", "https://api.moonshot.ai/v1", NormalizedChatOpenAI, False), + ("groq", "https://api.groq.com/openai/v1", NormalizedChatOpenAI, False), + ("nvidia", "https://integrate.api.nvidia.com/v1", NormalizedChatOpenAI, False), ("ollama", "http://localhost:11434/v1", NormalizedChatOpenAI, False), ]) def test_registry_spec(provider, base_url, chat_class, responses): diff --git a/tradingagents/llm_clients/api_key_env.py b/tradingagents/llm_clients/api_key_env.py index c9353963a..4d909c400 100644 --- a/tradingagents/llm_clients/api_key_env.py +++ b/tradingagents/llm_clients/api_key_env.py @@ -30,6 +30,12 @@ PROVIDER_API_KEY_ENV: dict[str, Optional[str]] = { "minimax": "MINIMAX_API_KEY", "minimax-cn": "MINIMAX_CN_API_KEY", "openrouter": "OPENROUTER_API_KEY", + # Additional hosted OpenAI-compatible providers (model is user-specified). + # kimi -> Moonshot AI; nvidia -> NVIDIA NIM. + "mistral": "MISTRAL_API_KEY", + "kimi": "MOONSHOT_API_KEY", + "groq": "GROQ_API_KEY", + "nvidia": "NVIDIA_API_KEY", # Local runtimes do not authenticate. "ollama": None, # Generic OpenAI-compatible endpoint: the client reads this when set (keyed diff --git a/tradingagents/llm_clients/model_catalog.py b/tradingagents/llm_clients/model_catalog.py index e25e2feeb..f1fc45b09 100644 --- a/tradingagents/llm_clients/model_catalog.py +++ b/tradingagents/llm_clients/model_catalog.py @@ -7,6 +7,13 @@ from typing import Dict, List, Tuple ModelOption = Tuple[str, str] ProviderModeOptions = Dict[str, Dict[str, List[ModelOption]]] +# Providers that serve many / frequently-changing models: offer only "Custom +# model ID" rather than a list that goes stale. +_CUSTOM_ONLY: Dict[str, List[ModelOption]] = { + "quick": [("Custom model ID", "custom")], + "deep": [("Custom model ID", "custom")], +} + # Shared model list for GLM via Z.AI (international) and BigModel (China). # Source: docs.z.ai (GLM Coding Plan supported models + LLM guides). @@ -177,10 +184,15 @@ MODEL_OPTIONS: ProviderModeOptions = { }, # Generic OpenAI-compatible endpoint: the model is whatever the user's # server serves, so only "Custom model ID" is offered. - "openai_compatible": { - "quick": [("Custom model ID", "custom")], - "deep": [("Custom model ID", "custom")], - }, + "openai_compatible": _CUSTOM_ONLY, + # Hosted OpenAI-compatible providers that serve many (and frequently + # changing) models — offer "Custom model ID" rather than a list that goes + # stale. The endpoint + key are wired by the provider; the user picks the + # model their account has access to. + "mistral": _CUSTOM_ONLY, + "kimi": _CUSTOM_ONLY, + "groq": _CUSTOM_ONLY, + "nvidia": _CUSTOM_ONLY, } diff --git a/tradingagents/llm_clients/openai_client.py b/tradingagents/llm_clients/openai_client.py index 262a6e55a..8aaa988df 100644 --- a/tradingagents/llm_clients/openai_client.py +++ b/tradingagents/llm_clients/openai_client.py @@ -189,6 +189,10 @@ OPENAI_COMPATIBLE_PROVIDERS: dict[str, ProviderSpec] = { "minimax": ProviderSpec(base_url="https://api.minimax.io/v1", chat_class=MinimaxChatOpenAI), "minimax-cn": ProviderSpec(base_url="https://api.minimaxi.com/v1", chat_class=MinimaxChatOpenAI), "openrouter": ProviderSpec(base_url="https://openrouter.ai/api/v1"), + "mistral": ProviderSpec(base_url="https://api.mistral.ai/v1"), + "kimi": ProviderSpec(base_url="https://api.moonshot.ai/v1"), + "groq": ProviderSpec(base_url="https://api.groq.com/openai/v1"), + "nvidia": ProviderSpec(base_url="https://integrate.api.nvidia.com/v1"), "ollama": ProviderSpec(base_url="http://localhost:11434/v1", base_url_env="OLLAMA_BASE_URL", key_optional=True, placeholder_key="ollama"), # Generic endpoint: user supplies base_url; key optional (keyless local). diff --git a/tradingagents/llm_clients/validators.py b/tradingagents/llm_clients/validators.py index 8d04a9384..bed09a51a 100644 --- a/tradingagents/llm_clients/validators.py +++ b/tradingagents/llm_clients/validators.py @@ -3,9 +3,13 @@ from .model_catalog import get_known_models -# Providers whose model names are user-defined (local servers, relays, any -# OpenAI-compatible endpoint), so any model string is accepted without warning. -_ANY_MODEL_PROVIDERS = ("ollama", "openrouter", "openai_compatible") +# Providers whose model names are user-defined (local servers, relays, hosted +# OpenAI-compatible endpoints serving many models), so any model string is +# accepted without warning. +_ANY_MODEL_PROVIDERS = ( + "ollama", "openrouter", "openai_compatible", + "mistral", "kimi", "groq", "nvidia", +) VALID_MODELS = { provider: models