Skip to content

Commit 5f39d40

Browse files
committed
inline build_generic_tool_calls_peg_parser
1 parent 509910d commit 5f39d40

6 files changed

Lines changed: 215 additions & 129 deletions

File tree

common/chat-parsers-internal.h

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -265,86 +265,3 @@ inline void common_chat_build_peg_grammar(const struct templates_params & inputs
265265
}
266266
}
267267

268-
// Format struct for XML-style tool calls with individual parameters
269-
// Example: <tool_call><function=name><parameter=key>value</parameter></function></tool_call>
270-
struct generic_tool_call_format {
271-
// Tool calls array wrapper (all default to eps if not set)
272-
std::optional<common_peg_parser> tool_calls_start;
273-
std::optional<common_peg_parser> tool_calls_sep;
274-
std::optional<common_peg_parser> tool_calls_end;
275-
276-
// Individual tool call structure (required)
277-
std::optional<common_peg_parser> tool_call_start; // e.g., <tool_call><function=
278-
std::optional<common_peg_parser> tool_call_name_params_sep; // e.g., >
279-
std::optional<common_peg_parser> tool_call_end; // e.g., </function></tool_call>
280-
281-
// Parameter structure (required)
282-
std::optional<common_peg_parser> param_start; // e.g., <parameter=
283-
std::optional<common_peg_parser> param_name_value_sep; // e.g., >
284-
std::string param_end; // e.g., </parameter> (string for schema_or_raw_string_until)
285-
286-
bool allow_raw_string_param_value = true;
287-
};
288-
289-
inline common_peg_parser build_generic_tool_calls_peg_parser(
290-
common_chat_peg_builder & p,
291-
const struct templates_params & inputs,
292-
const generic_tool_call_format & format
293-
)
294-
{
295-
using Tag = common_chat_peg_tag;
296-
297-
// Validate required fields
298-
if (!format.tool_call_start || !format.tool_call_name_params_sep || !format.tool_call_end) {
299-
throw std::runtime_error("tool_call_start, tool_call_name_params_sep, and tool_call_end are required");
300-
}
301-
if (!format.param_start || !format.param_name_value_sep || format.param_end.empty()) {
302-
throw std::runtime_error("param_start, param_name_value_sep, and param_end are required");
303-
}
304-
305-
// Default to eps() if not set
306-
auto tool_calls_start = format.tool_calls_start ? *format.tool_calls_start : p.eps();
307-
auto tool_calls_sep = format.tool_calls_sep ? *format.tool_calls_sep : p.eps();
308-
auto tool_calls_end = format.tool_calls_end ? *format.tool_calls_end : p.eps();
309-
310-
auto tool_call = p.choice();
311-
foreach_function(inputs.tools, [&](const auto &, const auto & name, const json & parameters, const auto & schema_info) {
312-
auto args = p.sequence();
313-
foreach_parameter(p, parameters, [&](const std::string & param_name, const common_peg_parser & param_p, const json & param_schema, ParameterType param_type) {
314-
auto arg = p.rule("tool-" + name + "-arg-" + param_name,
315-
p.tag(Tag::TOOL_ARG_OPEN, *format.param_start)
316-
+ p.tag(Tag::TOOL_ARG_NAME, param_p)
317-
+ *format.param_name_value_sep
318-
+ (format.allow_raw_string_param_value
319-
? p.schema_or_raw_string_until("tool-" + name + "-arg-" + param_name + "-schema", param_schema, format.param_end,
320-
schema_info, Tag::TOOL_ARG_STRING_VALUE, Tag::TOOL_ARG_JSON_VALUE, true)
321-
: p.schema(p.json(), "tool-" + name + "-arg-" + param_name, param_schema))
322-
+ p.literal_tag(Tag::TOOL_ARG_CLOSE, format.param_end));
323-
switch (param_type) {
324-
case ParameterType::Required:
325-
args += arg;
326-
break;
327-
case ParameterType::Optional:
328-
args += p.optional(arg);
329-
break;
330-
case ParameterType::Additional:
331-
args += p.repeat(arg, 0, -1);
332-
break;
333-
default:
334-
throw std::runtime_error("Unhandled param type");
335-
}
336-
});
337-
338-
tool_call |= p.rule("tool-" + name,
339-
p.tag(Tag::TOOL_OPEN, *format.tool_call_start)
340-
+ p.literal_tag(Tag::TOOL_NAME, name)
341-
+ *format.tool_call_name_params_sep
342-
+ args
343-
+ p.tag(Tag::TOOL_CLOSE, *format.tool_call_end));
344-
});
345-
346-
return
347-
tool_calls_start
348-
+ tool_call + p.repeat(tool_calls_sep + tool_call, 0, inputs.parallel_tool_calls ? -1 : 0)
349-
+ tool_calls_end;
350-
}

