Skip to content

[Fix] minimax-m3: Type nested tool-call arguments and count self-opened reasoning - #46133

Merged
ispobock merged 4 commits into
mainfrom
m3-tool-reasoning-fixes
Oct 24, 2026
Merged

ispobock merged 4 commits into
mainfrom
m3-tool-reasoning-fixes

Conversation

@ispobock

@ispobock ispobock commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes in the MiniMax-M3 tool-call parser and chat serving: type tool-call arguments nested in schema-less containers, and count reasoning tokens when the model opens the reasoning block itself.

Changes to existing code

These apply to every model:

  • Function.strict defaults to None and is left out of the rendered tool schema when unset; it was False and always injected.
  • Tool schemas keep the key order the client sent.
  • An image detail of "default" is read as "auto".
  • The root role is accepted alongside system and developer.
  • A thinking request field is accepted; only chat templates that define a thinking mode read it.
  • Usage reports reasoning tokens in completion_tokens_details.reasoning_tokens, set only when there are some.
  • ModelConfig.self_opened_think_start_ids defaults to None; the scheduler fills it only when a reasoning parser is configured.

MiniMax-M3 only: the request's own thinking, reasoning_effort and chat_template_kwargs settle thinking_mode and the effort before --default-chat-template-kwargs fill what the request left unset, so a server default never re-enables thinking the request turned off.

Verification

  • test_minimax_m3_detector, test_reasoning_parser, test_serving_chat, test_protocol, test_batch_result_processor_*, test_model_config (reasoning-token fields exist without a reasoning parser)

Cut byte-for-byte from #45925 (MiniMax-M3.1-Flash support) at 10e655a.


CI States

Latest PR Test (Base): 🚫 Run #40090965301
Latest PR Test (Extra): ❌ Run #40090965282
Latest PR Test (AMD ROCm 10): 🚫 Run #40090965289

Co-authored-by: Yuhao Yang <47235274+yhyang201@users.noreply.github.com>
Co-authored-by: Xinyuan Tong <xinyuantong.cs@gmail.com>
Co-authored-by: Yan Huang <yan.huang@radixark.ai>
@ispobock

Copy link
Copy Markdown
Collaborator Author

/rerun-test --changed

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🚀 ubuntu-latest (7 tests): ✅ View workflow run

cd test/ && python3 registered/unit/entrypoints/openai/test_protocol.py
cd test/ && python3 registered/unit/entrypoints/openai/test_serving_chat.py
cd test/ && python3 registered/unit/function_call/test_minimax_m3_detector.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_hidden_states.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_mamba_boundary.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_spec_grammar.py
cd test/ && python3 registered/unit/parser/test_reasoning_parser.py

@ispobock ispobock added run-ci CI: run the baseline test suite on this PR bypass-fail-fast CI: a failing job no longer aborts its siblings (lint still gates) labels Oct 24, 2026
@ispobock

Copy link
Copy Markdown
Collaborator Author

/rerun-test --changed

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

🚀 ubuntu-latest (8 tests): ✅ View workflow run

cd test/ && python3 registered/unit/configs/test_model_config.py
cd test/ && python3 registered/unit/entrypoints/openai/test_protocol.py
cd test/ && python3 registered/unit/entrypoints/openai/test_serving_chat.py
cd test/ && python3 registered/unit/function_call/test_minimax_m3_detector.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_hidden_states.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_mamba_boundary.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_spec_grammar.py
cd test/ && python3 registered/unit/parser/test_reasoning_parser.py

@ispobock

Copy link
Copy Markdown
Collaborator Author

/rerun-test --changed

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

🚀 ubuntu-latest (8 tests): ✅ View workflow run

cd test/ && python3 registered/unit/configs/test_model_config.py
cd test/ && python3 registered/unit/entrypoints/openai/test_protocol.py
cd test/ && python3 registered/unit/entrypoints/openai/test_serving_chat.py
cd test/ && python3 registered/unit/function_call/test_minimax_m3_detector.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_hidden_states.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_mamba_boundary.py
cd test/ && python3 registered/unit/managers/test_batch_result_processor_spec_grammar.py
cd test/ && python3 registered/unit/parser/test_reasoning_parser.py

