diff --git a/litellm/utils.py b/litellm/utils.py index e49916d025e..e3497ad71a6 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -6975,7 +6975,6 @@ def mock_completion_streaming_obj(model_response, mock_response, model, n: int | completion_obj = Delta(role="assistant", content=mock_response[i : i + 3]) if n is None: model_response.choices[0].delta = completion_obj - model_response.choices[0].finish_reason = None else: _all_choices = [] for j in range(n): @@ -6986,19 +6985,16 @@ def mock_completion_streaming_obj(model_response, mock_response, model, n: int | _all_choices.append(_streaming_choice) model_response.choices = _all_choices yield model_response + # Separate terminal object so content chunks keep finish_reason unset. + terminal: Final = model_response.model_copy(deep=True) if n is None: - model_response.choices[0].delta = Delta(role="assistant", content=None) - model_response.choices[0].finish_reason = "stop" + terminal.choices[0].delta = Delta(role="assistant", content=None) + terminal.choices[0].finish_reason = "stop" else: - model_response.choices = [ - litellm.utils.StreamingChoices( - index=j, - delta=litellm.utils.Delta(role="assistant", content=None), - finish_reason="stop", - ) - for j in range(n) - ] - yield model_response + for j in range(n): + terminal.choices[j].delta = litellm.utils.Delta(role="assistant", content=None) + terminal.choices[j].finish_reason = "stop" + yield terminal async def async_mock_completion_streaming_obj( @@ -7016,7 +7012,6 @@ async def async_mock_completion_streaming_obj( completion_obj = Delta(role="assistant", content=mock_response[i : i + 3]) if n is None: model_response.choices[0].delta = completion_obj - model_response.choices[0].finish_reason = None else: _all_choices = [] for j in range(n): @@ -7027,19 +7022,16 @@ async def async_mock_completion_streaming_obj( _all_choices.append(_streaming_choice) model_response.choices = _all_choices yield model_response + # Separate terminal object so content chunks keep finish_reason unset. + terminal: Final = model_response.model_copy(deep=True) if n is None: - model_response.choices[0].delta = Delta(role="assistant", content=None) - model_response.choices[0].finish_reason = "stop" + terminal.choices[0].delta = Delta(role="assistant", content=None) + terminal.choices[0].finish_reason = "stop" else: - model_response.choices = [ - litellm.utils.StreamingChoices( - index=j, - delta=litellm.utils.Delta(role="assistant", content=None), - finish_reason="stop", - ) - for j in range(n) - ] - yield model_response + for j in range(n): + terminal.choices[j].delta = litellm.utils.Delta(role="assistant", content=None) + terminal.choices[j].finish_reason = "stop" + yield terminal ########## Reading Config File ############################ diff --git a/tests/test_litellm/test_router.py b/tests/test_litellm/test_router.py index 7c044310e14..e3694ad5cdc 100644 --- a/tests/test_litellm/test_router.py +++ b/tests/test_litellm/test_router.py @@ -13295,10 +13295,14 @@ class _InFlightTracker: self.current -= 1 -_SSE_CHUNKS: Final[tuple[bytes, ...]] = tuple( +_SSE_CHUNKS: Final[tuple[bytes, ...]] = ( + *( + b'data: {"id":"c","object":"chat.completion.chunk","created":1,"model":"gpt-5.6",' + b'"choices":[{"index":0,"delta":{"content":"x"},"finish_reason":null}]}\n\n' + for _ in range(5) + ), b'data: {"id":"c","object":"chat.completion.chunk","created":1,"model":"gpt-5.6",' - b'"choices":[{"index":0,"delta":{"content":"x"},"finish_reason":null}]}\n\n' - for _ in range(5) + b'"choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\n', )