common/chat-parsers/glm-4-5.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,48 @@ common_chat_params common_chat_params_init_glm_4_5_peg(const common_chat_templat
110110
data.grammar_triggers.push_back({COMMON_GRAMMAR_TRIGGER_TYPE_WORD, "<tool_call>"});
111111
}
112112

113-
generic_tool_call_format format;
114-
format.tool_call_start = p.space() + "<tool_call>";
115-
format.tool_call_name_params_sep = p.space();
116-
format.tool_call_end = p.space() + "</tool_call>";
117-
format.param_start = p.space() + "<arg_key>";
118-
format.param_name_value_sep = "</arg_key>" + p.space() + "<arg_value>";
119-
format.param_end = "</arg_value>\n";
120-
format.allow_raw_string_param_value = true;
121-
auto tool_calls = build_generic_tool_calls_peg_parser(p, inputs, format);
113+
auto tool_call_start = p.space() + "<tool_call>";
114+
auto tool_call_name_params_sep = p.space();
115+
auto tool_call_end = p.space() + "</tool_call>";
116+
auto param_start = p.space() + "<arg_key>";
117+
auto param_name_value_sep = "</arg_key>" + p.space() + "<arg_value>";
118+
auto param_end = "</arg_value>\n";
119+
120+
auto tool_call = p.choice();
121+
foreach_function(inputs.tools, [&](const auto &, const auto & name, const json & parameters, const auto & schema_info) {
122+
auto args = p.sequence();
123+
foreach_parameter(p, parameters, [&](const std::string & param_name, const common_peg_parser & param_p, const json & param_schema, ParameterType param_type) {
124+
auto arg = p.rule("tool-" + name + "-arg-" + param_name,
125+
p.tag(Tag::TOOL_ARG_OPEN, param_start)
126+
+ p.tag(Tag::TOOL_ARG_NAME, param_p)
127+
+ param_name_value_sep
128+
+ p.schema_or_raw_string_until("tool-" + name + "-arg-" + param_name + "-schema", param_schema, param_end,
129+
schema_info, Tag::TOOL_ARG_STRING_VALUE, Tag::TOOL_ARG_JSON_VALUE, true)
130+
+ p.literal_tag(Tag::TOOL_ARG_CLOSE, param_end));
131+
switch (param_type) {
132+
case ParameterType::Required:
133+
args += arg;
134+
break;
135+
case ParameterType::Optional:
136+
args += p.optional(arg);
137+
break;
138+
case ParameterType::Additional:
139+
args += p.repeat(arg, 0, -1);
140+
break;
141+
default:
142+
throw std::runtime_error("Unhandled param type");
143+
}
144+
});
145+
146+
tool_call |= p.rule("tool-" + name,
147+
p.tag(Tag::TOOL_OPEN, tool_call_start)
148+
+ p.literal_tag(Tag::TOOL_NAME, name)
149+
+ tool_call_name_params_sep
150+
+ args
151+
+ p.tag(Tag::TOOL_CLOSE, tool_call_end));
152+
});
153+
154+
auto tool_calls = tool_call + p.repeat(tool_call, 0, inputs.parallel_tool_calls ? -1 : 0);
122155

123156
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
124157
// thinking? space? tools

common/chat-parsers/minimax-m2.cpp

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,53 @@ common_chat_params common_chat_params_init_minimax_m2_peg(const common_chat_temp
6666
data.grammar_triggers.push_back({COMMON_GRAMMAR_TRIGGER_TYPE_WORD, "<minimax:tool_call>"});
6767
}
6868

