From af44f48623abe1e70bcd828ae8efdcdb1fcdac79 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 16:11:08 +0000 Subject: [PATCH] fix(cost): resolve cache pricing via base_model to silence spurious register_model warning --- litellm/utils.py | 21 +++++++++++ .../test_register_model_custom_pricing.py | 35 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/litellm/utils.py b/litellm/utils.py index 19c2fe16085..5c80a092402 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -2651,6 +2651,23 @@ def _resolve_builtin_model_cost_entry(key: str, provider: str) -> Optional[Dict[ return None +def _resolve_base_model_cost_entry(base_model: Optional[str], provider: str) -> Optional[Dict[str, Any]]: + """Resolve a built-in ``model_cost`` entry from a deployment's ``base_model``. + + Deployments that price via ``model_info.base_model`` (e.g. an Azure + deployment aliasing ``azure/text-embedding-3-large``) carry no cost keys on + their own key, so ``register_model`` would otherwise warn about missing cache + pricing even though the base model fully describes it. Falls back to the + prefix/region resolver for base models whose exact key is not present. + """ + if not isinstance(base_model, str) or not base_model: + return None + entry = litellm.model_cost.get(base_model) + if entry is not None and entry.get("litellm_provider") is not None: + return dict(entry) + return _resolve_builtin_model_cost_entry(key=base_model, provider=provider) + + def register_model(model_cost: Union[str, dict]): """ Register new / Override existing models (and their pricing) to specific providers. @@ -2698,6 +2715,10 @@ def register_model(model_cost: Union[str, dict]): existing_model = {} model_cost_key = key builtin_entry = _resolve_builtin_model_cost_entry(key=_key_str, provider=provider) + if builtin_entry is None: + builtin_entry = _resolve_base_model_cost_entry( + base_model=value.get("base_model"), provider=provider + ) if builtin_entry is not None: for field in _CACHE_PRICING_FIELDS: if value.get(field) is None and builtin_entry.get(field) is not None: diff --git a/tests/test_litellm/test_register_model_custom_pricing.py b/tests/test_litellm/test_register_model_custom_pricing.py index ba82bfaadc6..508a89e742c 100644 --- a/tests/test_litellm/test_register_model_custom_pricing.py +++ b/tests/test_litellm/test_register_model_custom_pricing.py @@ -439,6 +439,41 @@ def test_register_model_warns_when_no_builtin_match_for_cache_pricing(caplog): litellm.model_cost.pop(registered_key, None) +def test_register_model_no_warning_when_base_model_resolves_cache_pricing(caplog): + """Regression for https://github.com/BerriAI/litellm/issues/32484. + + A deployment priced via ``model_info.base_model`` (e.g. an Azure deployment + aliasing ``azure/text-embedding-3-large``) carries no cost keys on its own + key, so ``register_model`` used to warn that cache cost fields default to 0 + even though the base model fully describes pricing. When ``base_model`` + resolves to a built-in entry the warning must not fire. + """ + import logging + + from litellm._logging import verbose_logger + + registered_key = "azure/my-deployment-name-32484" + litellm.model_cost.pop(registered_key, None) + + try: + with caplog.at_level(logging.WARNING, logger=verbose_logger.name): + litellm.register_model( + { + registered_key: { + "litellm_provider": "azure", + "base_model": "azure/text-embedding-3-large", + } + } + ) + + assert not any( + registered_key in record.message and "cache_creation_input_token_cost" in record.message + for record in caplog.records + ), "did not expect a cache-pricing warning when base_model resolves to a built-in entry" + finally: + litellm.model_cost.pop(registered_key, None) + + def test_register_model_router_add_deployment_custom_pricing_applies(): """End-to-end regression for https://github.com/BerriAI/litellm/issues/28336.