mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-10-05 12:28:22 +00:00
fix: reject unsupported web search before LiteLLM translation
This commit is contained in:
@@ -507,6 +507,32 @@ async def dispatch_anthropic_messages(
|
||||
|
||||
model_suffix = adapt_request(body) if adapt_request else ""
|
||||
|
||||
# LiteLLM turns Anthropic's server-side web_search tool into the OpenAI
|
||||
# `web_search_options` parameter. Generic OpenAI-compatible chat endpoints
|
||||
# (including those serving Claude through a proxy) may reject that field.
|
||||
# Only a provider with an explicit adaptation (e.g. Venice's model suffix)
|
||||
# can preserve search semantics; do not silently remove the tool and return
|
||||
# an answer that never searched. Native /v1/messages providers bypass this
|
||||
# dispatcher and receive the original tool unchanged.
|
||||
tools = body.get("tools")
|
||||
if provider_prefix == "openai/" and isinstance(tools, list) and any(
|
||||
isinstance(tool, dict)
|
||||
and (
|
||||
(
|
||||
isinstance(tool.get("type"), str)
|
||||
and tool["type"].startswith("web_search")
|
||||
)
|
||||
or tool.get("name") == "web_search"
|
||||
)
|
||||
for tool in tools
|
||||
):
|
||||
raise UpstreamError(
|
||||
"This upstream does not support Anthropic web search through "
|
||||
"OpenAI-compatible /v1/messages translation",
|
||||
status_code=400,
|
||||
code="UNSUPPORTED_WEB_SEARCH",
|
||||
)
|
||||
|
||||
# Convention: `model.id` is the canonical upstream model name;
|
||||
# `forwarded_model_id` is the public alias the internal API exposes
|
||||
# and echoes back to the client.
|
||||
|
||||
@@ -123,13 +123,35 @@ async def test_requests_without_web_search_are_untouched() -> None:
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_other_providers_keep_their_existing_behaviour() -> None:
|
||||
"""The base hook is a no-op, so no non-Venice upstream changes shape."""
|
||||
async def test_generic_openai_upstream_rejects_untranslatable_web_search() -> None:
|
||||
"""Do not let LiteLLM send unsupported web_search_options to a generic API."""
|
||||
provider = BaseUpstreamProvider(base_url="http://test", api_key="k")
|
||||
|
||||
with pytest.raises(UpstreamError) as excinfo:
|
||||
await _dispatch(provider, _body(tools=[WEB_SEARCH_TOOL, FUNCTION_TOOL]))
|
||||
|
||||
assert excinfo.value.status_code == 400
|
||||
assert excinfo.value.code == "UNSUPPORTED_WEB_SEARCH"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generic_openai_upstream_still_accepts_function_tools() -> None:
|
||||
provider = BaseUpstreamProvider(base_url="http://test", api_key="k")
|
||||
|
||||
kwargs = await _dispatch(provider, _body(tools=[FUNCTION_TOOL]))
|
||||
|
||||
assert kwargs["model"] == "openai/deepseek-v4-flash-0731"
|
||||
assert kwargs["tools"] == [FUNCTION_TOOL]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_openai_adapter_can_still_handle_search_tool() -> None:
|
||||
provider = BaseUpstreamProvider(
|
||||
base_url="https://openrouter.ai/api/v1", api_key="k"
|
||||
)
|
||||
|
||||
kwargs = await _dispatch(provider, _body(tools=[WEB_SEARCH_TOOL]))
|
||||
|
||||
assert kwargs["model"] == "openai/deepseek-v4-flash-0731"
|
||||
assert kwargs["tools"] == [WEB_SEARCH_TOOL]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user