Merge pull request #14587 from timelfrink/fix/streaming-tool-call-indices

Fix: Streaming tool call index assignment for multiple tool calls
This commit is contained in:
Krish Dholakia 2025-09-21 21:24:35 -07:00 committed by GitHub
commit cf429e77a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 1 deletions

View file

@ -757,10 +757,12 @@ class Delta(OpenAIObject):
self.function_call = function_call
if tool_calls is not None and isinstance(tool_calls, list):
self.tool_calls = []
current_index = 0
for tool_call in tool_calls:
if isinstance(tool_call, dict):
if tool_call.get("index", None) is None:
tool_call["index"] = 0
tool_call["index"] = current_index
current_index += 1
self.tool_calls.append(ChatCompletionDeltaToolCall(**tool_call))
elif isinstance(tool_call, ChatCompletionDeltaToolCall):
self.tool_calls.append(tool_call)

View file

@ -2328,6 +2328,54 @@ def test_get_whitelisted_models():
print("whitelisted_models written to whitelisted_bedrock_models.txt")
def test_delta_tool_calls_sequential_indices():
"""
Test that multiple tool calls without explicit indices receive sequential indices.
When providers don't include index fields in tool calls, the Delta class
should automatically assign sequential indices (0, 1, 2, ...) instead of
defaulting all tool calls to index=0.
"""
import json
from litellm.types.utils import Delta
# Simulate tool calls from streaming responses without explicit indices
tool_calls_without_indices = [
{
"id": "call_1",
"function": {
"name": "get_weather_for_dallas",
"arguments": json.dumps({})
},
"type": "function",
# Note: no "index" field - simulates provider response
},
{
"id": "call_2",
"function": {
"name": "get_weather_precise",
"arguments": json.dumps({"location": "Dallas, TX"})
},
"type": "function",
# Note: no "index" field - simulates provider response
}
]
# Create Delta object as LiteLLM would when processing streaming response
delta = Delta(
content=None,
tool_calls=tool_calls_without_indices
)
# Verify tool calls have sequential indices
assert delta.tool_calls is not None, "Tool calls should not be None"
assert len(delta.tool_calls) == 2
assert delta.tool_calls[0].index == 0, f"First tool call should have index 0, got {delta.tool_calls[0].index}"
assert delta.tool_calls[1].index == 1, f"Second tool call should have index 1, got {delta.tool_calls[1].index}"
# Verify tool call details are preserved
assert delta.tool_calls[0].function.name == "get_weather_for_dallas"
assert delta.tool_calls[1].function.name == "get_weather_precise"
def test_completion_with_no_model():
"""