mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 23:47:54 +08:00
config: default DeepSeek to web_search and honour its provider_tools
``provider_tools`` reached the effective provider only for the OpenAI preset,
so a DeepSeek ``provider_tools`` in TOML was dropped on the way — and the preset
defaulted to none, leaving search unavailable for every convention.
DeepSeek now defaults to ``[{type="web_search"}]`` like OpenAI does (``[]``
turns it off) and its list reaches the agent: the Anthropic convention runs the
hosted search inside the response, the Responses and chat conventions get the
local ``web_search`` tool (see ``config.routing.local_web_search``).
This commit is contained in:
@@ -332,8 +332,8 @@ def _default_openai_models() -> dict[str, ModelConfig]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _default_openai_provider_tools() -> list[dict[str, Any]]:
|
def _default_provider_tools() -> list[dict[str, Any]]:
|
||||||
"""Hosted tools when TOML omits ``provider_tools``."""
|
"""Hosted tools when TOML omits ``provider_tools`` (OpenAI and DeepSeek)."""
|
||||||
return [{"type": "web_search"}]
|
return [{"type": "web_search"}]
|
||||||
|
|
||||||
|
|
||||||
@@ -352,7 +352,7 @@ class OpenAIProvider(ProviderConfig, tag="openai"):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
models: dict[str, ModelConfig] = field(default_factory=_default_openai_models)
|
models: dict[str, ModelConfig] = field(default_factory=_default_openai_models)
|
||||||
provider_tools: list[dict[str, Any]] = field(default_factory=_default_openai_provider_tools)
|
provider_tools: list[dict[str, Any]] = field(default_factory=_default_provider_tools)
|
||||||
|
|
||||||
|
|
||||||
class OpenAICompatibleProvider(ProviderConfig, tag="openai-compatible"):
|
class OpenAICompatibleProvider(ProviderConfig, tag="openai-compatible"):
|
||||||
@@ -380,12 +380,18 @@ class DeepseekProvider(ProviderConfig, tag="deepseek"):
|
|||||||
- ``"anthropic"`` → Anthropic Messages API (``POST /messages`` on
|
- ``"anthropic"`` → Anthropic Messages API (``POST /messages`` on
|
||||||
``https://api.deepseek.com/anthropic``)
|
``https://api.deepseek.com/anthropic``)
|
||||||
|
|
||||||
|
``provider_tools`` asks for a search tool like OpenAI's does (``[]``
|
||||||
|
disables it). DeepSeek runs a hosted search only on the Anthropic surface, so
|
||||||
|
the other conventions get a local ``web_search`` tool instead (see
|
||||||
|
``config.routing.local_web_search``).
|
||||||
|
|
||||||
``extras`` keeps arbitrary provider keys; the legacy ``extras.convention``
|
``extras`` keeps arbitrary provider keys; the legacy ``extras.convention``
|
||||||
key is parsed but ignored (prefer the typed ``convention`` field).
|
key is parsed but ignored (prefer the typed ``convention`` field).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
models: dict[str, ModelConfig] = field(default_factory=_default_deepseek_models)
|
models: dict[str, ModelConfig] = field(default_factory=_default_deepseek_models)
|
||||||
convention: DeepSeekConvention = ""
|
convention: DeepSeekConvention = ""
|
||||||
|
provider_tools: list[dict[str, Any]] = field(default_factory=_default_provider_tools)
|
||||||
extras: dict[str, str] = field(default_factory=dict)
|
extras: dict[str, str] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -147,8 +147,12 @@ def resolve_effective_provider(provider: Provider, *, model: str | None = None)
|
|||||||
else:
|
else:
|
||||||
url = default_url_for_preset(preset)
|
url = default_url_for_preset(preset)
|
||||||
|
|
||||||
|
# Hosted tools belong to the preset that declares them: OpenAI's Responses
|
||||||
|
# surface, and DeepSeek's (whose Anthropic surface runs the search inside the
|
||||||
|
# response while its other surfaces get a local tool — see
|
||||||
|
# :func:`local_web_search`).
|
||||||
provider_tools: list[dict[str, object]] = []
|
provider_tools: list[dict[str, object]] = []
|
||||||
if preset == "openai" and isinstance(provider, OpenAIProvider) and parent_preset == "openai":
|
if parent_preset == preset and isinstance(provider, OpenAIProvider | DeepseekProvider):
|
||||||
provider_tools = [dict(item) for item in provider.provider_tools]
|
provider_tools = [dict(item) for item in provider.provider_tools]
|
||||||
|
|
||||||
return EffectiveProvider(
|
return EffectiveProvider(
|
||||||
|
|||||||
@@ -27,19 +27,18 @@ def _effective(
|
|||||||
return effective if tools is None else replace(effective, provider_tools=tools)
|
return effective if tools is None else replace(effective, provider_tools=tools)
|
||||||
|
|
||||||
|
|
||||||
def test_a_deepseek_provider_asks_for_no_hosted_tool_by_default() -> None:
|
def test_a_deepseek_provider_asks_for_a_search_tool_like_openai_does() -> None:
|
||||||
# OpenAI's preset defaults ``provider_tools`` to web_search; DeepSeek's does
|
# ``provider_tools`` defaults to web_search for both presets; ``[]`` disables.
|
||||||
# not, so search stays opt-in there (``provider_tools = [{type = "web_search"}]``).
|
assert wants_web_search(_effective()) is True
|
||||||
assert wants_web_search(_effective()) is False
|
assert wants_web_search(_effective(tools=[])) is False
|
||||||
assert wants_web_search(_effective(tools=SEARCH_TOOLS)) is True
|
|
||||||
|
|
||||||
|
|
||||||
def test_chat_and_responses_conventions_use_the_local_tool() -> None:
|
def test_chat_and_responses_conventions_use_the_local_tool() -> None:
|
||||||
# Only the Anthropic surface hosts a search; the others ignore a hosted tool,
|
# Only the Anthropic surface hosts a search; the others ignore a hosted tool,
|
||||||
# so an asked-for web_search becomes plyngent's own tool there.
|
# so the default web_search becomes plyngent's own tool there.
|
||||||
assert local_web_search(_effective(convention="", tools=SEARCH_TOOLS)) is True
|
assert local_web_search(_effective(convention="")) is True
|
||||||
assert local_web_search(_effective(convention="responses", tools=SEARCH_TOOLS)) is True
|
assert local_web_search(_effective(convention="responses")) is True
|
||||||
assert local_web_search(_effective(convention="anthropic", tools=SEARCH_TOOLS)) is False
|
assert local_web_search(_effective(convention="anthropic")) is False
|
||||||
|
|
||||||
|
|
||||||
def test_without_provider_tools_there_is_no_search() -> None:
|
def test_without_provider_tools_there_is_no_search() -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user