Skip to content

[Bug]: tool_calls.id is Missing in Streaming Responses (stream=true) but Present in Non-Streaming Responses #18412

Open
@Kalle12345

Description

@Kalle12345

🐛 Describe the bug

When making an API call to the chat completions endpoint with tools and stream=true, the tool_calls objects within the streamed chunks (delta.tool_calls) do not include the id field for each tool call. However, when stream=false, the tool_calls.id field is correctly present in the response.

This inconsistency makes it difficult to uniquely identify and track tool calls when processing streamed responses, which is crucial for many applications that rely on tool usage. The OpenAI API, which vLLM aims to be compatible with, includes the tool_call_id (or equivalent id) in streaming chunks.

Steps to Reproduce:

Make a request with stream=false:

Request Body:

{
    "model": "Qwen/Qwen3-14B-AWQ",
    "messages": [
        {
            "role": "user",
            "content": "What is the weather like in Boston today?"
        }
    ],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "Get the current weather in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city and state, e.g. San Francisco, CA"
                        },
                        "unit": {
                            "type": "string",
                            "enum": [
                                "celsius",
                                "fahrenheit"
                            ]
                        }
                    },
                    "required": [
                        "location"
                    ]
                }
            }
        }
    ],
    "tool_choice": {
        "type": "function",
        "function": {
            "name": "get_current_weather"
        }
    },
    "stream": false
}

Response :

{
    "id": "chatcmpl-26cfd57cdd4c4574b6cfe2d488d6caf0",
    "object": "chat.completion",
    "created": 1747748271,
    "model": "default",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "tool_calls": [
                    {
                        "id": "chatcmpl-tool-c562052db72a4e3c94b844712b4f38e1", // <--- ID IS PRESENT
                        "type": "function",
                        "function": {
                            "name": "get_current_weather",
                            "arguments": "{\"location\": \"Boston\", \"unit\": \"fahrenheit\"}"
                        }
                    }
                ]
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 196,
        "total_tokens": 210,
        "completion_tokens": 14
    }
}

Make a request with stream=true:

Request Body:

{
    "model": "Qwen/Qwen3-14B-AWQ",
    "messages": [
        {
            "role": "user",
            "content": "What is the weather like in Boston today?"
        }
    ],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "Get the current weather in a given location",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "The city and state, e.g. San Francisco, CA"
                        },
                        "unit": {
                            "type": "string",
                            "enum": [
                                "celsius",
                                "fahrenheit"
                            ]
                        }
                    },
                    "required": [
                        "location"
                    ]
                }
            }
        }
    ],
    "tool_choice": {
        "type": "function",
        "function": {
            "name": "get_current_weather"
        }
    },
    "stream": true
}

Response Chunks:

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"{\""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"location"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"\":"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":" \""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"Boston"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"\","}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":" \""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"unit"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"\":"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":" \""}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"f"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"ahrenheit"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}]}

data: {"id":"chatcmpl-f2a93065f04041d08a6af9fb23cf22d6","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"name":"get_current_weather","arguments":""}}]},"logprobs":null,"finish_reason":"stop","stop_reason":null}]}

data: [DONE]

Notice that in the chunks containing delta.tool_calls, the id field for the tool call is missing.

Expected Behavior:
When stream=true, streamed chunks containing delta.tool_calls should include an id field for each tool call. This id must be present in the first chunk that introduces that specific tool call (identified by its index), and may also be present in all subsequent chunks pertaining to that same tool call. This behavior is necessary for consistency with the non-streaming response and for OpenAI API compatibility.

For example, a chunk might look like:

data: {"id":"chatcmpl-xxxxxxxx","object":"chat.completion.chunk","created":1747748383,"model":"default","choices":[{"index":0,"delta":{"tool_calls":[{"index":0, "id": "call_xxxxxxxxxxxx", "type": "function", "function":{"name":"get_current_weather","arguments":"{""}}]},"logprobs":null,"finish_reason":null}]}

The id for a specific tool call must be provided in its introductory chunk. If it is also included in subsequent chunks for that same tool call, its value must remain consistent.

Before submitting a new issue...

  • Make sure you already searched for relevant issues, and asked the chatbot living at the bottom right corner of the documentation page, which can answer lots of frequently asked questions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions