diff --git a/src/webwright/models/anthropic_model.py b/src/webwright/models/anthropic_model.py index 53393b5..b28b309 100644 --- a/src/webwright/models/anthropic_model.py +++ b/src/webwright/models/anthropic_model.py @@ -101,11 +101,13 @@ def _usage_from_anthropic_payload(payload: dict[str, Any]) -> dict[str, int]: input_tokens = _safe_int(usage.get("input_tokens")) output_tokens = _safe_int(usage.get("output_tokens")) cached_input_tokens = _safe_int(usage.get("cache_read_input_tokens")) + cache_creation_input_tokens = _safe_int(usage.get("cache_creation_input_tokens")) return { "input_tokens": input_tokens, "output_tokens": output_tokens, "total_tokens": input_tokens + output_tokens, "cached_input_tokens": cached_input_tokens, + "cache_creation_input_tokens": cache_creation_input_tokens, "reasoning_output_tokens": 0, } diff --git a/src/webwright/models/base.py b/src/webwright/models/base.py index 7728bb8..e16d3b0 100644 --- a/src/webwright/models/base.py +++ b/src/webwright/models/base.py @@ -197,6 +197,7 @@ def _request_metrics_from_serialized_input(serialized_input: list[dict[str, Any] "output_tokens", "total_tokens", "cached_input_tokens", + "cache_creation_input_tokens", "reasoning_output_tokens", ) @@ -326,6 +327,7 @@ def _usage_snapshot(self) -> dict[str, dict[str, int]]: "image_part_count": self._last_request_metrics["image_part_count"], "input_tokens": self._last_usage_metrics["input_tokens"], "cached_input_tokens": self._last_usage_metrics["cached_input_tokens"], + "cache_creation_input_tokens": self._last_usage_metrics["cache_creation_input_tokens"], }, "last_response": dict(self._last_usage_metrics), "cumulative_request": { @@ -334,6 +336,7 @@ def _usage_snapshot(self) -> dict[str, dict[str, int]]: "image_part_count": self._cumulative_request_metrics["image_part_count"], "input_tokens": self._cumulative_usage_metrics["input_tokens"], "cached_input_tokens": self._cumulative_usage_metrics["cached_input_tokens"], + "cache_creation_input_tokens": self._cumulative_usage_metrics["cache_creation_input_tokens"], }, "cumulative_response": dict(self._cumulative_usage_metrics), } diff --git a/src/webwright/models/openai_model.py b/src/webwright/models/openai_model.py index f11806e..90e8cbe 100644 --- a/src/webwright/models/openai_model.py +++ b/src/webwright/models/openai_model.py @@ -98,6 +98,7 @@ def _usage_metrics_from_response_payload(payload: dict[str, Any]) -> dict[str, i "output_tokens": _safe_int(usage.get("output_tokens")), "total_tokens": _safe_int(usage.get("total_tokens")), "cached_input_tokens": _safe_int(input_details.get("cached_tokens")), + "cache_creation_input_tokens": 0, "reasoning_output_tokens": _safe_int(output_details.get("reasoning_tokens")), } diff --git a/src/webwright/models/openrouter_model.py b/src/webwright/models/openrouter_model.py index 95c300f..a61f532 100644 --- a/src/webwright/models/openrouter_model.py +++ b/src/webwright/models/openrouter_model.py @@ -113,6 +113,7 @@ def _usage_metrics_from_chat_completions(payload: dict[str, Any]) -> dict[str, i "output_tokens": _safe_int(usage.get("completion_tokens")), "total_tokens": _safe_int(usage.get("total_tokens")), "cached_input_tokens": 0, + "cache_creation_input_tokens": 0, "reasoning_output_tokens": 0, } diff --git a/tests/unit/test_cache_creation_tokens.py b/tests/unit/test_cache_creation_tokens.py new file mode 100644 index 0000000..e634a1e --- /dev/null +++ b/tests/unit/test_cache_creation_tokens.py @@ -0,0 +1,33 @@ +from webwright.models.anthropic_model import _usage_from_anthropic_payload +from webwright.models.base import _USAGE_METRIC_KEYS + + +def test_cache_creation_input_tokens_in_metric_keys() -> None: + assert "cache_creation_input_tokens" in _USAGE_METRIC_KEYS + + +def test_anthropic_payload_extracts_cache_creation_tokens() -> None: + payload = { + "usage": { + "input_tokens": 100, + "output_tokens": 50, + "cache_read_input_tokens": 20, + "cache_creation_input_tokens": 30, + } + } + metrics = _usage_from_anthropic_payload(payload) + assert metrics["cache_creation_input_tokens"] == 30 + assert metrics["cached_input_tokens"] == 20 + + +def test_anthropic_payload_defaults_cache_creation_to_zero() -> None: + payload = {"usage": {"input_tokens": 100, "output_tokens": 50}} + metrics = _usage_from_anthropic_payload(payload) + assert metrics["cache_creation_input_tokens"] == 0 + + +def test_anthropic_payload_returns_all_metric_keys() -> None: + payload = {"usage": {"input_tokens": 10, "output_tokens": 5}} + metrics = _usage_from_anthropic_payload(payload) + for key in _USAGE_METRIC_KEYS: + assert key in metrics, f"missing key: {key}"