|
19 | 19 | BaseOpenAIPassThroughHandler,
|
20 | 20 | RouteChecks,
|
21 | 21 | create_pass_through_route,
|
| 22 | + llm_passthrough_factory_proxy_route, |
| 23 | + vllm_proxy_route, |
22 | 24 | vertex_discovery_proxy_route,
|
23 | 25 | vertex_proxy_route,
|
24 | 26 | bedrock_llm_proxy_route,
|
@@ -914,3 +916,119 @@ async def test_bedrock_llm_proxy_route_regular_model(self):
|
914 | 916 | # For regular models, model should be just the model ID
|
915 | 917 | assert call_kwargs["model"] == "anthropic.claude-3-sonnet-20240229-v1:0"
|
916 | 918 | assert result == "success"
|
| 919 | + |
| 920 | + |
| 921 | +class TestLLMPassthroughFactoryProxyRoute: |
| 922 | + @pytest.mark.asyncio |
| 923 | + async def test_llm_passthrough_factory_proxy_route_success(self): |
| 924 | + from litellm.types.utils import LlmProviders |
| 925 | + mock_request = MagicMock(spec=Request) |
| 926 | + mock_request.method = "POST" |
| 927 | + mock_request.json = AsyncMock(return_value={"stream": False}) |
| 928 | + mock_fastapi_response = MagicMock(spec=Response) |
| 929 | + mock_user_api_key_dict = MagicMock() |
| 930 | + |
| 931 | + with patch( |
| 932 | + "litellm.utils.ProviderConfigManager.get_provider_model_info" |
| 933 | + ) as mock_get_provider, patch( |
| 934 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.passthrough_endpoint_router.get_credentials" |
| 935 | + ) as mock_get_creds, patch( |
| 936 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.create_pass_through_route" |
| 937 | + ) as mock_create_route: |
| 938 | + mock_provider_config = MagicMock() |
| 939 | + mock_provider_config.get_api_base.return_value = "https://example.com/v1" |
| 940 | + mock_provider_config.validate_environment.return_value = { |
| 941 | + "x-api-key": "dummy" |
| 942 | + } |
| 943 | + mock_get_provider.return_value = mock_provider_config |
| 944 | + mock_get_creds.return_value = "dummy" |
| 945 | + |
| 946 | + mock_endpoint_func = AsyncMock(return_value="success") |
| 947 | + mock_create_route.return_value = mock_endpoint_func |
| 948 | + |
| 949 | + result = await llm_passthrough_factory_proxy_route( |
| 950 | + custom_llm_provider=LlmProviders.VLLM, |
| 951 | + endpoint="/chat/completions", |
| 952 | + request=mock_request, |
| 953 | + fastapi_response=mock_fastapi_response, |
| 954 | + user_api_key_dict=mock_user_api_key_dict, |
| 955 | + ) |
| 956 | + |
| 957 | + assert result == "success" |
| 958 | + mock_get_provider.assert_called_once_with( |
| 959 | + provider=litellm.LlmProviders(LlmProviders.VLLM), model=None |
| 960 | + ) |
| 961 | + mock_get_creds.assert_called_once_with( |
| 962 | + custom_llm_provider=LlmProviders.VLLM, region_name=None |
| 963 | + ) |
| 964 | + mock_create_route.assert_called_once_with( |
| 965 | + endpoint="/chat/completions", |
| 966 | + target="https://example.com/v1/chat/completions", |
| 967 | + custom_headers={"x-api-key": "dummy"}, |
| 968 | + ) |
| 969 | + mock_endpoint_func.assert_awaited_once() |
| 970 | + |
| 971 | + |
| 972 | +class TestVLLMProxyRoute: |
| 973 | + @pytest.mark.asyncio |
| 974 | + @patch( |
| 975 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.get_request_body", |
| 976 | + return_value={"model": "router-model", "stream": False}, |
| 977 | + ) |
| 978 | + @patch( |
| 979 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.is_passthrough_request_using_router_model", |
| 980 | + return_value=True, |
| 981 | + ) |
| 982 | + @patch("litellm.proxy.proxy_server.llm_router") |
| 983 | + async def test_vllm_proxy_route_with_router_model( |
| 984 | + self, mock_llm_router, mock_is_router, mock_get_body |
| 985 | + ): |
| 986 | + mock_request = MagicMock(spec=Request) |
| 987 | + mock_request.method = "POST" |
| 988 | + mock_request.headers = {"content-type": "application/json"} |
| 989 | + mock_request.query_params = {} |
| 990 | + mock_fastapi_response = MagicMock(spec=Response) |
| 991 | + mock_user_api_key_dict = MagicMock() |
| 992 | + mock_llm_router.allm_passthrough_route = AsyncMock( |
| 993 | + return_value=httpx.Response(200, json={"response": "success"}) |
| 994 | + ) |
| 995 | + |
| 996 | + await vllm_proxy_route( |
| 997 | + endpoint="/chat/completions", |
| 998 | + request=mock_request, |
| 999 | + fastapi_response=mock_fastapi_response, |
| 1000 | + user_api_key_dict=mock_user_api_key_dict, |
| 1001 | + ) |
| 1002 | + |
| 1003 | + mock_is_router.assert_called_once() |
| 1004 | + mock_llm_router.allm_passthrough_route.assert_awaited_once() |
| 1005 | + |
| 1006 | + @pytest.mark.asyncio |
| 1007 | + @patch( |
| 1008 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.get_request_body", |
| 1009 | + return_value={"model": "other-model"}, |
| 1010 | + ) |
| 1011 | + @patch( |
| 1012 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.is_passthrough_request_using_router_model", |
| 1013 | + return_value=False, |
| 1014 | + ) |
| 1015 | + @patch( |
| 1016 | + "litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.llm_passthrough_factory_proxy_route" |
| 1017 | + ) |
| 1018 | + async def test_vllm_proxy_route_fallback_to_factory( |
| 1019 | + self, mock_factory_route, mock_is_router, mock_get_body |
| 1020 | + ): |
| 1021 | + mock_request = MagicMock(spec=Request) |
| 1022 | + mock_fastapi_response = MagicMock(spec=Response) |
| 1023 | + mock_user_api_key_dict = MagicMock() |
| 1024 | + mock_factory_route.return_value = "factory_success" |
| 1025 | + |
| 1026 | + result = await vllm_proxy_route( |
| 1027 | + endpoint="/chat/completions", |
| 1028 | + request=mock_request, |
| 1029 | + fastapi_response=mock_fastapi_response, |
| 1030 | + user_api_key_dict=mock_user_api_key_dict, |
| 1031 | + ) |
| 1032 | + |
| 1033 | + assert result == "factory_success" |
| 1034 | + mock_factory_route.assert_awaited_once() |
0 commit comments