Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions litellm/proxy/management_endpoints/common_daily_activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,25 @@


def update_metrics(existing_metrics: SpendMetrics, record: Any) -> SpendMetrics:
"""Update metrics with new record data."""
existing_metrics.spend += record.spend
existing_metrics.prompt_tokens += record.prompt_tokens
existing_metrics.completion_tokens += record.completion_tokens
existing_metrics.total_tokens += record.prompt_tokens + record.completion_tokens
existing_metrics.cache_read_input_tokens += record.cache_read_input_tokens
existing_metrics.cache_creation_input_tokens += record.cache_creation_input_tokens
existing_metrics.api_requests += record.api_requests
existing_metrics.successful_requests += record.successful_requests
existing_metrics.failed_requests += record.failed_requests
"""Update metrics with new record data.

Rollup rows can carry None for numeric fields when SUM() spans zero rows
(e.g. a key with no spend), so coalesce to 0 before accumulating to avoid
a TypeError. Mirrors the handling in ``_record_to_spend_metrics``.
"""
prompt_tokens = record.prompt_tokens or 0
completion_tokens = record.completion_tokens or 0
existing_metrics.spend += record.spend or 0.0
existing_metrics.prompt_tokens += prompt_tokens
existing_metrics.completion_tokens += completion_tokens
existing_metrics.total_tokens += prompt_tokens + completion_tokens
existing_metrics.cache_read_input_tokens += record.cache_read_input_tokens or 0
existing_metrics.cache_creation_input_tokens += (
record.cache_creation_input_tokens or 0
)
existing_metrics.api_requests += record.api_requests or 0
existing_metrics.successful_requests += record.successful_requests or 0
existing_metrics.failed_requests += record.failed_requests or 0
return existing_metrics


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import sys
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock

import pytest
Expand All @@ -10,10 +11,13 @@

from litellm.proxy.management_endpoints.common_daily_activity import (
_is_user_agent_tag,
_record_to_spend_metrics,
get_api_key_metadata,
get_daily_activity,
get_daily_activity_aggregated,
update_metrics,
)
from litellm.types.proxy.management_endpoints.common_daily_activity import SpendMetrics


@pytest.mark.asyncio
Expand Down Expand Up @@ -688,3 +692,45 @@ async def test_get_daily_activity_aggregated_empty_result_set():
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


def _no_spend_record():
"""A rollup row for a key with no spend, where SUM() returns NULL (None)."""
return SimpleNamespace(
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,
)


def test_record_to_spend_metrics_handles_none_values():
"""Keys with no spend produce NULL aggregates; treat them as zero, not a crash."""
metrics = _record_to_spend_metrics(_no_spend_record())
assert metrics.spend == 0
assert metrics.prompt_tokens == 0
assert metrics.completion_tokens == 0
assert metrics.total_tokens == 0
assert metrics.api_requests == 0
assert metrics.successful_requests == 0
assert metrics.failed_requests == 0
Comment thread
greptile-apps[bot] marked this conversation as resolved.
assert metrics.cache_read_input_tokens == 0
assert metrics.cache_creation_input_tokens == 0


def test_update_metrics_handles_none_values():
"""update_metrics should coalesce NULL aggregates instead of raising TypeError."""
metrics = update_metrics(SpendMetrics(), _no_spend_record())
assert metrics.spend == 0
assert metrics.prompt_tokens == 0
assert metrics.completion_tokens == 0
assert metrics.total_tokens == 0
Comment thread
greptile-apps[bot] marked this conversation as resolved.
assert metrics.api_requests == 0
assert metrics.successful_requests == 0
assert metrics.failed_requests == 0
assert metrics.cache_read_input_tokens == 0
assert metrics.cache_creation_input_tokens == 0
Loading