mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-14 04:09:09 +00:00
feat(openai): fake stream when model_info marks supports_native_streaming false
OpenAIGPTConfig inherited the base should_fake_stream default of False, so an OpenAI-compatible endpoint that cannot stream still received stream=True and errored. Override should_fake_stream to honor model_info supports_native_streaming, mirroring AzureOpenAIO1Config, so users can flag such a deployment with model_info supports_native_streaming=false to enable client-side fake streaming. Default behavior is unchanged. Closes #30208
This commit is contained in:
parent
80d3b69d9c
commit
6a5b94bca2
2 changed files with 84 additions and 1 deletions
|
|
@ -24,6 +24,7 @@ from urllib.parse import urlparse
|
|||
import httpx
|
||||
|
||||
import litellm
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.litellm_core_utils.core_helpers import map_finish_reason
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
_extract_reasoning_content,
|
||||
|
|
@ -56,7 +57,7 @@ from litellm.types.utils import (
|
|||
ModelResponse,
|
||||
ModelResponseStream,
|
||||
)
|
||||
from litellm.utils import convert_to_model_response_object
|
||||
from litellm.utils import convert_to_model_response_object, get_model_info
|
||||
|
||||
from ..common_utils import OpenAIError
|
||||
|
||||
|
|
@ -189,6 +190,32 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig):
|
|||
) # user is not a param supported by all openai-compatible endpoints - e.g. azure ai
|
||||
return base_params + model_specific_params
|
||||
|
||||
def should_fake_stream(
|
||||
self,
|
||||
model: Optional[str],
|
||||
stream: Optional[bool],
|
||||
custom_llm_provider: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Fake stream when the model is explicitly marked as not supporting native
|
||||
streaming via model_info (supports_native_streaming=False), e.g. an
|
||||
OpenAI-compatible endpoint that cannot stream.
|
||||
"""
|
||||
if stream is not True:
|
||||
return False
|
||||
if model is not None:
|
||||
try:
|
||||
model_info = get_model_info(
|
||||
model=model, custom_llm_provider=custom_llm_provider
|
||||
)
|
||||
if model_info.get("supports_native_streaming") is False:
|
||||
return True
|
||||
except Exception as e:
|
||||
verbose_logger.debug(
|
||||
f"Error getting model info in OpenAIGPTConfig.should_fake_stream: {e}"
|
||||
)
|
||||
return False
|
||||
|
||||
def _map_openai_params(
|
||||
self,
|
||||
non_default_params: dict,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Tests for OpenAI GPT transformation (litellm/llms/openai/chat/gpt_transformation
|
|||
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -731,3 +732,58 @@ class TestCacheControlPreservationForCustomEndpoint:
|
|||
headers={},
|
||||
)
|
||||
assert all("cache_control" not in m for m in body["messages"])
|
||||
|
||||
|
||||
class TestOpenAIShouldFakeStream:
|
||||
"""should_fake_stream honors model_info['supports_native_streaming'].
|
||||
|
||||
Regression test for: https://github.com/BerriAI/litellm/issues/30208
|
||||
OpenAI-compatible endpoints that cannot stream natively can be flagged with
|
||||
model_info={"supports_native_streaming": False} to enable client-side fake
|
||||
streaming instead of sending stream=True to an endpoint that rejects it.
|
||||
"""
|
||||
|
||||
GET_MODEL_INFO = "litellm.llms.openai.chat.gpt_transformation.get_model_info"
|
||||
|
||||
def setup_method(self):
|
||||
self.config = OpenAIGPTConfig()
|
||||
|
||||
def test_fake_stream_when_native_streaming_unsupported(self):
|
||||
with patch(
|
||||
self.GET_MODEL_INFO, return_value={"supports_native_streaming": False}
|
||||
):
|
||||
assert (
|
||||
self.config.should_fake_stream(model="openai/no-stream", stream=True)
|
||||
is True
|
||||
)
|
||||
|
||||
def test_no_fake_stream_when_native_streaming_supported(self):
|
||||
with patch(
|
||||
self.GET_MODEL_INFO, return_value={"supports_native_streaming": True}
|
||||
):
|
||||
assert (
|
||||
self.config.should_fake_stream(model="openai/gpt-4o", stream=True)
|
||||
is False
|
||||
)
|
||||
|
||||
def test_no_fake_stream_when_field_absent(self):
|
||||
with patch(self.GET_MODEL_INFO, return_value={}):
|
||||
assert (
|
||||
self.config.should_fake_stream(model="openai/gpt-4o", stream=True)
|
||||
is False
|
||||
)
|
||||
|
||||
def test_no_fake_stream_and_no_lookup_when_stream_not_requested(self):
|
||||
with patch(self.GET_MODEL_INFO) as mock_get_model_info:
|
||||
assert (
|
||||
self.config.should_fake_stream(model="openai/no-stream", stream=False)
|
||||
is False
|
||||
)
|
||||
mock_get_model_info.assert_not_called()
|
||||
|
||||
def test_no_fake_stream_when_model_info_lookup_fails(self):
|
||||
with patch(self.GET_MODEL_INFO, side_effect=Exception("unknown model")):
|
||||
assert (
|
||||
self.config.should_fake_stream(model="openai/unknown", stream=True)
|
||||
is False
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue