Add grok reasoning content
This commit is contained in:
parent
f95572e3ed
commit
e695cb5367
@ -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)
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user