@ispobock
ispobock merged commit d0f5171 into main Oct 24, 2026
178 of 190 checks passed
@ispobock
ispobock deleted the m3-tool-reasoning-fixes branch October 24, 2026 14:11
sherlockwu pushed a commit that referenced this pull request Oct 25, 2026
…alizer now does

Since #46133, Python's `Function` keeps the client's key order and drops an
unset `strict` or `defer_loading`, so a Jinja template no longer sees
`"strict": false` added to every tool.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…lizer now does

Since #46133, Python's `Function` keeps the client's key order and leaves
out an unset `strict` or `defer_loading` (a null `strict` included), so
GLM-5.3 and Qwen3.8 templates no longer see `"strict": false` added to
every tool. One `function_dump` now serves their renderers and the
template fallback; Kimi K3's dump accepts a null `strict` too.

Regenerated the GLM-5.3 and Qwen3.8 parity fixtures from current Python;
their prompts change only in tool cases (other changes are error wording).
The fixture generator's stub server gains `is_minimax_m3`.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…okens_details

Since #46133, Python's UsageProcessor also reports the reasoning count where
OpenAI puts it, `usage.completion_tokens_details.reasoning_tokens` (null
without reasoning), for chat and completions, unary and streamed.

Regenerated the GLM-5.3 and Qwen3.8 OpenAI fixtures from current Python,
keeping their recorded engine outputs; their tool cases' /generate ids also
take the new tool dump. The generator's stub template owner gains the
model config `load_chat_template` now reads.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…alizer now does

Since #46133, Python's `Function` keeps the client's key order and drops an
unset `strict` or `defer_loading`, so a Jinja template no longer sees
`"strict": false` added to every tool.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…lizer now does

Since #46133, Python's `Function` keeps the client's key order and leaves
out an unset `strict` or `defer_loading` (a null `strict` included), so
GLM-5.3 and Qwen3.8 templates no longer see `"strict": false` added to
every tool. One `function_dump` now serves their renderers and the
template fallback; Kimi K3's dump accepts a null `strict` too.

Regenerated the GLM-5.3 and Qwen3.8 parity fixtures from current Python;
their prompts change only in tool cases (other changes are error wording).
The fixture generator's stub server gains `is_minimax_m3`.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…okens_details

Since #46133, Python's UsageProcessor also reports the reasoning count where
OpenAI puts it, `usage.completion_tokens_details.reasoning_tokens` (null
without reasoning), for chat and completions, unary and streamed.

Regenerated the GLM-5.3 and Qwen3.8 OpenAI fixtures from current Python,
keeping their recorded engine outputs; their tool cases' /generate ids also
take the new tool dump. The generator's stub template owner gains the
model config `load_chat_template` now reads.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…alizer now does

Since #46133, Python's `Function` keeps the client's key order and drops an
unset `strict` or `defer_loading`, so a Jinja template no longer sees
`"strict": false` added to every tool.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…lizer now does

Since #46133, Python's `Function` keeps the client's key order and leaves
out an unset `strict` or `defer_loading` (a null `strict` included), so
GLM-5.3 and Qwen3.8 templates no longer see `"strict": false` added to
every tool. One `function_dump` now serves their renderers and the
template fallback; Kimi K3's dump accepts a null `strict` too.

Regenerated the GLM-5.3 and Qwen3.8 parity fixtures from current Python;
their prompts change only in tool cases (other changes are error wording).
The fixture generator's stub server gains `is_minimax_m3`.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…okens_details

Since #46133, Python's UsageProcessor also reports the reasoning count where
OpenAI puts it, `usage.completion_tokens_details.reasoning_tokens` (null
without reasoning), for chat and completions, unary and streamed.

Regenerated the GLM-5.3 and Qwen3.8 OpenAI fixtures from current Python,
keeping their recorded engine outputs; their tool cases' /generate ids also
take the new tool dump. The generator's stub template owner gains the
model config `load_chat_template` now reads.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…alizer now does

Since #46133, Python's `Function` keeps the client's key order and drops an
unset `strict` or `defer_loading`, so a Jinja template no longer sees
`"strict": false` added to every tool.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…lizer now does

Since #46133, Python's `Function` keeps the client's key order and leaves
out an unset `strict` or `defer_loading` (a null `strict` included), so
GLM-5.3 and Qwen3.8 templates no longer see `"strict": false` added to
every tool. One `function_dump` now serves their renderers and the
template fallback; Kimi K3's dump accepts a null `strict` too.

Regenerated the GLM-5.3 and Qwen3.8 parity fixtures from current Python;
their prompts change only in tool cases (other changes are error wording).
The fixture generator's stub server gains `is_minimax_m3`.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…okens_details

Since #46133, Python's UsageProcessor also reports the reasoning count where
OpenAI puts it, `usage.completion_tokens_details.reasoning_tokens` (null
without reasoning), for chat and completions, unary and streamed.

Regenerated the GLM-5.3 and Qwen3.8 OpenAI fixtures from current Python,
keeping their recorded engine outputs; their tool cases' /generate ids also
take the new tool dump. The generator's stub template owner gains the
model config `load_chat_template` now reads.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…alizer now does

Since #46133, Python's `Function` keeps the client's key order and drops an
unset `strict` or `defer_loading`, so a Jinja template no longer sees
`"strict": false` added to every tool.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…lizer now does

Since #46133, Python's `Function` keeps the client's key order and leaves
out an unset `strict` or `defer_loading` (a null `strict` included), so
GLM-5.3 and Qwen3.8 templates no longer see `"strict": false` added to
every tool. One `function_dump` now serves their renderers and the
template fallback; Kimi K3's dump accepts a null `strict` too.

Regenerated the GLM-5.3 and Qwen3.8 parity fixtures from current Python;
their prompts change only in tool cases (other changes are error wording).
The fixture generator's stub server gains `is_minimax_m3`.
sherlockwu pushed a commit that referenced this pull request Oct 26, 2026
…okens_details

Since #46133, Python's UsageProcessor also reports the reasoning count where
OpenAI puts it, `usage.completion_tokens_details.reasoning_tokens` (null
without reasoning), for chat and completions, unary and streamed.

Regenerated the GLM-5.3 and Qwen3.8 OpenAI fixtures from current Python,
keeping their recorded engine outputs; their tool cases' /generate ids also
take the new tool dump. The generator's stub template owner gains the
model config `load_chat_template` now reads.
@ispobock ispobock mentioned this pull request Oct 27, 2026
13 tasks done
Rockdu added a commit to radixark/miles that referenced this pull request Oct 31, 2026
…he parity test

SGLang v0.5.23 keeps the client's tool key order with strict unset
(sgl-project/sglang#46133), and its Anthropic converter now writes name,
description, parameters and strict (sgl-project/sglang#45254). The OpenAI
side of the Anthropic/OpenAI parity test must spell tools the way the codec
does for the two routes to render identical input_ids.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rockdu added a commit to radixark/miles that referenced this pull request Oct 31, 2026
The V4 encoder renders each tool dict verbatim, and the bridge built those
dicts with sglang's Tool.model_dump(). SGLang v0.5.23
(sgl-project/sglang#46133) made Function keep the client's key order and
drop an unset strict, so even with the vendored encoder every tool-bearing
V4 prompt changed. dsv4_tool_payload rebuilds the v0.5.22 shape (declared
order, strict defaulting to False). V4.1 already sends its own payload, and
V3.2 keeps following Tool.model_dump(), which sglang's dsv32 serving path
also uses.

Checked by rendering 108 V4 and 108 V4.1 cases (tool spellings, system
and tool turns, thinking on/off, generation prompt on/off) with miles main
on the old stack and with this branch on the new one: identical, where V4
differed in all 96 tool-bearing cases before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bypass-fail-fast CI: a failing job no longer aborts its siblings (lint still gates) run-ci CI: run the baseline test suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant