fix(streaming): map reasoning to reasoning_content in Delta for gpt-oss providers

Providers like Cerebras return delta.reasoning in streaming responses
for gpt-oss models, but LiteLLM's Delta class expects reasoning_content.
This causes reasoning content to be silently dropped during streaming.

Fixes #13300
This commit is contained in:
Chesars 2026-03-04 16:40:31 -03:00
parent 8665e92aa8
commit e48b7ae8f9
2 changed files with 34 additions and 0 deletions

View file

@ -1224,6 +1224,13 @@ class Delta(SafeAttributeModel, OpenAIObject):
annotations: Optional[List[ChatCompletionAnnotation]] = None,
**params,
):
# Map 'reasoning' to 'reasoning_content' for providers that return
# delta.reasoning (e.g., Cerebras, Groq gpt-oss models).
# Must be done before super().__init__ to prevent 'reasoning' from
# leaking as an extra attribute on the parent model.
if reasoning_content is None and "reasoning" in params:
reasoning_content = params.pop("reasoning", None)
super(Delta, self).__init__(**params)
add_provider_specific_fields(self, params.get("provider_specific_fields", {}))
self.content = content

View file

@ -222,3 +222,30 @@ def test_chat_completion_token_logprob_invalid_top_logprobs_rejected():
logprob=-0.31725305,
top_logprobs="invalid_string",
)
def test_delta_maps_reasoning_to_reasoning_content():
"""
Test that Delta maps 'reasoning' field to 'reasoning_content'.
Providers like Cerebras and Groq return delta.reasoning for gpt-oss models,
but LiteLLM expects delta.reasoning_content.
"""
from litellm.types.utils import Delta
# When provider sends 'reasoning' (e.g., Cerebras gpt-oss streaming)
delta = Delta(content=None, role="assistant", reasoning="thinking step by step")
assert delta.reasoning_content == "thinking step by step"
assert not hasattr(delta, "reasoning"), "reasoning should not leak as an extra attribute"
# When provider sends 'reasoning_content' directly (e.g., NIM), it still works
delta2 = Delta(content="hello", reasoning_content="direct reasoning")
assert delta2.reasoning_content == "direct reasoning"
# When both are present, reasoning_content takes precedence
delta3 = Delta(reasoning_content="from_rc", reasoning="from_r")
assert delta3.reasoning_content == "from_rc"
# When neither is present, reasoning_content is not set (OpenAI spec)
delta4 = Delta(content="hello")
assert not hasattr(delta4, "reasoning_content")