mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(ptu): read a share map only through the terms registration requires
A ptu_shares map stored without ptu_count, cost_per_ptu_per_hour and ptu_effective_from, or one that does not add up to ptu_count, is refused at registration but was enforced once loaded: every other team got the 400 and the share holder a ceiling while no flat cost accrued. _deployment_shares now reads the shares through ptu_terms, so such a row reserves nothing, the same as before the map was read.
This commit is contained in:
parent
495cf74ccd
commit
6fb24d1dad
2 changed files with 31 additions and 5 deletions
|
|
@ -10,7 +10,7 @@ from collections.abc import Mapping, Sequence
|
|||
from dataclasses import dataclass
|
||||
from typing import Final, Generic, TypeVar
|
||||
|
||||
from litellm.litellm_core_utils.ptu_pricing import is_model_info_mapping, parsed_ptu_shares, ptu_terms
|
||||
from litellm.litellm_core_utils.ptu_pricing import is_model_info_mapping, ptu_terms
|
||||
from litellm.llms.azure.ptu_capacity import PTUCapacity, deployment_ptu_capacity, is_azure_deployment
|
||||
from litellm.router_utils.common_utils import team_may_use_deployment
|
||||
|
||||
|
|
@ -36,10 +36,17 @@ class PTUShareFilterResult(Generic[_DeploymentT]):
|
|||
|
||||
|
||||
def _deployment_shares(deployment: Mapping[str, object]) -> Mapping[str, int] | None:
|
||||
"""The teams a deployment's capacity is split across, else None.
|
||||
|
||||
Only a map registration would accept counts, read through the same terms flat cost accrues
|
||||
under, so a row that reached the table without its count, rate and start reserves nothing
|
||||
instead of refusing every other team while charging nobody.
|
||||
"""
|
||||
model_info: Final = deployment.get("model_info")
|
||||
if not is_model_info_mapping(model_info):
|
||||
if not is_model_info_mapping(model_info) or model_info.get("ptu_shares") is None:
|
||||
return None
|
||||
return parsed_ptu_shares(model_info.get("ptu_shares"))
|
||||
terms: Final = ptu_terms(model_info)
|
||||
return None if terms is None else terms.shares
|
||||
|
||||
|
||||
def filter_ptu_shared_deployments(
|
||||
|
|
|
|||
|
|
@ -19,13 +19,15 @@ _GPT6SOL: Final = AZURE_PTU_CAPACITY["gpt-6-sol"]
|
|||
_SHARES: Final = {"team-a": 30, "team-b": 20}
|
||||
|
||||
|
||||
def _shared(model: str = "azure/gpt-4.1", shares: object = _SHARES, deployment_id: str = "shared") -> dict:
|
||||
def _shared(
|
||||
model: str = "azure/gpt-4.1", shares: object = _SHARES, deployment_id: str = "shared", ptu_count: int | None = None
|
||||
) -> dict:
|
||||
return {
|
||||
"model_name": "gpt-4.1-ptu",
|
||||
"litellm_params": {"model": model},
|
||||
"model_info": {
|
||||
"id": deployment_id,
|
||||
"ptu_count": 50,
|
||||
"ptu_count": ptu_count or (sum(shares.values()) if isinstance(shares, dict) else 50),
|
||||
"cost_per_ptu_per_hour": 1.0,
|
||||
"ptu_effective_from": "2026-01-01T00:00:00Z",
|
||||
"ptu_shares": shares,
|
||||
|
|
@ -81,6 +83,23 @@ def test_a_single_team_deployment_and_a_malformed_share_map_are_not_filtered_her
|
|||
assert result.withheld is False
|
||||
|
||||
|
||||
_TERMLESS_SHARED: Final = {
|
||||
"model_name": "gpt-4.1-ptu",
|
||||
"litellm_params": {"model": "azure/gpt-4.1"},
|
||||
"model_info": {"id": "shared", "ptu_shares": _SHARES},
|
||||
}
|
||||
|
||||
|
||||
def test_a_share_map_registration_would_refuse_reserves_nothing():
|
||||
"""Registration refuses ``ptu_shares`` without the count, rate and start they split, and a map
|
||||
that does not add up to the count, so a row carrying either shape holds nobody's capacity:
|
||||
every team is served from it and no ceiling applies, the same as before the map was read."""
|
||||
short: Final = _shared(shares={"team-a": 30}, ptu_count=50)
|
||||
for deployment in (_TERMLESS_SHARED, short):
|
||||
assert filter_ptu_shared_deployments([deployment], "team-z").withheld is False
|
||||
assert _unaliased_ceiling([deployment], "team-a", "gpt-4.1-ptu") is None
|
||||
|
||||
|
||||
def test_a_team_is_served_from_its_shared_deployment_first_and_never_from_another_teams_reservation():
|
||||
"""team-b holds a share on the shared deployment and the open one serves everyone, while the
|
||||
deployment reserved for team-a alone is withheld from it the way the router withholds it."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue