Skip to content

emitToolCallDelta incorrectly treats empty string id as new tool call instead of continuation #1900

@yzhengfei

Description

@yzhengfei

Description:

When processing streaming tool calls from OpenAI-qwen APIs, the subsequent chunks often have an empty string "" as the id field (instead of null) to indicate that this
is a continuation of the previous tool call, only appending arguments.

However, in StreamFrameFlowBuilder.emitToolCallDelta, the condition to detect a new tool call is:

  val new: PendingToolCall = if (id != null || index != previous?.index) {                                                                                                      
      tryEmitPendingToolCall()                                                                                                                                                  
      PendingToolCall(id, name, args, index)                                                                                                                                    
  } else {                                                                                                                                                                      
      // append to previous...                                                                                                                                                  
  }   

The problem is that id != null evaluates to true when id is an empty string "", because "" != null is true. This causes the framework to incorrectly treat the subsequent
arguments delta as a new tool call instead of appending to the previous one.

Example from OpenAI-qwen API response:

First chunk:
{"tool_calls":[{"index":0,"id":"call_abc123","function":{"name":"my_tool","arguments":""}}]}

Second chunk (arguments delta):
{"tool_calls":[{"index":0,"id":"","function":{"arguments":"{\"param\": "}}]}

The second chunk has id="", which should be treated as continuation (same tool call, just appending arguments). But due to "" != null being true, koog creates a new
PendingToolCall instead of appending.

Suggested fix:

Change the condition to treat empty strings as null:

  val new: PendingToolCall = if (id?.isNotBlank() == true || index != previous?.index) {
      // new tool call                                                                                                                                                          
  } else {                                                                                                                                                                      
      // append to previous                                                                                                                                                     
  }        

Metadata

Metadata

Labels

bugSomething isn't working

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions