mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-14 13:04:34 +00:00
[Bug Fix] The model gemini-2.5-flash with the merge_reasoning_content_in_choices parameter does not work (#13066)
* _optional_combine_thinking_block_in_choices * test_optional_combine_thinking_block_with_none_content
This commit is contained in:
@@ -922,6 +922,9 @@ class CustomStreamWrapper:
|
||||
)
|
||||
if reasoning_content:
|
||||
if self.sent_first_thinking_block is False:
|
||||
# Ensure content is not None before concatenation
|
||||
if model_response.choices[0].delta.content is None:
|
||||
model_response.choices[0].delta.content = ""
|
||||
model_response.choices[0].delta.content += (
|
||||
"<think>" + reasoning_content
|
||||
)
|
||||
@@ -938,7 +941,7 @@ class CustomStreamWrapper:
|
||||
and model_response.choices[0].delta.content
|
||||
):
|
||||
model_response.choices[0].delta.content = (
|
||||
"</think>" + model_response.choices[0].delta.content
|
||||
"</think>" + (model_response.choices[0].delta.content or "")
|
||||
)
|
||||
self.sent_last_thinking_block = True
|
||||
|
||||
|
||||
@@ -6,6 +6,12 @@ model_list:
|
||||
litellm_params:
|
||||
model: openai/*
|
||||
|
||||
- model_name: vertex_ai/gemini-2.5-pro # Vertex AI Gemini
|
||||
litellm_params:
|
||||
model: vertex_ai/gemini-2.5-pro
|
||||
thinking: {"type": "enabled", "budget_tokens": 1024}
|
||||
merge_reasoning_content_in_choices: true
|
||||
|
||||
|
||||
litellm_settings:
|
||||
callbacks: ["datadog_llm_observability"]
|
||||
|
||||
@@ -725,3 +725,91 @@ def test_streaming_handler_with_stream_options(
|
||||
mr_dict = mr.model_dump()
|
||||
print(mr_dict)
|
||||
assert "stream_options" not in mr_dict
|
||||
|
||||
|
||||
def test_optional_combine_thinking_block_with_none_content(
|
||||
initialized_custom_stream_wrapper: CustomStreamWrapper,
|
||||
):
|
||||
"""Test that reasoning_content is properly combined when delta.content is None"""
|
||||
# Setup the wrapper to use the merge feature
|
||||
initialized_custom_stream_wrapper.merge_reasoning_content_in_choices = True
|
||||
|
||||
# First chunk with reasoning_content and None content - should handle None gracefully
|
||||
first_chunk = {
|
||||
"id": "chunk1",
|
||||
"object": "chat.completion.chunk",
|
||||
"created": 1741037890,
|
||||
"model": "deepseek-reasoner",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"delta": {
|
||||
"content": None, # This is None, not empty string
|
||||
"reasoning_content": "Let me think about this problem",
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Second chunk with reasoning_content and None content
|
||||
second_chunk = {
|
||||
"id": "chunk2",
|
||||
"object": "chat.completion.chunk",
|
||||
"created": 1741037891,
|
||||
"model": "deepseek-reasoner",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"delta": {
|
||||
"content": None, # This is None, not empty string
|
||||
"reasoning_content": " step by step",
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Final chunk with actual content - should add </think> tag
|
||||
final_chunk = {
|
||||
"id": "chunk3",
|
||||
"object": "chat.completion.chunk",
|
||||
"created": 1741037892,
|
||||
"model": "deepseek-reasoner",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"delta": {
|
||||
"content": "The answer is 42",
|
||||
"reasoning_content": None
|
||||
},
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Process first chunk - should not raise TypeError
|
||||
first_response = ModelResponseStream(**first_chunk)
|
||||
initialized_custom_stream_wrapper._optional_combine_thinking_block_in_choices(
|
||||
first_response
|
||||
)
|
||||
assert first_response.choices[0].delta.content == "<think>Let me think about this problem"
|
||||
assert not hasattr(first_response.choices[0].delta, "reasoning_content")
|
||||
assert initialized_custom_stream_wrapper.sent_first_thinking_block is True
|
||||
|
||||
# Process second chunk - should work with continued reasoning
|
||||
second_response = ModelResponseStream(**second_chunk)
|
||||
initialized_custom_stream_wrapper._optional_combine_thinking_block_in_choices(
|
||||
second_response
|
||||
)
|
||||
assert second_response.choices[0].delta.content == " step by step"
|
||||
assert not hasattr(second_response.choices[0].delta, "reasoning_content")
|
||||
|
||||
# Process final chunk - should add </think> tag
|
||||
final_response = ModelResponseStream(**final_chunk)
|
||||
initialized_custom_stream_wrapper._optional_combine_thinking_block_in_choices(
|
||||
final_response
|
||||
)
|
||||
assert final_response.choices[0].delta.content == "</think>The answer is 42"
|
||||
assert initialized_custom_stream_wrapper.sent_last_thinking_block is True
|
||||
assert not hasattr(final_response.choices[0].delta, "reasoning_content")
|
||||
|
||||
Reference in New Issue
Block a user