diff --git a/litellm/proxy/management_endpoints/model_management_endpoints.py b/litellm/proxy/management_endpoints/model_management_endpoints.py index a247fc1672c..f705c296cdc 100644 --- a/litellm/proxy/management_endpoints/model_management_endpoints.py +++ b/litellm/proxy/management_endpoints/model_management_endpoints.py @@ -138,7 +138,6 @@ from litellm.types.router import ( updateLiteLLMParams, ) from litellm.types.utils import ( - COST_MAP_LOOKUP_KEY, echoed_cost_map_fields, echoed_cost_map_pricing_fields, without_server_derived_pricing, @@ -876,12 +875,11 @@ def _ptu_priced_deployment(model_params: Deployment) -> Deployment: ) -def _cost_map_entry(model_info: Mapping[str, object]) -> Mapping[str, object]: - key: Final = model_info.get(COST_MAP_LOOKUP_KEY) - if not isinstance(key, str): - return MappingProxyType({}) +def _cost_map_entry(db_model: Deployment, incoming_model_info: Mapping[str, object]) -> Mapping[str, object]: + base_model: Final = incoming_model_info.get("base_model") + lookup: Final = base_model if isinstance(base_model, str) else db_model.litellm_params.model try: - return MappingProxyType(dict(litellm.get_model_info(model=key))) + return MappingProxyType(dict(litellm.get_model_info(model=lookup))) except Exception: return MappingProxyType({}) @@ -909,7 +907,9 @@ def update_db_model(db_model: Deployment, updated_patch: updateDeployment) -> Pr # update model info if updated_patch.model_info: incoming_model_info: Final = updated_patch.model_info.model_dump(exclude_none=True) - echoed_fields: Final = echoed_cost_map_fields(incoming_model_info, _cost_map_entry(incoming_model_info)) + echoed_fields: Final = echoed_cost_map_fields( + incoming_model_info, _cost_map_entry(db_model, incoming_model_info) + ) merged_model_info.update( MappingProxyType( dict( diff --git a/tests/test_litellm/proxy/management_endpoints/test_model_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_model_management_endpoints.py index 38718e5752c..604c68d7134 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_model_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_model_management_endpoints.py @@ -3961,7 +3961,7 @@ class TestModelInfoCostMapEchoFilter: from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo - entry = litellm.get_model_info("gpt-5.6") + entry = litellm.get_model_info("openai/gpt-5.6") echo = {**entry, "id": "dep-echo-0", "db_model": True, "access_groups": ["prod"]} db_model = Deployment( model_name="gpt-5.6", @@ -3987,7 +3987,7 @@ class TestModelInfoCostMapEchoFilter: from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo - entry = litellm.get_model_info("gpt-5.6") + entry = litellm.get_model_info("openai/gpt-5.6") echo = { **entry, "id": "dep-echo-1", @@ -4020,7 +4020,7 @@ class TestModelInfoCostMapEchoFilter: from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo from litellm.types.utils import echoed_cost_map_fields - entry = litellm.get_model_info("gpt-5.6") + entry = litellm.get_model_info("openai/gpt-5.6") assert echoed_cost_map_fields({"max_input_tokens": entry["max_input_tokens"]}, entry) == () db_model = Deployment( model_name="gpt-5.6", @@ -4049,7 +4049,7 @@ class TestModelInfoCostMapEchoFilter: from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo - entry = litellm.get_model_info("gpt-5.6") + entry = litellm.get_model_info("openai/gpt-5.6") db_model = Deployment( model_name="gpt-5.6", litellm_params=LiteLLM_Params(model="openai/gpt-5.6"), @@ -4072,7 +4072,7 @@ class TestModelInfoCostMapEchoFilter: from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo - entry = litellm.get_model_info("gpt-5.6") + entry = litellm.get_model_info("openai/gpt-5.6") db_model = Deployment( model_name="gpt-5.6", litellm_params=LiteLLM_Params(model="openai/gpt-5.6"), @@ -4090,6 +4090,76 @@ class TestModelInfoCostMapEchoFilter: assert info["mode"] == "chat" assert info["access_groups"] == ["staging"] + def test_echo_is_compared_against_the_deployments_lookup_not_the_key(self): + import litellm + + from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model + from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo + + lookup_pairs: Final = ( + ("openai/gpt-5.6", "gpt-5.6"), + ("openai/gpt-4.1-mini", "gpt-4.1-mini"), + ) + lookup_data: Final = tuple( + (deployment_model, deployment_entry, differing_fields) + for deployment_model, key_model in lookup_pairs + for deployment_entry in (litellm.get_model_info(deployment_model),) + for key_entry in (litellm.get_model_info(key_model),) + for differing_fields in ( + frozenset( + k for k in deployment_entry if k in key_entry and deployment_entry[k] != key_entry[k] + ), + ) + if differing_fields + ) + if not lookup_data: + pytest.skip("No deployment/key cost-map lookup differences are available") + + deployment_model, entry, differing_fields = lookup_data[0] + assert differing_fields + db_model = Deployment( + model_name=deployment_model, + litellm_params=LiteLLM_Params(model=deployment_model), + model_info=ModelInfo(id="dep-echo-5"), + ) + echo = {**entry, "id": "dep-echo-5", "db_model": True, "access_groups": ["prod"]} + + result = update_db_model( + db_model=db_model, + updated_patch=updateDeployment(model_info=ModelInfo(**echo)), + ) + + info = json.loads(result["model_info"]) + assert not frozenset(info).intersection(frozenset(entry) - frozenset(("mode",))) + + def test_base_model_wins_over_litellm_params_model_for_the_lookup(self): + import litellm + + from litellm.proxy.management_endpoints.model_management_endpoints import update_db_model + from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo + + entry = litellm.get_model_info("azure/gpt-5.6") + db_model = Deployment( + model_name="azure/my-deploy", + litellm_params=LiteLLM_Params(model="azure/my-deploy"), + model_info=ModelInfo(id="dep-echo-6", base_model="azure/gpt-5.6"), + ) + echo = { + **entry, + "id": "dep-echo-6", + "base_model": "azure/gpt-5.6", + "db_model": True, + } + + result = update_db_model( + db_model=db_model, + updated_patch=updateDeployment(model_info=ModelInfo(**echo)), + ) + + info = json.loads(result["model_info"]) + assert not frozenset(info).intersection(frozenset(entry) - frozenset(("mode",))) + assert info["base_model"] == "azure/gpt-5.6" + class TestUpdateDBModelClearCacheControlInjectionPoints: def test_explicit_null_removes_stored_injection_points(self):