Repository navigation
[Rust Frontend] Support --exclude-tools-when-tool-choice-none - #62741
Merged
Merged
Conversation
Render request tools for tool_choice="none" by default to match the Python frontend, and drop them only when --exclude-tools-when-tool-choice-none is set. Previously most Rust renderers always dropped them, and the flag was rejected as unsupported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Woosuk Kwon <woosuk@inferact.ai>
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
Unified parsers (gemma4, hy, inkling, kimi_k3, muse, hf, beam) are built from the request tools regardless of `tool_choice`, so a call the model emits under `tool_choice=none` reached the response as `tool_calls`. Now that tools are rendered for `none`, this is reachable on the default path. Express the rule as a limit on surfaced tool calls in structured assembly, next to the existing `parallel_tool_calls=false` limit: `none` allows zero, so the call and its markup are parsed and dropped, matching Python's parser engine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A4uoBqR3wrXPrDzZLok7Xq Signed-off-by: Bugen Zhao <i@bugenzhao.com>
…equestProcessor` The flag was applied to the HTTP DTO in two places (the chat-completions handler and `lower_chat_request`), threaded as a bool argument and a parallel `RenderState` field, and it skipped tool conversion and validation for `none` requests. Configure it on `ChatRequestProcessor` at construction, like `tool_strict_level` (Python configures `OnlineRenderer` the same way), and apply it right before rendering. Every entry point that renders through the processor gets the same behavior, and request tools are still validated. Only request-level tools are dropped; message-scoped tools are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A4uoBqR3wrXPrDzZLok7Xq Signed-off-by: Bugen Zhao <i@bugenzhao.com>
BugenZhao
approved these changes
Oct 21, 2026
BugenZhao
left a comment
Member
There was a problem hiding this comment.
Thanks @WoosukKwon. I added a commit to unify handling for this flag with parallel_tool_calls
Member
|
/ci run |
|
✅ Triggered Buildkite CI #96370 for commit ℹ️ This PR is 47 commits behind upstream |
bantianyue
pushed a commit
to bantianyue/vllm
that referenced
this pull request
Oct 28, 2026
…roject#62741) Signed-off-by: Woosuk Kwon <woosuk@inferact.ai> Signed-off-by: Bugen Zhao <i@bugenzhao.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Bugen Zhao <i@bugenzhao.com> Co-authored-by: vllm-agent <claw@inferact.ai>
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.
Overview
The Rust frontend now supports
--exclude-tools-when-tool-choice-none. Before this change, it rejected the flag at startup. Its default handling of tools fortool_choice="none"now also matches the Python frontend.Claims
--exclude-tools-when-tool-choice-noneworks withvllm serve(including the Python→Rust--args-jsonhandoff) and withvllm-rs render. When the flag is set and a chat completion request hastool_choice="none", its request-leveltoolsare left out of the prompt.tool_choice="none". Before this change, the HF, DeepSeek (V3/V3.2/V4/V4.1), Harmony and Inkling renderers always dropped them, as if the flag were always on. Kimi K3 already matched Python.tool_choice="none"still disables tool-call parsing, and tool calls that a unified parser (Gemma 4, HunYuan, Inkling, Kimi K3, …) still recognizes are now dropped from the response instead of being returned astool_calls, matching Python's parser engine.Validation
Qwen3-0.6B on GB200,
vllm serve --enforce-eager --max-model-len 2048. The request has one tool andmax_tokens=1; the table showsusage.prompt_tokens:tool_choice="none"+ toolVLLM_USE_RUST_FRONTEND=0)All tests pass except three that also fail on
mainor for environment reasons in my setup. None of them involve this change:grammar_replay: HF cache permission error while downloading DeepSeek-V4.1-Flash.roundtrip_gemma4_hf: the locally cached tokenizer has noresponse_template. It fails onmaintoo.timing::tests::does_not_enable_debug_at_info: order-dependent in a full workspace run and passes on its own. It is in the untouchedvllm-tracingcrate.New and updated tests:
exclude_tools_only_drops_tools_for_tool_choice_none: only an explicit"none"drops tools."auto"and an unsettool_choicekeep them.chat_template_exposes_tools_to_templates_for_any_tool_choice: the HF renderer passes tools to the template for bothautoandnone.frontend_config_excludes_tools_when_tool_choice_none_from_args_json: the flag survives the--args-jsonhandoff from Python.processor_excludes_request_tools_for_tool_choice_none_when_configured: with the flag on,nonedrops only request-level tools and keeps developer-message tools;autokeeps both; without the flag,nonerenders both.tool_choice_none_drops_tool_calls_parsed_by_unified_parsers: a Gemma 4 tool call is returned forautoand dropped fornone.Details
OnlineRendererat construction and setstool_dicts = Nonefortool_choice == "none". Here it is likewise configured onChatRequestProcessorat construction (liketool_strict_level) and applied right before rendering, so the chat-completions,/renderand tokenize paths all get the same behavior. Request tools are still converted and validated; only request-level tools are dropped, and message-scoped tools are kept, as in Python. The server stores the setting inConfig, andvllm-rs renderinRenderConfig.none. Unified parsers are built from the request tools regardless oftool_choice. Now that tools are rendered fornone, a model may emit a call there, so structured assembly limits surfaced tool calls to zero fornone, reusing the existingparallel_tool_calls=falselimit (nowmax_tool_calls: Option<usize>).tool_parsing_enabled(), which is false fortool_choice="none". Python's native renderers never look attool_choicewhen deciding whether to render tools, so those gates are removed. Without that removal, the flag would have no effect for every renderer except Kimi K3.test_serving_chat.pystart the server with this flag. Running them under the Rust frontend in CI would need a larger GPU than the current Rust e2e step uses, so this PR doesn't add them.Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.
🤖 Generated with Claude Code