Fix Anthropic streaming web search usage

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>
This commit is contained in:
oss-agent-shin 2026-05-07 00:02:32 +00:00
parent f1c91d754d
commit 60cf6f9023
No known key found for this signature in database
3 changed files with 75 additions and 3 deletions

View file

@ -1553,7 +1553,7 @@ class Usage(SafeAttributeModel, CompletionUsage):
completion_tokens_details: Optional[
Union[CompletionTokensDetailsWrapper, dict]
] = None,
server_tool_use: Optional[ServerToolUse] = None,
server_tool_use: Optional[Union[ServerToolUse, Dict[str, Any]]] = None,
cost: Optional[float] = None,
**params,
):
@ -1655,6 +1655,8 @@ class Usage(SafeAttributeModel, CompletionUsage):
)
if server_tool_use is not None:
if isinstance(server_tool_use, dict):
server_tool_use = ServerToolUse(**server_tool_use)
self.server_tool_use = server_tool_use
else: # maintain openai compatibility in usage object if possible
del self.server_tool_use

View file

@ -8,7 +8,7 @@ sys.path.insert(
0, os.path.abspath("../../..")
) # Adds the parent directory to the system path
from litellm import stream_chunk_builder
from litellm import completion_cost, stream_chunk_builder
from litellm.litellm_core_utils.streaming_chunk_builder_utils import ChunkProcessor
from litellm.types.utils import (
ChatCompletionDeltaToolCall,
@ -520,7 +520,66 @@ def test_stream_chunk_builder_anthropic_web_search():
assert usage.prompt_tokens == 50
assert usage.completion_tokens == 27
assert usage.total_tokens == 77
assert usage.server_tool_use["web_search_requests"] == 2
assert usage.server_tool_use.web_search_requests == 2
def test_stream_chunk_builder_anthropic_web_search_cost_calculation():
chunk1 = ModelResponseStream(
id="chatcmpl-mocked-usage-1",
created=1745513206,
model="claude-sonnet-4-5-20250929",
object="chat.completion.chunk",
system_fingerprint=None,
choices=[
StreamingChoices(
finish_reason=None,
index=0,
delta=Delta(content="", role="assistant"),
logprobs=None,
)
],
provider_specific_fields=None,
stream_options={"include_usage": True},
usage=Usage(
completion_tokens=0,
prompt_tokens=50,
total_tokens=50,
completion_tokens_details=None,
server_tool_use=ServerToolUse(web_search_requests=2),
prompt_tokens_details=None,
),
)
chunk2 = ModelResponseStream(
id="chatcmpl-mocked-usage-1",
created=1745513207,
model="claude-sonnet-4-5-20250929",
object="chat.completion.chunk",
system_fingerprint=None,
choices=[
StreamingChoices(
finish_reason="stop",
index=0,
delta=Delta(content="done", role=None),
logprobs=None,
)
],
provider_specific_fields=None,
stream_options={"include_usage": True},
usage=Usage(
completion_tokens=27,
prompt_tokens=0,
total_tokens=27,
completion_tokens_details=None,
prompt_tokens_details=None,
),
)
response = stream_chunk_builder(chunks=[chunk1, chunk2])
assert response is not None
assert isinstance(response.usage.server_tool_use, ServerToolUse)
assert completion_cost(completion_response=response) > 0
def test_sort_chunks_handles_dict_hidden_params_created_at():

View file

@ -45,6 +45,7 @@ def test_usage_dump():
from litellm.types.utils import (
CompletionTokensDetailsWrapper,
PromptTokensDetailsWrapper,
ServerToolUse,
Usage,
)
@ -74,6 +75,16 @@ def test_usage_dump():
new_usage = Usage(**current_usage.model_dump())
assert new_usage.prompt_tokens_details.web_search_requests == 1
server_tool_usage = Usage(
completion_tokens=10,
prompt_tokens=5,
total_tokens=15,
server_tool_use=ServerToolUse(web_search_requests=2),
)
new_server_tool_usage = Usage(**server_tool_usage.model_dump())
assert isinstance(new_server_tool_usage.server_tool_use, ServerToolUse)
assert new_server_tool_usage.server_tool_use.web_search_requests == 2
def test_usage_completion_tokens_details_text_tokens():
from litellm.types.utils import Usage