From 1f628e43117d3cc8586671e530c4faaa0f3e81b1 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Sun, 19 Jul 2026 03:51:48 +0000 Subject: [PATCH] fix(cost-optimization): preserve cache token helper coverage Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/db/db_spend_update_writer.py | 4 ++ .../test_cost_optimization_endpoints.py | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/litellm/proxy/db/db_spend_update_writer.py b/litellm/proxy/db/db_spend_update_writer.py index f582dfe832f..55900ce8b34 100644 --- a/litellm/proxy/db/db_spend_update_writer.py +++ b/litellm/proxy/db/db_spend_update_writer.py @@ -73,6 +73,10 @@ else: ProxyLogging = Any +def _extract_cache_read_tokens(usage_obj: dict) -> int: + return extract_cache_read_tokens({"usage_object": usage_obj}) + + def _extract_cache_creation_tokens(usage_obj: dict) -> int: """ Anthropic: top-level cache_creation_input_tokens field. diff --git a/tests/test_litellm/proxy/management_endpoints/test_cost_optimization_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_cost_optimization_endpoints.py index 33bdaa81dbc..4b267a39c88 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_cost_optimization_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_cost_optimization_endpoints.py @@ -7,6 +7,7 @@ import pytest from litellm.proxy.management_endpoints.cost_optimization_endpoints import ( build_optimized_request_log, cost_optimization_usage_logs, + _parse_date, ) @@ -48,6 +49,30 @@ def test_build_optimized_request_log_computes_both_savings(): def test_build_optimized_request_log_ignores_unoptimized_row(): assert build_optimized_request_log(_row({"usage_object": {"prompt_tokens": 10}})) is None + assert build_optimized_request_log(_row("{invalid-json")) is None + + +def test_build_optimized_request_log_handles_cached_request_metadata_string(): + result = build_optimized_request_log( + _row( + '{"usage_object": {"prompt_tokens_details": {"cached_tokens": 50}}}', + startTime="2026-07-13T12:00:00+00:00", + total_tokens="invalid", + ) + ) + + assert result is not None + assert result.optimization_type == "caching" + assert result.cache_read_tokens == 50 + assert result.timestamp == "2026-07-13T12:00:00+00:00" + assert result.total_tokens == 0 + + +def test_parse_date_supports_empty_and_end_of_day_values(): + assert _parse_date(None) is None + assert _parse_date("2026-07-01") == datetime(2026, 7, 1, tzinfo=timezone.utc) + assert _parse_date("2026-07-01", end=True) == datetime(2026, 7, 2, tzinfo=timezone.utc) + assert _parse_date("2026-07-01 12:30:00") == datetime(2026, 7, 1, 12, 30, tzinfo=timezone.utc) @pytest.mark.asyncio @@ -81,3 +106,15 @@ async def test_cost_optimization_usage_logs_returns_paginated_entries(): assert result.logs[0].optimization_type == "compression" assert result.logs[0].tokens_saved == 25 assert query_raw_mock.await_count == 2 + + +@pytest.mark.asyncio +async def test_cost_optimization_usage_logs_returns_empty_without_prisma(): + with patch("litellm.proxy.proxy_server.prisma_client", None): + result = await cost_optimization_usage_logs(page=2, page_size=25) + + assert result.logs == [] + assert result.total == 0 + assert result.page == 2 + assert result.page_size == 25 + assert result.total_pages == 0