mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 08:13:11 +03:00
fix(providers): report Responses cached tokens
This commit is contained in:
@@ -203,11 +203,16 @@ def _usage_from_response_obj(response: object) -> dict[str, int]:
|
||||
usage.get("output_tokens") or usage.get("completion_tokens") or 0
|
||||
)
|
||||
total_tokens = int(usage.get("total_tokens") or prompt_tokens + completion_tokens)
|
||||
return {
|
||||
result = {
|
||||
"prompt_tokens": prompt_tokens,
|
||||
"completion_tokens": completion_tokens,
|
||||
"total_tokens": total_tokens,
|
||||
}
|
||||
input_details = _response_object(usage.get("input_tokens_details"))
|
||||
cached_tokens = int(input_details.get("cached_tokens") or 0) if input_details else 0
|
||||
if cached_tokens > 0:
|
||||
result["cached_tokens"] = cached_tokens
|
||||
return result
|
||||
|
||||
|
||||
def _parse_tool_call_arguments(args_raw: Any, name: str | None) -> Any:
|
||||
@@ -789,6 +794,13 @@ async def consume_sdk_stream(
|
||||
"completion_tokens": int(getattr(usage_obj, "output_tokens", 0) or 0),
|
||||
"total_tokens": int(getattr(usage_obj, "total_tokens", 0) or 0),
|
||||
}
|
||||
usage_data = _response_object(usage_obj) or {}
|
||||
input_details = _response_object(usage_data.get("input_tokens_details"))
|
||||
cached_tokens = (
|
||||
int(input_details.get("cached_tokens") or 0) if input_details else 0
|
||||
)
|
||||
if cached_tokens > 0:
|
||||
usage["cached_tokens"] = cached_tokens
|
||||
if not reasoning_content:
|
||||
reasoning_content = _extract_reasoning_summary_from_output(
|
||||
getattr(resp, "output", None)
|
||||
|
||||
@@ -1278,14 +1278,24 @@ class TestConsumeSse:
|
||||
"type": "response.completed",
|
||||
"response": {
|
||||
"status": "completed",
|
||||
"usage": {"input_tokens": 10, "output_tokens": 5, "total_tokens": 15},
|
||||
"usage": {
|
||||
"input_tokens": 10,
|
||||
"input_tokens_details": {"cached_tokens": 8},
|
||||
"output_tokens": 5,
|
||||
"total_tokens": 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
_, _, _, usage, _ = await consume_sse_with_reasoning(response)
|
||||
|
||||
assert usage == {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}
|
||||
assert usage == {
|
||||
"prompt_tokens": 10,
|
||||
"completion_tokens": 5,
|
||||
"total_tokens": 15,
|
||||
"cached_tokens": 8,
|
||||
}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tool_call_done_arguments_callback(self):
|
||||
@@ -1752,7 +1762,12 @@ class TestConsumeSdkStream:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_usage_extracted(self):
|
||||
usage_obj = MagicMock(input_tokens=10, output_tokens=5, total_tokens=15)
|
||||
usage_obj = MagicMock(
|
||||
input_tokens=10,
|
||||
input_tokens_details=MagicMock(cached_tokens=8),
|
||||
output_tokens=5,
|
||||
total_tokens=15,
|
||||
)
|
||||
resp_obj = MagicMock(status="completed", usage=usage_obj, output=[])
|
||||
ev = MagicMock(type="response.completed", response=resp_obj)
|
||||
|
||||
@@ -1760,7 +1775,12 @@ class TestConsumeSdkStream:
|
||||
yield ev
|
||||
|
||||
_, _, _, usage, _ = await consume_sdk_stream(stream())
|
||||
assert usage == {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}
|
||||
assert usage == {
|
||||
"prompt_tokens": 10,
|
||||
"completion_tokens": 5,
|
||||
"total_tokens": 15,
|
||||
"cached_tokens": 8,
|
||||
}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
Reference in New Issue
Block a user