Files
opensquilla--opensquilla/tests/test_provider_mainstream_profiles.py
2026-07-13 13:12:33 +08:00

374 lines
14 KiB
Python

from __future__ import annotations
import pytest
from opensquilla.provider.anthropic import AnthropicProvider
from opensquilla.provider.openai import OpenAIProvider
from opensquilla.provider.openai_responses import OpenAIResponsesProvider
from opensquilla.provider.registry import get_provider_spec
from opensquilla.provider.selector import ProviderBuildError, ProviderConfig, _build_provider
@pytest.mark.parametrize(
("provider", "provider_kind"),
[
("deepseek", "deepseek"),
("gemini", "gemini"),
("dashscope", "dashscope"),
("bailian_coding", "bailian_coding"),
("moonshot", "moonshot"),
("kimi_coding_openai", "moonshot"),
("minimax_coding_openai", "minimax"),
("mimo_openai", "mimo"),
("mistral", "mistral"),
("groq", "groq"),
("zhipu", "zhipu"),
("siliconflow", "siliconflow"),
("volcengine", "volcengine"),
("byteplus", "byteplus"),
("tencent_tokenhub", "tencent_tokenhub"),
("tencent_tokenhub_intl", "tencent_tokenhub"),
("tencent_token_plan", "tencent_tokenhub"),
("tokenrhythm", "tokenrhythm"),
("qianfan", "qianfan"),
("aihubmix", "aihubmix"),
("lm_studio", "lm_studio"),
("ovms", "ovms"),
],
)
def test_new_openai_compatible_profiles_have_vendor_provider_kind(
provider: str,
provider_kind: str,
) -> None:
assert get_provider_spec(provider).provider_kind == provider_kind
@pytest.mark.parametrize(
("provider", "env_key", "base_url"),
[
("deepseek", "DEEPSEEK_API_KEY", "https://api.deepseek.com"),
(
"gemini",
"GEMINI_API_KEY",
"https://generativelanguage.googleapis.com/v1beta/openai",
),
("dashscope", "DASHSCOPE_API_KEY", "https://dashscope.aliyuncs.com/compatible-mode/v1"),
(
"bailian_coding",
"BAILIAN_API_KEY",
"https://coding-intl.dashscope.aliyuncs.com/v1",
),
("moonshot", "MOONSHOT_API_KEY", "https://api.moonshot.ai/v1"),
(
"kimi_coding_openai",
"KIMI_CODING_API_KEY",
"https://api.kimi.com/coding/v1",
),
(
"minimax_coding_openai",
"MINIMAX_CODING_API_KEY",
"https://api.minimaxi.com/v1",
),
(
"mimo_openai",
"MIMO_API_KEY",
"https://token-plan-cn.xiaomimimo.com/v1",
),
("mistral", "MISTRAL_API_KEY", "https://api.mistral.ai/v1"),
("groq", "GROQ_API_KEY", "https://api.groq.com/openai/v1"),
("zhipu", "ZAI_API_KEY", "https://open.bigmodel.cn/api/paas/v4"),
("siliconflow", "SILICONFLOW_API_KEY", "https://api.siliconflow.cn/v1"),
("volcengine", "VOLCENGINE_API_KEY", "https://ark.cn-beijing.volces.com/api/v3"),
("byteplus", "BYTEPLUS_API_KEY", "https://ark.ap-southeast.bytepluses.com/api/v3"),
("tencent_tokenhub", "TENCENT_TOKENHUB_API_KEY", "https://tokenhub.tencentmaas.com/v1"),
(
"tencent_tokenhub_intl",
"TENCENT_TOKENHUB_INTL_API_KEY",
"https://tokenhub-intl.tencentcloudmaas.com/v1",
),
(
"tencent_token_plan",
"TENCENT_TOKEN_PLAN_API_KEY",
"https://api.lkeap.cloud.tencent.com/plan/v3",
),
("tokenrhythm", "TOKENRHYTHM_API_KEY", "https://tokenrhythm.studio/v1"),
("qianfan", "QIANFAN_API_KEY", "https://qianfan.baidubce.com/v2"),
("aihubmix", "AIHUBMIX_API_KEY", "https://aihubmix.com/v1"),
("lm_studio", "", "http://localhost:1234/v1"),
("ovms", "", "http://localhost:8000/v3"),
],
)
def test_openai_compatible_profiles_have_documented_config(
provider: str,
env_key: str,
base_url: str,
) -> None:
spec = get_provider_spec(provider)
assert spec.backend == "openai_compat"
assert spec.env_key == env_key
assert spec.default_base_url == base_url
expected_required = frozenset({"model"}) if not env_key else frozenset({"api_key", "model"})
assert spec.required_fields == expected_required
def test_tencent_tokenhub_profiles_pin_documented_endpoints() -> None:
"""The TokenHub trio maps Tencent's documented per-protocol endpoints:
OpenAI protocol on <host>/v1, Anthropic Messages on the bare host
(x-api-key auth), and the international deployment on the separate
tencentcloudmaas.com domain with its own account/key system."""
cn = get_provider_spec("tencent_tokenhub")
assert cn.backend == "openai_compat"
assert cn.provider_kind == "tencent_tokenhub"
assert cn.env_key == "TENCENT_TOKENHUB_API_KEY"
assert cn.default_base_url == "https://tokenhub.tencentmaas.com/v1"
assert cn.catalog_source == ("tencent-tokenhub",)
anthropic_compat = get_provider_spec("tencent_tokenhub_anthropic")
assert anthropic_compat.backend == "anthropic"
assert anthropic_compat.provider_kind == "tencent_tokenhub"
assert anthropic_compat.env_key == "TENCENT_TOKENHUB_API_KEY"
assert anthropic_compat.default_base_url == "https://tokenhub.tencentmaas.com"
assert anthropic_compat.failure_family == "anthropic"
assert anthropic_compat.auth_header_style == "x-api-key"
intl = get_provider_spec("tencent_tokenhub_intl")
assert intl.backend == "openai_compat"
assert intl.provider_kind == "tencent_tokenhub"
assert intl.env_key == "TENCENT_TOKENHUB_INTL_API_KEY"
assert intl.default_base_url == "https://tokenhub-intl.tencentcloudmaas.com/v1"
assert intl.catalog_source == ()
def test_tencent_token_plan_profiles_pin_documented_endpoints() -> None:
"""The Token Plan subscription lives on the lkeap host with dedicated
sk-tp keys: Chat Completions at /plan/v3 and Anthropic Messages at
/plan/anthropic (bearer auth per Tencent's tool guides)."""
plan = get_provider_spec("tencent_token_plan")
assert plan.backend == "openai_compat"
assert plan.provider_kind == "tencent_tokenhub"
assert plan.env_key == "TENCENT_TOKEN_PLAN_API_KEY"
assert plan.default_base_url == "https://api.lkeap.cloud.tencent.com/plan/v3"
assert plan.capabilities == frozenset({"chat", "coding_plan"})
assert plan.catalog_source == ("tencent-token-plan",)
plan_anthropic = get_provider_spec("tencent_token_plan_anthropic")
assert plan_anthropic.backend == "anthropic"
assert plan_anthropic.provider_kind == "tencent_tokenhub"
assert plan_anthropic.env_key == "TENCENT_TOKEN_PLAN_API_KEY"
assert plan_anthropic.default_base_url == "https://api.lkeap.cloud.tencent.com/plan/anthropic"
assert plan_anthropic.failure_family == "anthropic"
assert plan_anthropic.auth_header_style == "bearer"
assert plan_anthropic.capabilities == frozenset({"chat", "coding_plan"})
def test_model_selector_builds_tencent_token_plan_providers() -> None:
chat = _build_provider(
ProviderConfig(provider="tencent_token_plan", model="hy3", api_key="test-key")
)
assert isinstance(chat, OpenAIProvider)
messages = _build_provider(
ProviderConfig(provider="tencent_token_plan_anthropic", model="hy3", api_key="test-key")
)
assert isinstance(messages, AnthropicProvider)
def test_model_selector_builds_tencent_tokenhub_anthropic_provider() -> None:
built = _build_provider(
ProviderConfig(provider="tencent_tokenhub_anthropic", model="hy3", api_key="test-key")
)
assert isinstance(built, AnthropicProvider)
def test_minimax_mainland_profile_uses_anthropic_compatible_endpoint() -> None:
spec = get_provider_spec("minimax")
assert spec.backend == "anthropic"
assert spec.provider_kind == "minimax"
assert spec.env_key == "MINIMAX_API_KEY"
assert spec.default_base_url == "https://api.minimaxi.com/anthropic"
assert spec.failure_family == "anthropic"
def test_minimax_region_profiles_are_explicit_anthropic_compatible_endpoints() -> None:
mainland = get_provider_spec("minimax_cn")
global_ = get_provider_spec("minimax_global")
assert mainland.backend == "anthropic"
assert mainland.provider_kind == "minimax"
assert mainland.env_key == "MINIMAX_CN_API_KEY"
assert mainland.default_base_url == "https://api.minimaxi.com/anthropic"
assert mainland.failure_family == "anthropic"
assert global_.backend == "anthropic"
assert global_.provider_kind == "minimax"
assert global_.env_key == "MINIMAX_API_KEY"
assert global_.default_base_url == "https://api.minimax.io/anthropic"
assert global_.failure_family == "anthropic"
def test_kimi_coding_anthropic_profile_is_explicit_anthropic_compatible() -> None:
spec = get_provider_spec("kimi_coding_anthropic")
assert spec.backend == "anthropic"
assert spec.provider_kind == "moonshot"
assert spec.env_key == "KIMI_CODING_API_KEY"
assert spec.default_base_url == "https://api.kimi.com/coding"
assert spec.failure_family == "anthropic"
assert spec.auth_header_style == "bearer"
def test_minimax_coding_anthropic_profile_is_explicit_anthropic_compatible() -> None:
spec = get_provider_spec("minimax_coding_anthropic")
assert spec.backend == "anthropic"
assert spec.provider_kind == "minimax"
assert spec.env_key == "MINIMAX_CODING_API_KEY"
assert spec.default_base_url == "https://api.minimaxi.com/anthropic"
assert spec.failure_family == "anthropic"
assert spec.auth_header_style == "bearer"
def test_mimo_anthropic_profile_is_explicit_anthropic_compatible() -> None:
spec = get_provider_spec("mimo_anthropic")
assert spec.backend == "anthropic"
assert spec.provider_kind == "mimo"
assert spec.env_key == "MIMO_API_KEY"
assert spec.default_base_url == "https://token-plan-cn.xiaomimimo.com/anthropic"
assert spec.failure_family == "anthropic"
assert spec.auth_header_style == "bearer"
@pytest.mark.parametrize(
("provider", "model"),
[
("deepseek", "deepseek-chat"),
("gemini", "gemini-2.5-flash"),
("dashscope", "qwen-plus"),
("bailian_coding", "kimi-k2.5"),
("moonshot", "kimi-k2.5"),
("kimi_coding_openai", "kimi-for-coding"),
("mistral", "mistral-large-latest"),
("groq", "llama-3.3-70b-versatile"),
("zhipu", "glm-4.5"),
("siliconflow", "deepseek-ai/DeepSeek-V3"),
("volcengine", "ark-model-id"),
("byteplus", "ark-endpoint-id"),
("qianfan", "ernie-4.5-turbo-128k"),
("aihubmix", "openai/gpt-5-mini"),
("minimax_openai", "MiniMax-M2.7"),
("minimax_coding_openai", "MiniMax-M2.7"),
("mimo_openai", "mimo-v2.5"),
("tencent_tokenhub", "hy3"),
("tencent_tokenhub_intl", "deepseek-v3.2"),
("tencent_token_plan", "hy3"),
("lm_studio", "local-model"),
("ovms", "llama3"),
],
)
def test_model_selector_builds_registered_openai_compatible_providers(
provider: str,
model: str,
) -> None:
built = _build_provider(ProviderConfig(provider=provider, model=model, api_key="test-key"))
assert isinstance(built, OpenAIProvider)
def test_model_selector_preserves_volcengine_coding_plan_responses_contract() -> None:
spec = get_provider_spec("volcengine_coding_plan")
assert spec.backend == "openai_responses"
assert spec.provider_kind == "volcengine_coding_plan"
assert spec.env_key == "VOLCENGINE_API_KEY"
assert spec.default_base_url == "https://ark.cn-beijing.volces.com/api/coding/v3"
assert spec.capabilities == frozenset({"chat", "coding_plan", "responses"})
built = _build_provider(
ProviderConfig(
provider="volcengine_coding_plan",
model="doubao-seed-2.0-pro",
api_key="test-key",
)
)
assert isinstance(built, OpenAIResponsesProvider)
def test_model_selector_builds_minimax_mainland_anthropic_provider() -> None:
built = _build_provider(
ProviderConfig(provider="minimax", model="MiniMax-M2.7", api_key="test-key")
)
assert isinstance(built, AnthropicProvider)
def test_model_selector_builds_minimax_openai_compatible_provider() -> None:
spec = get_provider_spec("minimax_openai")
assert spec.backend == "openai_compat"
assert spec.provider_kind == "minimax"
assert spec.env_key == "MINIMAX_API_KEY"
assert spec.default_base_url == "https://api.minimax.io/v1"
built = _build_provider(
ProviderConfig(provider="minimax_openai", model="MiniMax-M2.7", api_key="test-key")
)
assert isinstance(built, OpenAIProvider)
@pytest.mark.parametrize("provider", ["minimax_cn", "minimax_global"])
def test_model_selector_builds_explicit_minimax_region_anthropic_providers(
provider: str,
) -> None:
built = _build_provider(
ProviderConfig(provider=provider, model="MiniMax-M2.7", api_key="test-key")
)
assert isinstance(built, AnthropicProvider)
@pytest.mark.parametrize(
("provider", "model"),
[
("kimi_coding_anthropic", "kimi-for-coding"),
("minimax_coding_anthropic", "MiniMax-M2.7"),
("mimo_anthropic", "mimo-v2.5-pro"),
],
)
def test_model_selector_builds_coding_plan_anthropic_providers(
provider: str,
model: str,
) -> None:
built = _build_provider(
ProviderConfig(provider=provider, model=model, api_key="test-key")
)
assert isinstance(built, AnthropicProvider)
def test_vllm_requires_explicit_base_url() -> None:
with pytest.raises(ProviderBuildError, match="requires an explicit base_url"):
_build_provider(ProviderConfig(provider="vllm", model="served-model", api_key="unused"))
built = _build_provider(
ProviderConfig(
provider="vllm",
model="served-model",
api_key="unused",
base_url="http://localhost:8001/v1",
)
)
assert isinstance(built, OpenAIProvider)
def test_azure_default_construction_is_outside_a_stage_support() -> None:
with pytest.raises(ProviderBuildError, match="requires an explicit base_url"):
_build_provider(
ProviderConfig(provider="azure", model="deployment-name", api_key="test-key")
)