This commit is contained in:
sushka 2026-03-20 17:35:41 +03:00
parent cd374fe357
commit d07050ed4f

View file

@ -7,7 +7,7 @@ sys.path.insert(
0, os.path.abspath("../../../../..")
) # Adds the parent directory to the system path
from litellm.llms.hosted_vllm.chat.transformation import HostedVLLMChatConfig
from litellm.llms.hosted_vllm.chat.transformation import HostedVLLMChatConfig, HostedVLLMChatCompletionStreamingHandler
def test_hosted_vllm_chat_transformation_file_url():
@ -257,3 +257,124 @@ def test_hosted_vllm_thinking_blocks_with_list_content():
}
assert assistant_msg["content"][2] == {"type": "text", "text": "Response text"}
assert "thinking_blocks" not in assistant_msg
class TestHostedVllmReasoning:
"""
Tests for vLLM reasoning field mapping.
vLLM 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 = HostedVLLMChatCompletionStreamingHandler(
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 = HostedVLLMChatCompletionStreamingHandler(
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 = HostedVLLMChatCompletionStreamingHandler(
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"