mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-06-16 21:06:15 +03:00
The OpenAI-compatible family (openai, xAI, DeepSeek, Qwen, GLM, MiniMax, OpenRouter, Ollama) all speak the same Chat Completions API and differ only by base_url, key, and two narrow wire-format quirks already isolated in subclasses. Replace the scattered base-URL dict, key handling, and client-class branches with one ProviderSpec registry that get_llm and the factory drive off; provider quirks stay in their subclasses. Add a generic "openai_compatible" provider for any OpenAI-compatible server (vLLM, LM Studio, llama.cpp, relays) via backend_url + optional key — adding a provider is now one registry row. Native Anthropic/Google keep their own clients (genuinely different APIs). Also fixes the env backend URL being ignored when the provider was chosen interactively (#978).
56 lines
2.5 KiB
Python
56 lines
2.5 KiB
Python
"""The OpenAI-compatible provider registry is the single source of truth for the
|
|
family; this guards each provider's resolved config (base URL, subclass, auth,
|
|
Responses API) so a future edit can't silently break one.
|
|
"""
|
|
import pytest
|
|
|
|
from tradingagents.llm_clients.openai_client import (
|
|
OPENAI_COMPATIBLE_PROVIDERS,
|
|
DeepSeekChatOpenAI,
|
|
MinimaxChatOpenAI,
|
|
NormalizedChatOpenAI,
|
|
is_openai_compatible,
|
|
)
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_registry_membership():
|
|
assert is_openai_compatible("openai")
|
|
assert is_openai_compatible("openai_compatible") # the generic endpoint
|
|
# native (different API) clients are intentionally NOT in the registry
|
|
assert not is_openai_compatible("anthropic")
|
|
assert not is_openai_compatible("google")
|
|
assert not is_openai_compatible("azure")
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize("provider,base_url,chat_class,responses", [
|
|
("openai", None, NormalizedChatOpenAI, True),
|
|
("xai", "https://api.x.ai/v1", NormalizedChatOpenAI, False),
|
|
("deepseek", "https://api.deepseek.com", DeepSeekChatOpenAI, False),
|
|
("qwen", "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", NormalizedChatOpenAI, False),
|
|
("qwen-cn", "https://dashscope.aliyuncs.com/compatible-mode/v1", NormalizedChatOpenAI, False),
|
|
("glm", "https://api.z.ai/api/paas/v4/", NormalizedChatOpenAI, False),
|
|
("glm-cn", "https://open.bigmodel.cn/api/paas/v4/", NormalizedChatOpenAI, False),
|
|
("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),
|
|
("ollama", "http://localhost:11434/v1", NormalizedChatOpenAI, False),
|
|
])
|
|
def test_registry_spec(provider, base_url, chat_class, responses):
|
|
spec = OPENAI_COMPATIBLE_PROVIDERS[provider]
|
|
assert spec.base_url == base_url
|
|
assert spec.chat_class is chat_class
|
|
assert spec.use_responses_api is responses
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_key_optionality():
|
|
# Local/generic endpoints are key-optional; hosted APIs require a key.
|
|
assert OPENAI_COMPATIBLE_PROVIDERS["ollama"].key_optional is True
|
|
assert OPENAI_COMPATIBLE_PROVIDERS["openai_compatible"].key_optional is True
|
|
assert OPENAI_COMPATIBLE_PROVIDERS["openai_compatible"].require_base_url is True
|
|
assert OPENAI_COMPATIBLE_PROVIDERS["xai"].key_optional is False
|
|
# OLLAMA_BASE_URL is the only base-URL env override.
|
|
assert OPENAI_COMPATIBLE_PROVIDERS["ollama"].base_url_env == "OLLAMA_BASE_URL"
|