mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-29 01:42:19 +00:00
Live proxy suites for the sail provider added in #42840: chat with service_tier flex, balanced and absent bills each window's cost-map rates read at run time and echoes no service_tier; /v1/responses with extra_body.metadata.completion_window balanced bills the _balanced keys; a flex-only sail model refuses the asap and balanced windows with sail's own 400 and leaves only a zero-spend failure row; openai keeps its own service_tier and bills the tier it reports back. MUTATIONS.md records the five production mutations, each killed, and the final green run. It is review evidence and not meant to merge.
140 lines
5.4 KiB
Python
140 lines
5.4 KiB
Python
"""Runtime-priced Sail deployments for the completion-window (service_tier) suites.
|
|
|
|
Sail bills a request by the `metadata.completion_window` it ran under, and the
|
|
cost map carries one rate set per window: the base keys for `asap`, `*_balanced`
|
|
and `*_flex`. Every rate here is read off the proxy's own
|
|
/public/litellm_model_cost_map at run time, so the tests compare a bill against
|
|
the same numbers the gateway priced it from and never pin a vendor's price.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping, Sequence
|
|
from dataclasses import dataclass
|
|
from typing import Final
|
|
|
|
from models import CostMapEntry
|
|
|
|
SAIL_PROVIDER: Final = "sail"
|
|
SAIL_API_KEY: Final = "os.environ/SAIL_API_KEY"
|
|
COST_REL_TOLERANCE: Final = 1e-9
|
|
|
|
|
|
def within_rel(actual: float | None, expected: float) -> bool:
|
|
"""Spend math agrees to one part in 1e9, the tightest tolerance float sums hold; no value never agrees."""
|
|
return actual is not None and abs(actual - expected) <= abs(expected) * COST_REL_TOLERANCE
|
|
|
|
|
|
def all_within_rel(actual: Sequence[float], expected: Sequence[float]) -> bool:
|
|
"""Every component of one bill agrees with the matching component of another."""
|
|
return len(actual) == len(expected) and all(within_rel(a, e) for a, e in zip(actual, expected, strict=True))
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class TierRates:
|
|
"""The three per-token rates one window bills at."""
|
|
|
|
input: float
|
|
output: float
|
|
cache_read: float
|
|
|
|
def bill(
|
|
self, *, prompt_tokens: int, cached_tokens: int, completion_tokens: int, reasoning_tokens: int
|
|
) -> tuple[float, float, float, float, float]:
|
|
"""(input_cost, output_cost, cache_read_cost, reasoning_cost, total_cost) the
|
|
gateway must file for this usage: cached prompt tokens at the cache-read rate,
|
|
the rest of the prompt at the input rate, every completion token (reasoning
|
|
included) at the output rate, reasoning also reported on its own line."""
|
|
cache_read_cost: Final = cached_tokens * self.cache_read
|
|
input_cost: Final = (prompt_tokens - cached_tokens) * self.input + cache_read_cost
|
|
output_cost: Final = completion_tokens * self.output
|
|
return (
|
|
input_cost,
|
|
output_cost,
|
|
cache_read_cost,
|
|
reasoning_tokens * self.output,
|
|
input_cost + output_cost,
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class WindowPricedModel:
|
|
"""A Sail cost-map row priced for every completion window."""
|
|
|
|
model: str
|
|
asap: TierRates
|
|
balanced: TierRates
|
|
flex: TierRates
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class FlexOnlyModel:
|
|
"""A Sail cost-map row priced for the flex window and nothing else."""
|
|
|
|
model: str
|
|
flex: TierRates
|
|
|
|
|
|
def _rates(input_rate: float | None, output_rate: float | None, cache_rate: float | None) -> TierRates | None:
|
|
if input_rate is None or output_rate is None or cache_rate is None:
|
|
return None
|
|
return TierRates(input=input_rate, output=output_rate, cache_read=cache_rate)
|
|
|
|
|
|
def _base(entry: CostMapEntry) -> TierRates | None:
|
|
return _rates(entry.input_cost_per_token, entry.output_cost_per_token, entry.cache_read_input_token_cost)
|
|
|
|
|
|
def _balanced(entry: CostMapEntry) -> TierRates | None:
|
|
return _rates(
|
|
entry.input_cost_per_token_balanced,
|
|
entry.output_cost_per_token_balanced,
|
|
entry.cache_read_input_token_cost_balanced,
|
|
)
|
|
|
|
|
|
def _flex(entry: CostMapEntry) -> TierRates | None:
|
|
return _rates(
|
|
entry.input_cost_per_token_flex, entry.output_cost_per_token_flex, entry.cache_read_input_token_cost_flex
|
|
)
|
|
|
|
|
|
def _sail_chat_rows(cost_map: Mapping[str, CostMapEntry]) -> tuple[tuple[str, CostMapEntry], ...]:
|
|
return tuple(
|
|
(model, entry)
|
|
for model, entry in sorted(cost_map.items())
|
|
if entry.litellm_provider == SAIL_PROVIDER and entry.mode == "chat" and entry.deprecation_date is None
|
|
)
|
|
|
|
|
|
def _window_priced(model: str, entry: CostMapEntry) -> WindowPricedModel | None:
|
|
asap: Final = _base(entry)
|
|
balanced: Final = _balanced(entry)
|
|
flex: Final = _flex(entry)
|
|
if asap is None or balanced is None or flex is None:
|
|
return None
|
|
totals: Final = {asap.input + asap.output, balanced.input + balanced.output, flex.input + flex.output}
|
|
return WindowPricedModel(model=model, asap=asap, balanced=balanced, flex=flex) if len(totals) == 3 else None
|
|
|
|
|
|
def cheapest_window_priced_model(cost_map: Mapping[str, CostMapEntry]) -> WindowPricedModel:
|
|
"""The Sail chat row with distinct asap, balanced and flex rate sets whose asap
|
|
input rate is lowest, so the tier comparison runs on the cheapest eligible model."""
|
|
priced: Final = tuple(
|
|
priced_row
|
|
for model, entry in _sail_chat_rows(cost_map)
|
|
if (priced_row := _window_priced(model, entry)) is not None
|
|
)
|
|
assert priced, f"no sail chat row carries distinct asap, balanced and flex rates: {sorted(cost_map)}"
|
|
return min(priced, key=lambda candidate: candidate.asap.input)
|
|
|
|
|
|
def cheapest_flex_only_model(cost_map: Mapping[str, CostMapEntry]) -> FlexOnlyModel:
|
|
"""The Sail chat row that carries flex rates and no balanced rates, cheapest first."""
|
|
priced: Final = tuple(
|
|
FlexOnlyModel(model=model, flex=flex)
|
|
for model, entry in _sail_chat_rows(cost_map)
|
|
if (flex := _flex(entry)) is not None and _balanced(entry) is None
|
|
)
|
|
assert priced, f"no sail chat row is priced for flex only: {sorted(cost_map)}"
|
|
return min(priced, key=lambda candidate: candidate.flex.input)
|