From fc091c1248e3cb3276fbebeda2a8ad40aae56bf5 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Tue, 1 Sep 2026 11:04:25 -0700 Subject: [PATCH] fix(prometheus): keep team alias and team wildcard names out of the other bucket --- litellm/integrations/prometheus.py | 16 ++++++-- ..._prometheus_requested_model_cardinality.py | 38 +++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/litellm/integrations/prometheus.py b/litellm/integrations/prometheus.py index 29b7419a91b..651f9c5d392 100644 --- a/litellm/integrations/prometheus.py +++ b/litellm/integrations/prometheus.py @@ -169,10 +169,11 @@ def _get_proxy_llm_router() -> Router | None: def _bounded_requested_model_label(requested_model: str | None) -> str | None: """ Bound ``requested_model`` label cardinality: names the router recognizes - (model names, deployment ids, aliases, routing groups) or matches via a - wildcard/pattern route keep their own label value; any other - client-supplied string collapses into the single ``other`` bucket. With no - router to vouch for the string, it also collapses to ``other``. + (model names, deployment ids, aliases, routing groups, team public model + names) or matches via a global or team wildcard/pattern route keep their + own label value; any other client-supplied string collapses into the + single ``other`` bucket. With no router to vouch for the string, it also + collapses to ``other``. """ if not requested_model: return requested_model @@ -181,8 +182,15 @@ def _bounded_requested_model_label(requested_model: str | None) -> str | None: return UNRECOGNIZED_REQUESTED_MODEL_LABEL if llm_router.is_recognized_model(requested_model): return requested_model + if requested_model in llm_router.team_public_model_names: + return requested_model if llm_router.pattern_router.route(requested_model) is not None: return requested_model + if any( + team_pattern_router.route(requested_model) is not None + for team_pattern_router in llm_router.team_pattern_routers.values() + ): + return requested_model return UNRECOGNIZED_REQUESTED_MODEL_LABEL diff --git a/tests/test_litellm/integrations/test_prometheus_requested_model_cardinality.py b/tests/test_litellm/integrations/test_prometheus_requested_model_cardinality.py index 2343384e762..8d803eeab18 100644 --- a/tests/test_litellm/integrations/test_prometheus_requested_model_cardinality.py +++ b/tests/test_litellm/integrations/test_prometheus_requested_model_cardinality.py @@ -58,6 +58,24 @@ def router(): ) +@pytest.fixture +def team_router(): + return litellm.Router( + model_list=[ + { + "model_name": "team-internal-gpt", + "litellm_params": {"model": "openai/gpt-4o-mini", "api_key": "fake-key"}, + "model_info": {"team_id": "team-1", "team_public_model_name": "team-alias-gpt"}, + }, + { + "model_name": "team-internal-bedrock", + "litellm_params": {"model": "openai/*", "api_key": "fake-key"}, + "model_info": {"team_id": "team-1", "team_public_model_name": "team-models/*"}, + }, + ] + ) + + def _requested_model_values(metric) -> set[str]: index = metric._labelnames.index("requested_model") return {sample_key[index] for sample_key in metric._metrics} @@ -118,6 +136,26 @@ async def test_known_alias_and_wildcard_models_keep_their_own_labels(router): } +@pytest.mark.asyncio +async def test_team_alias_and_team_wildcard_models_keep_their_own_labels(team_router): + logger = PrometheusLogger() + + with patch("litellm.proxy.proxy_server.llm_router", team_router, create=True): # test-quality-ok: production reads proxy_server.llm_router lazily, no injection seam + await _fire_proxy_failure(logger, "team-alias-gpt") + await _fire_proxy_failure(logger, "team-models/gpt-4o-audio-preview") + await _fire_proxy_failure(logger, "agent-typo-hallucinated") + + for metric in ( + logger.litellm_proxy_failed_requests_metric, + logger.litellm_proxy_total_requests_metric, + ): + assert _requested_model_values(metric) == { + "team-alias-gpt", + "team-models/gpt-4o-audio-preview", + UNRECOGNIZED_REQUESTED_MODEL_LABEL, + } + + @pytest.mark.asyncio async def test_unknown_models_collapse_to_other_when_router_is_unavailable(): logger = PrometheusLogger()