[Rust Frontend] Bump `xgrammar-structural-tag` and enable local extension (#49161)
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Bugen Zhao committed
Jul 20, 2026 at 23:22 UTC
e2d7adeb642bd6e6bdb4f3305005e8608765d7cf
20 files changed
+84
-85
rust/Cargo.lock
+2
-2
@@ -6321,9 +6321,9 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
6321
6322
[[package]]
6323
name = "xgrammar-structural-tag"
6324
-version = "0.1.0+xgrammar.0.2.2.4d145cc"
6324
+version = "0.2.0+xgrammar.0.2.4.dd729e7"
6325
source = "registry+https://github.com/rust-lang/crates.io-index"
6326
-checksum = "2436dea2393d55a3b188588aa300c5a8afe8f45a77da52c611fb4498a6c876e6"
6326
+checksum = "d4d24c842efc3c24e9756aa426d530cbdac0980e49af223cb384e276e981ca0a"
6327
dependencies = [
6328
"auto_impl",
6329
"serde",
rust/Cargo.toml
+1
-1
@@ -143,7 +143,7 @@ vllm-server = { path = "src/server" }
143
vllm-text = { path = "src/text" }
144
vllm-tokenizer = { path = "src/tokenizer" }
145
winnow = { version = "1.0.2", features = ["simd"] }
146
-xgrammar-structural-tag = "0.1.0"
146
+xgrammar-structural-tag = "0.2.0"
147
zeromq = { version = "0.6.0", default-features = false, features = [
148
"tokio-runtime",
149
"all-transport",
rust/src/chat/src/output/default/mod.rs
+1
-1
@@ -74,7 +74,7 @@ impl DefaultChatOutputProcessor {
74
Box::new(CombinedParser::new(reasoning_parser, tool_parser)) as Box<dyn UnifiedParser>
75
};
76
77
- apply_structural_tag_constraint(request, parser.structural_tag_model())?;
77
+ apply_structural_tag_constraint(request, parser.structural_tag_builder())?;
78
79
if parser.preserve_special_tokens() {
80
request.decode_options.skip_special_tokens = false;
rust/src/chat/src/output/default/structural_tag.rs
+22
-16
@@ -7,7 +7,8 @@ use thiserror_ext::AsReport;
7
use vllm_engine_core_client::protocol::structured_outputs::{
8
StructuredOutputBackend, StructuredOutputsParams,
9
};
10
-use vllm_parser::tool::StructuralTagModel;
10
+use vllm_parser::tool::StructuralTagBuilder;
11
+use xgrammar_structural_tag::builders::StructuralTagOptions;
12
use xgrammar_structural_tag::{
13
FunctionDefinition, FunctionToolParam, ToolChoice as StructuralTagToolChoice, ToolParam,
14
build_structural_tag,
@@ -20,9 +21,9 @@ use crate::{Error, Result as ChatResult};
21
/// support and the request's tool choice.
22
pub(super) fn apply_structural_tag_constraint(
23
request: &mut ChatRequest,
23
- model: Option<StructuralTagModel>,
24
+ builder: Option<&dyn StructuralTagBuilder>,
25
) -> ChatResult<()> {
25
- let Some(model) = model else {
26
+ let Some(builder) = builder else {
27
return Ok(());
28
};
29
let Some(tool_choice) = structural_tag_tool_choice(request) else {
@@ -42,11 +43,16 @@ pub(super) fn apply_structural_tag_constraint(
43
})
44
.collect::<Vec<_>>();
45
45
- let structural_tag = build_structural_tag(model, &tools, tool_choice, false)
46
- .and_then(|tag| tag.to_json_string())
47
- .map_err(|error| Error::StructuralTag {
48
- message: error.to_report_string(),
49
- })?;
46
+ let structural_tag = build_structural_tag(
47
+ builder,
48
+ &tools,
49
+ tool_choice,
50
+ StructuralTagOptions::default().with_reasoning(false),
51
+ )
52
+ .and_then(|tag| tag.to_json_string())
53
+ .map_err(|error| Error::StructuralTag {
54
+ message: error.to_report_string(),
55
+ })?;
56
57
// Overwrite any existing structured output settings with the structural tag constraint.
58
request.sampling_params.structured_outputs = Some(StructuredOutputsParams {
@@ -141,7 +147,7 @@ mod tests {
147
let mut request = request(ChatToolChoice::Auto, vec![chat_tool("search", Some(true))]);
148
let parser = qwen3_coder_parser(&request.tools);
149
144
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
150
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
151
.expect("structural tag should build");
152
153
let tag = structural_tag_value(&request);
@@ -154,7 +160,7 @@ mod tests {
160
let mut request = request(ChatToolChoice::Auto, vec![chat_tool("search", None)]);
161
let parser = qwen3_coder_parser(&request.tools);
162
157
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
163
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
164
.expect("structural tag decision should succeed");
165
166
assert!(request.sampling_params.structured_outputs.is_none());
@@ -169,7 +175,7 @@ mod tests {
175
});
176
let parser = qwen3_coder_parser(&request.tools);
177
172
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
178
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
179
.expect("structural tag should build");
180
181
let params = structured_outputs(&request);
@@ -184,7 +190,7 @@ mod tests {
190
let mut request = request(ChatToolChoice::Required, vec![chat_tool("search", None)]);
191
let parser = qwen3_coder_parser(&request.tools);
192
187
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
193
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
194
.expect("structural tag should build");
195
196
let tag = structural_tag_value(&request);
@@ -201,7 +207,7 @@ mod tests {
207
});
208
let parser = qwen3_coder_parser(&request.tools);
209
204
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
210
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
211
.expect("structural tag should build");
212
213
let params = structured_outputs(&request);
@@ -221,7 +227,7 @@ mod tests {
227
);
228
let parser = qwen3_coder_parser(&request.tools);
229
224
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
230
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
231
.expect("structural tag should build");
232
233
let tag = structural_tag_value(&request).to_string();
@@ -234,7 +240,7 @@ mod tests {
240
let mut request = request(ChatToolChoice::None, vec![chat_tool("search", Some(true))]);
241
let parser = qwen3_coder_parser(&request.tools);
242
237
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
243
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
244
.expect("structural tag decision should succeed");
245
246
assert!(request.sampling_params.structured_outputs.is_none());
@@ -249,7 +255,7 @@ mod tests {
255
});
256
let parser = qwen3_coder_parser(&request.tools);
257
252
- apply_structural_tag_constraint(&mut request, parser.structural_tag_model())
258
+ apply_structural_tag_constraint(&mut request, parser.structural_tag_builder())
259
.expect("structural tag decision should succeed");
260
261
let params = structured_outputs(&request);
rust/src/parser/benches/utils/adapter.rs
+3
-3
@@ -4,7 +4,7 @@
4
use std::sync::Arc;
5
6
use vllm_parser::tool::{
7
- Result, StructuralTagModel, Tool, ToolParser, ToolParserError, ToolParserOutput,
7
+ Result, StructuralTagBuilder, Tool, ToolParser, ToolParserError, ToolParserOutput,
8
};
9
use vllm_parser::unified::{
10
UnifiedParser, UnifiedParserError, UnifiedParserEvent, UnifiedParserOutput,
@@ -85,8 +85,8 @@ impl<T: UnifiedParser> ToolParser for UnifiedToolParserAdapter<T> {
85
self.inner.preserve_special_tokens()
86
}
87
88
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
89
- self.inner.structural_tag_model()
88
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
89
+ self.inner.structural_tag_builder()
90
}
91
92
fn tool_call_id(&self, tool_index: usize) -> Option<&str> {
rust/src/parser/src/tool/deepseek_dsml/deepseek_v32.rs
+3
-3
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{DeepSeekDsmlToolParser, DsmlTokens};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
/// Tool parser for DeepSeek V3.2 models.
8
///
@@ -47,8 +47,8 @@ impl ToolParser for DeepSeekV32ToolParser {
47
true
48
}
49
50
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
51
- Some(StructuralTagModel::DeepSeekV32)
50
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
51
+ Some(xgrammar_structural_tag::Model::DeepSeekV32.builder())
52
}
53
54
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/deepseek_dsml/deepseek_v4.rs
+6
-9
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{DeepSeekDsmlToolParser, DsmlTokens};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
/// Tool parser for DeepSeek V4 models.
8
///
@@ -50,8 +50,8 @@ impl ToolParser for DeepSeekV4ToolParser {
50
true
51
}
52
53
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
54
- Some(StructuralTagModel::DeepSeekV4)
53
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
54
+ Some(xgrammar_structural_tag::Model::DeepSeekV4.builder())
55
}
56
57
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
@@ -73,7 +73,7 @@ mod tests {
73
74
use super::DeepSeekV4ToolParser;
75
use crate::tool::test_utils::{collect_stream, test_tools};
76
- use crate::tool::{StructuralTagModel, ToolParser, ToolParserTestExt as _};
76
+ use crate::tool::{ToolParser, ToolParserTestExt as _};
77
78
fn build_tool_call(function_name: &str, params: &[(&str, &str)]) -> String {
79
let params = params
@@ -91,13 +91,10 @@ mod tests {
91
}
92
93
#[test]
94
- fn deepseek_v4_exposes_structural_tag_model() {
94
+ fn deepseek_v4_exposes_structural_tag_builder() {
95
let parser = DeepSeekV4ToolParser::new(&test_tools());
96
97
- assert_eq!(
98
- parser.structural_tag_model(),
99
- Some(StructuralTagModel::DeepSeekV4)
100
- );
97
+ assert!(parser.structural_tag_builder().is_some());
98
}
99
100
#[test]
rust/src/parser/src/tool/deepseek_json/deepseek_v3.rs
+3
-3
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{DeepSeekJsonFormat, DeepSeekJsonToolParser};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
/// Tool parser for DeepSeek V3 JSON-fenced tool calls.
8
///
@@ -35,8 +35,8 @@ impl ToolParser for DeepSeekV3ToolParser {
35
Ok(Box::new(Self::new(tools)))
36
}
37
38
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
39
- Some(StructuralTagModel::DeepSeekR1)
38
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
39
+ Some(xgrammar_structural_tag::Model::DeepSeekR1.builder())
40
}
41
42
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/deepseek_json/deepseek_v31.rs
+3
-3
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{DeepSeekJsonFormat, DeepSeekJsonToolParser};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
/// Tool parser for DeepSeek V3.1 raw JSON tool calls.
8
///
@@ -31,8 +31,8 @@ impl ToolParser for DeepSeekV31ToolParser {
31
Ok(Box::new(Self::new(tools)))
32
}
33
34
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
35
- Some(StructuralTagModel::DeepSeekV31)
34
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
35
+ Some(xgrammar_structural_tag::Model::DeepSeekV31.builder())
36
}
37
38
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/glm_xml/glm47_moe.rs
+3
-3
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{GlmXmlToolParser, Separator};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
/// Tool parser for GLM-4.7 MoE XML-style tool calls.
8
///
@@ -25,8 +25,8 @@ impl ToolParser for Glm47MoeToolParser {
25
Ok(Box::new(Self::new(tools)))
26
}
27
28
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
29
- Some(StructuralTagModel::Glm47)
28
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
29
+ Some(xgrammar_structural_tag::Model::Glm47.builder())
30
}
31
32
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/hy_v3.rs
+3
-3
@@ -10,7 +10,7 @@ use winnow::token::{literal, rest, take_until};
10
use super::parameters::ToolSchemas;
11
use super::utils::{MarkerScanState, parse_buffered_event, safe_text_len, take_until_marker};
12
use super::{Result, ToolCallDelta, ToolParser, ToolParserOutput};
13
-use crate::tool::{StructuralTagModel, Tool};
13
+use crate::tool::{StructuralTagBuilder, Tool};
14
15
const TOOL_CALLS_START: &str = "<tool_calls>";
16
const TOOL_CALLS_END: &str = "</tool_calls>";
@@ -116,8 +116,8 @@ impl ToolParser for HyV3ToolParser {
116
Ok(Box::new(Self::new(tools)))
117
}
118
119
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
120
- Some(StructuralTagModel::HyV3)
119
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
120
+ Some(xgrammar_structural_tag::Model::HyV3.builder())
121
}
122
123
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/json/hermes.rs
+3
-3
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{JsonToolCallConfig, JsonToolCallParser, JsonToolCallWhitespace};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
const HERMES_CONFIG: JsonToolCallConfig = JsonToolCallConfig {
8
parser_name: "Hermes",
@@ -48,8 +48,8 @@ impl ToolParser for HermesToolParser {
48
Ok(Box::new(Self::new(tools)))
49
}
50
51
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
52
- Some(StructuralTagModel::Hermes)
51
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
52
+ Some(xgrammar_structural_tag::Model::Hermes.builder())
53
}
54
55
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/json/llama.rs
+5
-3
@@ -12,7 +12,9 @@ use super::{
12
argument_delta_event, tool_call_header_event,
13
};
14
use crate::tool::utils::{JsonObjectScanState, parse_buffered_event};
15
-use crate::tool::{Result, StructuralTagModel, Tool, ToolCallDelta, ToolParser, ToolParserOutput};
15
+use crate::tool::{
16
+ Result, StructuralTagBuilder, Tool, ToolCallDelta, ToolParser, ToolParserOutput,
17
+};
18
19
#[derive(Debug, Clone, PartialEq, Eq)]
20
enum LlamaJsonMode {
@@ -136,8 +138,8 @@ impl ToolParser for Llama3JsonToolParser {
138
Ok(Box::new(Self::new(tools)))
139
}
140
139
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
140
- Some(StructuralTagModel::Llama)
141
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
142
+ Some(xgrammar_structural_tag::Model::Llama.builder())
143
}
144
145
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/json/qwen.rs
+3
-3
@@ -2,7 +2,7 @@
2
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
use super::{JsonToolCallConfig, JsonToolCallParser, JsonToolCallWhitespace};
5
-use crate::tool::{Result, StructuralTagModel, Tool, ToolParser, ToolParserOutput};
5
+use crate::tool::{Result, StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
6
7
const QWEN_XML_CONFIG: JsonToolCallConfig = JsonToolCallConfig {
8
parser_name: "Qwen XML",
@@ -50,8 +50,8 @@ impl ToolParser for Qwen3XmlToolParser {
50
Ok(Box::new(Self::new(tools)))
51
}
52
53
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
54
- Some(StructuralTagModel::Qwen3)
53
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
54
+ Some(xgrammar_structural_tag::Model::Qwen3.builder())
55
}
56
57
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/kimi_k2.rs
+3
-3
@@ -11,7 +11,7 @@ use winnow::token::{literal, rest, take_until, take_while};
11
12
use super::utils::{JsonObjectScanState, parse_buffered_event, safe_text_len, take_json_object};
13
use super::{Result, ToolCallDelta, ToolParser, ToolParserOutput};
14
-use crate::tool::{StructuralTagModel, Tool};
14
+use crate::tool::{StructuralTagBuilder, Tool};
15
16
const TOOL_CALLS_START: &str = "<|tool_calls_section_begin|>";
17
const TOOL_CALLS_END: &str = "<|tool_calls_section_end|>";
@@ -150,8 +150,8 @@ impl ToolParser for KimiK2ToolParser {
150
true
151
}
152
153
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
154
- Some(StructuralTagModel::Kimi)
153
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
154
+ Some(xgrammar_structural_tag::Model::Kimi.builder())
155
}
156
157
fn tool_call_id(&self, tool_index: usize) -> Option<&str> {
rust/src/parser/src/tool/minimax_m2.rs
+3
-3
@@ -10,7 +10,7 @@ use winnow::token::{literal, rest, take_until};
10
use super::parameters::ToolSchemas;
11
use super::utils::{MarkerScanState, parse_buffered_event, safe_text_len, take_until_marker};
12
use super::{Result, ToolCallDelta, ToolParser, ToolParserOutput};
13
-use crate::tool::{StructuralTagModel, Tool};
13
+use crate::tool::{StructuralTagBuilder, Tool};
14
15
const TOOL_CALL_START: &str = "<minimax:tool_call>";
16
const TOOL_CALL_END: &str = "</minimax:tool_call>";
@@ -115,8 +115,8 @@ impl ToolParser for MinimaxM2ToolParser {
115
Ok(Box::new(Self::new(tools)))
116
}
117
118
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
119
- Some(StructuralTagModel::Minimax)
118
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
119
+ Some(xgrammar_structural_tag::Model::Minimax.builder())
120
}
121
122
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
rust/src/parser/src/tool/mod.rs
+3
-3
@@ -36,7 +36,7 @@ pub use qwen_coder::Qwen3CoderToolParser;
36
pub use seed_oss::SeedOssToolParser;
37
use serde::{Deserialize, Serialize};
38
use serde_json::Value;
39
-pub use xgrammar_structural_tag::Model as StructuralTagModel;
39
+pub use xgrammar_structural_tag::builders::StructuralTagBuilder;
40
41
use crate::utils;
42
@@ -187,8 +187,8 @@ pub trait ToolParser: Send {
187
false
188
}
189
190
- /// Return the xgrammar structural-tag model used for strict tool calling.
191
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
190
+ /// Return the xgrammar structural-tag builder used for strict tool calling.
191
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
192
None
193
}
194
rust/src/parser/src/tool/qwen_coder.rs
+7
-10
@@ -9,8 +9,8 @@ use winnow::token::{literal, take_until};
9
10
use super::parameters::ToolSchemas;
11
use super::utils::{MarkerScanState, parse_buffered_event, safe_text_len, take_until_marker};
12
-use super::{Result, StructuralTagModel, ToolCallDelta, ToolParser, ToolParserOutput};
13
-use crate::tool::Tool;
12
+use super::{Result, ToolCallDelta, ToolParser, ToolParserOutput};
13
+use crate::tool::{StructuralTagBuilder, Tool};
14
15
const TOOL_CALL_START: &str = "<tool_call>";
16
const TOOL_CALL_END: &str = "</tool_call>";
@@ -146,8 +146,8 @@ impl ToolParser for Qwen3CoderToolParser {
146
Ok(Box::new(Self::new(tools)))
147
}
148
149
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
150
- Some(StructuralTagModel::Qwen3Coder)
149
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
150
+ Some(xgrammar_structural_tag::Model::Qwen3Coder.builder())
151
}
152
153
fn parse_into(&mut self, chunk: &str, output: &mut ToolParserOutput) -> Result<()> {
@@ -294,7 +294,7 @@ mod tests {
294
use serde_json::{Value, json};
295
use thiserror_ext::AsReport;
296
297
- use super::{Qwen3CoderToolParser, StructuralTagModel, ToolParser};
297
+ use super::{Qwen3CoderToolParser, ToolParser};
298
use crate::tool::test_utils::{collect_stream, split_by_chars, test_tools};
299
use crate::tool::{ToolParserOutput, ToolParserTestExt as _};
300
@@ -308,13 +308,10 @@ mod tests {
308
}
309
310
#[test]
311
- fn qwen_coder_exposes_structural_tag_model() {
311
+ fn qwen_coder_exposes_structural_tag_builder() {
312
let parser = Qwen3CoderToolParser::new(&test_tools());
313
314
- assert_eq!(
315
- parser.structural_tag_model(),
316
- Some(StructuralTagModel::Qwen3Coder)
317
- );
314
+ assert!(parser.structural_tag_builder().is_some());
315
}
316
317
#[test]
rust/src/parser/src/unified/combined.rs
+4
-7
@@ -7,7 +7,7 @@ use vllm_tokenizer::DynTokenizer;
7
8
use super::{Result, UnifiedParser, UnifiedParserError, UnifiedParserOutput};
9
use crate::reasoning::ReasoningParser;
10
-use crate::tool::{StructuralTagModel, Tool, ToolParser, ToolParserOutput};
10
+use crate::tool::{StructuralTagBuilder, Tool, ToolParser, ToolParserOutput};
11
12
/// Unified parser that composes existing reasoning and tool parsers.
13
pub struct CombinedParser {
@@ -79,8 +79,8 @@ impl UnifiedParser for CombinedParser {
79
|| self.tool.as_ref().is_some_and(|parser| parser.preserve_special_tokens())
80
}
81
82
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
83
- self.tool.as_ref().and_then(|parser| parser.structural_tag_model())
82
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
83
+ self.tool.as_ref().and_then(|parser| parser.structural_tag_builder())
84
}
85
86
fn tool_call_id(&self, tool_index: usize) -> Option<&str> {
@@ -269,10 +269,7 @@ mod tests {
269
fn combined_parser_emits_tool_calls_from_visible_content() {
270
let tool = Qwen3XmlToolParser::create(&test_tools()).unwrap();
271
let mut parser = CombinedParser::new(None, Some(tool));
272
- assert!(matches!(
273
- parser.structural_tag_model(),
274
- Some(crate::tool::StructuralTagModel::Qwen3)
275
- ));
272
+ assert!(parser.structural_tag_builder().is_some());
273
274
let output = collect(
275
&mut parser,
rust/src/parser/src/unified/mod.rs
+3
-3
@@ -16,7 +16,7 @@ use vllm_tokenizer::DynTokenizer;
16
17
use crate::reasoning::ReasoningError;
18
use crate::tool::{
19
- StructuralTagModel, Tool, ToolCallDelta, ToolParserError, ToolParserEvent, ToolParserOutput,
19
+ StructuralTagBuilder, Tool, ToolCallDelta, ToolParserError, ToolParserEvent, ToolParserOutput,
20
};
21
22
/// Result alias for unified parser operations.
@@ -171,8 +171,8 @@ pub trait UnifiedParser: Send {
171
false
172
}
173
174
- /// Return the xgrammar structural-tag model used for strict tool calling.
175
- fn structural_tag_model(&self) -> Option<StructuralTagModel> {
174
+ /// Return the xgrammar structural-tag builder used for strict tool calling.
175
+ fn structural_tag_builder(&self) -> Option<&dyn StructuralTagBuilder> {
176
None
177
}
178