core/runtime: map Provider config to protocol clients

create_client supports openai, openai-compatible, and deepseek
(openai convention); anthropic and deepseek anthropic raise.
This commit is contained in:
2026-07-14 17:25:18 +08:00
parent 0c5cc20d0b
commit c129498efa
2 changed files with 73 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
from .client_factory import ProviderNotSupportedError as ProviderNotSupportedError
from .client_factory import create_client as create_client
from .client_factory import provider_to_openai_config as provider_to_openai_config
+70
View File
@@ -0,0 +1,70 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from plyngent.config.models import (
DeepseekProvider,
OpenAICompatibleProvider,
OpenAIProvider,
Provider,
)
from plyngent.lmproto.deepseek import DeepseekOpenAIClient
from plyngent.lmproto.openai_compatible import OpenAIClient, OpenAIConfig
if TYPE_CHECKING:
from collections.abc import Mapping
DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1"
DEFAULT_DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
type OpenAICompatibleClient = OpenAIClient | DeepseekOpenAIClient
class ProviderNotSupportedError(NotImplementedError):
"""Raised when a provider preset cannot be turned into a runtime client."""
def provider_to_openai_config(provider: OpenAIProvider | OpenAICompatibleProvider | DeepseekProvider) -> OpenAIConfig:
"""Map a provider config entry to :class:`OpenAIConfig`."""
if isinstance(provider, OpenAIProvider):
base_url = provider.url or DEFAULT_OPENAI_BASE_URL
elif isinstance(provider, DeepseekProvider):
base_url = provider.url or DEFAULT_DEEPSEEK_BASE_URL
else:
base_url = provider.url
if not base_url:
msg = "openai-compatible provider requires a non-empty url"
raise ProviderNotSupportedError(msg)
return OpenAIConfig(
access_key_or_token=provider.access_key_or_token,
base_url=base_url,
)
def _deepseek_convention(extras: Mapping[str, str]) -> str:
return extras.get("convention", "openai").lower()
def create_client(provider: Provider) -> OpenAICompatibleClient:
"""Build a protocol client for the given provider config entry.
Raises:
ProviderNotSupportedError: When the provider preset (or DeepSeek convention)
has no implemented client yet.
"""
if isinstance(provider, OpenAIProvider):
return OpenAIClient(provider_to_openai_config(provider))
if isinstance(provider, OpenAICompatibleProvider):
return OpenAIClient(provider_to_openai_config(provider))
if isinstance(provider, DeepseekProvider):
convention = _deepseek_convention(provider.extras)
if convention in {"openai", "openai_compat", "openai-compatible"}:
return DeepseekOpenAIClient(provider_to_openai_config(provider))
if convention == "anthropic":
msg = "deepseek anthropic convention is not implemented"
raise ProviderNotSupportedError(msg)
msg = f"unknown deepseek convention {convention!r}"
raise ProviderNotSupportedError(msg)
# Remaining Provider variant: AnthropicProvider
msg = "anthropic provider client is not implemented"
raise ProviderNotSupportedError(msg)