Repository navigation
server: hold strict tools to their schema under tool_choice auto - #1688
Merged
Merged
Conversation
jayleaton
force-pushed
the
dsv41-up/strict-tools-auto
branch
from
October 31, 2026 16:01
8700ab5 to
d5855e0
Compare
Contributor
Author
|
Restacked on the rebased #1684 ( |
Under tool_choice auto (or none given) with a tool marked "strict": true, compile an xgrammar triggered_tags grammar: free text, and at the template's call opener a call tag whose strict tools' arguments follow their schema while other tools take any JSON object. TENSORFOLD_TOOL_GRAMMAR=1 (legacy TF_DSV41_TOOL_GRAMMAR) holds every auto tools request. LFM2 and engines without a grammar library stay unconstrained; required and named calls are unchanged. (cherry picked from commit 17eef71)
…e auto Structural tags compile argument schemas in strict mode, where an object that omits additionalProperties is closed. The fallback for a tool that is not strict now says additionalProperties: true, so it takes any JSON object. zig build test-grammar-tools -Dxgrammar=DIR walks the strict lookup(q, n) and non-strict now(tz) fixture's auto grammars through a real libtfgrammar in DeepSeek DSML, hermes JSON and Qwen XML markup. (cherry picked from commit c01e4cc)
ashhart
force-pushed
the
dsv41-up/strict-tools-auto
branch
from
October 31, 2026 21:02
d5855e0 to
c669910
Compare
Owner
|
Thank you @jayleaton. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes. |
Owner
|
Thanks @jayleaton! Strict tools held to their schema under |
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.
What this changes
Under
tool_choice: "auto"(or none given), a tool marked"strict": truewas not held to its schema. The model could call it with arguments that fail validation. Now, when any offered tool is strict, the server compiles an xgrammartriggered_tagsgrammar. Free text stays free. At the template's call opener a call tag begins, in which strict tools' arguments follow their schema and non-strict tools take any JSON object. Required and named calls are unchanged. LFM2, and engines without the grammar library, stay unconstrained.This changes default behaviour for every family that has a grammar runtime, not only DeepSeek: an auto request with a strict tool is now constrained.
TENSORFOLD_TOOL_GRAMMAR=1holds every auto tools request the same way.TF_DSV41_TOOL_GRAMMARis read as an alias, because the published DeepSeek recipe sets it. Say if you would rather not carry that alias.A second commit makes the non-strict fallback explicitly open (
additionalProperties: true). The pinned xgrammar v0.2.8 already treats the bare{"type":"object"}as open, so this fixes no observed bug. It makes the intent explicit and adds a test against the real library:zig build test-grammar-tools -Dxgrammar=DIRcompiles the mixed strictlookup(q, n)/ non-strictnow(tz)auto grammars through a reallibtfgrammarin DeepSeek DSML, hermes JSON and Qwen XML markup. It checks thatnow(tz="UTC")and nested arguments are accepted, and that wrong-type, extra and missing strictlookuparguments are refused, with parallel calls on and off.Issue: none open upstream. Stacked on: #1684 (DSML required tools), whose
deepseekstyle this uses for the call opener. Review onlye9f668512bb2..d5855e035461.Receipt
d5855e035461on maind2ad5a7f2; Zig 0.17.0; host checks on a Linux aarch64 DGX Spark (GB10, CUDA 13.0). Real-pack boot on two GB10s, TP=2 over RoCE, checkpointjayleaton/DeepSeek-V4.1-Flash-1017-EXL3-2.8bpwrevision859396591c34,TF_EXPERIMENTAL=deepseek.tool_grammar_auto_test.zig,tool_required_test.zig): the grammar shape for strict-only and mixed tools, the opener per style, the env override, and unchanged required and named calls.test-grammar-toolsruns the real-library cases above.83ba53298924: passed. Both ranks reached readiness; the recipe smoke, the canary and a strict tool call passed;MissingTritonVariant0 in both rank logs; 2048 greedy tokens in 51.1 s withtoken_sha2567538b20557b1…, the same as the downstream build of this series. On that boot, a required strictlookupreturned{"q":"tensor parallelism","n":3}, and an auto request to the non-strictnowreturned{"tz":"UTC"}.atc overlapreports the same additivetool_grammar.zigandreply_text.zigconflicts with minimax_m3: a CUDA backend for MiniMax-M3.1-Flash at TP over GB10s, from the release's own formats #1388, minimax_m3: serve MiniMax-M3.1-Flash (428B-A23B MoE, images) natively on Metal #1235 and minimax_m3 (CUDA): draft several streams' DSpark blocks in one pass #1426 as the PR this sits on.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (Not measured for this change alone.)SUMMARYline is in the receipt. (No kernel changes.)