Skip to content

parser: bypass tool parser for no-tools streams - #29

Merged
lukealonso merged 1 commit into
dev/dark-devotionfrom
codex/glm52-no-tools-parser-bypass-20260619
Jun 19, 2026
Merged

lukealonso merged 1 commit into
dev/dark-devotionfrom
codex/glm52-no-tools-parser-bypass-20260619

Conversation

@voipmonitor

@voipmonitor voipmonitor commented Jun 19, 2026 •

Copy link
Copy Markdown

Summary

Fixes a GLM-5.2 streaming corruption where plain post-reasoning content was routed through the tool parser even when the request did not provide any tools.

With --enable-auto-tool-choice, vLLM constructs a tool parser globally. After </think>, DelegatingParser._in_tool_call_phase() became true whenever that parser existed, regardless of whether the request had a tools list. For no-tools requests, the engine-based tool parser can re-emit buffered plain content and duplicate fragments in streamed deltas.

Observed on GLM-5.2 NVFP4/B12X MTP3 long-context streaming:

output_processor text: " 2:\n       "
served delta content: "< 2:\n        2:\n       "

This produced client-visible code corruption such as:

if limit < limit < 2:
    2:

Changes

  • Add a small request-level tools check in DelegatingParser.
  • Bypass tool-call extraction for post-reasoning content when request.tools is empty/missing.
  • Skip engine tool-parser final flush if tool-call streaming never started.
  • Update parser-engine tests so tool-parser flush tests explicitly use tools, and add a no-tools regression test.

Validation

  • Syntax check: python3 -m py_compile vllm/parser/abstract_parser.py tests/parser/engine/test_parser_engine.py
  • Whitespace check: git diff --check
  • Runtime soak on the live GLM-5.2 NVFP4/B12X MTP3 instance with this file overlaid: 30/30 /mnt/test.py long-context streaming iterations passed without the if limit < ... limit < corruption.

Note: upstream vLLM PR vllm-project#46149 fixes a related but separate forced/named tool-choice + reasoning grammar issue. This PR intentionally does not include that change.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of generated content when no tools are configured. Content generated after reasoning is no longer incorrectly interpreted as tool call markup, preventing spurious parsing errors.
    • Added validation to bypass tool parsing logic when the request has no tools enabled.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f151d12-8e87-4479-a21e-5b75c49b8dd3

📥 Commits

Reviewing files that changed from the base of the PR and between 774f42d and 6987a34.

📒 Files selected for processing (2)
  • tests/parser/engine/test_parser_engine.py
  • vllm/parser/abstract_parser.py

📝 Walkthrough

Walkthrough

Parser gains a _request_has_tools() helper. parse_delta() now routes post-</think> content directly to delta_message.content when the request has no tools, and _flush_engine_parsers() skips flushing the tool parser when tool_call_text_started is false. Tests are updated to carry a with_tools flag and a new regression test verifies the no-tools bypass path.

Changes

No-tools tool-parser bypass

Layer / File(s) Summary
Tool-parser bypass logic in Parser
vllm/parser/abstract_parser.py
Adds Parser._request_has_tools() static helper; guards parse_delta() tool-call phase to write current_text directly into delta_message.content when the request has no tools; conditionally skips _tool_parser flush in _flush_engine_parsers() when tool_call_text_started is false.
Test helper and regression test
tests/parser/engine/test_parser_engine.py
Extends _make_delegating_request with with_tools: bool = False; updates test_args_buffer_flushed_on_finished to use with_tools=True; adds test_no_tools_content_bypasses_tool_parser_after_reasoning asserting content accumulates normally and tool_call_text_started stays false for no-tools requests.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'parser: bypass tool parser for no-tools streams' directly and concisely describes the main change: bypassing the tool parser when requests have no tools configured, which is the core fix addressing the streaming corruption issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/glm52-no-tools-parser-bypass-20260619

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lukealonso
lukealonso merged commit 4b74109 into dev/dark-devotion Jun 19, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants