[Bugfix] [Parser] Fix empty tool block silently dropping subsequent content#46091
Merged
sfeng33 merged 2 commits intoJun 18, 2026
Merged
Conversation
…ontent Add missing TOOL_PREAMBLE → TOOL_END transitions to Qwen3 and Gemma4 parsers so empty tool blocks (open marker immediately followed by close marker) recover to CONTENT state instead of staying stuck in TOOL_PREAMBLE and silently dropping all subsequent output. Also fix deferred content release in the engine to emit content when tool events produce no actual deltas. MiniMax M2 already had this transition but gains the new empty-tool-block test scenario. Signed-off-by: Ben Browning <bbrownin@redhat.com>
sfeng33
approved these changes
Jun 18, 2026
sfeng33
left a comment
Collaborator
There was a problem hiding this comment.
LGTM, thanks for the work!
divineearthly
pushed a commit
to divineearthly/vllm
that referenced
this pull request
Jun 19, 2026
…ontent (vllm-project#46091) Signed-off-by: Ben Browning <bbrownin@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com> Signed-off-by: divineearthly <divineearthly@gmail.com>
xuebwang-amd
pushed a commit
to xuebwang-amd/vllm
that referenced
this pull request
Jun 21, 2026
…ontent (vllm-project#46091) Signed-off-by: Ben Browning <bbrownin@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com>
tunglinwood
pushed a commit
to tunglinwood/vllm
that referenced
this pull request
Jun 22, 2026
…ontent (vllm-project#46091) Signed-off-by: Ben Browning <bbrownin@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com>
nkzhenhua
pushed a commit
to nkzhenhua/vllm
that referenced
this pull request
Jun 24, 2026
…ontent (vllm-project#46091) Signed-off-by: Ben Browning <bbrownin@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com>
qli88
pushed a commit
to qli88/vllm
that referenced
this pull request
Jun 26, 2026
…ontent (vllm-project#46091) Signed-off-by: Ben Browning <bbrownin@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com> Signed-off-by: Qiang Li <qiang.li2@amd.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
I regularly run reviews of vLLM code through a variety coding assistants point to self-hosted models. One of my sessions (Codex CLI running w/ Qwen 3.6-27B) picked up a theoretical bug where an empty tool block (ie no parsed function, just open and close tool markers with empty or nonsense content in the middle) would cause all subsequent content to get dropped. So, I had a patch sitting on the side to get around to that.
Today, in another session (Claude Code running w/ Nemotron 3 Super), I hit that theoretical bug as it was reviewing some GLM 4.7 parser changes. The model was tracing some of the parser code paths, and when it started emitting content like
<tool_call>func_name<arg_key>key</arg_key><arg_value>value</arg_value></tool_call>it got stuck and didn't emit any more output. That particular output sequence caused the model to output its exact expected <tool_call> token ID and </tool_call> token ID, causing the parser to see start/end tool call but without any meaningful content in the middle. So, inadvertently, I tripped this exact bug.Now, the parser still parses this as a tool call (because it is the right special tokens, and we're streaming so we cannot just buffer the entirety of the tool call to make an educated guess after we see all of it). But, when the tool call leads to empty content, we keep emitting the rest of the content following the tool call. Previously everything after that bad tool call was dropped from the response.
This PR adds the missing
TOOL_PREAMBLE→TOOL_ENDtransitions to Qwen3 and Gemma4 parsers so empty tool blocks (open marker immediately followed by close marker) recover toCONTENTstate instead of staying stuck inTOOL_PREAMBLEand silently dropping all subsequent output. It also fixes deferred content release in the engine to emit content when tool events produce no actual deltas. MiniMax M2 already had this transition but gains the new empty-tool-block test scenario.Test Plan
A test for this scenario was added to trace_builder.py which means we test this behavior for all parsers using the new engine across multiple token per delta sizes. And, all the other unit tests from the impacted parsers were run.
Unit tests
Test Result
Unit tests