char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
acecd5603
char/aliceai-t5-moe
1#include "parsers.h" 2 3common_chat_params common_chat_params_init_ministral_3 (const common_chat_template & tmpl , 4const autoparser::generation_params & inputs ) { 5common_chat_params data ; 6 7// Build up messages to follow the format: https://huggingface.co/mistralai/Ministral-3-14B-Reasoning-2512/blob/main/chat_template.jinja 8auto adjusted_messages = json::array (); 9for (const auto & msg :inputs .messages ) { 10auto role = msg .value ("role" ,"" ); 11if (role != "system" && role != "assistant" ) { 12// Only adjust system and assistant messages. Interestingly, the system message may contain thinking. 13adjusted_messages .push_back (msg ); 14continue ; 15 } 16 17auto content = json::array (); 18 19// If message contains `reasoning_content`, add it as a block of type `thinking` 20if (msg .contains ("reasoning_content" )&& msg .at ("reasoning_content" ).is_string ()) { 21content .push_back ({ 22 {"type" ,"thinking" }, 23 {"thinking" ,msg .at ("reasoning_content" ).get < std::string > () }, 24 }); 25 } 26 27// If message contains `content`, add it as a block of type `text` 28if (msg .contains ("content" )) { 29if (msg .at ("content" ).is_string ()) { 30content .push_back ({ 31 {"type" ,"text" }, 32 {"text" ,msg .at ("content" ).get < std::string > () }, 33 }); 34 }else if (msg .at ("content" ).is_array ()) { 35auto blocks = msg .at ("content" ); 36content .insert (blocks ); 37 } 38 } 39 40auto adjusted = msg ; 41adjusted ["content" ]= content ; 42adjusted .erase ("reasoning_content" ); 43adjusted_messages .push_back (adjusted ); 44 } 45 46auto has_tools = inputs .tools .is_array ()&& !inputs .tools .empty (); 47auto has_response_format = inputs .json_schema .is_object ()&& !inputs .json_schema .empty (); 48auto extract_reasoning = inputs .reasoning_format != COMMON_REASONING_FORMAT_NONE ; 49auto include_grammar = true; 50 51data .supports_thinking = true; 52data .thinking_start_tag = "[THINK]" ; 53data .thinking_end_tags = {"[/THINK]" }; 54data .prompt = common_chat_template_direct_apply_impl (tmpl ,inputs ,/* messages_override = */ adjusted_messages ); 55data .generation_prompt = common_chat_template_generation_prompt_impl (tmpl ,inputs ,/* messages_override = */ adjusted_messages ); 56data .format = COMMON_CHAT_FORMAT_PEG_NATIVE ; 57data .preserved_tokens = { 58"[THINK]" , 59"[/THINK]" , 60"[TOOL_CALLS]" , 61"[ARGS]" , 62 }; 63 64if (inputs .has_continuation ()) { 65const auto & msg = inputs .continue_msg ; 66 67data .generation_prompt = "[THINK]" + msg .reasoning_content ; 68if (inputs .continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT ) { 69data .generation_prompt += "[/THINK]" + msg .render_content (); 70 } 71 72data .prompt += data .generation_prompt ; 73 } 74 75auto parser = build_chat_peg_parser ([& ](common_chat_peg_builder & p ) { 76auto generation_prompt = p .eps (); 77auto reasoning = 78extract_reasoning ?p .optional ("[THINK]" + p .reasoning (p .until ("[/THINK]" ))+ "[/THINK]" ) :p .eps (); 79 80// Response format parser 81if (has_response_format ) { 82// Ministral wants to emit json surrounded by code fences 83return generation_prompt + (reasoning <<"```json" <<p .content (p .schema (p .json (),"response-format" ,inputs .json_schema )) <<"```" ); 84 } 85 86// Tool call parser 87if (has_tools && inputs .tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE ) { 88auto tool_choice = p .choice (); 89foreach_function (inputs .tools , [& ](const json & tool ) { 90const auto & function = tool .at ("function" ); 91 std::string name = function .at ("name" ); 92const auto schema = common_chat_tool_parameters (function ); 93 94tool_choice |= 95p .rule ("tool-" + name ,p .tool_open (p .tool_name (p .literal (name ))+ "[ARGS]" )+ 96p .tool_args (p .schema (p .json (),"tool-" + name + "-schema" ,schema ))); 97 }); 98 99auto min_calls = inputs .tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ?1 :0 ; 100auto max_calls = inputs .parallel_tool_calls ?-1 :1 ; 101auto tool_calls = p .trigger_rule ("tool-call" ,p .repeat ("[TOOL_CALLS]" + tool_choice ,min_calls ,max_calls )); 102 103return generation_prompt + (reasoning <<p .content (p .until ("[TOOL_CALLS]" )) <<tool_calls ); 104 } 105 106// Content only parser 107include_grammar = false; 108return generation_prompt + (reasoning <<p .content (p .rest ())); 109 }); 110 111data .parser = parser .save (); 112 113if (include_grammar ) { 114data .grammar_lazy = has_tools && inputs .tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO ; 115 116data .grammar = build_grammar ([& ](const common_grammar_builder & builder ) { 117parser .build_grammar (builder ,data .grammar_lazy ); 118 }); 119 120data .grammar_triggers = { 121 {COMMON_GRAMMAR_TRIGGER_TYPE_WORD ,"[TOOL_CALLS]" } 122 }; 123 } 124 125return data ; 126}