@@ -175,6 +175,28 @@ static void foreach_function(const json & tools, const std::function<void(const
175175 }
176176}
177177
178+ static std::string apply (
179+ const common_chat_template & tmpl,
180+ const nlohmann::ordered_json & messages,
181+ const nlohmann::ordered_json & tools,
182+ bool add_generation_prompt,
183+ const nlohmann::ordered_json & extra_context = nlohmann::ordered_json())
184+ {
185+ minja::chat_template_inputs tmpl_inputs;
186+ tmpl_inputs.messages = messages;
187+ tmpl_inputs.tools = tools;
188+ tmpl_inputs.add_generation_prompt = add_generation_prompt;
189+ tmpl_inputs.extra_context = extra_context;
190+ // TODO: add flag to control date/time, if only for testing purposes.
191+ // tmpl_inputs.now = std::chrono::system_clock::now();
192+
193+ minja::chat_template_options tmpl_opts;
194+ tmpl_opts.use_bos_token = false ;
195+ tmpl_opts.use_eos_token = false ;
196+
197+ return tmpl.apply (tmpl_inputs, tmpl_opts);
198+ }
199+
178200static common_chat_params common_chat_params_init_generic (const common_chat_template & tmpl, const struct common_chat_inputs & inputs) {
179201 common_chat_params data;
180202
@@ -256,7 +278,7 @@ static common_chat_params common_chat_params_init_generic(const common_chat_temp
256278 inputs.messages ,
257279 " Respond in JSON format, either with `tool_call` (a request to call tools) or with `response` reply to the user's request" );
258280
259- data.prompt = tmpl. apply (tweaked_messages, inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
281+ data.prompt = apply (tmpl, tweaked_messages, inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
260282 data.format = COMMON_CHAT_FORMAT_GENERIC;
261283 return data;
262284}
@@ -322,7 +344,7 @@ static common_chat_params common_chat_params_init_mistral_nemo(const common_chat
322344 builder.add_rule (" root" , " \" [TOOL_CALLS]\" " + builder.add_schema (" tool_calls" , schema));
323345 }, grammar_options);
324346 data.grammar_triggers .push_back ({" [TOOL_CALLS]" , /* .at_start = */ true });
325- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
347+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
326348 data.format = COMMON_CHAT_FORMAT_MISTRAL_NEMO;
327349 return data;
328350}
@@ -372,7 +394,7 @@ static common_chat_params common_chat_params_init_command_r7b(const common_chat_
372394 " <|END_THINKING|>" ,
373395 " <|END_ACTION|>" ,
374396 };
375- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
397+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
376398 data.format = COMMON_CHAT_FORMAT_COMMAND_R7B;
377399 return data;
378400}
@@ -489,7 +511,7 @@ static common_chat_params common_chat_params_init_llama_3_1_tool_calls(const com
489511 builder.add_rule (" root" , string_join (tool_rules, " | " ));
490512 }, grammar_options);
491513 data.additional_stops .push_back (" <|eom_id|>" );
492- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt , {
514+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt , {
493515 {" tools_in_user_message" , false },
494516 {" builtin_tools" , builtin_tools.empty () ? json () : builtin_tools},
495517 });
@@ -568,7 +590,7 @@ static common_chat_params common_chat_params_init_deepseek_r1(const common_chat_
568590 " <|tool▁call▁end|>" ,
569591 };
570592 }, grammar_options);
571- auto prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
593+ auto prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
572594
573595 // Hacks to fix the official (broken) prompt.
574596 // It is advisable to use --chat-template-file models/templates/llama-cpp-deepseek-r1.jinja instead,
@@ -614,10 +636,10 @@ static common_chat_msg common_chat_parse_deepseek_r1(const std::string & input)
614636static common_chat_params common_chat_params_init_firefunction_v2 (const common_chat_template & tmpl, const struct common_chat_inputs & inputs) {
615637 fprintf (stderr, " %s\n " , __func__);
616638 common_chat_params data;
617- data.prompt = tmpl. apply (inputs.messages , /* tools= */ nullptr , inputs.add_generation_prompt , {
639+ data.prompt = apply (tmpl, inputs.messages , /* tools= */ nullptr , inputs.add_generation_prompt , {
618640 {" datetime" , " Jan 29 2025 13:00:00 GMT" },
619641 {" functions" , json (inputs.tools .empty () ? " " : inputs.tools .dump (2 ))},
620- }, /* adjust_inputs= */ false );
642+ });
621643 if (!inputs.tools .is_null () && !inputs.tools .empty ()) {
622644 data.grammar_lazy = inputs.tool_choice != " required" ;
623645 data.grammar = build_grammar ([&](const common_grammar_builder & builder) {
@@ -661,7 +683,7 @@ static common_chat_params common_chat_params_init_functionary_v3_2(const common_
661683 // >>>all\nlet's call functions>>>fn1\n{"arg1": 1...}\n>>>fn2\n{"arg1": 1...}...
662684 // Using ">>>f1\n", ">>>f2\n"... as trigger words for the grammar
663685 common_chat_params data;
664- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
686+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
665687 data.format = COMMON_CHAT_FORMAT_FUNCTIONARY_V3_2;
666688 if (!inputs.tools .is_null () && !inputs.tools .empty ()) {
667689 data.grammar_lazy = inputs.tool_choice != " required" ;
@@ -788,7 +810,7 @@ static common_chat_params common_chat_params_init_functionary_v3_1_llama_3_1(con
788810 data.grammar_triggers .push_back ({" <function=" , /* .at_start = */ false });
789811 }, grammar_options);
790812
791- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
813+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
792814 // TODO: if (has_raw_python)
793815 data.format = COMMON_CHAT_FORMAT_FUNCTIONARY_V3_1_LLAMA_3_1;
794816 return data;
@@ -843,7 +865,7 @@ static common_chat_params common_chat_params_init_hermes_2_pro(const common_chat
843865 data.preserved_tokens = { " </tool_call>" };
844866 }, grammar_options);
845867
846- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
868+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
847869 data.format = COMMON_CHAT_FORMAT_HERMES_2_PRO;
848870 return data;
849871}
@@ -904,7 +926,7 @@ static common_chat_msg common_chat_parse_hermes_2_pro(const std::string & input)
904926
905927static common_chat_params common_chat_params_init_without_tools (const common_chat_template & tmpl, const struct common_chat_inputs & inputs) {
906928 common_chat_params data;
907- data.prompt = tmpl. apply (inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
929+ data.prompt = apply (tmpl, inputs.messages , inputs.tools .empty () ? json () : inputs.tools , inputs.add_generation_prompt );
908930 data.format = COMMON_CHAT_FORMAT_CONTENT_ONLY;
909931 data.grammar_lazy = false ;
910932 if (!inputs.json_schema .is_null ()) {
0 commit comments