Repository navigation
feat(parsers-v2): add structural tag support - #189
Conversation
|
parsers/v2/src/structural_tag/builders/mod.rs:82 — 🤖 AI FixIn |
|
Thanks for the contribution @jellysnack ! Tagging @keivenchang @indrajit96 to help review |
dba64b1 to
4a056c7
Compare
Signed-off-by: jellysnack <oleg.jellysnack@gmail.com>
4a056c7 to
16246d6
Compare
The |
|
Thanks @jellysnack for this taking a look right now |
Signed-off-by: Ryan McCormick <rmccormick@nvidia.com>
|
/ok to test 35d583c |
|
📊 Conformance matrix rendered — view in CI summary |
indrajit96
left a comment
There was a problem hiding this comment.
Hi @jellysnack thanks a lot for adding this!
@keivenchang Adding you for desing review.
PR looks good to me and mostly carries the V1 structural-tag architecture into V2 with stronger encapsulation.
Belwo are few deviations I found from V1 to V2 and my notes
| Design choice | V1 | V2 in this PR | Review note |
|---|---|---|---|
| Parser and builder association | ToolCallConfig contains both the parser configuration and optional structural-tag builder. |
FamilySpec associates the parser factory with an optional static builder. |
Appropriate for V2's factory-based parser creation. |
| Public API and extensibility | V1 exposes constructible builder configurations and XGrammar format types. | V2 exposes semantic request types while keeping builders and XGrammar wire types private. | Better encapsulation, but external consumers cannot construct or register V2 builders. |
| Policy resolution | Tool selection, schema behavior, and cardinality are handled within builder paths. | ResolvedToolCallingPolicy centralizes selected tools, mode, cardinality, and schema mode. |
Good separation and easier cross-family consistency. |
tool_choice = none |
Uses a separate build_tool_call_ban() path with token-level exclusions. |
The main build() path returns an AnyText format with text-pattern exclusions. |
Meaningful semantic change that should be confirmed against backend behavior. |
| Structured output | No equivalent generic alternation between native tool calls and a structured final response. | auto can produce an Or between native tool calls and a JSON-schema response. |
New V2 behavior; confirm that Dynamo requires this public feature. |
| Reasoning boundary | Mainly wraps prompt-opened reasoning for required and named calls. | Supports wrapping auto, required, named, and structured-output paths, plus ReasoningBoundary::External. |
Intentional expansion beyond V1; ownership of the boundary should be documented. |
| Deployment integration | Dynamo obtains the builder from the selected V1 ToolCallConfig. |
Dynamo must call structural_tag_builder_for_family(family) after selecting V2. |
A Dynamo integration change is required; this PR only exposes the crates API. |
| Reference validation | Tests primarily cover Dynamo's existing builder behavior. | Tests assert locally generated XGrammar JSON. | Consider parity tests against pinned XGrammar reference builders to avoid encoding incorrect assumptions. |
@jellysnack can you open a corresponding PR on Dynamo showing the integragration?
Internally I can pick both the PRs create a custom build and run CI along with some custom 2e2 tests.
Sure. And good catches on the review comments, I’ll address those and open a draft Dynamo integration PR shortly |
|
@indrajit96 Hi! I’ve addressed both issues and also added a small GLM parser fix after E2E testing showed that the model could emit whitespace between XML elements when using structural tag Here’s also the draft PR with the corresponding Dynamo integration: ai-dynamo/dynamo#13903 |
rmccorm4
left a comment
There was a problem hiding this comment.
LGTM aside from 1 comment
Signed-off-by: jellysnack <oleg.jellysnack@gmail.com>
Signed-off-by: jellysnack <oleg.jellysnack@gmail.com>
Signed-off-by: jellysnack <oleg.jellysnack@gmail.com>
d582fcd to
0cc987f
Compare
|
Hi @rmccorm4 @keivenchang, just a friendly ping on this PR |
|
/ok to test |
indrajit96
left a comment
There was a problem hiding this comment.
LGTM!
All comments addressed!
|
/ok to test e2994f1 |
Summary
This PR adds XGrammar structural-tag support to parsers v2.
It includes:
qwen3_coder,deepseek_v4, andglm47Motivation
Structural tags are supported by parsers v1 but are not yet available with parsers v2. This PR adds that support.
Differences from v1
The v2 implementation uses v1 as a behavioral baseline while separating request policy from model-specific formatting and adding several capabilities.
tool_choice=nonebans are built through separate methodsparallel_tool_callstool_choicecontracttool_choice=noneprimarily uses token-level bansautocan choose between model-native tool calls and a JSON Schema-constrained final responseany_order, disabled by default because it weakens required-property and duplicate-key validationTemplatedToolCallFormat, complex formats implementToolCallGrammardirectlyRequest semantics are represented by
StructuralTagContextand resolved into a model-independent policy before reaching the model-specific grammar.StructuralTagOptionscontains serving-time behavior settings configured by the integration and reused across requests, including:The XGrammar wire representation remains private, so it can evolve without becoming part of the public parsers v2 API.
For
autorequests with both tools and a structured-output schema, the builder produces an alternative between a calls-only model-native tool-call format and a JSON Schema-constrained final response. This allows the model to call a tool first and produce the structured final response after receiving the tool result.Supported model formats
The parser-family registry now declares both the v2 parser factory and its optional structural-tag capability, keeping model-family routing in one place.
Validation
The structural-tag builders were validated end to end with downstream Dynamo changes that integrate parsers v2 structural tags into request preprocessing. The Dynamo integration will be submitted as a separate PR after this frontend-crates change is merged.
Parser compatibility improvements discovered during end-to-end validation will be submitted separately.