69-
generic_tool_call_format format;
70-
format.tool_calls_start = p.space() + "<minimax:tool_call>";
71-
format.tool_calls_sep = p.eps();
72-
format.tool_calls_end = p.literal("</minimax:tool_call>");
73-
format.tool_call_start = p.space() + "<invoke name=\"";
74-
format.tool_call_name_params_sep = p.literal("\">");
75-
format.tool_call_end = p.space() + "</invoke>" + p.space();
76-
format.param_start = p.space() + "<parameter name=\"";
77-
format.param_name_value_sep = p.literal("\">");
78-
format.param_end = "</parameter>";
79-
format.allow_raw_string_param_value = true;
80-
auto tool_calls = build_generic_tool_calls_peg_parser(p, inputs, format);
69+
auto tool_calls_start = p.space() + "<minimax:tool_call>";
70+
auto tool_calls_end = p.literal("</minimax:tool_call>");
71+
auto tool_call_start = p.space() + "<invoke name=\"";
72+
auto tool_call_name_params_sep = p.literal("\">");
73+
auto tool_call_end = p.space() + "</invoke>" + p.space();
74+
auto param_start = p.space() + "<parameter name=\"";
75+
auto param_name_value_sep = p.literal("\">");
76+
auto param_end = "</parameter>";
77+
78+
auto tool_call = p.choice();
79+
foreach_function(inputs.tools, [&](const auto &, const auto & name, const json & parameters, const auto & schema_info) {
80+
auto args = p.sequence();
81+
foreach_parameter(p, parameters, [&](const std::string & param_name, const common_peg_parser & param_p, const json & param_schema, ParameterType param_type) {
82+
auto arg = p.rule("tool-" + name + "-arg-" + param_name,
83+
p.tag(Tag::TOOL_ARG_OPEN, param_start)
84+
+ p.tag(Tag::TOOL_ARG_NAME, param_p)
85+
+ param_name_value_sep
86+
+ p.schema_or_raw_string_until("tool-" + name + "-arg-" + param_name + "-schema", param_schema, param_end,
87+
schema_info, Tag::TOOL_ARG_STRING_VALUE, Tag::TOOL_ARG_JSON_VALUE, true)
88+
+ p.literal_tag(Tag::TOOL_ARG_CLOSE, param_end));
89+
switch (param_type) {
90+
case ParameterType::Required:
91+
args += arg;
92+
break;
93+
case ParameterType::Optional:
94+
args += p.optional(arg);
95+
break;
96+
case ParameterType::Additional:
97+
args += p.repeat(arg, 0, -1);
98+
break;
99+
default:
100+
throw std::runtime_error("Unhandled param type");
101+
}
102+
});
103+
104+
tool_call |= p.rule("tool-" + name,
105+
p.tag(Tag::TOOL_OPEN, tool_call_start)
106+
+ p.literal_tag(Tag::TOOL_NAME, name)
107+
+ tool_call_name_params_sep
108+
+ args
109+
+ p.tag(Tag::TOOL_CLOSE, tool_call_end));
110+
});
111+
112+
auto tool_calls =
113+
tool_calls_start
114+
+ tool_call + p.repeat(tool_call, 0, inputs.parallel_tool_calls ? -1 : 0)
115+
+ tool_calls_end;
81116

82117
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
83118
return reasoning << tool_calls;

common/chat-parsers/nemotron-v3.cpp

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,48 @@ common_chat_params common_chat_params_init_nemotron_v3_peg(const common_chat_tem
7676
};
7777
}
7878

79-
generic_tool_call_format format;
80-
format.tool_call_start = "<tool_call>" + p.space() + "<function=";
81-
format.tool_call_name_params_sep = ">" + p.space();
82-
format.tool_call_end = "</function>" + p.space() + "</tool_call>" + p.space();
83-
format.param_start = p.literal("<parameter=");
84-
format.param_name_value_sep = ">" + p.space();
85-
format.param_end = "\n</parameter>\n";
86-
auto tool_calls = build_generic_tool_calls_peg_parser(p, inputs, format);
79+
auto tool_call_start = "<tool_call>" + p.space() + "<function=";
80+
auto tool_call_name_params_sep = ">" + p.space();
81+
auto tool_call_end = "</function>" + p.space() + "</tool_call>" + p.space();
82+
auto param_start = p.literal("<parameter=");
83+
auto param_name_value_sep = ">" + p.space();
84+
auto param_end = "\n</parameter>\n";
85+
86+
auto tool_call = p.choice();
87+
foreach_function(inputs.tools, [&](const auto &, const auto & name, const json & parameters, const auto & schema_info) {
88+
auto args = p.sequence();
89+
foreach_parameter(p, parameters, [&](const std::string & param_name, const common_peg_parser & param_p, const json & param_schema, ParameterType param_type) {
90+
auto arg = p.rule("tool-" + name + "-arg-" + param_name,
91+
p.tag(Tag::TOOL_ARG_OPEN, param_start)
92+
+ p.tag(Tag::TOOL_ARG_NAME, param_p)
93+
+ param_name_value_sep
94+
+ p.schema_or_raw_string_until("tool-" + name + "-arg-" + param_name + "-schema", param_schema, param_end,
95+
schema_info, Tag::TOOL_ARG_STRING_VALUE, Tag::TOOL_ARG_JSON_VALUE, true)
96+
+ p.literal_tag(Tag::TOOL_ARG_CLOSE, param_end));
97+
switch (param_type) {
98+
case ParameterType::Required:
99+
args += arg;
100+
break;
101+
case ParameterType::Optional:
102+
args += p.optional(arg);
103+
break;
104+
case ParameterType::Additional:
105+
args += p.repeat(arg, 0, -1);
106+
break;
107+
default:
108+
throw std::runtime_error("Unhandled param type");
109+
}
110+
});
111+
112+
tool_call |= p.rule("tool-" + name,
113+
p.tag(Tag::TOOL_OPEN, tool_call_start)
114+
+ p.literal_tag(Tag::TOOL_NAME, name)
115+
+ tool_call_name_params_sep
116+
+ args
117+
+ p.tag(Tag::TOOL_CLOSE, tool_call_end));
118+
});
119+
120+
auto tool_calls = tool_call + p.repeat(tool_call, 0, inputs.parallel_tool_calls ? -1 : 0);
87121

88122
auto stop_before = std::vector<std::string>{
89123
"\n<tool_call>", "\r\n<tool_call>", "<tool_call>",

common/chat-parsers/qwen3-coder-xml.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,48 @@ common_chat_params common_chat_params_init_qwen3_coder_xml_peg(const common_chat
6060
data.grammar_triggers.push_back({COMMON_GRAMMAR_TRIGGER_TYPE_WORD, "<tool_call>"});
6161
}
6262

63-
generic_tool_call_format format;
64-
format.tool_call_start = p.space() + "<tool_call>\n<function=";
65-
format.tool_call_name_params_sep = ">" + p.space();
66-
format.tool_call_end = "</function>" + p.space() + "</tool_call>";
67-
format.param_start = p.literal("<parameter=");
68-
format.param_name_value_sep = ">" + p.space();
69-
format.param_end = "\n</parameter>\n";
70-
format.allow_raw_string_param_value = true;
71-
auto tool_calls = build_generic_tool_calls_peg_parser(p, inputs, format);
63+
auto tool_call_start = p.space() + "<tool_call>\n<function=";
64+
auto tool_call_name_params_sep = ">" + p.space();
65+
auto tool_call_end = "</function>" + p.space() + "</tool_call>";
66+
auto param_start = p.literal("<parameter=");
67+
auto param_name_value_sep = ">" + p.space();
68+
auto param_end = "\n</parameter>\n";
69+
70+
auto tool_call = p.choice();
71+
foreach_function(inputs.tools, [&](const auto &, const auto & name, const json & parameters, const auto & schema_info) {
72+
auto args = p.sequence();
73+
foreach_parameter(p, parameters, [&](const std::string & param_name, const common_peg_parser & param_p, const json & param_schema, ParameterType param_type) {
74+
auto arg = p.rule("tool-" + name + "-arg-" + param_name,
75+
p.tag(Tag::TOOL_ARG_OPEN, param_start)
76+
+ p.tag(Tag::TOOL_ARG_NAME, param_p)
77+
+ param_name_value_sep
78+
+ p.schema_or_raw_string_until("tool-" + name + "-arg-" + param_name + "-schema", param_schema, param_end,
79+
schema_info, Tag::TOOL_ARG_STRING_VALUE, Tag::TOOL_ARG_JSON_VALUE, true)
80+
+ p.literal_tag(Tag::TOOL_ARG_CLOSE, param_end));
81+
switch (param_type) {
82+
case ParameterType::Required:
83+
args += arg;
84+
break;
85+
case ParameterType::Optional:
86+
args += p.optional(arg);
87+
break;
88+
case ParameterType::Additional:
89+
args += p.repeat(arg, 0, -1);
90+
break;
91+
default:
92+
throw std::runtime_error("Unhandled param type");
93+
}
94+
});
95+
96+
tool_call |= p.rule("tool-" + name,
97+
p.tag(Tag::TOOL_OPEN, tool_call_start)
98+
+ p.literal_tag(Tag::TOOL_NAME, name)
99+
+ tool_call_name_params_sep
100+
+ args
101+
+ p.tag(Tag::TOOL_CLOSE, tool_call_end));
102+
});
103+
104+
auto tool_calls = tool_call + p.repeat(tool_call, 0, inputs.parallel_tool_calls ? -1 : 0);
72105

73106
if (inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED) {
74107
return tool_calls + consume_end_block();

0 commit comments

Comments
 (0)