mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
Merge pull request #22320 from tombii/fix/openrouter-native-model-double-stripping
fix(openrouter): pattern-based fix for native model double-stripping
This commit is contained in:
commit
5d512f64fe
2 changed files with 98 additions and 0 deletions
|
|
@ -159,6 +159,14 @@ 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
|
||||
# "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/"):
|
||||
return model, custom_llm_provider, dynamic_api_key, api_base
|
||||
|
||||
if api_key and api_key.startswith("os.environ/"):
|
||||
dynamic_api_key = get_secret_str(api_key)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
"""
|
||||
Tests for OpenRouter model name routing in get_llm_provider.
|
||||
|
||||
OpenRouter-native models have IDs that start with "openrouter/" (e.g.
|
||||
openrouter/auto, openrouter/free, openrouter/aurora-alpha). When a user
|
||||
configures such a model in LiteLLM they use the double-prefixed form
|
||||
"openrouter/openrouter/aurora-alpha". get_llm_provider must strip only
|
||||
the outer "openrouter/" provider prefix and leave the inner one intact,
|
||||
so the correct model ID is sent to the OpenRouter API.
|
||||
|
||||
See: https://github.com/BerriAI/litellm/issues/16353
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../../../../.."))
|
||||
|
||||
import litellm
|
||||
|
||||
|
||||
class TestOpenRouterNativeModelRouting:
|
||||
"""get_llm_provider must not double-strip native OpenRouter model names."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_model,expected_model",
|
||||
[
|
||||
# Well-known native models
|
||||
("openrouter/openrouter/auto", "openrouter/auto"),
|
||||
("openrouter/openrouter/free", "openrouter/free"),
|
||||
("openrouter/openrouter/bodybuilder", "openrouter/bodybuilder"),
|
||||
# Arbitrary native models — the fix must be pattern-based, not a hardcoded list
|
||||
("openrouter/openrouter/aurora-alpha", "openrouter/aurora-alpha"),
|
||||
("openrouter/openrouter/polaris-alpha", "openrouter/polaris-alpha"),
|
||||
("openrouter/openrouter/some-future-model", "openrouter/some-future-model"),
|
||||
],
|
||||
)
|
||||
def test_double_prefixed_strips_once(self, input_model, expected_model):
|
||||
"""openrouter/openrouter/<model> should yield model=openrouter/<model>."""
|
||||
result_model, provider, _, _ = litellm.get_llm_provider(model=input_model)
|
||||
assert provider == "openrouter"
|
||||
assert result_model == expected_model
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_model",
|
||||
[
|
||||
"openrouter/openrouter/aurora-alpha",
|
||||
"openrouter/openrouter/auto",
|
||||
"openrouter/openrouter/free",
|
||||
"openrouter/openrouter/some-future-model",
|
||||
],
|
||||
)
|
||||
def test_bridge_double_call_preserves_native_model(self, input_model):
|
||||
"""Simulates two consecutive get_llm_provider calls (bridge → completion).
|
||||
|
||||
The first call (bridge) strips the outer prefix:
|
||||
openrouter/openrouter/<model> → openrouter/<model>
|
||||
|
||||
The second call (completion) receives custom_llm_provider="openrouter"
|
||||
from the bridge, detects the native model, and preserves it:
|
||||
openrouter/<model> → openrouter/<model> (no further stripping)
|
||||
"""
|
||||
# First call: bridge resolves provider
|
||||
model_first, provider, _, _ = litellm.get_llm_provider(model=input_model)
|
||||
assert provider == "openrouter"
|
||||
expected_model = input_model.split("/", 1)[1] # openrouter/<model>
|
||||
assert model_first == expected_model
|
||||
|
||||
# Second call: completion receives model + custom_llm_provider from bridge
|
||||
model_second, provider2, _, _ = litellm.get_llm_provider(
|
||||
model=model_first,
|
||||
custom_llm_provider="openrouter",
|
||||
)
|
||||
assert provider2 == "openrouter"
|
||||
assert model_second == expected_model # preserved, not stripped further
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_model,expected_model",
|
||||
[
|
||||
("openrouter/anthropic/claude-3-haiku", "anthropic/claude-3-haiku"),
|
||||
("openrouter/meta-llama/llama-3-70b-instruct", "meta-llama/llama-3-70b-instruct"),
|
||||
],
|
||||
)
|
||||
def test_regular_models_still_strip_normally(self, input_model, expected_model):
|
||||
"""Non-native OpenRouter models should still have their prefix stripped."""
|
||||
result_model, provider, _, _ = litellm.get_llm_provider(model=input_model)
|
||||
assert provider == "openrouter"
|
||||
assert result_model == expected_model
|
||||
Loading…
Add table
Reference in a new issue