mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-16 23:41:43 +00:00
fix(convert_dict_to_response): handle empty choices list without raising 500 APIError (Fixes #40276)
This commit is contained in:
parent
9fffda4117
commit
c1132d0454
2 changed files with 72 additions and 4 deletions
|
|
@ -179,7 +179,7 @@ async def convert_to_streaming_response_async(
|
|||
|
||||
choice_list: Final[list[StreamingChoices]] = []
|
||||
|
||||
if not response_object.get("choices"):
|
||||
if "choices" not in response_object or not isinstance(response_object["choices"], Iterable):
|
||||
from litellm.exceptions import APIError
|
||||
|
||||
raise APIError(
|
||||
|
|
@ -287,7 +287,7 @@ def convert_to_streaming_response(
|
|||
model_response_object: Final = ModelResponseStream()
|
||||
choice_list: Final[list[StreamingChoices]] = []
|
||||
|
||||
if not response_object.get("choices"):
|
||||
if "choices" not in response_object or not isinstance(response_object["choices"], Iterable):
|
||||
from litellm.exceptions import APIError
|
||||
|
||||
raise APIError(
|
||||
|
|
@ -623,7 +623,7 @@ def convert_to_model_response_object(
|
|||
return convert_to_streaming_response(response_object=response_object)
|
||||
choice_list: Final[list[Choices]] = []
|
||||
|
||||
if not response_object.get("choices") or not isinstance(response_object["choices"], Iterable):
|
||||
if "choices" not in response_object or not isinstance(response_object["choices"], Iterable):
|
||||
from litellm.exceptions import APIError
|
||||
|
||||
raise APIError(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from litellm.constants import RESPONSE_FORMAT_TOOL_NAME
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
|
|
@ -99,3 +99,71 @@ def test_handle_invalid_parallel_tool_calls_skips_custom_tool_calls():
|
|||
)
|
||||
result = _handle_invalid_parallel_tool_calls([custom_tool_call, function_tool_call])
|
||||
assert result == [custom_tool_call, function_tool_call]
|
||||
|
||||
|
||||
def test_convert_empty_choices_response() -> None:
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
convert_to_streaming_response,
|
||||
)
|
||||
|
||||
resp = {
|
||||
"id": "x",
|
||||
"created": 1,
|
||||
"model": "gemini-3.5-flash",
|
||||
"object": "chat.completion",
|
||||
"choices": [],
|
||||
"usage": {"prompt_tokens": 10, "completion_tokens": 0, "total_tokens": 10},
|
||||
"vertex_ai_safety_results": ["blocked"],
|
||||
}
|
||||
result = convert_to_model_response_object(
|
||||
response_object=resp,
|
||||
model_response_object=ModelResponse(),
|
||||
response_type="completion",
|
||||
)
|
||||
assert result.choices == []
|
||||
assert getattr(result, "vertex_ai_safety_results") == ["blocked"]
|
||||
|
||||
# Test sync streaming generator handles empty choices
|
||||
sync_stream = list(convert_to_streaming_response(response_object=resp))
|
||||
assert len(sync_stream) == 1
|
||||
assert sync_stream[0].choices == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_empty_choices_response_async() -> None:
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
convert_to_streaming_response_async,
|
||||
)
|
||||
|
||||
resp = {
|
||||
"id": "x",
|
||||
"created": 1,
|
||||
"model": "gemini-3.5-flash",
|
||||
"object": "chat.completion",
|
||||
"choices": [],
|
||||
"usage": {"prompt_tokens": 10, "completion_tokens": 0, "total_tokens": 10},
|
||||
}
|
||||
async_chunks = []
|
||||
async for chunk in convert_to_streaming_response_async(response_object=resp):
|
||||
async_chunks.append(chunk)
|
||||
assert len(async_chunks) == 1
|
||||
assert async_chunks[0].choices == []
|
||||
|
||||
|
||||
def test_convert_missing_choices_raises_api_error() -> None:
|
||||
from litellm.exceptions import APIError
|
||||
|
||||
resp = {
|
||||
"id": "x",
|
||||
"created": 1,
|
||||
"model": "gemini-3.5-flash",
|
||||
"object": "chat.completion",
|
||||
}
|
||||
with pytest.raises(APIError) as exc_info:
|
||||
convert_to_model_response_object(
|
||||
response_object=resp,
|
||||
model_response_object=ModelResponse(),
|
||||
response_type="completion",
|
||||
)
|
||||
assert "no 'choices'" in str(exc_info.value)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue