mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
fix(cost-tracking): bill web searches reported only in server_side_tool_usage_details
This commit is contained in:
parent
6bce073520
commit
d96f76ca66
2 changed files with 50 additions and 0 deletions
|
|
@ -2,6 +2,7 @@
|
|||
Helper utilities for tracking the cost of built-in tools.
|
||||
"""
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any, Final, Literal
|
||||
|
||||
import litellm
|
||||
|
|
@ -23,6 +24,14 @@ from litellm.types.utils import (
|
|||
)
|
||||
|
||||
|
||||
def _usage_reports_server_side_web_search_calls(usage: Usage) -> bool:
|
||||
details: Final = getattr(usage, "server_side_tool_usage_details", None)
|
||||
if not isinstance(details, Mapping):
|
||||
return False
|
||||
calls: Final = details.get("web_search_calls")
|
||||
return isinstance(calls, int) and calls > 0
|
||||
|
||||
|
||||
class StandardBuiltInToolCostTracking:
|
||||
"""
|
||||
Helper class for tracking the cost of built-in tools
|
||||
|
|
@ -351,6 +360,10 @@ class StandardBuiltInToolCostTracking:
|
|||
# and _handle_web_search_cost() is never called.
|
||||
if hasattr(usage, "server_tool_use") and _get_web_search_requests(usage.server_tool_use) is not None:
|
||||
return True
|
||||
# xAI reports usage.server_side_tool_usage_details.web_search_calls; a searched
|
||||
# answer with no url_citation annotations has no other chat-path signal
|
||||
if _usage_reports_server_side_web_search_calls(usage):
|
||||
return True
|
||||
return False
|
||||
elif isinstance(response_object, ResponsesAPIResponse):
|
||||
# response api explicitly includes web_search_call in the output
|
||||
|
|
@ -370,6 +383,8 @@ class StandardBuiltInToolCostTracking:
|
|||
)
|
||||
):
|
||||
return True
|
||||
if _usage_reports_server_side_web_search_calls(usage):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -632,3 +632,38 @@ def test_response_includes_output_type_reads_dict_output_items():
|
|||
assert not StandardBuiltInToolCostTracking.response_includes_output_type(
|
||||
response_object=response, output_type="file_search_call"
|
||||
)
|
||||
|
||||
|
||||
def test_web_search_gate_reads_server_side_tool_usage_details_without_citations():
|
||||
"""
|
||||
Regression: xAI chat responses bridged from the Responses API only carry
|
||||
usage.server_side_tool_usage_details; a searched answer with no url_citation
|
||||
annotations must still be billed for its web search calls.
|
||||
"""
|
||||
from litellm.llms.xai.cost_calculator import _DEFAULT_WEB_SEARCH_COST_PER_CALL
|
||||
from litellm.types.utils import Usage
|
||||
|
||||
usage = Usage(
|
||||
prompt_tokens=10,
|
||||
completion_tokens=20,
|
||||
total_tokens=30,
|
||||
server_side_tool_usage_details={"web_search_calls": 3},
|
||||
)
|
||||
response = ModelResponse(model="xai/grok-4.5")
|
||||
|
||||
assert StandardBuiltInToolCostTracking.response_object_includes_web_search_call(
|
||||
response_object=response, usage=usage
|
||||
)
|
||||
assert not StandardBuiltInToolCostTracking.response_object_includes_web_search_call(
|
||||
response_object=response,
|
||||
usage=Usage(prompt_tokens=10, completion_tokens=20, total_tokens=30),
|
||||
)
|
||||
|
||||
cost = StandardBuiltInToolCostTracking.get_cost_for_built_in_tools(
|
||||
model="xai/grok-4.5",
|
||||
response_object=response,
|
||||
usage=usage,
|
||||
custom_llm_provider="xai",
|
||||
standard_built_in_tools_params=None,
|
||||
)
|
||||
assert cost == 3 * _DEFAULT_WEB_SEARCH_COST_PER_CALL
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue