mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix(auth): resolve model_group_alias before the zero-cost budget bypass check
This commit is contained in:
parent
3c2264cfac
commit
901cfbd4bf
2 changed files with 60 additions and 2 deletions
|
|
@ -187,7 +187,8 @@ def _is_model_cost_zero(model: Optional[Union[str, List[str]]], llm_router: Opti
|
|||
continue
|
||||
try:
|
||||
# Use router's get_model_group_info method directly for better reliability
|
||||
model_group_info = llm_router.get_model_group_info(model_group=model_name)
|
||||
resolved_name = _resolve_model_group_alias(model_name, llm_router)
|
||||
model_group_info = llm_router.get_model_group_info(model_group=resolved_name)
|
||||
|
||||
if model_group_info is None:
|
||||
# Model not found or no pricing info available
|
||||
|
|
@ -224,7 +225,7 @@ def _is_model_cost_zero(model: Optional[Union[str, List[str]]], llm_router: Opti
|
|||
# not from defaulted sparse auto-registration entries.
|
||||
# See: https://github.com/BerriAI/litellm/issues/24770
|
||||
safe_name = str(model_name).replace("\n", "").replace("\r", "")
|
||||
if not _is_cost_explicitly_configured(model_name, llm_router):
|
||||
if not _is_cost_explicitly_configured(resolved_name, llm_router):
|
||||
verbose_proxy_logger.debug(
|
||||
"Model %s has zero cost but no explicit cost "
|
||||
"configuration in model_cost entry — treating as unknown "
|
||||
|
|
@ -253,6 +254,20 @@ def _is_model_cost_zero(model: Optional[Union[str, List[str]]], llm_router: Opti
|
|||
return True
|
||||
|
||||
|
||||
def _resolve_model_group_alias(model: str, llm_router: "Router") -> str:
|
||||
"""
|
||||
Map a user-facing ``model_group_alias`` name onto the model group it points at.
|
||||
|
||||
Returns ``model`` unchanged when it isn't an alias.
|
||||
"""
|
||||
item = llm_router.model_group_alias.get(model)
|
||||
if isinstance(item, str):
|
||||
return item
|
||||
if isinstance(item, dict):
|
||||
return item.get("model", model)
|
||||
return model
|
||||
|
||||
|
||||
def _is_cost_explicitly_configured(model: str, llm_router: "Router") -> bool:
|
||||
"""
|
||||
Check if any deployment in the model group has cost fields explicitly
|
||||
|
|
|
|||
|
|
@ -162,6 +162,49 @@ class TestUnmappedModelBudgetEnforcement:
|
|||
# Subsequent call sees the new pricing and enforces budget.
|
||||
assert _is_model_cost_zero(model="ramping-model", llm_router=router) is False
|
||||
|
||||
def test_free_model_behind_model_group_alias_bypasses_budget(self):
|
||||
"""
|
||||
Regression test for https://github.com/BerriAI/litellm/issues/35369:
|
||||
an alias pointing at an explicitly free model group must bypass budget
|
||||
checks exactly like the underlying model group does.
|
||||
"""
|
||||
router = Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "free-model",
|
||||
"litellm_params": {
|
||||
"model": "openai/nonexistent-but-free-model",
|
||||
"api_key": "sk-fake",
|
||||
"input_cost_per_token": 0.0,
|
||||
"output_cost_per_token": 0.0,
|
||||
},
|
||||
},
|
||||
],
|
||||
model_group_alias={
|
||||
"free-alias": "free-model",
|
||||
"free-alias-hidden": {"model": "free-model", "hidden": True},
|
||||
},
|
||||
)
|
||||
assert _is_model_cost_zero(model="free-model", llm_router=router) is True
|
||||
assert _is_model_cost_zero(model="free-alias", llm_router=router) is True
|
||||
assert _is_model_cost_zero(model="free-alias-hidden", llm_router=router) is True
|
||||
|
||||
def test_paid_model_behind_model_group_alias_enforces_budget(self):
|
||||
"""An alias pointing at a paid model group must still enforce budget."""
|
||||
router = Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "paid-model",
|
||||
"litellm_params": {
|
||||
"model": "openai/gpt-4o-mini",
|
||||
"api_key": "sk-fake",
|
||||
},
|
||||
},
|
||||
],
|
||||
model_group_alias={"paid-alias": "paid-model"},
|
||||
)
|
||||
assert _is_model_cost_zero(model="paid-alias", llm_router=router) is False
|
||||
|
||||
def test_handles_router_without_zero_cost_cache_attribute(self):
|
||||
"""Tolerate router-like objects (e.g. ``MagicMock`` stand-ins) that
|
||||
do not expose ``_zero_cost_cache`` — the auth check must still
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue