Add grok reasoning content

This commit is contained in:
Sameer Kankute 2026-01-27 16:34:57 +05:30
parent f95572e3ed
commit e695cb5367
2 changed files with 133 additions and 1 deletions

View File

@ -323,4 +323,12 @@ class GroqChatCompletionStreamingHandler(OpenAIChatCompletionStreamingHandler):
status_code=error.get("code"), message=error.get("message"), body=error
)
# Map Groq's 'reasoning' field to LiteLLM's 'reasoning_content' field
# Groq returns delta.reasoning, but LiteLLM expects delta.reasoning_content
choices = chunk.get("choices", [])
for choice in choices:
delta = choice.get("delta", {})
if "reasoning" in delta:
delta["reasoning_content"] = delta.pop("reasoning")
return super().chunk_parser(chunk)

View File

@ -11,7 +11,10 @@ import pytest
import litellm
from base_llm_unit_tests import BaseLLMChatTest
from litellm.llms.groq.chat.transformation import GroqChatConfig
from litellm.llms.groq.chat.transformation import (
GroqChatConfig,
GroqChatCompletionStreamingHandler,
)
class TestGroq(BaseLLMChatTest):
def get_base_completion_call_args(self) -> dict:
@ -164,3 +167,124 @@ class TestGroqStructuredOutputs:
if "tools" in result:
tool_names = [t.get("function", {}).get("name") for t in result["tools"]]
assert "json_tool_call" not in tool_names
class TestGroqReasoning:
"""
Tests for Groq reasoning field mapping.
Groq returns 'reasoning' field in delta, but LiteLLM expects 'reasoning_content'.
"""
def test_reasoning_field_mapping_in_streaming_chunks(self):
"""
Test that Groq's 'reasoning' field in streaming chunks is properly mapped
to LiteLLM's 'reasoning_content' field.
"""
handler = GroqChatCompletionStreamingHandler(
streaming_response=None, sync_stream=True
)
# Simulate a chunk with reasoning field as returned by Groq
groq_chunk = {
"id": "chatcmpl-test",
"object": "chat.completion.chunk",
"created": 1769511767,
"model": "qwen/qwen3-32b",
"choices": [
{
"delta": {
"reasoning": "This is reasoning content",
"role": None,
},
"finish_reason": None,
"index": 0,
}
],
}
# Parse the chunk
parsed_chunk = handler.chunk_parser(groq_chunk)
# Verify that reasoning was mapped to reasoning_content
assert parsed_chunk.choices[0].delta.reasoning_content == "This is reasoning content"
# Verify that the original 'reasoning' field was removed
assert not hasattr(parsed_chunk.choices[0].delta, "reasoning")
def test_reasoning_field_not_present(self):
"""
Test that chunks without reasoning field still work correctly.
"""
handler = GroqChatCompletionStreamingHandler(
streaming_response=None, sync_stream=True
)
# Simulate a chunk without reasoning field
groq_chunk = {
"id": "chatcmpl-test",
"object": "chat.completion.chunk",
"created": 1769511767,
"model": "qwen/qwen3-32b",
"choices": [
{
"delta": {
"content": "Regular content",
"role": "assistant",
},
"finish_reason": None,
"index": 0,
}
],
}
# Parse the chunk
parsed_chunk = handler.chunk_parser(groq_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")
def test_reasoning_with_tool_calls(self):
"""
Test that reasoning field is properly mapped even when tool_calls are present.
"""
handler = GroqChatCompletionStreamingHandler(
streaming_response=None, sync_stream=True
)
# Simulate a chunk with both reasoning and tool_calls
groq_chunk = {
"id": "chatcmpl-test",
"object": "chat.completion.chunk",
"created": 1769511767,
"model": "qwen/qwen3-32b",
"choices": [
{
"delta": {
"reasoning": "Reasoning before tool call",
"tool_calls": [
{
"index": 0,
"id": "call_123",
"function": {"name": "test_function", "arguments": "{}"},
"type": "function",
}
],
},
"finish_reason": None,
"index": 0,
}
],
}
# Parse the chunk
parsed_chunk = handler.chunk_parser(groq_chunk)
# Verify that reasoning was mapped to reasoning_content
assert parsed_chunk.choices[0].delta.reasoning_content == "Reasoning before tool call"
# Verify tool_calls are still present
assert parsed_chunk.choices[0].delta.tool_calls is not None
assert len(parsed_chunk.choices[0].delta.tool_calls) == 1
assert parsed_chunk.choices[0].delta.tool_calls[0]["function"]["name"] == "test_function"