Skip to content
Closed
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
17 changes: 2 additions & 15 deletions litellm/proxy/db/db_spend_update_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1737,22 +1737,9 @@ async def add_spend_log_transaction_to_daily_agent_transaction(
"agent_id is None for request. Skipping incrementing agent spend."
)
return
payload_with_agent_id = cast(
SpendLogsPayload,
{
**payload,
"agent_id": payload["agent_id"],
},
)
base_daily_transaction = (
await self._common_add_spend_log_transaction_to_daily_transaction(
payload_with_agent_id, prisma_client, "agent"
)
)
if base_daily_transaction is None:
return

endpoint_str = base_daily_transaction.get("endpoint") or ""
daily_transaction_key = f"{payload['agent_id']}_{base_daily_transaction['date']}_{payload_with_agent_id['api_key']}_{payload_with_agent_id['model']}_{payload_with_agent_id['custom_llm_provider']}_{endpoint_str}"
daily_transaction_key = f"{payload['agent_id']}_{base_daily_transaction['date']}_{payload['api_key']}_{payload['model']}_{payload['custom_llm_provider']}_{endpoint_str}"
daily_transaction = DailyAgentSpendTransaction(
agent_id=payload['agent_id'], **base_daily_transaction
)
Expand Down
47 changes: 47 additions & 0 deletions tests/test_litellm/proxy/db/test_db_spend_update_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,53 @@ async def test_add_spend_log_transaction_to_daily_agent_transaction_skips_when_a
writer.daily_agent_spend_update_queue.add_update.assert_not_called()


@pytest.mark.asyncio
async def test_daily_agent_transaction_calls_common_helper_once():
"""
Regression test for #21181: _common_add_spend_log_transaction_to_daily_transaction
should be called exactly once per request in the agent spend path, not twice.
"""
writer = DBSpendUpdateWriter()
mock_prisma = MagicMock()
mock_prisma.get_request_status = MagicMock(return_value="success")

payload = {
"request_id": "req-dedup",
"agent_id": "agent-dedup",
"user": "test-user",
"startTime": "2024-01-01T12:00:00",
"api_key": "test-key",
"model": "gpt-4",
"custom_llm_provider": "openai",
"model_group": "gpt-4-group",
"prompt_tokens": 20,
"completion_tokens": 10,
"spend": 0.3,
"metadata": '{"usage_object": {}}',
}

writer.daily_agent_spend_update_queue.add_update = AsyncMock()

with patch.object(
writer,
"_common_add_spend_log_transaction_to_daily_transaction",
wraps=writer._common_add_spend_log_transaction_to_daily_transaction,
) as mock_common:
await writer.add_spend_log_transaction_to_daily_agent_transaction(
payload=payload,
prisma_client=mock_prisma,
)

# The common helper should be called exactly once, not twice
assert mock_common.call_count == 1, (
f"Expected _common_add_spend_log_transaction_to_daily_transaction to be "
f"called once, but it was called {mock_common.call_count} times"
)

# Verify the transaction was still queued correctly
writer.daily_agent_spend_update_queue.add_update.assert_called_once()


@pytest.mark.asyncio
async def test_endpoint_field_is_correctly_mapped_from_call_type():
"""
Expand Down
Loading