Skip to content

fix(openai): tolerate empty content in forced tool choice#40148

Merged
chaunceyjiang merged 6 commits into
vllm-project:mainfrom
QwertyJack:fix/tool-choice-content-none-assert
May 6, 2026
Merged

fix(openai): tolerate empty content in forced tool choice#40148
chaunceyjiang merged 6 commits into
vllm-project:mainfrom
QwertyJack:fix/tool-choice-content-none-assert

Conversation

@QwertyJack

Copy link
Copy Markdown
Contributor

Summary

This fixes a forced-tool-choice crash when reasoning extraction returns content=None.

Some reasoning parsers, including the glm45 / DeepSeekV3ReasoningWithThinkingParser path, may consume the full model output and return (reasoning, None). The forced tool-choice branches in both chat-completions and responses parsing previously asserted that content is not None, which made this a server-side failure instead of a valid function call with empty arguments.

Changes

  • normalize content=None to "" in OpenAIServing._parse_tool_calls_from_content(...)
  • normalize content=None to "" in DelegatingParser._parse_tool_calls(...)
  • add regression tests for:
    • chat-completions named tool_choice with content=None
    • responses named tool_choice with content=None

Fixes #40147.

Testing

pytest -sv tests/entrypoints/openai/test_tool_choice_content_none.py

@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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the OpenAI serving engine and abstract parser to handle cases where a named tool choice is provided but the content is null. Specifically, it replaces assertions with a default empty string for the content variable, preventing potential runtime errors during forced function calls. Additionally, a new test suite has been added to verify this behavior for both Chat Completion and Responses APIs. I have no feedback to provide.

QwertyJack added a commit to QwertyJack/vllm-ascend that referenced this pull request Apr 17, 2026
Backport the upstream forced-tool-choice fix to the v0.18.0 compatibility layer. Some reasoning parsers may consume the full model output and return content=None; normalize that to an empty argument string before the forced named tool-choice branches delegate back to upstream parsing.

References: vllm-project/vllm#40147, vllm-project/vllm#40148
Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
@ywang96

ywang96 commented Apr 21, 2026

Copy link
Copy Markdown
Member

Is this PR still needed? cc @JaredforReal

zzzzwwjj pushed a commit to vllm-project/vllm-ascend that referenced this pull request Apr 23, 2026
…pty content (#8400)

### What this PR does / why we need it?

This backports the forced-tool-choice `content=None` guard to the
`releases/v0.18.0` compatibility layer.

Upstream vLLM still has forced named tool-choice branches that assert
`content is not None` after reasoning extraction. Some reasoning parsers
can legally consume the full output and return `(reasoning, None)`,
which makes the assert reachable and can surface as a server-side
failure.

This PR follows the same compatibility-patch pattern used by:
- `7314bbe2` fix(platform): reimplement MiniMax usage accounting patch
(#7835)
- `f83cb0e6` [Bugfix][Platform] Fix GLM47 tool-call finish backfill
(#7710)

The patch is intentionally narrow:
- normalize `content=None` to `""` only for forced named tool choice
- patch both chat-completions and responses parser entry points
- keep the rest of upstream behavior unchanged

Upstream tracking:
- issue: vllm-project/vllm#40147
- PR: vllm-project/vllm#40148

### Does this PR introduce _any_ user-facing change?

Yes.

Forced named tool choice becomes robust when the reasoning parser
returns no post-reasoning content, avoiding an internal assertion
failure and emitting an empty-argument function call instead.

### How was this patch tested?

Unit tests:
```bash
pytest -sv tests/ut/patch/platform/test_patch_tool_choice_none_content.py \
  tests/ut/patch/platform/test_patch_glm_tool_call_parser.py \
  tests/ut/patch/platform/test_patch_minimax_usage_accounting.py
```

Result: 22 passed.

---------

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
@chaunceyjiang chaunceyjiang self-assigned this Apr 28, 2026
@mergify

mergify Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @QwertyJack.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Apr 28, 2026
@chaunceyjiang

Copy link
Copy Markdown
Collaborator

Hi @QwertyJack Please fix the conflicts.

@QwertyJack QwertyJack force-pushed the fix/tool-choice-content-none-assert branch from 2f88d21 to 5dc783e Compare April 28, 2026 10:54
@QwertyJack QwertyJack requested a review from bbrowning as a code owner April 28, 2026 10:54
@mergify mergify Bot removed the needs-rebase label Apr 28, 2026
@QwertyJack

Copy link
Copy Markdown
Contributor Author

@chaunceyjiang PTAL

):
# Named function with standard JSON-based parsing
assert content is not None
content = content or ""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think that when content is None, arguments should be "{}""" is not a standard OpenAI-defined semantic representation.

@chaunceyjiang

Copy link
Copy Markdown
Collaborator

I feel that making modifications here is not very elegant. Perhaps it would be better to modify the corresponding parser.

@QwertyJack QwertyJack force-pushed the fix/tool-choice-content-none-assert branch from 5dc783e to 1184780 Compare April 28, 2026 12:35
@mergify mergify Bot added the deepseek Related to DeepSeek models label Apr 28, 2026
Comment thread vllm/entrypoints/openai/engine/serving.py Outdated
Normalize None content to an empty argument string when forced tool choice runs after reasoning extraction. This avoids AssertionError in both chat-completions and responses parsing paths and adds regression coverage for the named tool-choice case.

Fixes vllm-project#40147

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
@QwertyJack QwertyJack force-pushed the fix/tool-choice-content-none-assert branch from 1554a8b to 1147f21 Compare April 29, 2026 16:18
@QwertyJack

Copy link
Copy Markdown
Contributor Author

Correction to my previous note: the latest patch follows your inline suggestion. When forced tool choice sees content is None, it now returns no function calls ([]) instead of synthesizing an empty tool call/{} arguments.

DeepSeek parser remains unchanged, and the branch is rebased. @chaunceyjiang PTAL.

wangxiyuan pushed a commit to vllm-project/vllm-ascend that referenced this pull request Apr 30, 2026
)

### What this PR does / why we need it?
Backports the forced tool-choice `content=None` handling from vLLM
Ascend PR #8400 for the
vLLM 0.19.1 patch layer.

Related issue and PR:
- vLLM issue: vllm-project/vllm#40147
- vLLM PR: vllm-project/vllm#40148
- vLLM Ascend PR: #8400

Per the latest PR #40148 discussion, this patch does not synthesize an
empty function call or empty `{}` arguments. When forced tool choice
sees `content=None`, it returns an empty tool-call list and preserves
normal forced tool-call behavior when content is present.

### Does this PR introduce _any_ user-facing change?
Yes. Forced tool-choice requests no longer assert when reasoning
extraction leaves `content=None`; they return no tool calls for that
empty-content result instead.

### How was this patch tested?
- `ruff format --check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `ruff check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `python -m py_compile
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`
- `PYTHONPATH=../vllm:. pytest -q --confcutdir=tests/ut/patch/platform
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`

Also ran `bash format.sh ci`; it passed the available hooks but could
not complete `shellcheck` because `shellcheck` is not installed in this
environment.

- vLLM version: v0.19.1
- vLLM main:
vllm-project/vllm@d886c26

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
@chaunceyjiang chaunceyjiang added the ready ONLY add when PR is ready to merge/full CI is needed label Apr 30, 2026

@chaunceyjiang chaunceyjiang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM.

@QwertyJack I added an e2e test based on your work.

@chaunceyjiang chaunceyjiang enabled auto-merge (squash) April 30, 2026 07:01
yangzhe-2026 pushed a commit to yangzhe-2026/vllm-ascend that referenced this pull request May 6, 2026
…lm-project#8833)

### What this PR does / why we need it?
Backports the forced tool-choice `content=None` handling from vLLM
Ascend PR vllm-project#8400 for the
vLLM 0.19.1 patch layer.

Related issue and PR:
- vLLM issue: vllm-project/vllm#40147
- vLLM PR: vllm-project/vllm#40148
- vLLM Ascend PR: vllm-project#8400

Per the latest PR #40148 discussion, this patch does not synthesize an
empty function call or empty `{}` arguments. When forced tool choice
sees `content=None`, it returns an empty tool-call list and preserves
normal forced tool-call behavior when content is present.

### Does this PR introduce _any_ user-facing change?
Yes. Forced tool-choice requests no longer assert when reasoning
extraction leaves `content=None`; they return no tool calls for that
empty-content result instead.

### How was this patch tested?
- `ruff format --check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `ruff check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `python -m py_compile
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`
- `PYTHONPATH=../vllm:. pytest -q --confcutdir=tests/ut/patch/platform
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`

Also ran `bash format.sh ci`; it passed the available hooks but could
not complete `shellcheck` because `shellcheck` is not installed in this
environment.

- vLLM version: v0.19.1
- vLLM main:
vllm-project/vllm@d886c26

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
@chaunceyjiang chaunceyjiang merged commit 6467213 into vllm-project:main May 6, 2026
50 checks passed
PiratePai pushed a commit to PiratePai/vllm-ascend that referenced this pull request May 7, 2026
…lm-project#8833)

### What this PR does / why we need it?
Backports the forced tool-choice `content=None` handling from vLLM
Ascend PR vllm-project#8400 for the
vLLM 0.19.1 patch layer.

Related issue and PR:
- vLLM issue: vllm-project/vllm#40147
- vLLM PR: vllm-project/vllm#40148
- vLLM Ascend PR: vllm-project#8400

Per the latest PR #40148 discussion, this patch does not synthesize an
empty function call or empty `{}` arguments. When forced tool choice
sees `content=None`, it returns an empty tool-call list and preserves
normal forced tool-call behavior when content is present.

### Does this PR introduce _any_ user-facing change?
Yes. Forced tool-choice requests no longer assert when reasoning
extraction leaves `content=None`; they return no tool calls for that
empty-content result instead.

### How was this patch tested?
- `ruff format --check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `ruff check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `python -m py_compile
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`
- `PYTHONPATH=../vllm:. pytest -q --confcutdir=tests/ut/patch/platform
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`

Also ran `bash format.sh ci`; it passed the available hooks but could
not complete `shellcheck` because `shellcheck` is not installed in this
environment.

- vLLM version: v0.19.1
- vLLM main:
vllm-project/vllm@d886c26

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: PiratePai <416932041@qq.com>
ikaadil pushed a commit to ikaadil/vllm that referenced this pull request May 7, 2026
…ct#40148)

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: chaunceyjiang <chaunceyjiang@gmail.com>
Signed-off-by: Ifta Khairul Alam Adil <ikaadil007@gmail.com>
libinta pushed a commit to libinta/vllm that referenced this pull request May 8, 2026
…ct#40148)

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: chaunceyjiang <chaunceyjiang@gmail.com>
Signed-off-by: Libin Tang <libin.tang@intel.com>
yangzhe-2026 pushed a commit to yangzhe-2026/vllm-ascend that referenced this pull request May 10, 2026
…lm-project#8833)

### What this PR does / why we need it?
Backports the forced tool-choice `content=None` handling from vLLM
Ascend PR vllm-project#8400 for the
vLLM 0.19.1 patch layer.

Related issue and PR:
- vLLM issue: vllm-project/vllm#40147
- vLLM PR: vllm-project/vllm#40148
- vLLM Ascend PR: vllm-project#8400

Per the latest PR #40148 discussion, this patch does not synthesize an
empty function call or empty `{}` arguments. When forced tool choice
sees `content=None`, it returns an empty tool-call list and preserves
normal forced tool-call behavior when content is present.

### Does this PR introduce _any_ user-facing change?
Yes. Forced tool-choice requests no longer assert when reasoning
extraction leaves `content=None`; they return no tool calls for that
empty-content result instead.

### How was this patch tested?
- `ruff format --check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `ruff check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `python -m py_compile
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`
- `PYTHONPATH=../vllm:. pytest -q --confcutdir=tests/ut/patch/platform
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`

Also ran `bash format.sh ci`; it passed the available hooks but could
not complete `shellcheck` because `shellcheck` is not installed in this
environment.

- vLLM version: v0.19.1
- vLLM main:
vllm-project/vllm@d886c26

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: yangzhe-2026 <yangzhe@isrc.iscas.ac.cn>
ZhuQi-seu pushed a commit to ZhuQi-seu/vllm-ascend that referenced this pull request May 12, 2026
…lm-project#8833)

### What this PR does / why we need it?
Backports the forced tool-choice `content=None` handling from vLLM
Ascend PR vllm-project#8400 for the
vLLM 0.19.1 patch layer.

Related issue and PR:
- vLLM issue: vllm-project/vllm#40147
- vLLM PR: vllm-project/vllm#40148
- vLLM Ascend PR: vllm-project#8400

Per the latest PR #40148 discussion, this patch does not synthesize an
empty function call or empty `{}` arguments. When forced tool choice
sees `content=None`, it returns an empty tool-call list and preserves
normal forced tool-call behavior when content is present.

### Does this PR introduce _any_ user-facing change?
Yes. Forced tool-choice requests no longer assert when reasoning
extraction leaves `content=None`; they return no tool calls for that
empty-content result instead.

### How was this patch tested?
- `ruff format --check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `ruff check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `python -m py_compile
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`
- `PYTHONPATH=../vllm:. pytest -q --confcutdir=tests/ut/patch/platform
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`

Also ran `bash format.sh ci`; it passed the available hooks but could
not complete `shellcheck` because `shellcheck` is not installed in this
environment.

- vLLM version: v0.19.1
- vLLM main:
vllm-project/vllm@d886c26

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: ZhuQi-seu <zhuqi12@huawei.com>
weifang231 pushed a commit to weifang231/eb-vllm that referenced this pull request May 13, 2026
…ct#40148)

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: chaunceyjiang <chaunceyjiang@gmail.com>
nanxingMy pushed a commit to nanxingMy/vllm-ascend that referenced this pull request May 15, 2026
…lm-project#8833)

### What this PR does / why we need it?
Backports the forced tool-choice `content=None` handling from vLLM
Ascend PR vllm-project#8400 for the
vLLM 0.19.1 patch layer.

Related issue and PR:
- vLLM issue: vllm-project/vllm#40147
- vLLM PR: vllm-project/vllm#40148
- vLLM Ascend PR: vllm-project#8400

Per the latest PR #40148 discussion, this patch does not synthesize an
empty function call or empty `{}` arguments. When forced tool choice
sees `content=None`, it returns an empty tool-call list and preserves
normal forced tool-call behavior when content is present.

### Does this PR introduce _any_ user-facing change?
Yes. Forced tool-choice requests no longer assert when reasoning
extraction leaves `content=None`; they return no tool calls for that
empty-content result instead.

### How was this patch tested?
- `ruff format --check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `ruff check
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py
vllm_ascend/patch/platform/__init__.py vllm_ascend/patch/__init__.py`
- `python -m py_compile
vllm_ascend/patch/platform/patch_tool_choice_none_content.py
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`
- `PYTHONPATH=../vllm:. pytest -q --confcutdir=tests/ut/patch/platform
tests/ut/patch/platform/test_patch_tool_choice_none_content.py`

Also ran `bash format.sh ci`; it passed the available hooks but could
not complete `shellcheck` because `shellcheck` is not installed in this
environment.

- vLLM version: v0.19.1
- vLLM main:
vllm-project/vllm@d886c26

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: nanxing <1014662416@qq.com>
@QwertyJack QwertyJack deleted the fix/tool-choice-content-none-assert branch May 17, 2026 15:17
mfylcek pushed a commit to mfylcek/vllm that referenced this pull request May 19, 2026
…ct#40148)

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: chaunceyjiang <chaunceyjiang@gmail.com>
jhu960213 pushed a commit to jhu960213/vllm that referenced this pull request May 20, 2026
…ct#40148)

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: chaunceyjiang <chaunceyjiang@gmail.com>
immengzi pushed a commit to immengzi/vllm-ascend that referenced this pull request May 21, 2026
…pty content (vllm-project#8400)

### What this PR does / why we need it?

This backports the forced-tool-choice `content=None` guard to the
`releases/v0.18.0` compatibility layer.

Upstream vLLM still has forced named tool-choice branches that assert
`content is not None` after reasoning extraction. Some reasoning parsers
can legally consume the full output and return `(reasoning, None)`,
which makes the assert reachable and can surface as a server-side
failure.

This PR follows the same compatibility-patch pattern used by:
- `7314bbe2` fix(platform): reimplement MiniMax usage accounting patch
(vllm-project#7835)
- `f83cb0e6` [Bugfix][Platform] Fix GLM47 tool-call finish backfill
(vllm-project#7710)

The patch is intentionally narrow:
- normalize `content=None` to `""` only for forced named tool choice
- patch both chat-completions and responses parser entry points
- keep the rest of upstream behavior unchanged

Upstream tracking:
- issue: vllm-project/vllm#40147
- PR: vllm-project/vllm#40148

### Does this PR introduce _any_ user-facing change?

Yes.

Forced named tool choice becomes robust when the reasoning parser
returns no post-reasoning content, avoiding an internal assertion
failure and emitting an empty-argument function call instead.

### How was this patch tested?

Unit tests:
```bash
pytest -sv tests/ut/patch/platform/test_patch_tool_choice_none_content.py \
  tests/ut/patch/platform/test_patch_glm_tool_call_parser.py \
  tests/ut/patch/platform/test_patch_minimax_usage_accounting.py
```

Result: 22 passed.

---------

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
mvanhorn pushed a commit to mvanhorn/vllm that referenced this pull request Jun 4, 2026
…ct#40148)

Signed-off-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
Co-authored-by: QwertyJack <7554089+QwertyJack@users.noreply.github.com>
Co-authored-by: chaunceyjiang <chaunceyjiang@gmail.com>
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deepseek Related to DeepSeek models frontend ready ONLY add when PR is ready to merge/full CI is needed tool-calling

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: forced tool_choice asserts when reasoning extraction returns content=None

3 participants