From a3e4c77fff90242f4bd5c344789adc9e46c5ee2e Mon Sep 17 00:00:00 2001 From: Xubin Ren Date: Thu, 2 Apr 2026 04:48:11 +0000 Subject: [PATCH] fix(providers): normalize anthropic cached token usage --- nanobot/providers/anthropic_provider.py | 9 ++++++--- tests/providers/test_cached_tokens.py | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/nanobot/providers/anthropic_provider.py b/nanobot/providers/anthropic_provider.py index fabcd5656..8e102d305 100644 --- a/nanobot/providers/anthropic_provider.py +++ b/nanobot/providers/anthropic_provider.py @@ -370,17 +370,20 @@ class AnthropicProvider(LLMProvider): usage: dict[str, int] = {} if response.usage: + input_tokens = response.usage.input_tokens + cache_creation = getattr(response.usage, "cache_creation_input_tokens", 0) or 0 + cache_read = getattr(response.usage, "cache_read_input_tokens", 0) or 0 + total_prompt_tokens = input_tokens + cache_creation + cache_read usage = { - "prompt_tokens": response.usage.input_tokens, + "prompt_tokens": total_prompt_tokens, "completion_tokens": response.usage.output_tokens, - "total_tokens": response.usage.input_tokens + response.usage.output_tokens, + "total_tokens": total_prompt_tokens + response.usage.output_tokens, } for attr in ("cache_creation_input_tokens", "cache_read_input_tokens"): val = getattr(response.usage, attr, 0) if val: usage[attr] = val # Normalize to cached_tokens for downstream consistency. - cache_read = usage.get("cache_read_input_tokens", 0) if cache_read: usage["cached_tokens"] = cache_read diff --git a/tests/providers/test_cached_tokens.py b/tests/providers/test_cached_tokens.py index fce22cf65..1b01408a4 100644 --- a/tests/providers/test_cached_tokens.py +++ b/tests/providers/test_cached_tokens.py @@ -198,7 +198,7 @@ def test_anthropic_maps_cache_fields_to_cached_tokens(): usage_obj = FakeUsage( input_tokens=800, output_tokens=200, - cache_creation_input_tokens=0, + cache_creation_input_tokens=300, cache_read_input_tokens=1200, ) content_block = FakeUsage(type="text", text="hello") @@ -211,7 +211,9 @@ def test_anthropic_maps_cache_fields_to_cached_tokens(): ) result = AnthropicProvider._parse_response(response) assert result.usage["cached_tokens"] == 1200 - assert result.usage["prompt_tokens"] == 800 + assert result.usage["prompt_tokens"] == 2300 + assert result.usage["total_tokens"] == 2500 + assert result.usage["cache_creation_input_tokens"] == 300 def test_anthropic_no_cache_fields():