diff --git a/litellm/litellm_core_utils/get_llm_provider_logic.py b/litellm/litellm_core_utils/get_llm_provider_logic.py index 36218417377..a79dcfe98c6 100644 --- a/litellm/litellm_core_utils/get_llm_provider_logic.py +++ b/litellm/litellm_core_utils/get_llm_provider_logic.py @@ -158,12 +158,15 @@ def get_llm_provider( # noqa: PLR0915 ): # handle scenario where model="azure/*" and custom_llm_provider="azure" model = custom_llm_provider + "/" + model - # Native OpenRouter models have IDs like "openrouter/free" where the + # Native OpenRouter models have IDs like "openrouter/auto" where the # "openrouter/" prefix is part of the actual model name on the API. - # When called from a bridge (e.g. anthropic_messages adapter), - # custom_llm_provider is already resolved, so return early to prevent - # the provider-list stripping below from removing the prefix. - if custom_llm_provider == "openrouter" and model.startswith("openrouter/"): + # Only preserve prefix for single-segment native models (no extra '/'), + # not for provider-routed models like "openrouter/anthropic/claude-3.5-sonnet". + if ( + custom_llm_provider == "openrouter" + and model.startswith("openrouter/") + and "/" not in model[len("openrouter/") :] + ): return model, custom_llm_provider, dynamic_api_key, api_base if api_key and api_key.startswith("os.environ/"): diff --git a/tests/local_testing/test_get_llm_provider.py b/tests/local_testing/test_get_llm_provider.py index 9b07111ea54..019b938842c 100644 --- a/tests/local_testing/test_get_llm_provider.py +++ b/tests/local_testing/test_get_llm_provider.py @@ -420,3 +420,19 @@ def test_get_llm_provider_use_proxy_arg_true_with_direct_args(): assert provider == "litellm_proxy" assert key == arg_api_key # Should use the argument key assert base == arg_api_base # Should use the argument base + + +def test_openrouter_model_prefix_stripped(): + """ + GH#24234: OpenRouter models like "openrouter/anthropic/claude-3.5-sonnet" + should have the "openrouter/" prefix stripped before being sent to the API. + The API expects "anthropic/claude-3.5-sonnet", not the full prefixed name. + """ + model, provider, _, _ = litellm.get_llm_provider( + model="openrouter/anthropic/claude-3.5-sonnet" + ) + assert provider == "openrouter" + assert model == "anthropic/claude-3.5-sonnet", ( + f"Expected 'anthropic/claude-3.5-sonnet' but got '{model}'. " + "The 'openrouter/' prefix was not stripped." + )