Skip to content

[Bugfix] Buffer and validate provisional DSML tool-call recovery (#56482) - #56667

Open
nandan2003 wants to merge 1 commit into
vllm-project:mainfrom
nandan2003:fix/deepseek-v4-dsml-recovery-provisional-commit
Open

nandan2003 wants to merge 1 commit into
vllm-project:mainfrom
nandan2003:fix/deepseek-v4-dsml-recovery-provisional-commit

Conversation

@nandan2003

@nandan2003 nandan2003 commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #56482

PR #55954 introduced recovery for tool calls when the model omits the opening <|DSML|tool_calls> wrapper tag by eagerly transitioning (ParserState.CONTENT, "INVOKE_PREFIX") -> TOOL_NAME and emitting TOOL_CALL_START.

This eager transition caused 3 critical regressions in production:

  • Truncation / Ghost Calls: If generation stopped at token limits before arguments or closing tags, an empty-argument call ({}) was emitted.
  • Narration Hijacking: Mentions of <|DSML|invoke name="..."> in prose/documentation were intercepted as tool calls.
  • Undeclared Tool Promotion: Tool names not declared in request.tools (or requests with tool_choice="none") were promoted to executable tool calls.

Solution

  • Marked (ParserState.CONTENT, "INVOKE_PREFIX") as a provisional_tool_call.
  • Buffers semantic events and raw tokens in StreamingParserEngine during recovery hold.
  • Validates tool name against declared request.tools at TOOL_NAME -> TOOL_ARGS.
  • Commits the tool call only when </|DSML|invoke> is reached (commit_provisional_tool_call=True).
  • If validation fails or the stream is truncated prematurely (finish()), rolls back and flushes the buffered raw tokens as plain user content.

Test Plan & Result

  • pytest tests/parser/engine/test_deepseek_v4.py (108 passed)
  • pytest tests/tool_parsers/test_deepseekv4_tool_parser.py (12 passed)
  • pytest tests/parser/engine/ (4,290 passed, 0 regressions across all registered models)

Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • The test plan, such as providing test command.
  • The test results, such as pasting the results comparison before and after, or e2e results
  • (Optional) The necessary documentation update, such as updating supported_models.md and examples for a new model.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify mergify Bot added deepseek Related to DeepSeek models tool-calling bug Something isn't working labels Sep 13, 2026
@nandan2003
nandan2003 force-pushed the fix/deepseek-v4-dsml-recovery-provisional-commit branch 2 times, most recently from df39d2f to 17e7464 Compare September 16, 2026 03:54
…m-project#56482)

PR vllm-project#55954 introduced recovery for tool calls when the model omits
the opening <|DSML|tool_calls> wrapper tag by adding an eager
transition (ParserState.CONTENT, "INVOKE_PREFIX") -> TOOL_NAME
emitting TOOL_CALL_START.

This eager transition caused several regressions:
1. Truncation / Ghost Calls: If model output ends before arguments
   or invoke closing tag, an empty-argument tool call ({}) was emitted.
2. Narration / Text Hijacking: Mentioning <|DSML|invoke name="..."> in
   prose or documentation triggered unintended tool calls and swallowed text.
3. Undeclared Tool Execution: Tool names not declared in the request
   (or requests with tools=None / tool_choice='none') were recovered as
   real tool calls.

Fix:
- Make (ParserState.CONTENT, "INVOKE_PREFIX") a provisional transition.
- Buffer semantic events and raw tokens in StreamingParserEngine during
  the recovery hold.
- Verify tool name against declared request tools when exiting TOOL_NAME.
- Only commit the tool call when (ParserState.TOOL_ARGS, "INVOKE_END")
  is reached with commit_provisional_tool_call=True.
- On any validation failure, truncation at finish(), or unexpected terminal,
  abort the recovery hold and flush the buffered raw tokens as plain content.

Fixes vllm-project#56482.

Signed-off-by: Nandan Vallamdasu <nandan.vallamdasu@outlook.com>
@nandan2003
nandan2003 force-pushed the fix/deepseek-v4-dsml-recovery-provisional-commit branch from 17e7464 to 2776924 Compare September 16, 2026 04:05
@nandan2003

Copy link
Copy Markdown
Contributor Author

Hey @aarnphm, @bbrowning, @chaunceyjiang and @sfeng33! could you please check this PR when you get a chance? Thanks

This branch has not been deployed

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

Labels

bug Something isn't working deepseek Related to DeepSeek models tool-calling

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[Bug]: DSML tool-call recovery (#55954) emits ghost empty-argument calls on truncation and narration, and recovers undeclared tools

1 participant