[Bug] Preserve DeepSeek-V3.2 tool-call markers in reasoning parsing - #21179
[Bug] Preserve DeepSeek-V3.2 tool-call markers in reasoning parsing#21179robellliu-dev wants to merge 2 commits into
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6302c18ae0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "</think>", | ||
| force_reasoning=force_reasoning, | ||
| stream_reasoning=stream_reasoning, | ||
| tool_start_token=f"<{dsml_token}function_calls>", |
There was a problem hiding this comment.
Handle newline-prefixed DSML markers in streaming reasoning
DeepSeekV3Detector only registers tool_start_token as the bare <|DSML|function_calls> tag, but BaseReasoningFormatDetector.parse_streaming_increment() buffers partial matches only when the entire buffer is a prefix of that exact token. DeepSeek-V3.2’s own formatter/parser expects tool calls to start with \n\n<|DSML|function_calls (encoding_dsv32.py), so if streaming splits at a common boundary like "\n\n<" / "|DSML|function_calls>", the first chunk is emitted as reasoning_content and the raw marker never reaches the tool-call parser. In practice this leaves the PD-mode streaming fix incomplete for normal DSML-formatted tool calls.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch. I updated the DeepSeek-V3 reasoning detector to handle both the bare DSML marker and the formatted \n\n<...function_calls> marker that DeepSeek-V3.2 emits.
I also tightened the streaming parser so that if a chunk ends with a partial tool-call prefix (for example reasoning\n\n<), that suffix stays buffered instead of being emitted as reasoning content. This preserves the full raw DSML marker for the downstream tool-call parser once the next chunk arrives.
I added regression coverage for both:
- direct DeepSeek-V3.2 DSML interruption
- the formatted streaming split case with
"\n\n<"followed by the rest of the marker
|
Heads-up: #34458 (5899674) landed and covers part of what this PR does — reasoning is now interrupted at What it does not cover is the part that is specific to this PR: Could you rebase on main and drop the parts that are now redundant, leaving the |
Summary
deepseek-v3reasoning output switches into tool callsRoot Cause
deepseek-v3currently reusesQwen3Detector, which only recognizes<think>/</think>transitions. DeepSeek-V3.2 tool calls can start with the DSML<function_calls>marker before</think>is emitted. In that case the reasoning parser keeps treating the DSML marker as reasoning text instead of handing it off to the function-call parser, which can surface as malformed tool-call deltas or empty tool output in PD mode.Fix
Introduce a DeepSeek-V3-specific reasoning detector that uses the DeepSeek-V3.2 DSML function-call start marker as a reasoning interruption token. This preserves the raw tool-call marker in normal text so the existing DeepSeek-V3.2 tool-call parser can consume it unchanged.
Testing
python -m py_compile python/sglang/srt/parser/reasoning_parser.py test/registered/unit/parser/test_reasoning_parser.pypython test/registered/unit/parser/test_reasoning_parser.py(blocked locally because this environment is missingPillow, which is imported by the repo test utilities)Fixes #21176