mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
Merge df6126edaa into 9ffb82e139
This commit is contained in:
commit
852de0bf7d
2 changed files with 69 additions and 0 deletions
|
|
@ -442,6 +442,7 @@ class OllamaChatCompletionResponseIterator(BaseModelResponseIterator):
|
|||
started_reasoning_content: bool = False
|
||||
finished_reasoning_content: bool = False
|
||||
seen_tool_calls: bool = False
|
||||
_next_tool_call_index: int = 0
|
||||
|
||||
def _is_function_call_complete(self, function_args: str | dict) -> bool:
|
||||
if isinstance(function_args, dict):
|
||||
|
|
@ -489,6 +490,8 @@ class OllamaChatCompletionResponseIterator(BaseModelResponseIterator):
|
|||
if tool_calls is not None:
|
||||
self.seen_tool_calls = True
|
||||
for tool_call in tool_calls:
|
||||
tool_call["index"] = self._next_tool_call_index
|
||||
self._next_tool_call_index += 1
|
||||
function_args = tool_call.get("function").get("arguments")
|
||||
if function_args is not None and len(function_args) > 0:
|
||||
is_function_call_complete = self._is_function_call_complete(function_args)
|
||||
|
|
|
|||
|
|
@ -1044,6 +1044,72 @@ class TestOllamaToolCallTransformation:
|
|||
assert tool_msg["tool_call_id"] == "call_abc123"
|
||||
|
||||
|
||||
class TestOllamaStreamingParallelToolCallIndex:
|
||||
"""Regression for https://github.com/BerriAI/litellm/issues/33678.
|
||||
|
||||
Ollama streams each parallel tool call in its own chunk without an OpenAI-style top-level
|
||||
index. Every delta used to carry index 0, so index-accumulating clients appended the
|
||||
arguments of every later call onto the first one.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _chunk(*tool_calls: dict) -> dict:
|
||||
return {
|
||||
"model": "qwen3:8b",
|
||||
"message": {"role": "assistant", "content": "", "tool_calls": list(tool_calls)},
|
||||
"done": False,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _parsed_tool_calls(iterator: OllamaChatCompletionResponseIterator, *chunks: dict) -> list:
|
||||
return [
|
||||
tool_call
|
||||
for chunk in chunks
|
||||
for tool_call in (iterator.chunk_parser(chunk).choices[0].delta.tool_calls or [])
|
||||
]
|
||||
|
||||
def test_tool_calls_in_separate_chunks_get_distinct_sequential_indices(self):
|
||||
iterator = OllamaChatCompletionResponseIterator(streaming_response=iter([]), sync_stream=True)
|
||||
chunks = [
|
||||
self._chunk({"function": {"name": "bash", "arguments": {"command": command}}})
|
||||
for command in ("date", "uname -a", "whoami")
|
||||
]
|
||||
|
||||
tool_calls = self._parsed_tool_calls(iterator, *chunks)
|
||||
|
||||
assert [tool_call.index for tool_call in tool_calls] == [0, 1, 2]
|
||||
assert [json.loads(tool_call.function.arguments) for tool_call in tool_calls] == [
|
||||
{"command": "date"},
|
||||
{"command": "uname -a"},
|
||||
{"command": "whoami"},
|
||||
]
|
||||
|
||||
def test_tool_calls_in_one_chunk_get_distinct_indices(self):
|
||||
iterator = OllamaChatCompletionResponseIterator(streaming_response=iter([]), sync_stream=True)
|
||||
chunk = self._chunk(
|
||||
{"function": {"name": "bash", "arguments": {"command": "date"}}},
|
||||
{"function": {"name": "bash", "arguments": {"command": "whoami"}}},
|
||||
)
|
||||
|
||||
tool_calls = self._parsed_tool_calls(iterator, chunk)
|
||||
|
||||
assert [tool_call.index for tool_call in tool_calls] == [0, 1]
|
||||
|
||||
def test_index_counter_continues_across_chunks(self):
|
||||
iterator = OllamaChatCompletionResponseIterator(streaming_response=iter([]), sync_stream=True)
|
||||
chunks = [
|
||||
self._chunk(
|
||||
{"function": {"name": "bash", "arguments": {"command": "date"}}},
|
||||
{"function": {"name": "bash", "arguments": {"command": "uname -a"}}},
|
||||
),
|
||||
self._chunk({"function": {"name": "bash", "arguments": {"command": "whoami"}}}),
|
||||
]
|
||||
|
||||
tool_calls = self._parsed_tool_calls(iterator, *chunks)
|
||||
|
||||
assert [tool_call.index for tool_call in tool_calls] == [0, 1, 2]
|
||||
|
||||
|
||||
class TestOllamaStreamingUsage:
|
||||
@staticmethod
|
||||
def _parse(chunk: dict) -> ModelResponseStream:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue