mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
fix(proxy): report a zero cost split only under a zero cost total
The component headers were filled from call-type membership alone, while the total they sit beside keeps its real value when the read priced normally, so a breakdown that had not landed by the time headers were built could advertise a real total next to an all-zero split. The split is now reported as zero only when the total agrees with it, and is otherwise left absent.
This commit is contained in:
parent
271fdbd22e
commit
5bde81a5f9
2 changed files with 42 additions and 3 deletions
|
|
@ -1308,21 +1308,37 @@ _ZERO_COST_BREAKDOWN: Final = CostBreakdownHeaderValues(
|
|||
read or management route still finds the whole family rather than a partially populated one."""
|
||||
|
||||
|
||||
def _totals_to_zero(response_cost: float | str | None) -> bool:
|
||||
"""Whether the total these headers carry is zero, counting a total no route ever priced as one.
|
||||
|
||||
A component split is only reported as zero alongside a total that agrees with it, so a read
|
||||
that did price normally never advertises a real total beside an all-zero split.
|
||||
"""
|
||||
if response_cost is None or response_cost == "":
|
||||
return True
|
||||
try:
|
||||
return float(response_cost) == 0.0
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
|
||||
|
||||
def _get_cost_breakdown_from_logging_obj(
|
||||
litellm_logging_obj: LiteLLMLoggingObj | None,
|
||||
response_cost: float | str | None = None,
|
||||
) -> CostBreakdownHeaderValues:
|
||||
"""Extract discount, margin, and per-component cost information from logging object's cost breakdown.
|
||||
|
||||
A non-inference call that priced at zero never records a breakdown, so its components are
|
||||
reported as zero here. Any such call that did price normally (retrieving a background response,
|
||||
and the cost poller's read of one) has a stored breakdown and takes the branch below instead.
|
||||
and the cost poller's read of one) reports the breakdown it stored, or nothing at all when the
|
||||
breakdown has not landed yet.
|
||||
"""
|
||||
if not litellm_logging_obj or not hasattr(litellm_logging_obj, "cost_breakdown"):
|
||||
return CostBreakdownHeaderValues()
|
||||
|
||||
cost_breakdown: Final = litellm_logging_obj.cost_breakdown
|
||||
if not cost_breakdown:
|
||||
if litellm_logging_obj.call_type in NON_INFERENCE_CALL_TYPES:
|
||||
if litellm_logging_obj.call_type in NON_INFERENCE_CALL_TYPES and _totals_to_zero(response_cost):
|
||||
return _ZERO_COST_BREAKDOWN
|
||||
return CostBreakdownHeaderValues()
|
||||
|
||||
|
|
@ -1467,7 +1483,9 @@ class ProxyBaseLLMRequestProcessing:
|
|||
exclude_values: Final = {"", None, "None"}
|
||||
hidden_params = hidden_params or {}
|
||||
|
||||
cost_breakdown: Final = _get_cost_breakdown_from_logging_obj(litellm_logging_obj=litellm_logging_obj)
|
||||
cost_breakdown: Final = _get_cost_breakdown_from_logging_obj(
|
||||
litellm_logging_obj=litellm_logging_obj, response_cost=response_cost
|
||||
)
|
||||
|
||||
# Calculate updated spend for header (include current response_cost)
|
||||
current_spend: Final = user_api_key_dict.spend or 0.0
|
||||
|
|
|
|||
|
|
@ -5116,6 +5116,27 @@ class TestCostHeadersForCallsPricedAtZero:
|
|||
|
||||
assert breakdown == CostBreakdownHeaderValues()
|
||||
|
||||
def test_cost_breakdown_never_zeroes_the_split_under_a_real_total(self):
|
||||
"""Reading a background response prices normally, so a breakdown that has not landed by the
|
||||
time headers are built is reported as absent rather than as a zero split contradicting the
|
||||
real total alongside it."""
|
||||
breakdown = _get_cost_breakdown_from_logging_obj(
|
||||
litellm_logging_obj=self._logging_obj(call_type="aget_responses"),
|
||||
response_cost=1.96e-05,
|
||||
)
|
||||
|
||||
assert breakdown == CostBreakdownHeaderValues()
|
||||
|
||||
def test_cost_breakdown_reports_zero_components_under_a_zero_total(self):
|
||||
breakdown = _get_cost_breakdown_from_logging_obj(
|
||||
litellm_logging_obj=self._logging_obj(call_type="aget_responses"),
|
||||
response_cost=0.0,
|
||||
)
|
||||
|
||||
assert breakdown.original_cost == 0.0
|
||||
assert breakdown.input_cost == 0.0
|
||||
assert breakdown.output_cost == 0.0
|
||||
|
||||
|
||||
class TestPreCallWithFallbacksOnLocalRateLimit:
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue