mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-03 12:24:08 +00:00
Merge pull request #20516 from Chesars/fix/openrouter-native-model-double-strip
fix(adapter): double-stripping of model names with provider-matching prefixes
This commit is contained in:
@@ -3,6 +3,7 @@ from typing import Optional, Tuple
|
||||
import litellm
|
||||
from litellm.constants import REPLICATE_MODEL_NAME_WITH_ID_LENGTH
|
||||
from litellm.llms.openai_like.json_loader import JSONProviderRegistry
|
||||
from litellm.llms.openrouter.common_utils import NATIVE_OPENROUTER_MODELS
|
||||
from litellm.secret_managers.main import get_secret, get_secret_str
|
||||
|
||||
from ..types.router import LiteLLM_Params
|
||||
@@ -171,6 +172,12 @@ def get_llm_provider( # noqa: PLR0915
|
||||
dynamic_api_key=dynamic_api_key,
|
||||
)
|
||||
|
||||
# Check native OpenRouter models before provider_list stripping.
|
||||
# These models have IDs like "openrouter/free" which would be
|
||||
# incorrectly stripped to just "free" by the logic below.
|
||||
if model in NATIVE_OPENROUTER_MODELS:
|
||||
return model, "openrouter", dynamic_api_key, api_base
|
||||
|
||||
# check if llm provider part of model name
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
from litellm.llms.base_llm.chat.transformation import BaseLLMException
|
||||
|
||||
# Native OpenRouter models whose IDs start with "openrouter/".
|
||||
# When used via LiteLLM (openrouter/openrouter/free), get_llm_provider()
|
||||
# must not strip the inner "openrouter/" prefix on its second invocation.
|
||||
# See: https://github.com/BerriAI/litellm/issues/16353
|
||||
NATIVE_OPENROUTER_MODELS = {
|
||||
"openrouter/auto",
|
||||
"openrouter/free",
|
||||
"openrouter/bodybuilder",
|
||||
}
|
||||
|
||||
|
||||
class OpenRouterException(BaseLLMException):
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Tests for native OpenRouter model name handling in get_llm_provider.
|
||||
|
||||
OpenRouter's native models (openrouter/auto, openrouter/free,
|
||||
openrouter/bodybuilder) should not have their "openrouter/" prefix
|
||||
stripped when passed to get_llm_provider(), since that prefix is part
|
||||
of the actual model ID on OpenRouter's API.
|
||||
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
import litellm
|
||||
|
||||
|
||||
class TestNativeOpenRouterModelsNotStripped:
|
||||
"""get_llm_provider must preserve native OpenRouter model names."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
[
|
||||
"openrouter/auto",
|
||||
"openrouter/free",
|
||||
"openrouter/bodybuilder",
|
||||
],
|
||||
)
|
||||
def test_native_model_not_stripped(self, model):
|
||||
"""Native OpenRouter model IDs are returned as-is."""
|
||||
result_model, provider, _, _ = litellm.get_llm_provider(model=model)
|
||||
assert result_model == model
|
||||
assert provider == "openrouter"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model,expected_model",
|
||||
[
|
||||
("openrouter/openrouter/free", "openrouter/free"),
|
||||
("openrouter/openrouter/auto", "openrouter/auto"),
|
||||
("openrouter/openrouter/bodybuilder", "openrouter/bodybuilder"),
|
||||
],
|
||||
)
|
||||
def test_double_prefixed_model_strips_once_to_native(self, model, expected_model):
|
||||
"""openrouter/openrouter/free strips to openrouter/free (not further)."""
|
||||
result_model, provider, _, _ = litellm.get_llm_provider(model=model)
|
||||
assert result_model == expected_model
|
||||
assert provider == "openrouter"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model,expected_model",
|
||||
[
|
||||
("openrouter/openrouter/free", "openrouter/free"),
|
||||
("openrouter/openrouter/auto", "openrouter/auto"),
|
||||
],
|
||||
)
|
||||
def test_full_round_trip_no_double_strip(self, model, expected_model):
|
||||
"""Simulates the bridge flow: two consecutive get_llm_provider calls."""
|
||||
# First call (in adapter/handler)
|
||||
model_after_first, provider, _, _ = litellm.get_llm_provider(model=model)
|
||||
assert model_after_first == expected_model
|
||||
|
||||
# Second call (inside litellm.completion)
|
||||
model_after_second, provider2, _, _ = litellm.get_llm_provider(
|
||||
model=model_after_first
|
||||
)
|
||||
# Should stay as native model, not stripped further
|
||||
assert model_after_second == expected_model
|
||||
assert provider2 == "openrouter"
|
||||
|
||||
def test_regular_openrouter_model_still_strips_normally(self):
|
||||
"""Non-native models like openrouter/anthropic/claude-3-haiku still strip normally."""
|
||||
model, provider, _, _ = litellm.get_llm_provider(
|
||||
model="openrouter/anthropic/claude-3-haiku"
|
||||
)
|
||||
assert provider == "openrouter"
|
||||
# Should strip the openrouter/ prefix
|
||||
assert model == "anthropic/claude-3-haiku"
|
||||
Reference in New Issue
Block a user