Skip to content

Fix ChunkMerger streaming: NoSuchElementException, empty id, reasoning_content#6522

Closed
freshman-wang wants to merge 1 commit into
spring-projects:mainfrom
freshman-wang:fix-chunk-merger-streaming
Closed

Fix ChunkMerger streaming: NoSuchElementException, empty id, reasoning_content#6522
freshman-wang wants to merge 1 commit into
spring-projects:mainfrom
freshman-wang:fix-chunk-merger-streaming

Conversation

@freshman-wang

@freshman-wang freshman-wang commented Jun 26, 2026

Copy link
Copy Markdown

Problem

Three bugs in ChunkMerger affect streaming tool_calls with OpenAI-compatible providers (DashScope/Qwen, DeepSeek):

  • NoSuchElementException: Optional.get() without null checks on tool call fields
  • Empty id causes arguments loss: DashScope sends id="" in continuation chunks, Optional.of("") passes isPresent(), so fragments are never merged
  • reasoning_content lost: chunkToChatCompletion only copies content + refusal, drops provider-specific fields

Fix

  1. Filter empty string id in mergeDeltas
  2. Guard empty tcs1 + function().orElseGet()
  3. Carry delta._additionalProperties() to ChatCompletionMessage
  4. Replace Optional.get() with orElse("") / ifPresent()

Fixes #6484

…g_content

- Filter empty string id in mergeDeltas (DashScope sends id="" in continuation chunks)
- Guard against empty tcs1 and missing function in mergeDeltas
- Pass delta additionalProperties (reasoning_content) to ChatCompletionMessage
- Replace Optional.get() with orElse/ifPresent in chunkToChatCompletion

Signed-off-by: lingg <244305699@qq.com>
@jewoodev

Copy link
Copy Markdown
Contributor

For review context, this overlaps with #6373 and #6381. #6373 covers the reasoning_content loss, including final advisor/chat-memory aggregation; #6381 covers empty-id tool-call deltas by merging by index with tests. This PR combines parts of both, but keeps the one-tool-call-per-chunk assumption and does not add coverage.

@freshman-wang freshman-wang force-pushed the fix-chunk-merger-streaming branch from 6281003 to 1f75959 Compare June 26, 2026 12:28
@freshman-wang

Copy link
Copy Markdown
Author

Closing in favor of #6373 (reasoning_content) and #6381 (empty-id tool-call deltas).

After reviewing @jewoodev's comment, I realize this PR overlaps significantly with both. However, there are two NoSuchElementException cases that I encountered in production with DashScope/Qwen that are not covered by either:

  1. mergeDeltas: lastFromTc1.function().get() throws when function is absent — my fix used .orElseGet(() -> Function.builder().build()).
  2. chunkToChatCompletion: tc.id().get(), tc.function().get(), tc.function().get().name().get(), tc.function().get().arguments().get() all throw without isPresent() checks — my fix used orElse("") / ifPresent().

It would be great if #6381 could also cover these Optional.get() calls. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

reasoning_content from OpenAI compatible providers is lost in streaming responses

3 participants