mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-11 08:38:24 +00:00
fix(cost): skip a chat usage.cost that already holds litellm's stamped bill and Responses API objects
This commit is contained in:
parent
55bfef86d9
commit
0d0877c73a
3 changed files with 33 additions and 9 deletions
|
|
@ -1021,16 +1021,23 @@ OWN_REPORTED_COST_READER_PROVIDERS: Final = frozenset({"xai", "perplexity", "ope
|
|||
|
||||
|
||||
def _carries_litellm_bill(response: object) -> bool:
|
||||
"""A response the stream builder already priced carries litellm's own bill in ``usage.cost`` too."""
|
||||
hidden: Final[object] = getattr(response, "_hidden_params", None)
|
||||
stamped: Final = hidden.get("response_cost") if isinstance(hidden, Mapping) else None
|
||||
hidden: Final = as_str_mapping(getattr(response, "_hidden_params", None))
|
||||
stamped: Final[object] = None if hidden is None else hidden.get("response_cost")
|
||||
return isinstance(stamped, (int, float)) and not isinstance(stamped, bool)
|
||||
|
||||
|
||||
def billed_usage_cost(response: object, custom_llm_provider: str | None) -> float | None:
|
||||
"""The charge an OpenAI-compatible upstream reports in ``usage.cost``, billed unless the provider has its own
|
||||
reader or the number is litellm's own bill written back onto the usage."""
|
||||
if custom_llm_provider in OWN_REPORTED_COST_READER_PROVIDERS or _carries_litellm_bill(response):
|
||||
"""The charge an OpenAI-compatible upstream reports in a chat completion's ``usage.cost``. Skipped once the stream
|
||||
builder stamped litellm's own bill onto the response (its ``usage.cost`` then holds that bill), and for Responses
|
||||
API objects, whose terminal ``usage.cost`` litellm also rewrites and whose upstream figure is billed through
|
||||
``set_response_cost_in_hidden_params``."""
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
if (
|
||||
custom_llm_provider in OWN_REPORTED_COST_READER_PROVIDERS
|
||||
or not isinstance(response, ModelResponse)
|
||||
or _carries_litellm_bill(response)
|
||||
):
|
||||
return None
|
||||
cost: Final = provider_reported_usage_cost(_usage_field(response, "usage"), custom_llm_provider)
|
||||
return cost if cost is not None and math.isfinite(cost) and cost >= 0 else None
|
||||
|
|
|
|||
|
|
@ -803,3 +803,20 @@ class TestReceiveStampSurvivesASecondMetadataBucket:
|
|||
}
|
||||
|
||||
assert get_litellm_metadata_from_kwargs(kwargs)["litellm_received_at"] is own
|
||||
|
||||
|
||||
def test_billed_usage_cost_bills_any_chat_upstream_without_its_own_reader() -> None:
|
||||
from types import SimpleNamespace
|
||||
|
||||
from litellm.litellm_core_utils.core_helpers import billed_usage_cost
|
||||
from litellm.types.utils import ModelResponse, Usage
|
||||
|
||||
usage = Usage(prompt_tokens=100, completion_tokens=20, total_tokens=120, cost=0.037)
|
||||
chat = ModelResponse(usage=usage)
|
||||
assert billed_usage_cost(chat, "openai") == 0.037
|
||||
assert billed_usage_cost(chat, "openrouter") == 0.037
|
||||
assert billed_usage_cost(chat, "xai") is None
|
||||
assert billed_usage_cost(SimpleNamespace(usage=usage), "openai") is None
|
||||
stamped = ModelResponse(usage=usage)
|
||||
stamped._hidden_params["response_cost"] = 0.037
|
||||
assert billed_usage_cost(stamped, "openai") is None
|
||||
|
|
|
|||
|
|
@ -2659,7 +2659,7 @@ def test_perplexity_streaming_dict_cost_bills_through_its_own_calculator():
|
|||
) == pytest.approx(0.00503)
|
||||
|
||||
|
||||
def test_openai_compatible_streaming_cost_is_priced_from_the_cost_map():
|
||||
def test_openai_compatible_streaming_reported_cost_is_billed_instead_of_the_cost_map():
|
||||
import litellm
|
||||
from litellm.cost_calculator import (
|
||||
get_response_cost_from_hidden_params,
|
||||
|
|
@ -2681,7 +2681,7 @@ def test_openai_compatible_streaming_cost_is_priced_from_the_cost_map():
|
|||
id="chatcmpl-openai-compatible",
|
||||
model=model,
|
||||
choices=[],
|
||||
usage=Usage(completion_tokens=5, prompt_tokens=10, total_tokens=15, cost=3_144_000),
|
||||
usage=Usage(completion_tokens=5, prompt_tokens=10, total_tokens=15, cost=0.037),
|
||||
)
|
||||
|
||||
CustomStreamWrapper._propagate_usage_cost_to_hidden_params(complete_response, "openai")
|
||||
|
|
@ -2693,7 +2693,7 @@ def test_openai_compatible_streaming_cost_is_priced_from_the_cost_map():
|
|||
custom_llm_provider="openai",
|
||||
call_type="completion",
|
||||
optional_params={},
|
||||
) == pytest.approx(2e-5)
|
||||
) == pytest.approx(0.037)
|
||||
|
||||
|
||||
def test_xai_streaming_reported_cost_still_takes_the_margin(monkeypatch):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue