mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-15 09:12:18 +00:00
fix(proxy): list videos only on a deployment the router sends to the asked provider
A provider-only list picked a team deployment whose unprefixed model (claude-haiku-4-5) the credential lookup reads as OpenAI while the router dispatches it as Anthropic, so the list answered 400. The pick now skips a deployment whose router provider differs. Also updates the DashScope list test to the error the deployment's key now reaches.
This commit is contained in:
parent
e52d7ee73f
commit
55be5dc7ae
3 changed files with 51 additions and 8 deletions
|
|
@ -23,6 +23,7 @@ from typing_extensions import NotRequired, ReadOnly, TypedDict
|
|||
|
||||
from litellm.batches.batch_utils import batch_cost_is_final
|
||||
from litellm.constants import MAX_FILE_LIST_LIMIT
|
||||
from litellm.litellm_core_utils.routing_common_utils import provider_for_generic_call
|
||||
from litellm.proxy._types import ProxyException
|
||||
from litellm.repositories.managed_file_repository import ManagedFileRepository
|
||||
from litellm.repositories.table_repositories import (
|
||||
|
|
@ -575,15 +576,22 @@ def get_team_provider_deployment_id(
|
|||
) -> str | None:
|
||||
if llm_router is None:
|
||||
return None
|
||||
match: Final = next(
|
||||
_authorized_provider_credentials(llm_router, user_api_key_dict, custom_llm_provider, True), None
|
||||
registry: Final = llm_router.registry()
|
||||
authorized_deployments: Final = (
|
||||
registry.credentials(model_id, form="deployment", team_id=user_api_key_dict.team_id)
|
||||
for model_id, _ in _authorized_provider_credentials(llm_router, user_api_key_dict, custom_llm_provider, True)
|
||||
)
|
||||
deployment: Final = (
|
||||
None
|
||||
if match is None
|
||||
else llm_router.registry().credentials(match[0], form="deployment", team_id=user_api_key_dict.team_id)
|
||||
routed_deployment: Final = next(
|
||||
(
|
||||
deployment
|
||||
for deployment in authorized_deployments
|
||||
if deployment is not None
|
||||
and provider_for_generic_call(deployment.litellm_params.model_dump(exclude_none=True))
|
||||
== custom_llm_provider
|
||||
),
|
||||
None,
|
||||
)
|
||||
return None if deployment is None else deployment.model_info.id
|
||||
return None if routed_deployment is None else routed_deployment.model_info.id
|
||||
|
||||
|
||||
def _authorized_provider_credentials(
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ def test_the_proxy_has_no_video_delete_route_so_a_dashscope_task_is_never_touche
|
|||
|
||||
@pytest.mark.parametrize(
|
||||
("operation", "message"),
|
||||
[("remix", "Video remix is not supported by DashScope"), ("list", "DashScope API key is required")],
|
||||
[("remix", "Video remix is not supported by DashScope"), ("list", "Video list is not supported by DashScope")],
|
||||
)
|
||||
def test_operations_dashscope_has_no_api_for_answer_an_error_and_send_nothing_upstream(
|
||||
gateway: Gateway, operation: str, message: str
|
||||
|
|
|
|||
|
|
@ -753,6 +753,41 @@ def test_list__provider_only_never_borrows_a_deployment_the_key_cannot_use(
|
|||
assert upstream.calls.last.request.url.host != _DEPLOYMENT_ARK_HOST
|
||||
|
||||
|
||||
def test_list__provider_only_skips_a_deployment_the_router_sends_to_another_provider(
|
||||
proxy_client_for_key_models: Callable[[list[str]], TestClient], monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setattr(
|
||||
proxy_server,
|
||||
"llm_router",
|
||||
Router(
|
||||
model_list=[
|
||||
{
|
||||
"model_name": "haiku",
|
||||
"litellm_params": {"model": "claude-haiku-4-5", "api_key": "deployment-anthropic-key"},
|
||||
"model_info": {"team_id": "team-video"},
|
||||
},
|
||||
{
|
||||
"model_name": "sora",
|
||||
"litellm_params": {"model": "openai/sora-2", "api_key": "deployment-openai-key"},
|
||||
},
|
||||
]
|
||||
),
|
||||
)
|
||||
team_key: Final = UserAPIKeyAuth(api_key="sk-video-list", team_id="team-video")
|
||||
monkeypatch.setitem(proxy_server.app.dependency_overrides, user_api_key_auth, lambda: team_key)
|
||||
client: Final = TestClient(proxy_server.app)
|
||||
|
||||
with respx.mock(assert_all_called=False) as respx_mock:
|
||||
upstream: Final = respx_mock.get("https://api.openai.com/v1/videos").mock(
|
||||
return_value=httpx.Response(200, json={"object": "list", "data": []})
|
||||
)
|
||||
response: Final = client.get("/v1/videos", params={"custom_llm_provider": "openai"})
|
||||
|
||||
assert response.status_code == 200, response.text
|
||||
assert upstream.call_count == 1
|
||||
assert upstream.calls.last.request.headers["authorization"] == "Bearer deployment-openai-key"
|
||||
|
||||
|
||||
def test_list__provider_only_on_a_proxy_without_a_router_is_a_clean_client_error(
|
||||
proxy_client_for_key_models: Callable[[list[str]], TestClient], monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue