From b35ca7d2c3ed52d28d0801e28c63d8cadc3fe1f4 Mon Sep 17 00:00:00 2001 From: yassin Date: Thu, 17 Sep 2026 00:03:01 +0000 Subject: [PATCH] fix(spend_tracking): honour the global litellm_proxy override when inferring a model group provider Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../get_llm_provider_logic.py | 2 +- .../llms/litellm_proxy/chat/transformation.py | 2 +- .../spend_tracking/spend_tracking_utils.py | 3 +++ .../test_spend_tracking_utils.py | 27 +++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/litellm/litellm_core_utils/get_llm_provider_logic.py b/litellm/litellm_core_utils/get_llm_provider_logic.py index 3a1dbd24e86..b7067a45117 100644 --- a/litellm/litellm_core_utils/get_llm_provider_logic.py +++ b/litellm/litellm_core_utils/get_llm_provider_logic.py @@ -160,7 +160,7 @@ def get_llm_provider( if model is None: raise ValueError("model parameter is required but was None. Please provide a valid model name.") - if litellm.LiteLLMProxyChatConfig._should_use_litellm_proxy_by_default( + if litellm.LiteLLMProxyChatConfig.should_use_litellm_proxy_by_default( litellm_params=cast(LiteLLM_Params | None, litellm_params) ): return litellm.LiteLLMProxyChatConfig.litellm_proxy_get_custom_llm_provider_info( diff --git a/litellm/llms/litellm_proxy/chat/transformation.py b/litellm/llms/litellm_proxy/chat/transformation.py index c11db6b000a..cf4c41cd3f3 100644 --- a/litellm/llms/litellm_proxy/chat/transformation.py +++ b/litellm/llms/litellm_proxy/chat/transformation.py @@ -54,7 +54,7 @@ class LiteLLMProxyChatConfig(OpenAIGPTConfig): return api_key or get_secret_str("LITELLM_PROXY_API_KEY") @staticmethod - def _should_use_litellm_proxy_by_default( + def should_use_litellm_proxy_by_default( litellm_params: LiteLLM_Params | None = None, ): """ diff --git a/litellm/proxy/spend_tracking/spend_tracking_utils.py b/litellm/proxy/spend_tracking/spend_tracking_utils.py index fadd596efea..df8e18c3c56 100644 --- a/litellm/proxy/spend_tracking/spend_tracking_utils.py +++ b/litellm/proxy/spend_tracking/spend_tracking_utils.py @@ -49,6 +49,7 @@ from litellm.types.utils import ( PROMPT_CARRYING_GUARDRAIL_FIELDS, CallTypes, CostBreakdown, + LlmProviders, StandardLoggingGuardrailInformation, StandardLoggingMCPToolCall, StandardLoggingModelInformation, @@ -346,6 +347,8 @@ def _sl_attribution_fallback( def _deployment_provider(deployment: DeploymentTypedDict) -> str | None: litellm_params: Final = LiteLLM_Params.model_validate(deployment["litellm_params"]) + if litellm.LiteLLMProxyChatConfig.should_use_litellm_proxy_by_default(litellm_params=litellm_params): + return LlmProviders.LITELLM_PROXY.value declared: Final = declared_authenticating_provider(litellm_params.model, litellm_params.custom_llm_provider) if declared is not None: return declared diff --git a/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py b/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py index 5f59d696f81..bff995e5504 100644 --- a/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py +++ b/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py @@ -4078,6 +4078,33 @@ def test_get_logging_payload_inferred_provider_never_resolves_declared_authentic assert resolution_attempts == [] +@pytest.mark.parametrize( + "litellm_params", + [ + {"model": "github_copilot/gpt-4o"}, + {"model": "gpt-5", "custom_llm_provider": "chatgpt"}, + {"model": "openai/gpt-4o-mini", "api_key": "sk-a"}, + ], +) +def test_get_logging_payload_inferred_provider_honours_global_litellm_proxy_override( + monkeypatch, litellm_params: dict[str, str] +): + def _router_init_stub(model, custom_llm_provider=None, *args, **kwargs): + return model.split("/", 1)[-1], custom_llm_provider or model.split("/", 1)[0], None, None + + def _oauth_tripwire(model, *args, **kwargs): + raise AssertionError("get_llm_provider would run the OAuth device flow") + + monkeypatch.setattr(litellm, "get_llm_provider", _router_init_stub) + llm_router = litellm.Router(model_list=[{"model_name": "proxied-group", "litellm_params": litellm_params}]) + monkeypatch.setattr(litellm, "get_llm_provider", _oauth_tripwire) + monkeypatch.setattr(litellm, "use_litellm_proxy", True) + + payload = _router_rejected_failure_payload("proxied-group", llm_router) + + assert payload["custom_llm_provider"] == "litellm_proxy" + + def test_get_logging_payload_router_rejected_request_for_unresolvable_deployment_leaves_provider_empty( monkeypatch, ):