char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
acecd5603
char/aliceai-t5-moe
1#include "parsers.h" 2 3// LFM2 format detection: template uses <|tool_list_start|>[...]<|tool_list_end|> around the tool list 4// and <|tool_call_start|>[...]<|tool_call_end|> around each tool call 5bool is_lfm2_template (const std::string & src ) { 6return src .find ("<|tool_list_start|>" )!= std::string::npos && 7src .find ("<|tool_list_end|>" )!= std::string::npos ; 8} 9 10// LFM2/LFM2.5 parser. Tool calls are almost Python-style and parallel-capable 11// (except dotted names and JSON literals true/false/null). 12// Always wrapped in <|tool_call_start|>[name(args)]<|tool_call_end|> with optional <think> reasoning. 13// tool_list_tokens preserves LFM2 system tool-list markers. 14common_chat_params common_chat_params_init_lfm2 (const common_chat_template & tmpl , 15const autoparser::generation_params & inputs , 16bool tool_list_tokens ) { 17common_chat_params data ; 18 19const std::string TOOL_CALL_START = "<|tool_call_start|>" ; 20const std::string TOOL_CALL_END = "<|tool_call_end|>" ; 21const std::string TOOL_LIST_START = "<|tool_list_start|>" ; 22const std::string TOOL_LIST_END = "<|tool_list_end|>" ; 23const std::string THINK_START = "<think>" ; 24const std::string THINK_END = "</think>" ; 25const std::string GEN_PROMPT = "<|im_start|>assistant\n" ; 26 27// Copy reasoning to the "thinking" field the template expects 28auto adjusted_messages = json::array (); 29for (auto msg :inputs .messages ) { 30if (msg .contains ("reasoning_content" )&& msg .at ("reasoning_content" ).is_string ()) { 31msg ["thinking" ]= msg .at ("reasoning_content" ); 32 } 33adjusted_messages .push_back (msg ); 34 } 35 36data .prompt = common_chat_template_direct_apply_impl (tmpl ,inputs ,adjusted_messages ); 37data .generation_prompt = common_chat_template_generation_prompt_impl (tmpl ,inputs ,adjusted_messages ); 38data .format = COMMON_CHAT_FORMAT_PEG_NATIVE ; 39data .supports_thinking = true; 40data .preserved_tokens = {TOOL_CALL_START ,TOOL_CALL_END ,THINK_START ,THINK_END }; 41if (tool_list_tokens ) { 42data .preserved_tokens .push_back (TOOL_LIST_START ); 43data .preserved_tokens .push_back (TOOL_LIST_END ); 44 } 45 46data .thinking_start_tag = THINK_START ; 47data .thinking_end_tags = {THINK_END }; 48 49auto has_tools = inputs .tools .is_array ()&& !inputs .tools .empty (); 50auto has_response_format = !inputs .json_schema .is_null ()&& inputs .json_schema .is_object (); 51// Gate by reasoning format and whether the template supports <think> 52auto extract_reasoning = inputs .reasoning_format != COMMON_REASONING_FORMAT_NONE && 53tmpl .source ().find (THINK_START )!= std::string::npos ; 54auto include_grammar = has_response_format || (has_tools && inputs .tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE ); 55 56if (inputs .has_continuation ()) { 57const auto & msg = inputs .continue_msg ; 58 59data .generation_prompt = GEN_PROMPT + THINK_START + msg .reasoning_content ; 60if (inputs .continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT ) { 61data .generation_prompt += THINK_END + msg .render_content (); 62 } 63 64data .prompt += data .generation_prompt ; 65 } 66 67auto parser = build_chat_peg_parser ([& ](common_chat_peg_builder & p ) { 68auto generation_prompt = p .literal (GEN_PROMPT ); 69auto end = p .end (); 70 71auto reasoning = p .eps (); 72if (extract_reasoning ) { 73reasoning = p .optional (THINK_START + p .reasoning (p .until (THINK_END ))+ THINK_END ); 74 } 75 76if (!has_tools || inputs .tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE ) { 77if (has_response_format ) { 78auto response_format = p .content (p .schema (p .json (),"response-format-schema" ,inputs .json_schema )); 79return generation_prompt + reasoning + response_format + end ; 80 } 81return generation_prompt + reasoning + p .content (p .rest ())+ end ; 82 } 83auto tool_calls = p .rule ("tool-calls" , 84p .trigger_rule ("tool-call" , 85p .literal (TOOL_CALL_START )+ 86p .python_style_tool_calls (inputs .tools ,inputs .parallel_tool_calls ,/* allow_json_literals = */ true)+ 87p .literal (TOOL_CALL_END ) 88 ) 89 ); 90 91auto content = p .content (p .until (TOOL_CALL_START )); 92 93return generation_prompt + reasoning + content + tool_calls + end ; 94 }); 95 96data .parser = parser .save (); 97 98if (include_grammar ) { 99data .grammar_lazy = !(has_response_format || (has_tools && inputs .tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED )); 100data .grammar = build_grammar ([& ](const common_grammar_builder & builder ) { 101parser .build_grammar (builder ,data .grammar_lazy ); 102 }); 103 104data .grammar_triggers = { 105 {COMMON_GRAMMAR_TRIGGER_TYPE_WORD ,TOOL_CALL_START } 106 }; 107 } 108 109return data ; 110}