Merge pull request #38479 from yatishgoel/litellm_fix_model_rename_router_sync

fix(router): apply model renames to the in-memory deployment list
This commit is contained in:
Mateo Wang 2026-08-31 15:22:30 -07:00 • committed by GitHub
commit 5a0ed05765
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 67 additions and 1 deletions

View file

@ -9152,7 +9152,8 @@ class Router:
if _deployment_on_router is not None:
# deployment with this model_id exists on the router
if (
deployment.litellm_params == _deployment_on_router.litellm_params
deployment.model_name == _deployment_on_router.model_name
and deployment.litellm_params == _deployment_on_router.litellm_params
and deployment.model_info == _deployment_on_router.model_info
):
# No need to update

View file

@ -8155,6 +8155,71 @@ class TestUpsertDeploymentRollback:
assert len(router.model_list) == 1
class TestUpsertDeploymentRename:
"""
Issue #38360: renaming a model wrote the new `model_name` to the db, but the reload's
`upsert_deployment` compared only `litellm_params` and `model_info`. A rename with no
other edit therefore compared equal and the router kept the old name until a restart,
so `/model/info` and `/v1/models` served the stale name and the new one was unroutable.
"""
@staticmethod
def _router() -> "litellm.Router":
return litellm.Router(
model_list=[
{
"model_name": "old-name",
"litellm_params": {"model": "openai/gpt-4o", "api_key": "sk-test"},
"model_info": {"id": "rename-1", "db_model": True},
}
]
)
@staticmethod
def _deployment(model_name: str, tpm: int | None = None):
from litellm.types.router import Deployment, LiteLLM_Params, ModelInfo
return Deployment(
model_name=model_name,
litellm_params=LiteLLM_Params(model="openai/gpt-4o", api_key="sk-test", tpm=tpm),
model_info=ModelInfo(id="rename-1", db_model=True),
)
def test_rename_only_updates_the_router(self):
router = self._router()
assert router.upsert_deployment(deployment=self._deployment("new-name")) is not None
assert [model["model_name"] for model in router.model_list] == ["new-name"]
renamed = router.get_deployment(model_id="rename-1")
assert renamed is not None
assert renamed.model_name == "new-name"
def test_rename_only_makes_the_new_name_routable(self):
router = self._router()
router.upsert_deployment(deployment=self._deployment("new-name"))
assert router.get_model_ids(model_name="new-name") == ["rename-1"]
assert router.get_model_ids(model_name="old-name") == []
def test_rename_alongside_another_edit_still_updates(self):
router = self._router()
router.upsert_deployment(deployment=self._deployment("new-name", tpm=1234))
assert router.get_model_ids(model_name="new-name") == ["rename-1"]
renamed = router.get_deployment(model_id="rename-1")
assert renamed is not None
assert renamed.litellm_params.tpm == 1234
def test_unchanged_deployment_is_still_a_no_op(self):
router = self._router()
assert router.upsert_deployment(deployment=self._deployment("old-name")) is None
assert [model["model_name"] for model in router.model_list] == ["old-name"]
class TestConsumedRequestTagsStamp:
"""Issue #36621: when a request's tags select a tagged pre-routing strategy, those
tags are consumed by the selection; the hook must stamp the rewritten model group so