mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 15:37:55 +08:00
config: add typed DeepSeek convention field for API surface
This commit is contained in:
@@ -10,6 +10,7 @@ from .models import DEFAULT_TOOL_DIRECTIVES as DEFAULT_TOOL_DIRECTIVES
|
||||
from .models import AgentConfig as AgentConfig
|
||||
from .models import AnthropicProvider as AnthropicProvider
|
||||
from .models import DatabaseConfig as DatabaseConfig
|
||||
from .models import DeepSeekConvention as DeepSeekConvention
|
||||
from .models import DeepseekProvider as DeepseekProvider
|
||||
from .models import HttpTimeoutConfig as HttpTimeoutConfig
|
||||
from .models import ModelConfig as ModelConfig
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
from typing import Any
|
||||
from typing import Any, Literal
|
||||
|
||||
from msgspec import Struct, field
|
||||
|
||||
# DeepSeek API surface convention (``DeepseekProvider.convention`` and
|
||||
# per-model ``ModelConfig.convention`` override).
|
||||
# - "" (default) / "openai" → OpenAI-compatible chat completions
|
||||
# - "responses" → OpenAI Responses API (``POST /responses``)
|
||||
# - "anthropic" → legacy value, ignored (still chat completions)
|
||||
type DeepSeekConvention = Literal["", "openai", "anthropic", "responses"]
|
||||
|
||||
# Built-in persona when ``[agent].system_prompt`` is omitted.
|
||||
# Set ``system_prompt = ""`` to omit the persona block only.
|
||||
# Override with a multi-line TOML literal (prefer ''' so nested " is fine).
|
||||
@@ -162,6 +169,8 @@ class ModelConfig(Struct, omit_defaults=True):
|
||||
cost_factor: float = 1.0
|
||||
preset: str = ""
|
||||
url: str = ""
|
||||
# DeepSeek API surface override ("" = inherit provider convention).
|
||||
convention: DeepSeekConvention = ""
|
||||
|
||||
|
||||
class HttpTimeoutConfig(Struct, omit_defaults=True):
|
||||
@@ -244,9 +253,19 @@ def _default_deepseek_models() -> dict[str, ModelConfig]:
|
||||
|
||||
|
||||
class DeepseekProvider(ProviderConfig, tag="deepseek"):
|
||||
"""Deepseek API provider with optional extras (e.g. convention)."""
|
||||
"""DeepSeek API provider.
|
||||
|
||||
``convention`` selects the API surface on ``https://api.deepseek.com``:
|
||||
- ``""`` / ``"openai"`` → OpenAI-compatible chat completions (default)
|
||||
- ``"responses"`` → OpenAI Responses API (``POST /responses``)
|
||||
- ``"anthropic"`` → legacy value, ignored (still chat completions)
|
||||
|
||||
``extras`` keeps arbitrary provider keys; the legacy ``extras.convention``
|
||||
key is parsed but ignored (prefer the typed ``convention`` field).
|
||||
"""
|
||||
|
||||
models: dict[str, ModelConfig] = field(default_factory=_default_deepseek_models)
|
||||
convention: DeepSeekConvention = ""
|
||||
extras: dict[str, str] = field(default_factory=dict)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Literal, cast
|
||||
|
||||
from .models import (
|
||||
AnthropicProvider,
|
||||
DeepseekProvider,
|
||||
HttpTimeoutConfig,
|
||||
ModelConfig,
|
||||
OpenAICompatibleProvider,
|
||||
@@ -30,6 +31,9 @@ class EffectiveProvider:
|
||||
timeout: float | HttpTimeoutConfig | None
|
||||
provider_tools: list[dict[str, object]]
|
||||
source: Provider
|
||||
# DeepSeek API surface (see DeepSeekConvention): "openai" / "anthropic" /
|
||||
# "responses" for deepseek presets; "" (unused) for other presets.
|
||||
convention: str = ""
|
||||
|
||||
|
||||
def provider_preset(provider: Provider) -> ProviderPreset:
|
||||
@@ -73,6 +77,9 @@ def resolve_effective_provider(provider: Provider, *, model: str | None = None)
|
||||
|
||||
``preset`` always decides API conventions: ``openai`` means Responses,
|
||||
``openai-compatible`` means Chat Completions, ``anthropic`` means Messages.
|
||||
Exception: a ``deepseek`` preset may pick the Responses surface via the
|
||||
``convention`` field (``"responses"``); model-level ``convention`` wins
|
||||
over the provider-level one.
|
||||
"""
|
||||
parent_preset = provider_preset(provider)
|
||||
model_cfg = model_config_for(provider, model)
|
||||
@@ -88,6 +95,13 @@ def resolve_effective_provider(provider: Provider, *, model: str | None = None)
|
||||
if preset == "openai" and isinstance(provider, OpenAIProvider) and parent_preset == "openai":
|
||||
provider_tools = [dict(item) for item in provider.provider_tools]
|
||||
|
||||
# DeepSeek API surface: model override > provider convention > chat default.
|
||||
convention = ""
|
||||
if preset == "deepseek" and isinstance(provider, DeepseekProvider):
|
||||
convention = provider.convention or "openai"
|
||||
if model_cfg is not None and model_cfg.convention:
|
||||
convention = model_cfg.convention
|
||||
|
||||
return EffectiveProvider(
|
||||
preset=preset,
|
||||
access_key_or_token=provider.access_key_or_token,
|
||||
@@ -96,6 +110,7 @@ def resolve_effective_provider(provider: Provider, *, model: str | None = None)
|
||||
timeout=provider.timeout,
|
||||
provider_tools=provider_tools,
|
||||
source=provider,
|
||||
convention=convention,
|
||||
)
|
||||
|
||||
|
||||
@@ -108,4 +123,5 @@ def effective_provider_to_config_dict(effective: EffectiveProvider) -> Mapping[s
|
||||
"model": effective.model or "",
|
||||
"timeout": effective.timeout,
|
||||
"provider_tools": effective.provider_tools,
|
||||
"convention": effective.convention,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user