free-claude-code/tests/api/test_web_server_tools.py
Alishahryar1 b926f60f64 feat: Anthropic web server tools, provider metadata, messaging hardening
- Add local web_search/web_fetch SSE handling and optional tool schemas
- Extend HeuristicToolParser for JSON-style WebFetch/WebSearch text
- Consolidate provider defaults, ids, and exception typing; stream contracts
- Messaging: typed options, voice config injection, platform contract cleanup
- Tests for web server tools, converters, parsers, contracts; ignore debug-*.log
2026-04-24 23:01:14 -07:00

96 lines
3.3 KiB
Python

import json
import pytest
from api.models.anthropic import Message, MessagesRequest, Tool
from api.web_server_tools import (
is_web_server_tool_request,
stream_web_server_tool_response,
)
def _event_data(event: str) -> dict:
data_line = next(line for line in event.splitlines() if line.startswith("data: "))
return json.loads(data_line.removeprefix("data: "))
def test_detects_web_search_server_tool_request():
request = MessagesRequest(
model="claude-haiku-4-5-20251001",
max_tokens=100,
messages=[Message(role="user", content="search")],
tools=[Tool(name="web_search", type="web_search_20250305")],
)
assert is_web_server_tool_request(request)
@pytest.mark.asyncio
async def test_streams_web_search_server_tool_result(monkeypatch):
async def fake_search(query: str) -> list[dict[str, str]]:
assert query == "DeepSeek V4 model release 2026"
return [{"title": "DeepSeek V4 Released", "url": "https://example.com/v4"}]
monkeypatch.setattr("api.web_server_tools._run_web_search", fake_search)
request = MessagesRequest(
model="claude-haiku-4-5-20251001",
max_tokens=100,
messages=[
Message(
role="user",
content=(
"Perform a web search for the query: DeepSeek V4 model release 2026"
),
)
],
tools=[Tool(name="web_search", type="web_search_20250305")],
tool_choice={"type": "tool", "name": "web_search"},
)
events = [
event
async for event in stream_web_server_tool_response(request, input_tokens=42)
]
payloads = [_event_data(event) for event in events]
assert payloads[1]["content_block"]["type"] == "server_tool_use"
assert payloads[1]["content_block"]["name"] == "web_search"
assert payloads[3]["content_block"]["type"] == "web_search_tool_result"
assert payloads[3]["content_block"]["content"][0]["url"] == "https://example.com/v4"
assert payloads[-2]["usage"]["server_tool_use"] == {"web_search_requests": 1}
@pytest.mark.asyncio
async def test_streams_web_fetch_server_tool_result(monkeypatch):
async def fake_fetch(url: str) -> dict[str, str]:
assert url == "https://example.com/article"
return {
"url": url,
"title": "Example Article",
"media_type": "text/plain",
"data": "Article body",
}
monkeypatch.setattr("api.web_server_tools._run_web_fetch", fake_fetch)
request = MessagesRequest(
model="claude-haiku-4-5-20251001",
max_tokens=100,
messages=[
Message(role="user", content="Fetch https://example.com/article please")
],
tools=[Tool(name="web_fetch", type="web_fetch_20250910")],
tool_choice={"type": "tool", "name": "web_fetch"},
)
events = [
event
async for event in stream_web_server_tool_response(request, input_tokens=42)
]
payloads = [_event_data(event) for event in events]
assert payloads[1]["content_block"]["type"] == "server_tool_use"
assert payloads[3]["content_block"]["type"] == "web_fetch_tool_result"
assert payloads[3]["content_block"]["content"]["content"]["title"] == (
"Example Article"
)
assert payloads[-2]["usage"]["server_tool_use"] == {"web_fetch_requests": 1}