11#include " chat-auto-parser.h"
22#include " chat-peg-parser.h"
33#include " chat.h"
4+ #include " common.h"
45#include " json-schema-to-grammar.h"
56#include " nlohmann/json.hpp"
67
@@ -51,13 +52,15 @@ common_chat_params peg_generator::generate_parser(const common_chat_template &
5152 bool has_tools =
5253 autoparser.tools .format .mode != tool_format::NONE && inputs.tools .is_array () && !inputs.tools .empty ();
5354 std::string trigger_marker = !autoparser.tools .format .section_start .empty () ? autoparser.tools .format .section_start :
54- autoparser.tools .format .per_call_start ;
55- bool include_grammar =
56- has_tools && ((inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO && !trigger_marker.empty ()) ||
57- inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED );
55+ autoparser.tools .format .per_call_start ;
56+
57+ bool has_response_format = !inputs.json_schema .empty () && inputs.json_schema .is_object ();
58+ bool include_grammar = has_response_format || (has_tools &&
59+ ((inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO && !trigger_marker.empty ()) ||
60+ inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ));
5861
5962 if (include_grammar) {
60- data.grammar_lazy = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO ;
63+ data.grammar_lazy = !has_response_format && inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO ;
6164 data.grammar = build_grammar ([&](const common_grammar_builder & builder) {
6265 foreach_function (inputs.tools , [&](const json & tool) {
6366 const auto & function = tool.at (" function" );
@@ -68,7 +71,7 @@ common_chat_params peg_generator::generate_parser(const common_chat_template &
6871 });
6972
7073 // Set grammar triggers based on tool section markers (fall back to per-call markers)
71- if (data.grammar_lazy ) { // only do triggers on lazy grammar
74+ if (data.grammar_lazy ) {
7275 data.grammar_triggers = {
7376 { COMMON_GRAMMAR_TRIGGER_TYPE_WORD , trigger_marker }
7477 };
@@ -104,8 +107,11 @@ common_peg_arena autoparser::build_parser(const templates_params & inputs) const
104107 bool has_response_format = inputs.json_schema .is_object () && !inputs.json_schema .empty ();
105108
106109 if (has_response_format) {
107- return ctx.reasoning_parser + p.space () +
108- p.content (p.schema (p.json (), " response-format" , inputs.json_schema )) + p.end ();
110+ auto response_format = p.rule (" response-format" , p.content (p.schema (p.json (), " response-format-schema" , inputs.json_schema )));
111+ return ctx.reasoning_parser + p.space () + p.choice ({
112+ p.literal (" ```json" ) + p.space () + response_format + p.space () + p.literal (" ```" ),
113+ response_format
114+ }) + p.end ();
109115 }
110116
111117 if (has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE && jinja_caps.supports_tool_calls ) {
0 commit comments