From c5ca2afec3b0e98cb014c36c439a749226e434d3 Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Mon, 15 Sep 2025 21:11:13 +0200 Subject: [PATCH 1/2] Add test for tool call sequential index assignment - Test multiple tool calls without explicit indices receive sequential indices - Verify Delta class assigns indices 0, 1, 2... instead of defaulting all to 0 - Add comprehensive assertions for tool call details preservation - Cover provider-agnostic streaming response scenarios --- tests/litellm_utils_tests/test_utils.py | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/litellm_utils_tests/test_utils.py b/tests/litellm_utils_tests/test_utils.py index 8d4fc3ac451..482cda1e104 100644 --- a/tests/litellm_utils_tests/test_utils.py +++ b/tests/litellm_utils_tests/test_utils.py @@ -2326,3 +2326,53 @@ def test_get_whitelisted_models(): file.write(f"{model}\n") 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" From 802f7011e260d729410fe152151811b24ff90913 Mon Sep 17 00:00:00 2001 From: Tim Elfrink Date: Mon, 15 Sep 2025 21:11:31 +0200 Subject: [PATCH 2/2] Fix tool call index assignment in Delta class - Update tool call index logic to assign sequential indices when missing - Replace default index=0 behavior with proper sequential assignment - Maintain OpenAI API compatibility with correct tool call indexing - Preserve existing behavior for tool calls with explicit indices - Universal fix benefiting all providers using Delta class --- litellm/types/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 289291bde08..228677a17a7 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -754,10 +754,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)