Add reasoning' field to 'reasoning_content' field in delta

This commit is contained in:
Sameer Kankute 2026-02-18 16:47:05 +05:30
parent 2517c069ca
commit 9678c723b0
2 changed files with 99 additions and 2 deletions

View file

@ -770,14 +770,36 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig):
class OpenAIChatCompletionStreamingHandler(BaseModelResponseIterator):
def _map_reasoning_to_reasoning_content(self, choices: list) -> list:
"""
Map 'reasoning' field to 'reasoning_content' field in delta.
Some OpenAI-compatible providers (e.g., GLM-5, hosted_vllm) return
delta.reasoning, but LiteLLM expects delta.reasoning_content.
Args:
choices: List of choice objects from the streaming chunk
Returns:
List of choices with reasoning field mapped to reasoning_content
"""
for choice in choices:
delta = choice.get("delta", {})
if "reasoning" in delta:
delta["reasoning_content"] = delta.pop("reasoning")
return choices
def chunk_parser(self, chunk: dict) -> ModelResponseStream:
try:
choices = chunk.get("choices", [])
choices = self._map_reasoning_to_reasoning_content(choices)
kwargs = {
"id": chunk["id"],
"object": "chat.completion.chunk",
"created": chunk.get("created"),
"model": chunk.get("model"),
"choices": chunk.get("choices", []),
"choices": choices,
}
if "usage" in chunk and chunk["usage"] is not None:
kwargs["usage"] = chunk["usage"]

View file

@ -10,8 +10,8 @@ import pytest
sys.path.insert(0, os.path.abspath("../../../../.."))
from litellm.llms.openai.chat.gpt_transformation import (
OpenAIGPTConfig,
OpenAIChatCompletionStreamingHandler,
OpenAIGPTConfig,
)
@ -204,6 +204,81 @@ class TestOpenAIChatCompletionStreamingHandler:
assert result.choices[0].delta.content == "Hello"
assert not hasattr(result, "usage") or result.usage is None
def test_chunk_parser_maps_reasoning_to_reasoning_content(self):
"""
Test that chunk_parser maps 'reasoning' field to 'reasoning_content'.
Some OpenAI-compatible providers (e.g., GLM-5, hosted_vllm) return
delta.reasoning, but LiteLLM expects delta.reasoning_content.
Regression test for: Streaming responses with delta.reasoning field
coming back empty when using openai/ or hosted_vllm/ providers.
"""
handler = OpenAIChatCompletionStreamingHandler(
streaming_response=None, sync_stream=True
)
# Simulate a chunk with reasoning field (as returned by GLM-5)
chunk = {
"id": "chatcmpl-8e3d624de9b12528",
"object": "chat.completion.chunk",
"created": 1771411455,
"model": "glm-5",
"choices": [
{
"index": 0,
"delta": {
"reasoning": "The capital of France",
"role": None,
},
"finish_reason": None,
}
],
}
# Parse the chunk
parsed_chunk = handler.chunk_parser(chunk)
# Verify that reasoning was mapped to reasoning_content
assert parsed_chunk.choices[0].delta.reasoning_content == "The capital of France"
# Verify that the original 'reasoning' field was removed
assert not hasattr(parsed_chunk.choices[0].delta, "reasoning")
def test_chunk_parser_reasoning_field_not_present(self):
"""
Test that chunks without reasoning field still work correctly.
"""
handler = OpenAIChatCompletionStreamingHandler(
streaming_response=None, sync_stream=True
)
# Simulate a chunk without reasoning field
chunk = {
"id": "chatcmpl-test",
"object": "chat.completion.chunk",
"created": 1769511767,
"model": "gpt-4o",
"choices": [
{
"delta": {
"content": "Regular content",
"role": "assistant",
},
"finish_reason": None,
"index": 0,
}
],
}
# Parse the chunk
parsed_chunk = handler.chunk_parser(chunk)
# Verify that content is present
assert parsed_chunk.choices[0].delta.content == "Regular content"
assert parsed_chunk.choices[0].delta.role == "assistant"
# Verify that reasoning_content is not set (it should be deleted by Delta.__init__)
assert not hasattr(parsed_chunk.choices[0].delta, "reasoning_content")
class TestPromptCacheKeyIntegration:
"""Tests for prompt_cache_key support"""