The non-streaming path never runs the tool parser for tool_choice="none"
(which is also the default when a request has no tools) and returns any
tool-call markup the model writes as content. Streaming ran the tool parser
on every delta regardless of tool_choice, so the same output became a tool
call with finish_reason "tool_calls" in Chat Completions and Responses
streams.
Return the text as content for tool_choice="none", as
vllm-project/vllm#42752 does. An empty delta after some text still yields
empty content, which is what qwen3_coder returns for plain text, so
content-only streams keep their final chunk. The only other difference for
such streams is that a trailing "<" is no longer held back for one delta.
Generation is not affected.
Backported from Leonccaa/ReVolta commit c87254c7566dafe0b6533921e38aeb1715f13b91.
Keep CPU fixture helpers local so this PR stands alone on 1Cat main.
Signed-off-by: Leonccaa <166551845+Leonccaa@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>