mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-30 06:43:27 +00:00
fix(openrouter): validate region input and expand test coverage
This commit is contained in:
parent
ca755f14fd
commit
b2e9da602f
2 changed files with 59 additions and 25 deletions
|
|
@ -61,9 +61,7 @@ def resolve_openrouter_api_base(
|
|||
resolved_region = None
|
||||
if isinstance(litellm_params, dict):
|
||||
resolved_region = (
|
||||
litellm_params.get("region")
|
||||
or litellm_params.get("region_name")
|
||||
or litellm_params.get("data_residency")
|
||||
litellm_params.get("region") or litellm_params.get("region_name") or litellm_params.get("data_residency")
|
||||
)
|
||||
if not resolved_region and isinstance(optional_params, dict):
|
||||
resolved_region = (
|
||||
|
|
@ -73,11 +71,7 @@ def resolve_openrouter_api_base(
|
|||
)
|
||||
if not resolved_region:
|
||||
resolved_region = (
|
||||
region
|
||||
or getattr(litellm, "openrouter_region", None)
|
||||
or getattr(litellm, "openrouter_data_residency", None)
|
||||
or get_secret_str("OPENROUTER_REGION")
|
||||
or get_secret_str("OPENROUTER_DATA_RESIDENCY")
|
||||
region or getattr(litellm, "openrouter_region", None) or getattr(litellm, "openrouter_data_residency", None)
|
||||
)
|
||||
|
||||
if resolved_region and isinstance(resolved_region, str):
|
||||
|
|
@ -90,15 +84,11 @@ def resolve_openrouter_api_base(
|
|||
return "https://eu.openrouter.ai/api/v1"
|
||||
if normalized_region.startswith(("us-", "us_", "usa-", "usa_")):
|
||||
return "https://us.openrouter.ai/api/v1"
|
||||
# Dynamic regional hostname for future OpenRouter regions without breaking client-side
|
||||
return f"https://{normalized_region}.openrouter.ai/api/v1"
|
||||
raise ValueError(
|
||||
f"Unsupported OpenRouter region: '{resolved_region}'. Supported regions are 'eu', 'us', 'global'."
|
||||
)
|
||||
|
||||
return (
|
||||
api_base
|
||||
or litellm.api_base
|
||||
or get_secret_str("OPENROUTER_API_BASE")
|
||||
or _DEFAULT_OPENROUTER_API_BASE
|
||||
)
|
||||
return api_base or litellm.api_base or get_secret_str("OPENROUTER_API_BASE") or _DEFAULT_OPENROUTER_API_BASE
|
||||
|
||||
|
||||
def infer_openrouter_data_residency(
|
||||
|
|
|
|||
|
|
@ -43,18 +43,34 @@ def test_resolve_openrouter_api_base(api_base, region, expected):
|
|||
assert resolve_openrouter_api_base(api_base=api_base, region=region) == expected
|
||||
|
||||
|
||||
def test_resolve_openrouter_api_base_env_var(monkeypatch):
|
||||
monkeypatch.setenv("OPENROUTER_REGION", "eu")
|
||||
def test_resolve_openrouter_api_base_litellm_attrs(monkeypatch):
|
||||
monkeypatch.setattr(litellm, "openrouter_region", "eu", raising=False)
|
||||
assert resolve_openrouter_api_base() == "https://eu.openrouter.ai/api/v1"
|
||||
monkeypatch.delattr(litellm, "openrouter_region", raising=False)
|
||||
monkeypatch.setattr(litellm, "openrouter_data_residency", "us", raising=False)
|
||||
assert resolve_openrouter_api_base() == "https://us.openrouter.ai/api/v1"
|
||||
|
||||
|
||||
def test_resolve_openrouter_api_base_dynamic_region():
|
||||
assert resolve_openrouter_api_base(region="apac") == "https://apac.openrouter.ai/api/v1"
|
||||
def test_resolve_openrouter_api_base_unsupported_region_raises():
|
||||
with pytest.raises(ValueError, match="Unsupported OpenRouter region"):
|
||||
resolve_openrouter_api_base(region="apac")
|
||||
with pytest.raises(ValueError, match="Unsupported OpenRouter region"):
|
||||
resolve_openrouter_api_base(region="collector.attacker.example/")
|
||||
|
||||
|
||||
def test_resolve_openrouter_api_base_from_dict_params():
|
||||
assert resolve_openrouter_api_base(litellm_params={"region": "eu"}) == "https://eu.openrouter.ai/api/v1"
|
||||
assert resolve_openrouter_api_base(litellm_params={"region_name": "us"}) == "https://us.openrouter.ai/api/v1"
|
||||
assert resolve_openrouter_api_base(litellm_params={"data_residency": "eu"}) == "https://eu.openrouter.ai/api/v1"
|
||||
assert resolve_openrouter_api_base(optional_params={"region": "us"}) == "https://us.openrouter.ai/api/v1"
|
||||
assert resolve_openrouter_api_base(optional_params={"region_name": "eu"}) == "https://eu.openrouter.ai/api/v1"
|
||||
assert resolve_openrouter_api_base(optional_params={"data_residency": "us"}) == "https://us.openrouter.ai/api/v1"
|
||||
assert (
|
||||
resolve_openrouter_api_base(api_base="https://openrouter.ai", region="eu") == "https://eu.openrouter.ai/api/v1"
|
||||
)
|
||||
assert (
|
||||
resolve_openrouter_api_base(api_base="http://openrouter.ai", region="us") == "https://us.openrouter.ai/api/v1"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -79,10 +95,7 @@ def test_infer_openrouter_data_residency(api_base, expected):
|
|||
|
||||
@pytest.mark.parametrize("custom_llm_provider", [None, "openai", "anthropic", "azure", "bedrock"])
|
||||
def test_infer_openrouter_data_residency_non_openrouter(custom_llm_provider):
|
||||
assert (
|
||||
infer_openrouter_data_residency(custom_llm_provider, "https://eu.openrouter.ai/api/v1")
|
||||
is None
|
||||
)
|
||||
assert infer_openrouter_data_residency(custom_llm_provider, "https://eu.openrouter.ai/api/v1") is None
|
||||
|
||||
|
||||
def test_get_litellm_params_infers_openrouter_data_residency():
|
||||
|
|
@ -177,6 +190,38 @@ def test_openrouter_region_not_supported_error_mapping():
|
|||
)
|
||||
assert not isinstance(exc_info_standard.value, OpenRouterRegionNotSupportedError)
|
||||
|
||||
# 3. 404 with no response object or no URL
|
||||
fake_exc_no_resp = Exception("404 Not Found")
|
||||
fake_exc_no_resp.status_code = 404
|
||||
with pytest.raises(OpenRouterRegionNotSupportedError) as exc_no_resp:
|
||||
_map_openrouter_exception(
|
||||
model="openrouter/anthropic/claude-sonnet-4",
|
||||
original_exception=fake_exc_no_resp,
|
||||
custom_llm_provider="openrouter",
|
||||
error_str=error_msg,
|
||||
exception_type="NotFoundError",
|
||||
exception_provider="openrouter",
|
||||
extra_information="",
|
||||
)
|
||||
assert exc_no_resp.value.region is None
|
||||
|
||||
# 4. Exception class default initialization
|
||||
custom_err = OpenRouterRegionNotSupportedError(message="error", model="test-model")
|
||||
assert custom_err.llm_provider == "openrouter"
|
||||
assert custom_err.region is None
|
||||
|
||||
|
||||
def test_openrouter_chat_config_endpoint_already_in_api_base():
|
||||
cfg = OpenrouterConfig(region="eu")
|
||||
url = cfg.get_complete_url(
|
||||
api_base="https://eu.openrouter.ai/api/v1/chat/completions",
|
||||
api_key="sk-test",
|
||||
model="anthropic/claude-3-opus",
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
)
|
||||
assert url == "https://eu.openrouter.ai/api/v1/chat/completions"
|
||||
|
||||
|
||||
def test_openrouter_completion_with_region_parameter(monkeypatch):
|
||||
"""Test that completion() resolves regional api_base and tracks data_residency."""
|
||||
|
|
@ -213,4 +258,3 @@ def test_openrouter_completion_with_region_parameter(monkeypatch):
|
|||
assert captured_litellm_params.get("api_base") == "https://eu.openrouter.ai/api/v1"
|
||||
assert captured_litellm_params.get("data_residency") == "eu"
|
||||
assert resp.choices[0].message.content == "Hello from EU"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue