fix(proxy): coalesce NULL rollup metrics in aggregated daily-activity (#30151)
This commit is contained in:
parent
a2c916fb45
commit
8e12d42ea7
@ -699,17 +699,23 @@ _GROUP_DATE_ENDPOINT_API_KEY = 30 # 0b0011110
|
|||||||
|
|
||||||
|
|
||||||
def _record_to_spend_metrics(record: Any) -> SpendMetrics:
|
def _record_to_spend_metrics(record: Any) -> SpendMetrics:
|
||||||
"""Build a SpendMetrics directly from one already-aggregated rollup row."""
|
"""Build a SpendMetrics directly from one already-aggregated rollup row.
|
||||||
|
|
||||||
|
SUM() over zero rows is SQL NULL, so rollup rows (notably the grand-total
|
||||||
|
row, which Postgres emits even on an empty match) can carry None values.
|
||||||
|
"""
|
||||||
|
prompt_tokens = record.prompt_tokens or 0
|
||||||
|
completion_tokens = record.completion_tokens or 0
|
||||||
return SpendMetrics(
|
return SpendMetrics(
|
||||||
spend=record.spend,
|
spend=record.spend or 0.0,
|
||||||
prompt_tokens=record.prompt_tokens,
|
prompt_tokens=prompt_tokens,
|
||||||
completion_tokens=record.completion_tokens,
|
completion_tokens=completion_tokens,
|
||||||
total_tokens=record.prompt_tokens + record.completion_tokens,
|
total_tokens=prompt_tokens + completion_tokens,
|
||||||
cache_read_input_tokens=record.cache_read_input_tokens,
|
cache_read_input_tokens=record.cache_read_input_tokens or 0,
|
||||||
cache_creation_input_tokens=record.cache_creation_input_tokens,
|
cache_creation_input_tokens=record.cache_creation_input_tokens or 0,
|
||||||
api_requests=record.api_requests,
|
api_requests=record.api_requests or 0,
|
||||||
successful_requests=record.successful_requests,
|
successful_requests=record.successful_requests or 0,
|
||||||
failed_requests=record.failed_requests,
|
failed_requests=record.failed_requests or 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -585,3 +585,61 @@ async def test_aggregated_activity_preserves_metadata_for_deleted_keys():
|
|||||||
assert key_data.metadata.key_alias == "toto-test-2"
|
assert key_data.metadata.key_alias == "toto-test-2"
|
||||||
assert key_data.metadata.team_id == "69cd4b77-b095-4489-8c46-4f2f31d840a2"
|
assert key_data.metadata.team_id == "69cd4b77-b095-4489-8c46-4f2f31d840a2"
|
||||||
assert key_data.metrics.spend == 10.0
|
assert key_data.metrics.spend == 10.0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_daily_activity_aggregated_empty_result_set():
|
||||||
|
"""Regression test for the empty-range 500.
|
||||||
|
|
||||||
|
When the date filter matches zero rows, Postgres still emits the
|
||||||
|
grand-total () grouping-set row with every SUM column NULL. The
|
||||||
|
endpoint must return an empty result set with zeroed totals, not
|
||||||
|
crash on None + None.
|
||||||
|
"""
|
||||||
|
mock_prisma = MagicMock()
|
||||||
|
mock_prisma.db = MagicMock()
|
||||||
|
|
||||||
|
mock_rows = [
|
||||||
|
{
|
||||||
|
"date": None,
|
||||||
|
"api_key": None,
|
||||||
|
"model": None,
|
||||||
|
"model_group": None,
|
||||||
|
"custom_llm_provider": None,
|
||||||
|
"mcp_namespaced_tool_name": None,
|
||||||
|
"endpoint": None,
|
||||||
|
"group_level": 127,
|
||||||
|
"spend": None,
|
||||||
|
"prompt_tokens": None,
|
||||||
|
"completion_tokens": None,
|
||||||
|
"cache_read_input_tokens": None,
|
||||||
|
"cache_creation_input_tokens": None,
|
||||||
|
"api_requests": None,
|
||||||
|
"successful_requests": None,
|
||||||
|
"failed_requests": None,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
mock_prisma.db.query_raw = AsyncMock(return_value=mock_rows)
|
||||||
|
|
||||||
|
result = await get_daily_activity_aggregated(
|
||||||
|
prisma_client=mock_prisma,
|
||||||
|
table_name="litellm_dailyuserspend",
|
||||||
|
entity_id_field="user_id",
|
||||||
|
entity_id=None,
|
||||||
|
entity_metadata_field=None,
|
||||||
|
start_date="2026-06-16",
|
||||||
|
end_date="2026-06-16",
|
||||||
|
model=None,
|
||||||
|
api_key=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.results == []
|
||||||
|
assert result.metadata.total_spend == 0.0
|
||||||
|
assert result.metadata.total_prompt_tokens == 0
|
||||||
|
assert result.metadata.total_completion_tokens == 0
|
||||||
|
assert result.metadata.total_tokens == 0
|
||||||
|
assert result.metadata.total_api_requests == 0
|
||||||
|
assert result.metadata.total_successful_requests == 0
|
||||||
|
assert result.metadata.total_failed_requests == 0
|
||||||
|
assert result.metadata.total_cache_read_input_tokens == 0
|
||||||
|
assert result.metadata.total_cache_creation_input_tokens == 0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user