From d1dda3d30b3b32e79eddb3df82f6f230164d4d2a Mon Sep 17 00:00:00 2001 From: harish876 Date: Fri, 10 Apr 2026 23:29:16 +0000 Subject: [PATCH] Enhance file content streaming handler to support custom LLM provider routing - Updated `FileContentStreamingHandler` to utilize `custom_llm_provider` from credentials for routing. - Added error handling for missing `custom_llm_provider` in credentials. - Introduced new tests to validate streaming behavior with routed providers and non-OpenAI providers. - Cleaned up imports and ensured proper type casting for improved clarity. --- .../file_content_streaming_handler.py | 6 +- .../test_files_endpoint.py | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/openai_files_endpoints/file_content_streaming_handler.py b/litellm/proxy/openai_files_endpoints/file_content_streaming_handler.py index b22077e8c1..9833891f1d 100644 --- a/litellm/proxy/openai_files_endpoints/file_content_streaming_handler.py +++ b/litellm/proxy/openai_files_endpoints/file_content_streaming_handler.py @@ -62,18 +62,22 @@ class FileContentStreamingHandler: user_api_key_dict: UserAPIKeyAuth, version: str, ) -> StreamingResponse: + effective_custom_llm_provider = custom_llm_provider if should_route: prepare_data_with_credentials( data=data, credentials=credentials, # type: ignore[arg-type] file_id=original_file_id, ) + effective_custom_llm_provider = cast( + str, credentials["custom_llm_provider"] + ) stream_result = cast( FileContentStreamingResult, await litellm.afile_content( **{ - "custom_llm_provider": custom_llm_provider, + "custom_llm_provider": effective_custom_llm_provider, "file_id": file_id, "stream": True, **data, diff --git a/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py b/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py index 476b57d9f3..aeca75e936 100644 --- a/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py +++ b/tests/test_litellm/proxy/openai_files_endpoint/test_files_endpoint.py @@ -1647,3 +1647,69 @@ def test_get_file_content_streams_openai_direct_path( assert captured_kwargs["stream"] is True proxy_logging_obj.update_request_status.assert_awaited_once() proxy_logging_obj.post_call_failure_hook.assert_not_called() + + +def test_get_file_content_streams_with_routed_provider( + mocker: MockerFixture, monkeypatch, llm_router: Router +): + import litellm.proxy.proxy_server as ps + from litellm.proxy._types import LitellmUserRoles + + proxy_logging_obj = setup_proxy_logging_object(monkeypatch, llm_router) + monkeypatch.setattr("litellm.proxy.proxy_server.master_key", None) + monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", None) + proxy_logging_obj.update_request_status = mocker.AsyncMock() + proxy_logging_obj.post_call_failure_hook = mocker.AsyncMock() + + captured_kwargs = {} + + async def _mock_afile_content(**kwargs): + captured_kwargs.update(kwargs) + + async def _stream(): + yield b"hello " + yield b"world" + + return FileContentStreamingResult( + stream_iterator=_stream(), + headers={"content-length": "11"}, + ) + + monkeypatch.setattr(litellm, "afile_content", _mock_afile_content) + monkeypatch.setattr( + "litellm.proxy.openai_files_endpoints.files_endpoints.handle_model_based_routing", + lambda **kwargs: ( + True, + "azure-gpt-3-5-turbo", + "file-original-123", + { + "custom_llm_provider": "azure", + "api_key": "azure-key", + "api_base": "https://azure.example.com", + }, + ), + ) + + app.dependency_overrides[ps.user_api_key_auth] = lambda: UserAPIKeyAuth( + api_key="test-key", + user_role=LitellmUserRoles.PROXY_ADMIN, + user_id="test-user", + ) + + try: + response = client.get( + "/v1/files/file-abc123/content", + headers={"Authorization": "Bearer test-key"}, + ) + finally: + app.dependency_overrides.pop(ps.user_api_key_auth, None) + + assert response.status_code == 200, response.text + assert response.content == b"hello world" + assert captured_kwargs["custom_llm_provider"] == "azure" + assert captured_kwargs["file_id"] == "file-original-123" + assert captured_kwargs["api_key"] == "azure-key" + assert captured_kwargs["api_base"] == "https://azure.example.com" + assert captured_kwargs["stream"] is True + proxy_logging_obj.update_request_status.assert_awaited_once() + proxy_logging_obj.post_call_failure_hook.assert_not_called()