fix(ollama): Enhance chunk parsing for empty responses without 'thinking' and improve error logging (#13333) (#15717)

This commit is contained in:
wenhua
2025-10-21 16:59:01 -07:00
committed by GitHub
parent e1cb92862e
commit b0ccc35a9c
2 changed files with 36 additions and 1 deletions
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any, AsyncIterator, Iterator, List, Optional,
from httpx._models import Headers, Response
import litellm
from litellm._logging import verbose_proxy_logger
from litellm.litellm_core_utils.prompt_templates.common_utils import (
get_str_from_messages,
)
@@ -577,6 +578,18 @@ class OllamaTextCompletionResponseIterator(BaseModelResponseIterator):
]
)
else:
raise Exception(f"Unable to parse ollama chunk - {chunk}")
# In this case, 'thinking' is not present in the chunk, chunk["done"] is false,
# and chunk["response"] is falsy (None or empty string),
# but Ollama is just starting to stream, so it should be processed as a normal dict
return ModelResponseStream(
choices=[
StreamingChoices(
index=0,
delta=Delta(reasoning_content=""),
)
]
)
# raise Exception(f"Unable to parse ollama chunk - {chunk}")
except Exception as e:
verbose_proxy_logger.error(f"Unable to parse ollama chunk - {chunk}")
raise e
@@ -459,6 +459,28 @@ class TestOllamaTextCompletionResponseIterator:
assert result.choices and result.choices[0].delta is not None
assert result.choices[0].delta.content == "Hello world"
assert getattr(result.choices[0].delta, "reasoning_content", None) is None
def test_chunk_parser_empty_response_without_thinking(self):
"""Test that empty response chunks without thinking still work."""
iterator = OllamaTextCompletionResponseIterator(
streaming_response=iter([]), sync_stream=True, json_mode=False
)
# Test empty response chunk without thinking
empty_response_chunk = {
"model": "qwen3:4b",
"created_at": "2025-10-16T11:27:14.82881Z",
"response": "",
"done": False,
}
result = iterator.chunk_parser(empty_response_chunk)
# Updated to handle ModelResponseStream return type
assert isinstance(result, ModelResponseStream)
assert result.choices and result.choices[0].delta is not None
assert result.choices[0].delta.content == None
assert getattr(result.choices[0].delta, "reasoning_content", None) is ""
def test_chunk_parser_done_chunk(self):
"""Test that done chunks work correctly."""