mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-23 00:41:40 +00:00
fix(proxy): resolve credential routing provider from deployment config
When the user-facing model name has no provider prefix (e.g. "claude-sonnet-4.6" instead of "bedrock/claude-sonnet-4.6"), _apply_credential_overrides_from_model_config sets provider to None. The fallback in _extract_credential_from_entry then picks the first entry in defaultconfig dict order instead of the correct provider. Resolve the provider from the deployment's litellm_params.model (e.g. "bedrock/us.anthropic.claude-sonnet-4-6" -> "bedrock") when the request model name has no "/" prefix. Fixes #27516
This commit is contained in:
parent
0af33fbe70
commit
aecf410e93
2 changed files with 93 additions and 0 deletions
|
|
@ -1860,6 +1860,24 @@ def _update_model_if_key_alias_exists(
|
|||
return
|
||||
|
||||
|
||||
def _resolve_provider_from_deployment(model_name: str) -> Optional[str]:
|
||||
"""
|
||||
Look up the provider prefix from the router's deployment config for a
|
||||
given user-facing model name (e.g. "claude-sonnet-4.6" ->
|
||||
"bedrock" via litellm_params.model "bedrock/us.anthropic...").
|
||||
"""
|
||||
from litellm.proxy.proxy_server import llm_router
|
||||
|
||||
if llm_router is None:
|
||||
return None
|
||||
for deployment in llm_router.model_list:
|
||||
if deployment.get("model_name") == model_name:
|
||||
litellm_model = (deployment.get("litellm_params") or {}).get("model", "")
|
||||
if "/" in litellm_model:
|
||||
return litellm_model.split("/", 1)[0]
|
||||
return None
|
||||
|
||||
|
||||
def _apply_credential_overrides_from_model_config(
|
||||
data: dict,
|
||||
user_api_key_dict: UserAPIKeyAuth,
|
||||
|
|
@ -1900,9 +1918,13 @@ def _apply_credential_overrides_from_model_config(
|
|||
return
|
||||
|
||||
# Extract provider hint from model name (e.g. "azure/gpt-4" -> "azure")
|
||||
# When the user-facing model name has no "/" prefix, resolve from the
|
||||
# deployment's litellm_params.model instead (e.g. "bedrock/us.anthropic...")
|
||||
provider: Optional[str] = None
|
||||
if "/" in model_name:
|
||||
provider = model_name.split("/", 1)[0]
|
||||
else:
|
||||
provider = _resolve_provider_from_deployment(model_name)
|
||||
|
||||
credential_name = _resolve_credential_from_model_config(
|
||||
model_name=model_name,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ from litellm.proxy.litellm_pre_call_utils import (
|
|||
_get_enforced_params,
|
||||
_get_metadata_variable_name,
|
||||
_resolve_credential_from_model_config,
|
||||
_resolve_provider_from_deployment,
|
||||
_update_model_if_key_alias_exists,
|
||||
add_guardrails_from_policy_engine,
|
||||
add_litellm_data_to_request,
|
||||
|
|
@ -3821,6 +3822,76 @@ def test_resolve_provider_hint_from_model_name():
|
|||
assert result == "azure-cred"
|
||||
|
||||
|
||||
def test_resolve_provider_from_deployment():
|
||||
"""
|
||||
Regression test for https://github.com/BerriAI/litellm/issues/27516
|
||||
When the user-facing model name has no "/" prefix (e.g. "claude-sonnet-4.6"),
|
||||
the provider should be resolved from the deployment's litellm_params.model
|
||||
(e.g. "bedrock/us.anthropic.claude-sonnet-4-6" -> "bedrock").
|
||||
"""
|
||||
mock_router = MagicMock()
|
||||
mock_router.model_list = [
|
||||
{
|
||||
"model_name": "claude-sonnet-4.6",
|
||||
"litellm_params": {"model": "bedrock/us.anthropic.claude-sonnet-4-6"},
|
||||
},
|
||||
{
|
||||
"model_name": "gemini-2.5-pro",
|
||||
"litellm_params": {"model": "gemini/gemini-2.5-pro-preview"},
|
||||
},
|
||||
]
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.proxy_server.llm_router",
|
||||
mock_router,
|
||||
):
|
||||
assert _resolve_provider_from_deployment("claude-sonnet-4.6") == "bedrock"
|
||||
assert _resolve_provider_from_deployment("gemini-2.5-pro") == "gemini"
|
||||
assert _resolve_provider_from_deployment("unknown-model") is None
|
||||
|
||||
|
||||
def test_resolve_provider_from_deployment_no_router():
|
||||
"""When llm_router is None, _resolve_provider_from_deployment returns None."""
|
||||
with patch(
|
||||
"litellm.proxy.proxy_server.llm_router",
|
||||
None,
|
||||
):
|
||||
assert _resolve_provider_from_deployment("claude-sonnet-4.6") is None
|
||||
|
||||
|
||||
def test_credential_routing_uses_deployment_provider():
|
||||
"""
|
||||
End-to-end: defaultconfig with multiple providers should resolve the
|
||||
correct credential when the user model name has no "/" prefix.
|
||||
"""
|
||||
mock_router = MagicMock()
|
||||
mock_router.model_list = [
|
||||
{
|
||||
"model_name": "claude-sonnet-4.6",
|
||||
"litellm_params": {"model": "bedrock/us.anthropic.claude-sonnet-4-6"},
|
||||
},
|
||||
]
|
||||
|
||||
team_model_config = {
|
||||
"defaultconfig": {
|
||||
"gemini": {"litellm_credentials": "gemini-team-1"},
|
||||
"bedrock": {"litellm_credentials": "bedrock-team-1"},
|
||||
},
|
||||
}
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.proxy_server.llm_router",
|
||||
mock_router,
|
||||
):
|
||||
result = _resolve_credential_from_model_config(
|
||||
model_name="claude-sonnet-4.6",
|
||||
project_model_config=None,
|
||||
team_model_config=team_model_config,
|
||||
provider="bedrock",
|
||||
)
|
||||
assert result == "bedrock-team-1"
|
||||
|
||||
|
||||
def test_clean_headers_preserves_x_api_key_when_byok_enabled():
|
||||
"""
|
||||
Regression test: when forward_llm_provider_auth_headers=True,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue