Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions tests/tool_parsers/test_structural_tag_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,17 @@ def test_get_function_parameters_relaxes_function_strict_false():
)

assert _get_function_parameters(function) is True


def test_deepseek_v4_auto_non_strict_gets_structural_tag(
sample_tools: list[ChatCompletionToolsParam],
):
# auto + non-strict must still constrain DSML for DeepSeek-V4 so malformed
# tool calls don't leak into content / drop as empty responses (#40801).
tag = get_model_structural_tag(
model="deepseek_v4",
tools=sample_tools,
tool_choice="auto",
reasoning=True,
)
assert isinstance(tag, StructuralTag)
7 changes: 6 additions & 1 deletion vllm/tool_parsers/structural_tag_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ def get_model_structural_tag(
return None

if tool_choice == "auto" and not _any_tool_strict(tools):
return None
# DeepSeek-V4: keep DSML grammar guidance on for auto + non-strict so
# the model is constrained to valid DSML when it attempts a tool call.
# Without this, malformed DSML leaks into content or is dropped as an
# empty response (see #40801).
if model != "deepseek_v4":
return None

dumped_tools = [_dump_tool_for_xgrammar(tool) for tool in tools]
dumped_tool_choice = _dump_tool_choice_for_xgrammar(tool_choice)
Expand Down
Loading