#776·shell_gpt

Multiple tool_calls Aggregation Produces Corrupted Output

Author: wangengzhengCreated Jun 11, 2026Updated Jun 11, 2026

Description

When the model returns multiple tool_calls in a streaming response, the tool call data is incorrectly concatenated, causing malformed output and making it impossible to reliably parse individual function calls.


Expected Behavior

The response should contain 3 independent tool calls:

Tool 1

json
{
  "function": "execute_shell_command",
  "arguments": {
    "shell_command": "dotnet --version 2>/dev/null || echo \"dotnet not found\""
  }
}

Tool 2

json
{
  "function": "execute_shell_command",
  "arguments": {
    "shell_command": "sw_vers 2>/dev/null && uname -a"
  }
}

Tool 3

json
{
  "function": "execute_shell_command",
  "arguments": {
    "shell_command": "ls -la *.csproj 2>/dev/null || find . -name \"*.csproj\" -maxdepth 3 2>/dev/null | head -5"
  }
}

Actual Behavior

Multiple tool calls are merged into a single corrupted string:

execute_shell_command
({"shell_command":"dotnet --version ..."})

{"shell_command":"sw_vers 2>/dev/null && uname -a"}

{"shell_command":"ls -la *.csproj ..."}

Resulting output contains:

  • Function names repeated unexpectedly
  • Arguments from different tool calls concatenated together
  • Invalid JSON fragments
  • Corrupted characters (^M, broken quotes, malformed command strings)
  • Loss of tool_call boundaries

Example corrupted output:

execute_shell_command ({"shell_command":
"dotnet --version 2>/dev/null || echo \"dotnet not found\""})

{"shell_command":"sw_vers 2>/dev/null && uname -a"}

{"shell_command":"ls -la ^M*.csproj 2>/dev/null || find . ^M-name \"*.csproj\" -maxdepth 3 2>/dev/null | head -5"}

Impact

  • Cannot reliably reconstruct tool calls from stream chunks.
  • JSON parsing fails.
  • Multi-tool execution workflow breaks.
  • Tool arguments may become mixed between different function calls.
  • Tool invocation order cannot be guaranteed.

Root Cause Analysis

The streaming parser appears to aggregate delta.tool_calls incorrectly.

Each streamed chunk contains a tool_call.index identifying which tool call the delta belongs to.

Example:

Chunk 1

json
{
  "tool_calls": [
    {
      "index": 0,
      "function": {
        "arguments": "dotnet"
      }
    }
  ]
}

Chunk 2

json
{
  "tool_calls": [
    {
      "index": 1,
      "function": {
        "arguments": "sw_vers"
      }
    }
  ]
}

Chunk 3

json
{
  "tool_calls": [
    {
      "index": 2,
      "function": {
        "arguments": "ls -la"
      }
    }
  ]
}

Current Aggregation Result

dotnetsw_versls -la

Expected Aggregation Result

json
{
  "tool_calls": [
    {
      "index": 0,
      "arguments": "dotnet ..."
    },
    {
      "index": 1,
      "arguments": "sw_vers ..."
    },
    {
      "index": 2,
      "arguments": "ls -la ..."
    }
  ]
}

Recommended Fix

Aggregate streamed tool call fragments by tool_call.index.

Example Implementation

python
tool_calls = {}

for tc in delta.tool_calls:
    idx = tc.index

    if idx not in tool_calls:
        tool_calls[idx] = {
            "id": "",
            "function": {
                "name": "",
                "arguments": ""
            }
        }

    if tc.id:
        tool_calls[idx]["id"] += tc.id

    if tc.function.name:
        tool_calls[idx]["function"]["name"] += tc.function.name

    if tc.function.arguments:
        tool_calls[idx]["function"]["arguments"] += tc.function.arguments

Final Processing

python
for idx in sorted(tool_calls.keys()):
    process(tool_calls[idx])

Acceptance Criteria

  • Multiple tool calls are reconstructed independently.
  • Tool call boundaries are preserved.
  • Arguments are appended only to their corresponding tool_call.index.
  • Generated JSON is valid.
  • Tool execution order matches the original response.
  • Streaming and non-streaming responses produce equivalent tool call structures.

Severity

High

Multi-tool-call responses cannot be parsed correctly, leading to:

  • Invalid JSON payloads
  • Tool execution failures
  • Corrupted command arguments
  • Unreliable agent behavior
  • Broken streaming compatibility

Environment

Item Value
Feature Streaming Chat Completion
Response Type tool_calls
Scenario Multiple tool calls in a single assistant response
Impact Scope All function-calling agents using streaming mode
Severity High