char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
4a08fa297
char/aliceai-t5-moe
1#include <string> 2#include <utility> 3#include <vector> 4#include <sstream> 5#include <regex> 6#include <iostream> 7#include <fstream> 8#include <filesystem> 9 10#include "json.h" 11 12#undef NDEBUG 13#include <cassert> 14 15#include "llama.h" 16#include "common.h" 17#include "chat.h" 18#include "jinja/runtime.h" 19#include "jinja/parser.h" 20#include "jinja/lexer.h" 21#include "jinja/caps.h" 22 23using json = common_json ; 24 25static int main_automated_tests (void ); 26 27static void run_multiple (const std::string & dir_path ,bool stop_on_first_failure ,const json & input ,bool use_common = false); 28static void run_single (const std::string & contents ,json input ,bool use_common = false,bool dump_prog = false,const std::string & output_path = "" ); 29 30static std::string HELP = R"( 31Test the Jinja engine by rendering chat templates and comparing the output against expected results. 32 33Usage: test-chat-template [OPTIONS] PATH_TO_TEMPLATE 34Options: 35-h, --help Show this help message and exit. 36--with-tools Add a tool and a tool call to the default JSON input 37--json <path> Path to the JSON input file. 38--stop-on-first-fail Stop testing on the first failure (default: false). 39--no-common Use direct Jinja engine instead of common chat templates (default: use common). 40--dump-prog Dump the parsed program for debugging (only for single template runs). 41--output <path> Path to output results (only for single template runs). 42If PATH_TO_TEMPLATE is a file, runs that single template. 43If PATH_TO_TEMPLATE is a directory, runs all .jinja files in that directory. 44If PATH_TO_TEMPLATE is omitted, runs automated tests (default CI mode). 45)" ; 46 47static std::string DEFAULT_JSON = R"({ 48"messages": [ 49{ 50"role": "user", 51"content": "Hello, how are you?" 52}, 53{ 54"role": "assistant", 55"content": "I am fine, thank you!" 56} 57], 58"bos_token": "<s>", 59"eos_token": "</s>", 60"add_generation_prompt": true 61})" ; 62 63static std::string DEFAULT_JSON_WITH_TOOLS = R"({ 64"messages": [ 65{ 66"role": "user", 67"content": "Hello, how are you?" 68}, 69{ 70"role": "assistant", 71"content": "I am fine, thank you!" 72}, 73{ 74"role": "user", 75"content": "Call a tool!" 76}, 77{ 78"role": "assistant", 79"tool_calls": [ 80{ 81"id": "call00001", 82"type": "function", 83"function": { 84"name": "test", 85"arguments": { "arg": "hello" } 86} 87} 88] 89} 90], 91"tools": [ 92{ 93"type": "function", 94"function": { 95"name": "test", 96"description": "Test", 97"parameters": { 98"type": "object", 99"properties": { 100"arg": { 101"type": "string" 102} 103} 104}, 105"required": ["arg"] 106} 107} 108], 109"bos_token": "<s>", 110"eos_token": "</s>", 111"add_generation_prompt": true 112})" ; 113 114 115int main (int argc ,char ** argv ) { 116 std::vector < std::string > args (argv ,argv + argc ); 117 118 std::string tmpl_path ; 119 std::string json_path ; 120 std::string output_path ; 121 std::string & json_to_use = DEFAULT_JSON ; 122bool stop_on_first_fail = false; 123bool use_common = true; 124bool dump_prog = false; 125 126for (size_t i = 1 ;i < args .size ();i ++ ) { 127if (args [i ]== "--help" || args [i ]== "-h" ) { 128 std::cout <<HELP <<"\n" ; 129return 0 ; 130 } 131if (args [i ]== "--json" && i + 1 < args .size ()) { 132json_path = args [i + 1 ]; 133i ++ ; 134 }else if (args [i ]== "--with-tools" ) { 135json_to_use = DEFAULT_JSON_WITH_TOOLS ; 136 }else if (args [i ]== "--stop-on-first-fail" ) { 137stop_on_first_fail = true; 138 }else if (args [i ]== "--output" && i + 1 < args .size ()) { 139output_path = args [i + 1 ]; 140i ++ ; 141 }else if (args [i ]== "--no-common" ) { 142use_common = false; 143 }else if (args [i ]== "--dump-prog" ) { 144dump_prog = true; 145 }else if (tmpl_path .empty ()) { 146tmpl_path = args [i ]; 147 }else { 148 std::cerr <<"Unknown argument: " <<args [i ] <<"\n" ; 149 std::cout <<HELP <<"\n" ; 150return 1 ; 151 } 152 } 153 154if (tmpl_path .empty ()) { 155return main_automated_tests (); 156 } 157 158json input_json ; 159if (!json_path .empty ()) { 160 std::ifstream json_file (json_path ); 161if (!json_file ) { 162 std::cerr <<"Error: Could not open JSON file: " <<json_path <<"\n" ; 163return 1 ; 164 } 165 std::string content = std::string ( 166 std::istreambuf_iterator < char > (json_file ), 167 std::istreambuf_iterator < char > ()); 168input_json = json::parse (content ); 169 }else { 170input_json = json::parse (json_to_use ); 171 } 172 173 std::filesystem::path p (tmpl_path ); 174if (std::filesystem::is_directory (p )) { 175run_multiple (tmpl_path ,stop_on_first_fail ,input_json ,use_common ); 176 }else if (std::filesystem::is_regular_file (p )) { 177 std::ifstream infile (tmpl_path ); 178 std::string contents = std::string ( 179 std::istreambuf_iterator < char > (infile ), 180 std::istreambuf_iterator < char > ()); 181run_single (contents ,input_json ,use_common ,dump_prog ,output_path ); 182 }else { 183 std::cerr <<"Error: PATH_TO_TEMPLATE is not a valid file or directory: " <<tmpl_path <<"\n" ; 184return 1 ; 185 } 186 187return 0 ; 188} 189 190void run_multiple (const std::string & dir_path ,bool stop_on_first_fail ,const json & input ,bool use_common ) { 191 std::vector < std::string > failed_tests ; 192 193// list all files in models/templates/ and run each 194size_t test_count = 0 ; 195 196for (const auto & entry : std::filesystem::directory_iterator (dir_path )) { 197// only process .jinja files 198if (entry .path ().extension ()== ".jinja" && entry .is_regular_file ()) { 199test_count ++ ; 200 std::cout <<"\n\n=== RUNNING TEMPLATE FILE: " <<entry .path ().string () <<" ===\n" ; 201 std::ifstream infile (entry .path ()); 202 std::string contents ((std::istreambuf_iterator < char > (infile )), std::istreambuf_iterator < char > ()); 203try { 204run_single (contents ,input ,use_common ); 205 }catch (const std::exception & e ) { 206 std::cout <<"Exception: " <<e .what () <<"\n" ; 207 std::cout <<"=== ERROR WITH TEMPLATE FILE: " <<entry .path ().string () <<" ===\n" ; 208failed_tests .push_back (entry .path ().string ()); 209if (stop_on_first_fail ) { 210break ; 211 } 212 } 213 } 214 } 215 216 std::cout <<"\n\n=== TEST SUMMARY ===\n" ; 217 std::cout <<"Total tests run: " <<test_count <<"\n" ; 218 std::cout <<"Total failed tests: " <<failed_tests .size () <<"\n" ; 219for (const auto & test :failed_tests ) { 220 std::cout <<"FAILED TEST: " <<test <<"\n" ; 221 } 222} 223 224 225static std::string normalize_newlines (const std::string & s ) { 226#ifdef _WIN32 227static const std::regex nl_regex ("\r\n" ); 228return std::regex_replace (s ,nl_regex ,"\n" ); 229#else 230return s ; 231#endif 232} 233 234 235static std::string format_using_common ( 236const std::string & template_str , 237const std::string & bos_token , 238const std::string & eos_token , 239 std::vector < common_chat_msg > & messages , 240 std::vector < common_chat_tool > tools = {}) { 241auto tmpls = common_chat_templates_init ( /* model= */ nullptr , template_str , bos_token , eos_token ); 242common_chat_templates_inputs inputs ; 243inputs . use_jinja = true; 244inputs . messages = messages ; 245inputs . tools = std:: move ( tools ); 246inputs . add_generation_prompt = true; 247auto output = common_chat_templates_apply ( tmpls . get (), inputs ). prompt ; 248output = normalize_newlines ( output ); 249return output ; 250} 251 252 253// skip libcommon, use direct jinja engine 254static jinja::value_string format_using_direct_engine ( 255const std::string & template_str , 256json & input ) { 257// lexing 258jinja::lexer lexer ; 259auto lexer_res = lexer . tokenize ( template_str ); 260 261// compile to AST 262jinja::program ast = jinja:: parse_from_tokens ( lexer_res ); 263 264// check caps for workarounds 265jinja:: caps_get ( ast ); 266 267std:: cout << "\n=== RUN ===\n" ; 268jinja::context ctx (template_str); 269 270jinja:: global_from_json ( ctx , input , true); 271 272jinja::runtime runtime (ctx); 273const jinja::value results = runtime . execute ( ast ); 274auto parts = jinja::runtime:: gather_string_parts ( results ); 275 276std:: cout << "\n=== RESULTS ===\n" ; 277for ( const auto & part : parts -> as_string (). parts ) { 278std:: cout << ( part . is_input ? "DATA" : "TMPL" ) << ": " << part . val << "\n" ; 279} 280 281return parts ; 282} 283 284 285void run_single ( const std::string & contents , json input , bool use_common , bool dump_prog , const std::string & output_path ) { 286jinja:: enable_debug (true); 287 288jinja::value_string output_parts ; 289 290if ( dump_prog ) { 291jinja::lexer lexer ; 292auto lexer_res = lexer . tokenize ( contents ); 293jinja::program ast = jinja:: parse_from_tokens ( lexer_res ); 294std::string prog_dump = jinja::runtime:: debug_dump_program ( ast , contents ); 295std:: cout << "\n=== DUMPED PROGRAM ===\n" ; 296std:: cout << prog_dump << "\n" ; 297return ; 298} 299 300if ( use_common ) { 301std::string bos_token = "<s>" ; 302std::string eos_token = "</s>" ; 303if ( input . contains ( "bos_token" )) { 304bos_token = input [ "bos_token" ]. get < std::string > (); 305} 306if ( input . contains ( "eos_token" )) { 307eos_token = input [ "eos_token" ]. get < std::string > (); 308} 309common_json msgs_json = input [ "messages" ]; 310common_json tools_json = input [ "tools" ]; 311auto messages = common_chat_msgs_parse_oaicompat ( msgs_json ); 312auto tools = common_chat_tools_parse_oaicompat ( tools_json ); 313auto output = format_using_common ( contents , bos_token , eos_token , messages , tools ); 314std:: cout << "\n=== OUTPUT ===\n" ; 315std:: cout << output << "\n" ; 316output_parts = jinja:: mk_val < jinja::value_string > ( output ); 317 318} else { 319output_parts = format_using_direct_engine ( contents , input ); 320std:: cout << "\n=== OUTPUT ===\n" ; 321std:: cout << output_parts -> as_string (). str () << "\n" ; 322} 323 324if (! output_path . empty ()) { 325std::ofstream outfile (output_path); 326if (! outfile ) { 327throw std:: runtime_error ( "Could not open output file: " + output_path ); 328} 329outfile << output_parts -> as_string (). str (); 330outfile . close (); 331std:: cout << "\n=== OUTPUT WRITTEN TO " << output_path << " ===\n" ; 332} 333} 334 335 336 337 338 339// 340// Automated tests for chat templates 341// 342 343#define U8C ( x ) (const char*)(u8##x) 344 345static common_chat_msg simple_msg ( const std::string & role , const std::string & content ) { 346common_chat_msg msg ; 347msg . role = role ; 348msg . content = content ; 349return msg ; 350} 351 352int main_automated_tests (void) { 353// jinja::enable_debug(true); 354 355std::vector < llama_chat_message > conversation { 356{ "system" , "You are a helpful assistant" }, 357{ "user" , "Hello" }, 358{ "assistant" , "Hi there" }, 359{ "user" , "Who are you" }, 360{ "assistant" , " I am an assistant " }, 361{ "user" , "Another question" }, 362}; 363 364// std::string wrong = /* .template_str= */ u8"[gMASK]<sop>{% for item in messages %}{% if item['tools'] is defined %}<|system|>\n你是一个名为 ChatGLM 的人工智能助手。你是基于智谱AI训练的语言模型 GLM-4 模型开发的,你的任务是针对用户的问题和要求提供适当的答复和支持。\n\n# 可用工具{% set tools = item['tools'] %}{% for tool in tools %}{% if tool['type'] == 'function' %}\n\n## {{ tool['function']['name'] }}\n\n{{ tool['function'] | tojson(indent=4) }}\n......{% endif %}{% endfor %}{% endif %}{% if item['content'] %}<|{{ item['role'] }}|>{{ item['metadata'] }}\n{{ item['content'] }}{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>{% endif %}"; 365struct TestCase { 366std::string name ; 367std::string template_str ; 368std::string expected_output ; 369std::string expected_output_jinja ; 370std::string bos_token = "" ; 371std::string eos_token = "" ; 372bool supported_with_jinja = true; 373std::vector < llama_chat_message > extra_conversation = {}; 374}; 375std::vector < TestCase > test_cases { 376{ 377/* .name= */ "teknium/OpenHermes-2.5-Mistral-7B" , 378/* .template_str= */ "{% for message in messages %}{{'<|im_start|>' + message['role'] + '\\n' + message['content'] + '<|im_end|>' + '\\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\\n' }}{% endif %}" , 379/* .expected_output= */ "<|im_start|>system\nYou are a helpful assistant<|im_end|>\n<|im_start|>user\nHello<|im_end|>\n<|im_start|>assistant\nHi there<|im_end|>\n<|im_start|>user\nWho are you<|im_end|>\n<|im_start|>assistant\n I am an assistant <|im_end|>\n<|im_start|>user\nAnother question<|im_end|>\n<|im_start|>assistant\n" , 380/* .expected_output_jinja= */ "" , 381/* .bos_token= */ "" , 382/* .eos_token= */ "" , 383}, 384{ 385/* .name= */ "mistralai/Mistral-7B-Instruct-v0.2 (NOTE: Old pre-v1 without a system prompt)" , 386/* .template_str= */ "{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + ' [/INST]' }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token}}{% else %}{{ raise_exception('Only user and assistant roles are supported!') }}{% endif %}{% endfor %}" , 387/* .expected_output= */ "[INST] You are a helpful assistant\nHello [/INST]Hi there</s>[INST] Who are you [/INST] I am an assistant </s>[INST] Another question [/INST]" , 388/* .expected_output_jinja= */ "" , 389/* .bos_token= */ "" , 390/* .eos_token= */ "</s>" , 391}, 392{ 393/* .name= */ "TheBloke/FusionNet_34Bx2_MoE-AWQ" , 394/* .template_str= */ "{%- for idx in range(0, messages|length) -%}\n{%- if messages[idx]['role'] == 'user' -%}\n{%- if idx > 1 -%}\n{{- bos_token + '[INST] ' + messages[idx]['content'] + ' [/INST]' -}}\n{%- else -%}\n{{- messages[idx]['content'] + ' [/INST]' -}}\n{%- endif -%}\n{% elif messages[idx]['role'] == 'system' %}\n{{- '[INST] <<SYS>>\\n' + messages[idx]['content'] + '\\n<</SYS>>\\n\\n' -}}\n{%- elif messages[idx]['role'] == 'assistant' -%}\n{{- ' ' + messages[idx]['content'] + ' ' + eos_token -}}\n{% endif %}\n{% endfor %}" , 395/* .expected_output= */ "[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST]Hi there</s><s>[INST] Who are you [/INST] I am an assistant </s><s>[INST] Another question [/INST]" , 396/* .expected_output_jinja= */ "[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST] Hi there </s><s>[INST] Who are you [/INST] I am an assistant </s><s>[INST] Another question [/INST]" , 397/* .bos_token= */ "<s>" , 398/* .eos_token= */ "</s>" , 399}, 400{ 401/* .name= */ "bofenghuang/vigogne-2-70b-chat" , 402/* .template_str= */ "{{ bos_token }}{% if messages[0]['role'] == 'system' %}{% set loop_messages = messages[1:] %}{% set system_message = messages[0]['content'] %}{% elif true == true and not '<<SYS>>' in messages[0]['content'] %}{% set loop_messages = messages %}{% set system_message = 'Vous êtes Vigogne, un assistant IA créé par Zaion Lab. Vous suivez extrêmement bien les instructions. Aidez autant que vous le pouvez.' %}{% else %}{% set loop_messages = messages %}{% set system_message = false %}{% endif %}{% for message in loop_messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if loop.index0 == 0 and system_message != false %}{% set content = '<<SYS>>\\n' + system_message + '\\n<</SYS>>\\n\\n' + message['content'] %}{% else %}{% set content = message['content'] %}{% endif %}{% if message['role'] == 'user' %}{{ '[INST] ' + content.strip() + ' [/INST]' }}{% elif message['role'] == 'system' %}{{ '<<SYS>>\\n' + content.strip() + '\\n<</SYS>>\\n\\n' }}{% elif message['role'] == 'assistant' %}{{ ' ' + content.strip() + ' ' + eos_token }}{% endif %}{% endfor %}" , 403/* .expected_output= */ "[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST]Hi there</s>[INST] Who are you [/INST]I am an assistant</s>[INST] Another question [/INST]" , 404/* .expected_output_jinja= */ "[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST] Hi there </s>[INST] Who are you [/INST] I am an assistant </s>[INST] Another question [/INST]" , 405/* .bos_token= */ "" , 406/* .eos_token= */ "</s>" , 407}, 408{ 409/* .name= */ "mlabonne/AlphaMonarch-7B" , 410/* .template_str= */ "{% for message in messages %}{{bos_token + message['role'] + '\\n' + message['content'] + eos_token + '\\n'}}{% endfor %}{% if add_generation_prompt %}{{ bos_token + 'assistant\\n' }}{% endif %}" , 411/* .expected_output= */ "system\nYou are a helpful assistant</s>\n<s>user\nHello</s>\n<s>assistant\nHi there</s>\n<s>user\nWho are you</s>\n<s>assistant\n I am an assistant </s>\n<s>user\nAnother question</s>\n<s>assistant\n" , 412/* .expected_output_jinja= */ "<s>system\nYou are a helpful assistant</s>\n<s>user\nHello</s>\n<s>assistant\nHi there</s>\n<s>user\nWho are you</s>\n<s>assistant\n I am an assistant </s>\n<s>user\nAnother question</s>\n<s>assistant\n" , 413/* .bos_token= */ "<s>" , 414/* .eos_token= */ "</s>" , 415}, 416{ 417/* .name= */ "google/gemma-7b-it" , 418/* .template_str= */ "{% if messages[0]['role'] == 'system' %}{{ raise_exception('System role not supported') }}{% endif %}{% for message in messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% if (message['role'] == 'assistant') %}{% set role = 'model' %}{% else %}{% set role = message['role'] %}{% endif %}{{ '<start_of_turn>' + role + '\\n' + message['content'] | trim + '<end_of_turn>\\n' }}{% endfor %}{% if add_generation_prompt %}{{'<start_of_turn>model\\n'}}{% endif %}" , 419/* .expected_output= */ "<start_of_turn>user\nYou are a helpful assistant\n\nHello<end_of_turn>\n<start_of_turn>model\nHi there<end_of_turn>\n<start_of_turn>user\nWho are you<end_of_turn>\n<start_of_turn>model\nI am an assistant<end_of_turn>\n<start_of_turn>user\nAnother question<end_of_turn>\n<start_of_turn>model\n" , 420/* .expected_output_jinja= */ "<start_of_turn>user\nYou are a helpful assistant\nHello<end_of_turn>\n<start_of_turn>model\nHi there<end_of_turn>\n<start_of_turn>user\nWho are you<end_of_turn>\n<start_of_turn>model\nI am an assistant<end_of_turn>\n<start_of_turn>user\nAnother question<end_of_turn>\n<start_of_turn>model\n" , 421}, 422{ 423/* .name= */ "OrionStarAI/Orion-14B-Chat" , 424/* .template_str= */ "{% for message in messages %}{% if loop.first %}{{ bos_token }}{% endif %}{% if message['role'] == 'user' %}{{ 'Human: ' + message['content'] + '\\n\\nAssistant: ' + eos_token }}{% elif message['role'] == 'assistant' %}{{ message['content'] + eos_token }}{% endif %}{% endfor %}" , 425/* .expected_output= */ "Human: You are a helpful assistant\n\nHello\n\nAssistant: </s>Hi there</s>Human: Who are you\n\nAssistant: </s> I am an assistant </s>Human: Another question\n\nAssistant: </s>" , 426/* .expected_output_jinja= */ "Human: You are a helpful assistant\nHello\n\nAssistant: </s>Hi there</s>Human: Who are you\n\nAssistant: </s> I am an assistant </s>Human: Another question\n\nAssistant: </s>" , 427/* .bos_token= */ "" , 428/* .eos_token= */ "</s>" , 429}, 430{ 431/* .name= */ "openchat/openchat-3.5-0106" , 432// The included chat_template differs from the author's suggestions here: https://huggingface.co/openchat/openchat_3.5/discussions/5#65448109b4a3f3a2f486fd9d 433// So we match against the included template but implement the suggested version. 434/* .template_str= */ "{{ bos_token }}{% for message in messages %}{{ 'GPT4 Correct ' + message['role'].title() + ': ' + message['content'] + '<|end_of_turn|>'}}{% endfor %}{% if add_generation_prompt %}{{ 'GPT4 Correct Assistant:' }}{% endif %}" , 435/* .expected_output= */ "You are a helpful assistant<|end_of_turn|>GPT4 Correct User: Hello<|end_of_turn|>GPT4 Correct Assistant: Hi there<|end_of_turn|>GPT4 Correct User: Who are you<|end_of_turn|>GPT4 Correct Assistant: I am an assistant <|end_of_turn|>GPT4 Correct User: Another question<|end_of_turn|>GPT4 Correct Assistant:" , 436/* .expected_output_jinja= */ "GPT4 Correct System: You are a helpful assistant<|end_of_turn|>GPT4 Correct User: Hello<|end_of_turn|>GPT4 Correct Assistant: Hi there<|end_of_turn|>GPT4 Correct User: Who are you<|end_of_turn|>GPT4 Correct Assistant: I am an assistant <|end_of_turn|>GPT4 Correct User: Another question<|end_of_turn|>GPT4 Correct Assistant:" , 437}, 438{ 439/* .name= */ "deepseek-ai/deepseek-coder-33b-instruct" , 440/* .template_str= */ "{% if not add_generation_prompt is defined %}\n{% set add_generation_prompt = false %}\n{% endif %}\n{%- set ns = namespace(found=false) -%}\n{%- for message in messages -%}\n {%- if message['role'] == 'system' -%}\n {%- set ns.found = true -%}\n {%- endif -%}\n{%- endfor -%}\n{{bos_token}}{%- if not ns.found -%}\n{{'You are an AI programming assistant, utilizing the Deepseek Coder model, developed by Deepseek Company, and you only answer questions related to computer science. For politically sensitive questions, security and privacy issues, and other non-computer science questions, you will refuse to answer\\n'}}\n{%- endif %}\n{%- for message in messages %}\n {%- if message['role'] == 'system' %}\n{{ message['content'] }}\n {%- else %}\n {%- if message['role'] == 'user' %}\n{{'### Instruction:\\n' + message['content'] + '\\n'}}\n {%- else %}\n{{'### Response:\\n' + message['content'] + '\\n<|EOT|>\\n'}}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{% if add_generation_prompt %}\n{{'### Response:'}}\n{% endif %}" , 441/* .expected_output= */ "You are a helpful assistant### Instruction:\nHello\n### Response:\nHi there\n<|EOT|>\n### Instruction:\nWho are you\n### Response:\n I am an assistant \n<|EOT|>\n### Instruction:\nAnother question\n### Response:\n" , 442/* .expected_output_jinja= */ "" , 443}, 444{ 445/* .name= */ "eachadea/vicuna-13b-1.1" , 446// No template included in tokenizer_config.json, so this template likely needs to be manually set. 447/* .template_str= */ "{%- for message in messages %}{%- if message['role'] == 'system' -%}{{- '' + message['content'] + '\n\n' -}}{%- else -%}{%- if message['role'] == 'user' -%}{{-'USER: ' + message['content'] + '\n'-}}{%- else -%}{{-'ASSISTANT: ' + message['content'] + '</s>\n' -}}{%- endif -%}{%- endif -%}{%- endfor -%}{%- if add_generation_prompt -%}{{-'ASSISTANT:'-}}{%- endif -%}" , 448/* .expected_output= */ "You are a helpful assistant\n\nUSER: Hello\nASSISTANT: Hi there</s>\nUSER: Who are you\nASSISTANT: I am an assistant </s>\nUSER: Another question\nASSISTANT:" , 449/* .expected_output_jinja= */ "" , 450/* .bos_token= */ "" , 451/* .eos_token= */ "" , 452}, 453{ 454/* .name= */ "Orca-Vicuna" , 455// No template included in tokenizer_config.json, so this template likely needs to be manually set. 456/* .template_str= */ "{%- for message in messages %}{%- if message['role'] == 'system' -%}{{-'SYSTEM: ' + message['content'] + '\n' -}}{%- else -%}{%- if message['role'] == 'user' -%}{{-'USER: ' + message['content'] + '\n'-}}{%- else -%}{{-'ASSISTANT: ' + message['content'] + '</s>\n' -}}{%- endif -%}{%- endif -%}{%- endfor -%}{%- if add_generation_prompt -%}{{-'ASSISTANT:'-}}{%- endif -%}" , 457/* .expected_output= */ "SYSTEM: You are a helpful assistant\nUSER: Hello\nASSISTANT: Hi there</s>\nUSER: Who are you\nASSISTANT: I am an assistant </s>\nUSER: Another question\nASSISTANT:" , 458/* .expected_output_jinja= */ "" , 459/* .bos_token= */ "" , 460/* .eos_token= */ "" , 461}, 462{ 463/* .name= */ "CohereForAI/c4ai-command-r-plus" , 464/* .template_str= */ "{{ bos_token }}{% if messages[0]['role'] == 'system' %}{% set loop_messages = messages[1:] %}{% set system_message = messages[0]['content'] %}{% elif false == true %}{% set loop_messages = messages %}{% set system_message = 'You are Command-R, a brilliant, sophisticated, AI-assistant trained to assist human users by providing thorough responses. You are trained by Cohere.' %}{% else %}{% set loop_messages = messages %}{% set system_message = false %}{% endif %}{% if system_message != false %}{{ '<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>' + system_message + '<|END_OF_TURN_TOKEN|>' }}{% endif %}{% for message in loop_messages %}{% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}{{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}{% endif %}{% set content = message['content'] %}{% if message['role'] == 'user' %}{{ '<|START_OF_TURN_TOKEN|><|USER_TOKEN|>' + content.strip() + '<|END_OF_TURN_TOKEN|>' }}{% elif message['role'] == 'assistant' %}{{ '<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>' + content.strip() + '<|END_OF_TURN_TOKEN|>' }}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>' }}{% endif %}" , 465/* .expected_output= */ "<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>You are a helpful assistant<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>Hello<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>Hi there<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>Who are you<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>I am an assistant<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>Another question<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>" , 466/* .expected_output_jinja= */ "" , 467}, 468{ 469/* .name= */ "Llama-3" , 470/* .template_str= */ "{% set loop_messages = messages %}{% for message in loop_messages %}{% set content = '<|start_header_id|>' + message['role'] + '<|end_header_id|>\n\n'+ message['content'] | trim + '<|eot_id|>' %}{% if loop.index0 == 0 %}{% set content = bos_token + content %}{% endif %}{{ content }}{% endfor %}{{ '<|start_header_id|>assistant<|end_header_id|>\n\n' }}" , 471/* .expected_output= */ "<|start_header_id|>system<|end_header_id|>\n\nYou are a helpful assistant<|eot_id|><|start_header_id|>user<|end_header_id|>\n\nHello<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\nHi there<|eot_id|><|start_header_id|>user<|end_header_id|>\n\nWho are you<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\nI am an assistant<|eot_id|><|start_header_id|>user<|end_header_id|>\n\nAnother question<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n" , 472/* .expected_output_jinja= */ "" , 473}, 474{ 475/* .name= */ "Phi-3-mini" , 476/* .template_str= */ "{{ bos_token }}{% for message in messages %}{% if (message['role'] == 'user') %}{{'<|user|>' + '\n' + message['content'] + '<|end|>' + '\n' + '<|assistant|>' + '\n'}}{% elif (message['role'] == 'assistant') %}{{message['content'] + '<|end|>' + '\n'}}{% endif %}{% endfor %}" , 477/* .expected_output= */ "<|system|>\nYou are a helpful assistant<|end|>\n<|user|>\nHello<|end|>\n<|assistant|>\nHi there<|end|>\n<|user|>\nWho are you<|end|>\n<|assistant|>\n I am an assistant <|end|>\n<|user|>\nAnother question<|end|>\n<|assistant|>\n" , 478/* .expected_output_jinja= */ "<|user|>\nYou are a helpful assistant\nHello<|end|>\n<|assistant|>\nHi there<|end|>\n<|user|>\nWho are you<|end|>\n<|assistant|>\n I am an assistant <|end|>\n<|user|>\nAnother question<|end|>\n<|assistant|>\n" , 479}, 480{ 481/* .name= */ "Phi-3-small" , 482/* .template_str= */ "{{ bos_token }}{% for message in messages %}{{'<|' + message['role'] + '|>' + '\n' + message['content'] + '<|end|>\n' }}{% endfor %}{% if add_generation_prompt %}{{ '<|assistant|>\n' }}{% else %}{{ eos_token }}{% endif %}" , 483/* .expected_output= */ "<|system|>\nYou are a helpful assistant<|end|>\n<|user|>\nHello<|end|>\n<|assistant|>\nHi there<|end|>\n<|user|>\nWho are you<|end|>\n<|assistant|>\n I am an assistant <|end|>\n<|user|>\nAnother question<|end|>\n<|assistant|>\n" , 484/* .expected_output_jinja= */ "" , 485}, 486{ 487/* .name= */ "Phi-3-medium" , 488/* .template_str= */ "{% for message in messages %}{% if (message['role'] == 'user') %}{{'<|user|>' + '\n' + message['content'] + '<|end|>' + '\n' + '<|assistant|>' + '\n'}}{% elif (message['role'] == 'assistant') %}{{message['content'] + '<|end|>' + '\n'}}{% endif %}{% endfor %}" , 489/* .expected_output= */ "<|system|>\nYou are a helpful assistant<|end|>\n<|user|>\nHello<|end|>\n<|assistant|>\nHi there<|end|>\n<|user|>\nWho are you<|end|>\n<|assistant|>\n I am an assistant <|end|>\n<|user|>\nAnother question<|end|>\n<|assistant|>\n" , 490/* .expected_output_jinja= */ "<|user|>\nYou are a helpful assistant\nHello<|end|>\n<|assistant|>\nHi there<|end|>\n<|user|>\nWho are you<|end|>\n<|assistant|>\n I am an assistant <|end|>\n<|user|>\nAnother question<|end|>\n<|assistant|>\n" , 491}, 492{ 493/* .name= */ "Phi-3-vision" , 494/* .template_str= */ "{% for message in messages %}{{'<|' + message['role'] + '|>' + '\n' + message['content'] + '<|end|>\n' }}{% endfor %}{% if add_generation_prompt and messages[-1]['role'] != 'assistant' %}{{- '<|assistant|>\n' -}}{% endif %}" , 495/* .expected_output= */ "<|system|>\nYou are a helpful assistant<|end|>\n<|user|>\nHello<|end|>\n<|assistant|>\nHi there<|end|>\n<|user|>\nWho are you<|end|>\n<|assistant|>\n I am an assistant <|end|>\n<|user|>\nAnother question<|end|>\n<|assistant|>\n" , 496/* .expected_output_jinja= */ "" , 497/* .bos_token= */ "" , 498/* .eos_token= */ "" , 499}, 500{ 501/* .name= */ "ChatGLM3" , 502/* .template_str= */ "{% for message in messages %}{% if loop.first %}[gMASK]sop<|{{ message['role'] }}|>\n {{ message['content'] }}{% else %}<|{{ message['role'] }}|>\n {{ message['content'] }}{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>{% endif %}" , 503/* .expected_output= */ "[gMASK]sop<|system|>\n You are a helpful assistant<|user|>\n Hello<|assistant|>\n Hi there<|user|>\n Who are you<|assistant|>\n I am an assistant <|user|>\n Another question<|assistant|>" , 504/* .expected_output_jinja= */ "[gMASK]sop<|system|>\n You are a helpful assistant<|user|>\n Hello<|assistant|>\n Hi there<|user|>\n Who are you<|assistant|>\n I am an assistant <|user|>\n Another question<|assistant|>" , 505}, 506{ 507/* .name= */ "ChatGLM4" , 508/* .template_str= */ U8C ( "[gMASK]<sop>{% for item in messages %}{% if item['tools'] is defined %}<|system|>\n你是一个名为 ChatGLM 的人工智能助手。你是基于智谱AI训练的语言模型 GLM-4 模型开发的,你的任务是针对用户的问题和要求提供适当的答复和支持。\n\n# 可用工具{% set tools = item['tools'] %}{% for tool in tools %}{% if tool['type'] == 'function' %}\n\n## {{ tool['function']['name'] }}\n\n{{ tool['function'] | tojson(indent=4) }}\n......{% endif %}{% endfor %}{% endif %}{% if item['content'] %}<|{{ item['role'] }}|>{{ item['metadata'] }}\n{{ item['content'] }}{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>\n{% endif %}" ), 509/* .expected_output= */ "[gMASK]<sop><|system|>\nYou are a helpful assistant<|user|>\nHello<|assistant|>\nHi there<|user|>\nWho are you<|assistant|>\n I am an assistant <|user|>\nAnother question<|assistant|>\n" , 510/* .expected_output_jinja= */ "" , 511/* .bos_token= */ "" , 512/* .eos_token= */ "" , 513}, 514{ 515/* .name= */ "GLMEdge" , 516/* .template_str= */ "{% for item in messages %}{% if item['role'] == 'system' %}<|system|>\n{{ item['content'] }}{% elif item['role'] == 'user' %}<|user|>\n{{ item['content'] }}{% elif item['role'] == 'assistant' %}<|assistant|>\n{{ item['content'] }}{% endif %}{% endfor %}<|assistant|>" , 517/* .expected_output= */ "<|system|>\nYou are a helpful assistant<|user|>\nHello<|assistant|>\nHi there<|user|>\nWho are you<|assistant|>\n I am an assistant <|user|>\nAnother question<|assistant|>" , 518/* .expected_output_jinja= */ "<|system|>\nYou are a helpful assistant<|user|>\nHello<|assistant|>\nHi there<|user|>\nWho are you<|assistant|>\n I am an assistant <|user|>\nAnother question<|assistant|>" , 519/* .bos_token= */ "" , 520/* .eos_token= */ "" , 521}, 522{ 523/* .name= */ "MiniCPM-3B-OpenHermes-2.5-v2-GGUF" , 524/* .template_str= */ U8C ( "{% for message in messages %}{% if message['role'] == 'user' %}{{'<用户>' + message['content'].strip() + '<AI>'}}{% else %}{{message['content'].strip()}}{% endif %}{% endfor %}" ), 525/* .expected_output= */ U8C ( "You are a helpful assistant<用户>Hello<AI>Hi there<用户>Who are you<AI>I am an assistant<用户>Another question<AI>" ), 526/* .expected_output_jinja= */ "" , 527/* .bos_token= */ "" , 528/* .eos_token= */ "" , 529}, 530{ 531/* .name= */ "DeepSeek-V2" , 532/* .template_str= */ "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{{ bos_token }}{% for message in messages %}{% if message['role'] == 'user' %}{{ 'User: ' + message['content'] + '\n\n' }}{% elif message['role'] == 'assistant' %}{{ 'Assistant: ' + message['content'] + eos_token }}{% elif message['role'] == 'system' %}{{ message['content'] + '\n\n' }}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'Assistant:' }}{% endif %}" , 533/* .expected_output= */ U8C ( "You are a helpful assistant\n\nUser: Hello\n\nAssistant: Hi there<|end▁of▁sentence|>User: Who are you\n\nAssistant: I am an assistant <|end▁of▁sentence|>User: Another question\n\nAssistant:" ), 534/* .expected_output_jinja= */ "" , 535/* .bos_token= */ "" , 536/* .eos_token= */ "<|end▁of▁sentence|>" , 537}, 538{ 539/* .name= */ "ibm-granite/granite-3.0-8b-instruct" , 540/* .template_str= */ "{%- if tools %}\n {{- '<|start_of_role|>available_tools<|end_of_role|>\n' }}\n {%- for tool in tools %}\n {{- tool | tojson(indent=4) }}\n {%- if not loop.last %}\n {{- '\n\n' }}\n {%- endif %}\n {%- endfor %}\n {{- '<|end_of_text|>\n' }}\n{%- endif %}\n{%- for message in messages %}\n {%- if message['role'] == 'system' %}\n {{- '<|start_of_role|>system<|end_of_role|>' + message['content'] + '<|end_of_text|>\n' }}\n {%- elif message['role'] == 'user' %}\n {{- '<|start_of_role|>user<|end_of_role|>' + message['content'] + '<|end_of_text|>\n' }}\n {%- elif message['role'] == 'assistant' %}\n {{- '<|start_of_role|>assistant<|end_of_role|>' + message['content'] + '<|end_of_text|>\n' }}\n {%- elif message['role'] == 'assistant_tool_call' %}\n {{- '<|start_of_role|>assistant<|end_of_role|><|tool_call|>' + message['content'] + '<|end_of_text|>\n' }}\n {%- elif message['role'] == 'tool_response' %}\n {{- '<|start_of_role|>tool_response<|end_of_role|>' + message['content'] + '<|end_of_text|>\n' }}\n {%- endif %}\n {%- if loop.last and add_generation_prompt %}\n {{- '<|start_of_role|>assistant<|end_of_role|>' }}\n {%- endif %}\n{%- endfor %}" , 541/* .expected_output= */ "<|start_of_role|>system<|end_of_role|>You are a helpful assistant<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Hello<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>Hi there<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Who are you<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|> I am an assistant <|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Another question<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>" , 542/* .expected_output_jinja= */ "<|start_of_role|>system<|end_of_role|>You are a helpful assistant<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Hello<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>Hi there<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Who are you<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|> I am an assistant <|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Another question<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>" , 543}, 544{ 545/* .name= */ "mistralai/Mistral-7B-Instruct-v0.2 (mistralai 'v1' template with a system prompt)" , 546/* .template_str= */ "{%- if messages[0]['role'] == 'system' %}\n {%- set system_message = messages[0]['content'] %}\n {%- set loop_messages = messages[1:] %}\n{%- else %}\n {%- set loop_messages = messages %}\n{%- endif %}\n\n{{- bos_token }}\n{%- for message in loop_messages %}\n {%- if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}\n {{- raise_exception('After the optional system message, conversation roles must alternate user/assistant/user/assistant/...') }}\n {%- endif %}\n {%- if message['role'] == 'user' %}\n {%- if loop.first and system_message is defined %}\n {{- ' [INST] ' + system_message + '\\n\\n' + message['content'] + ' [/INST]' }}\n {%- else %}\n {{- ' [INST] ' + message['content'] + ' [/INST]' }}\n {%- endif %}\n {%- elif message['role'] == 'assistant' %}\n {{- ' ' + message['content'] + eos_token}}\n {%- else %}\n {{- raise_exception('Only user and assistant roles are supported, with the exception of an initial optional system message!') }}\n {%- endif %}\n{%- endfor %}\n" , 547/* .expected_output= */ " [INST] You are a helpful assistant\n\nHello [/INST] Hi there</s> [INST] Who are you [/INST] I am an assistant </s> [INST] Another question [/INST]" , 548/* .expected_output_jinja= */ " [INST] You are a helpful assistant\n\nHello [/INST] Hi there</s> [INST] Who are you [/INST] I am an assistant </s> [INST] Another question [/INST]" , 549/* .bos_token= */ "" , 550/* .eos_token= */ "</s>" , 551}, 552{ 553/* .name= */ "Mistral-Large-Instruct-2407 (mistralai 'v3' template; modified to have system prompt at start)" , 554/* .template_str= */ "{%- if messages[0][\"role\"] == \"system\" %}\n {%- set system_message = messages[0][\"content\"] %}\n {%- set loop_messages = messages[1:] %}\n{%- else %}\n {%- set loop_messages = messages %}\n{%- endif %}\n{%- if not tools is defined %}\n {%- set tools = none %}\n{%- endif %}\n{%- set user_messages = loop_messages | selectattr(\"role\", \"equalto\", \"user\") | list %}\n\n{#- This block checks for alternating user/assistant messages, skipping tool calling messages #}\n{%- set ns = namespace() %}\n{%- set ns.index = 0 %}\n{%- for message in loop_messages %}\n {%- if not (message.role == \"tool\" or message.role == \"tool_results\" or (message.tool_calls is defined and message.tool_calls is not none)) %}\n {%- if (message[\"role\"] == \"user\") != (ns.index % 2 == 0) %}\n {{- raise_exception(\"After the optional system message, conversation roles must alternate user/assistant/user/assistant/...\") }}\n {%- endif %}\n {%- set ns.index = ns.index + 1 %}\n {%- endif %}\n{%- endfor %}\n\n{{- bos_token }}\n{%- for message in loop_messages %}\n {%- if message[\"role\"] == \"user\" %}\n {%- if tools is not none and (message == user_messages[-1]) %}\n {{- \"[AVAILABLE_TOOLS] [\" }}\n {%- for tool in tools %}\n {%- set tool = tool.function %}\n {{- '{\"type\": \"function\", \"function\": {' }}\n {%- for key, val in tool.items() if key != \"return\" %}\n {%- if val is string %}\n {{- '\"' + key + '\": \"' + val + '\"' }}\n {%- else %}\n {{- '\"' + key + '\": ' + val|tojson }}\n {%- endif %}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- endif %}\n {%- endfor %}\n {{- \"}}\" }}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- else %}\n {{- \"]\" }}\n {%- endif %}\n {%- endfor %}\n {{- \"[/AVAILABLE_TOOLS]\" }}\n {%- endif %}\n {%- if loop.last and system_message is defined %}\n {{- \"[INST] \" + system_message + \"\\n\\n\" + message[\"content\"] + \"[/INST]\" }}\n {%- else %}\n {{- \"[INST] \" + message[\"content\"] + \"[/INST]\" }}\n {%- endif %}\n {%- elif message.tool_calls is defined and message.tool_calls is not none %}\n {{- \"[TOOL_CALLS] [\" }}\n {%- for tool_call in message.tool_calls %}\n {%- set out = tool_call.function|tojson %}\n {{- out[:-1] }}\n {%- if not tool_call.id is defined or tool_call.id|length != 9 %}\n {{- raise_exception(\"Tool call IDs should be alphanumeric strings with length 9!\") }}\n {%- endif %}\n {{- ', \"id\": \"' + tool_call.id + '\"}' }}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- else %}\n {{- \"]\" + eos_token }}\n {%- endif %}\n {%- endfor %}\n {%- elif message[\"role\"] == \"assistant\" %}\n {{- \" \" + message[\"content\"]|trim + eos_token}}\n {%- elif message[\"role\"] == \"tool_results\" or message[\"role\"] == \"tool\" %}\n {%- if message.content is defined and message.content.content is defined %}\n {%- set content = message.content.content %}\n {%- else %}\n {%- set content = message.content %}\n {%- endif %}\n {{- '[TOOL_RESULTS] {\"content\": ' + content|string + \", \" }}\n {%- if not message.tool_call_id is defined or message.tool_call_id|length != 9 %}\n {{- raise_exception(\"Tool call IDs should be alphanumeric strings with length 9!\") }}\n {%- endif %}\n {{- '\"call_id\": \"' + message.tool_call_id + '\"}[/TOOL_RESULTS]' }}\n {%- else %}\n {{- raise_exception(\"Only user and assistant roles are supported, with the exception of an initial optional system message!\") }}\n {%- endif %}\n{%- endfor %}\n" , 555/* .expected_output= */ "[INST] You are a helpful assistant\n\nHello[/INST] Hi there</s>[INST] Who are you[/INST] I am an assistant</s>[INST] Another question[/INST]" , 556/* .expected_output_jinja= */ "[INST] Hello[/INST] Hi there</s>[INST] Who are you[/INST] I am an assistant</s>[INST] You are a helpful assistant\n\nAnother question[/INST]" , 557/* .bos_token= */ "" , 558/* .eos_token= */ "</s>" , 559}, 560{ 561/* .name= */ "Mistral-Nemo-Instruct-2407 (mistralai 'v3-tekken' template; modified to have system prompt at start)" , 562/* .template_str= */ "{%- if messages[0][\"role\"] == \"system\" %}\n {%- set system_message = messages[0][\"content\"] %}\n {%- set loop_messages = messages[1:] %}\n{%- else %}\n {%- set loop_messages = messages %}\n{%- endif %}\n{%- if not tools is defined %}\n {%- set tools = none %}\n{%- endif %}\n{%- set user_messages = loop_messages | selectattr(\"role\", \"equalto\", \"user\") | list %}\n\n{#- This block checks for alternating user/assistant messages, skipping tool calling messages #}\n{%- set ns = namespace() %}\n{%- set ns.index = 0 %}\n{%- for message in loop_messages %}\n {%- if not (message.role == \"tool\" or message.role == \"tool_results\" or (message.tool_calls is defined and message.tool_calls is not none)) %}\n {%- if (message[\"role\"] == \"user\") != (ns.index % 2 == 0) %}\n {{- raise_exception(\"After the optional system message, conversation roles must alternate user/assistant/user/assistant/...\") }}\n {%- endif %}\n {%- set ns.index = ns.index + 1 %}\n {%- endif %}\n{%- endfor %}\n\n{{- bos_token }}\n{%- for message in loop_messages %}\n {%- if message[\"role\"] == \"user\" %}\n {%- if tools is not none and (message == user_messages[-1]) %}\n {{- \"[AVAILABLE_TOOLS][\" }}\n {%- for tool in tools %}\n {%- set tool = tool.function %}\n {{- '{\"type\": \"function\", \"function\": {' }}\n {%- for key, val in tool.items() if key != \"return\" %}\n {%- if val is string %}\n {{- '\"' + key + '\": \"' + val + '\"' }}\n {%- else %}\n {{- '\"' + key + '\": ' + val|tojson }}\n {%- endif %}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- endif %}\n {%- endfor %}\n {{- \"}}\" }}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- else %}\n {{- \"]\" }}\n {%- endif %}\n {%- endfor %}\n {{- \"[/AVAILABLE_TOOLS]\" }}\n {%- endif %}\n {%- if loop.last and system_message is defined %}\n {{- \"[INST]\" + system_message + \"\\n\\n\" + message[\"content\"] + \"[/INST]\" }}\n {%- else %}\n {{- \"[INST]\" + message[\"content\"] + \"[/INST]\" }}\n {%- endif %}\n {%- elif (message.tool_calls is defined and message.tool_calls is not none) %}\n {{- \"[TOOL_CALLS][\" }}\n {%- for tool_call in message.tool_calls %}\n {%- set out = tool_call.function|tojson %}\n {{- out[:-1] }}\n {%- if not tool_call.id is defined or tool_call.id|length != 9 %}\n {{- raise_exception(\"Tool call IDs should be alphanumeric strings with length 9!\") }}\n {%- endif %}\n {{- ', \"id\": \"' + tool_call.id + '\"}' }}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- else %}\n {{- \"]\" + eos_token }}\n {%- endif %}\n {%- endfor %}\n {%- elif message[\"role\"] == \"assistant\" %}\n {{- message[\"content\"] + eos_token}}\n {%- elif message[\"role\"] == \"tool_results\" or message[\"role\"] == \"tool\" %}\n {%- if message.content is defined and message.content.content is defined %}\n {%- set content = message.content.content %}\n {%- else %}\n {%- set content = message.content %}\n {%- endif %}\n {{- '[TOOL_RESULTS]{\"content\": ' + content|string + \", \" }}\n {%- if not message.tool_call_id is defined or message.tool_call_id|length != 9 %}\n {{- raise_exception(\"Tool call IDs should be alphanumeric strings with length 9!\") }}\n {%- endif %}\n {{- '\"call_id\": \"' + message.tool_call_id + '\"}[/TOOL_RESULTS]' }}\n {%- else %}\n {{- raise_exception(\"Only user and assistant roles are supported, with the exception of an initial optional system message!\") }}\n {%- endif %}\n{%- endfor %}\n" , 563/* .expected_output= */ "[INST]You are a helpful assistant\n\nHello[/INST]Hi there</s>[INST]Who are you[/INST] I am an assistant </s>[INST]Another question[/INST]" , 564/* .expected_output_jinja= */ "[INST]Hello[/INST]Hi there</s>[INST]Who are you[/INST] I am an assistant </s>[INST]You are a helpful assistant\n\nAnother question[/INST]" , 565/* .bos_token= */ "" , 566/* .eos_token= */ "</s>" , 567}, 568{ 569/* .name= */ "mistralai/Mistral-Large-Instruct-2411 (mistralai 'v7' template)" , 570/* .template_str= */ "{{ bos_token }}{% for message in messages %}{% if message['role'] == 'user' %}{{ '[INST] ' + message['content'] + '[/INST]' }}{% elif message['role'] == 'system' %}{{ '[SYSTEM_PROMPT] ' + message['content'] + '[/SYSTEM_PROMPT]' }}{% elif message['role'] == 'assistant' %}{{ ' ' + message['content'] + eos_token }}{% else %}{{ raise_exception('Only user, system and assistant roles are supported!') }}{% endif %}{% endfor %}" , 571/* .expected_output= */ "[SYSTEM_PROMPT] You are a helpful assistant[/SYSTEM_PROMPT][INST] Hello[/INST] Hi there</s>[INST] Who are you[/INST] I am an assistant </s>[INST] Another question[/INST]" , 572/* .expected_output_jinja= */ "" , 573/* .bos_token= */ "" , 574/* .eos_token= */ "</s>" , 575}, 576{ 577/* .name= */ "ai-sage/GigaChat-20B-A3B-instruct" , 578/* .template_str= */ "{% if messages[0]['role'] == 'system' -%}\n {%- set loop_messages = messages[1:] -%}\n {%- set system_message = bos_token + messages[0]['content'] + additional_special_tokens[1] -%}\n{%- else -%}\n {%- set loop_messages = messages -%}\n {%- set system_message = bos_token + '' -%}\n{%- endif -%}\n{%- for message in loop_messages %}\n {% if (message['role'] == 'user') != (loop.index0 % 2 == 0) %}\n {{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}\n {% endif %}\n \n {%- if loop.index0 == 0 -%}\n {{ system_message -}}\n {%- endif -%}\n {%- if message['role'] == 'user' -%}\n {{ message['role'] + additional_special_tokens[0] + message['content'] + additional_special_tokens[1] -}}\n {{ 'available functions' + additional_special_tokens[0] + additional_special_tokens[2] + additional_special_tokens[3] + additional_special_tokens[1] -}}\n {%- endif -%}\n {%- if message['role'] == 'assistant' -%}\n {{ message['role'] + additional_special_tokens[0] + message['content'] + additional_special_tokens[1] -}}\n {%- endif -%}\n {%- if loop.last and add_generation_prompt -%}\n {{ 'assistant' + additional_special_tokens[0] -}}\n {%- endif -%}\n{%- endfor %}" , 579/* .expected_output= */ "<s>You are a helpful assistant<|message_sep|>user<|role_sep|>Hello<|message_sep|>available functions<|role_sep|>[]<|message_sep|>assistant<|role_sep|>Hi there<|message_sep|>user<|role_sep|>Who are you<|message_sep|>available functions<|role_sep|>[]<|message_sep|>assistant<|role_sep|> I am an assistant <|message_sep|>user<|role_sep|>Another question<|message_sep|>available functions<|role_sep|>[]<|message_sep|>assistant<|role_sep|>" , 580/* .expected_output_jinja= */ "" , 581/* .bos_token= */ "" , 582/* .eos_token= */ "" , 583/* .supported_with_jinja= */ false, // Requires additional_special_tokens as extra context 584}, 585{ 586/* .name= */ "Infinigence/Megrez-3B-Instruct" , 587/* .template_str= */ U8C ( "{% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|role_start|>system<|role_end|>你是Megrez-3B-Instruct,将针对用户的问题给出详细的、积极的回答。<|turn_end|>' }}{% endif %}{{ '<|role_start|>' + message['role'] + '<|role_end|>' + message['content'] + '<|turn_end|>' }}{% endfor %}{% if add_generation_prompt %}{{ '<|role_start|>assistant<|role_end|>' }}{% endif %}" ), 588/* .expected_output= */ "<|role_start|>system<|role_end|>You are a helpful assistant<|turn_end|><|role_start|>user<|role_end|>Hello<|turn_end|><|role_start|>assistant<|role_end|>Hi there<|turn_end|><|role_start|>user<|role_end|>Who are you<|turn_end|><|role_start|>assistant<|role_end|> I am an assistant <|turn_end|><|role_start|>user<|role_end|>Another question<|turn_end|><|role_start|>assistant<|role_end|>" , 589/* .expected_output_jinja= */ "" , 590/* .bos_token= */ "" , 591/* .eos_token= */ "" , 592}, 593{ 594/* .name= */ "phi-4" , 595/* .template_str= */ "{% for message in messages %}{% if (message['role'] == 'system') %}{{'<|im_start|>system<|im_sep|>' + message['content'] + '<|im_end|>'}}{% elif (message['role'] == 'user') %}{{'<|im_start|>user<|im_sep|>' + message['content'] + '<|im_end|><|im_start|>assistant<|im_sep|>'}}{% elif (message['role'] == 'assistant') %}{{message['content'] + '<|im_end|>'}}{% endif %}{% endfor %}" , 596/* .expected_output= */ "<|im_start|>system<|im_sep|>You are a helpful assistant<|im_end|><|im_start|>user<|im_sep|>Hello<|im_end|><|im_start|>assistant<|im_sep|>Hi there<|im_end|><|im_start|>user<|im_sep|>Who are you<|im_end|><|im_start|>assistant<|im_sep|> I am an assistant <|im_end|><|im_start|>user<|im_sep|>Another question<|im_end|><|im_start|>assistant<|im_sep|>" , 597/* .expected_output_jinja= */ "" , 598/* .bos_token= */ "" , 599/* .eos_token= */ "" , 600}, 601{ 602/* .name= */ "yandex/YandexGPT-5-Lite-8B-instruct" , 603/* .template_str= */ "<s>{%- set names = {'assistant': ' Ассистент:', 'user': ' Пользователь:'} %}\n{%- set tools_prefix = 'Тебе доступны следующие функции:' %}\n{%- macro __render_tool(tool) %}\n {%- set name = tool.function.name %}\n {%- set description = tool.function.description|default('') %}\n {%- set parameters = tool.function.parameters|tojson %}\n {{- '\\n' }}function {{ '{' }}'name':'{{ name }}',\n {%- if tool.function.description %}'description':'{{ description }}',{% endif %}\n'parameters':{{ parameters }}\n {{- '}' }}\n{%- endmacro %}\n{%- macro __render_tools(tools) %}\n {{- tools_prefix }}\n {%- for tool in tools %}\n {{- __render_tool(tool) }}\n {%- endfor %}\n {{- '\\n\\n' }}\n{%- endmacro %}\n{%- macro __render_tool_message(message) %}\n {{- '\\n\\nРезультат вызова' }} {{ message.name }}: {{ message.content }} {{ '\\n\\n' }}\n{%- endmacro %}\n{%- if tools -%}\n {{- __render_tools(tools) }}\n{%- endif -%}\n{%- macro __render_user_message(message) %}\n{{ names.user }} {{ message.content + '\\n\\n' }}\n{%- endmacro %}\n{%- macro __render_assistant_message(message) %}\n {{- names.assistant }}\n {%- set call = message['function_call'] %}\n {%- if call %}\n {{- '\\n[TOOL_CALL_START]' }}{{ call.name }}{{ '\\n' }}{{ call.arguments|tojson }}\n {%- else %}\n {{- ' ' + message.content + '\\n\\n' }}\n {%- endif %}\n{%- endmacro %}\n{%- if not add_generation_prompt is defined %}\n{%- set add_generation_prompt = false %}\n{%- endif %}\n{%- for message in messages %}\n {%- if message['role'] == 'user' %}\n {{- __render_user_message(message) }}\n {%- endif %}\n {%- if message.role == 'assistant' and not loop.last %}\n {{- __render_assistant_message(message) }}\n {%- endif %}\n {%- if message.role == 'tool' %}\n {{- __render_tool_message(message) }}\n {%- endif %}\n {%- if loop.last %}\n {{- ' Ассистент:[SEP]' }}\n {%- endif %}\n{%- endfor %}\n" , 604/* .expected_output= */ " Пользователь: Hello\n\n Ассистент: Hi there\n\n Пользователь: Who are you\n\n Ассистент: I am an assistant \n\n Пользователь: Another question\n\n Ассистент:[SEP]" , 605/* .expected_output_jinja= */ "<s> Пользователь: You are a helpful assistant\nHello\n\n Ассистент: Hi there\n\n Пользователь: Who are you\n\n Ассистент: I am an assistant \n\n Пользователь: Another question\n\n Ассистент:[SEP]" , 606/* .bos_token= */ "<s>" , 607/* .eos_token= */ "" , 608}, 609{ 610/* .name= */ "inclusionAI/Ling-lite" , 611/* .template_str */ "{% for message in messages %}{% set role = message['role'] | lower %}{% if role == 'user' %}{% set role = 'HUMAN' %}{% endif %}{% set role = role | upper %}{{ '<role>' + role + '</role>' + message['content'] }}{% endfor %}{% if add_generation_prompt %}{{ '<role>ASSISTANT</role>' }}{% endif %}" , 612/* .expected_output= */ "<role>SYSTEM</role>You are a helpful assistant<role>HUMAN</role>Hello<role>ASSISTANT</role>Hi there<role>HUMAN</role>Who are you<role>ASSISTANT</role> I am an assistant <role>HUMAN</role>Another question<role>ASSISTANT</role>" , 613/* .expected_output_jinja= */ "" , 614/* .bos_token= */ "" , 615/* .eos_token= */ "" , 616}, 617{ 618/* .name= */ "ByteDance-Seed/Seed-OSS-36B-Instruct" , 619/* .template_str */ "{# <seed:bos> #}{%- for message in messages %}{%- if message.role in [\"user\", \"system\"] %}{{ bos_token + message.role + \"\\n\" + message.content + eos_token }}{%- elif message.role == \"assistant\" %}{{ bos_token + message.role }}{%- if message.content is defined and message.content is string and message.content|trim|length > 0 %}{{ \"\\n\" + message.content|trim + eos_token }}{%- endif %}{%- else %}{{ bos_token + message.role + \"\\n\" + message.content + eos_token }}{%- endif %}{%- endfor %}{%- if add_generation_prompt %}{{ bos_token + \"assistant\\n\" }}{%- endif %}" , 620/* .expected_output= */ "<seed:bos>system\nYou are a helpful assistant<seed:eos><seed:bos>user\nHello<seed:eos><seed:bos>assistant\nHi there<seed:eos><seed:bos>user\nWho are you<seed:eos><seed:bos>assistant\nI am an assistant<seed:eos><seed:bos>user\nAnother question<seed:eos><seed:bos>assistant\n" , 621/* .expected_output_jinja= */ "<seed:bos>system\nYou are a helpful assistant<seed:eos><seed:bos>user\nHello<seed:eos><seed:bos>assistant\nHi there<seed:eos><seed:bos>user\nWho are you<seed:eos><seed:bos>assistant\nI am an assistant<seed:eos><seed:bos>user\nAnother question<seed:eos><seed:bos>assistant\n" , 622/* .bos_token= */ "<seed:bos>" , 623/* .eos_token= */ "<seed:eos>" , 624}, 625{ 626/* .name= */ "ibm-granite/granite-3.x (tool call)" , 627/* .template_str= */ "{%- for message in messages %}\n {%- if message['role'] == 'assistant_tool_call' %}\n {{- '<|start_of_role|>assistant<|end_of_role|><|tool_call|>' + message['content'] + '<|end_of_text|>\\n' }}\n {%- else %}\n {{- '<|start_of_role|>' + message['role'] + '<|end_of_role|>' + message['content'] + '<|end_of_text|>\\n' }}\n {%- endif %}\n {%- if loop.last and add_generation_prompt %}\n {{- '<|start_of_role|>assistant<|end_of_role|>' }}\n {%- endif %}\n{%- endfor %}" , 628/* .expected_output= */ "<|start_of_role|>system<|end_of_role|>You are a helpful assistant<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Hello<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>Hi there<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Who are you<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|> I am an assistant <|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Another question<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>What is the weather?<|end_of_text|>\n<|start_of_role|>assistant_tool_call<|end_of_role|><|tool_call|>[{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}]<|end_of_text|>\n<|start_of_role|>tool_response<|end_of_role|>{\"temperature\": 72}<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>" , 629/* .expected_output_jinja= */ "<|start_of_role|>system<|end_of_role|>You are a helpful assistant<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Hello<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>Hi there<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Who are you<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|> I am an assistant <|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Another question<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>What is the weather?<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|><|tool_call|>[{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}]<|end_of_text|>\n<|start_of_role|>tool_response<|end_of_role|>{\"temperature\": 72}<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>" , 630/* .bos_token= */ "" , 631/* .eos_token= */ "" , 632/* .supported_with_jinja= */ true, 633/* .extra_conversation= */ {{ "user" , "What is the weather?" }, { "assistant_tool_call" , "[{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}]" }, { "tool_response" , "{\"temperature\": 72}" }}, 634}, 635{ 636/* .name= */ "ibm-granite/granite-4.0 (tool call)" , 637/* .template_str= */ "{%- for message in messages %}\n {%- if message['role'] == 'assistant_tool_call' %}\n {{- '<|start_of_role|>assistant<|end_of_role|><|tool_call|>' + message['content'] + '<|end_of_text|>\\n' }}\n {%- else %}\n {{- '<|start_of_role|>' + message['role'] + '<|end_of_role|>' + message['content'] + '<|end_of_text|>\\n' }}\n {%- endif %}\n {%- if loop.last and add_generation_prompt %}\n {{- '<|start_of_role|>assistant<|end_of_role|>' }}\n {%- endif %}\n{%- endfor %}\n{# <tool_call> <tools> g4_default_system_message #}" , 638/* .expected_output= */ "<|start_of_role|>system<|end_of_role|>You are a helpful assistant<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Hello<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>Hi there<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Who are you<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|> I am an assistant <|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Another question<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>What is the weather?<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|><|tool_call|><tool_call>\n{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}\n</tool_call><|end_of_text|>\n<|start_of_role|>tool_response<|end_of_role|>{\"temperature\": 72}<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>" , 639/* .expected_output_jinja= */ "" , 640/* .bos_token= */ "" , 641/* .eos_token= */ "" , 642/* .supported_with_jinja= */ true, 643/* .extra_conversation= */ {{ "user" , "What is the weather?" }, { "assistant_tool_call" , "<tool_call>\n{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}\n</tool_call>" }, { "tool_response" , "{\"temperature\": 72}" }}, 644}, 645{ 646/* .name= */ "ibm-granite/granite-4.1 (tool call)" , 647/* .template_str= */ "{%- for message in messages %}\n {%- if message['role'] == 'assistant_tool_call' %}\n {{- '<|start_of_role|>assistant<|end_of_role|><|tool_call|>' + message['content'] + '<|end_of_text|>\\n' }}\n {%- else %}\n {{- '<|start_of_role|>' + message['role'] + '<|end_of_role|>' + message['content'] + '<|end_of_text|>\\n' }}\n {%- endif %}\n {%- if loop.last and add_generation_prompt %}\n {{- '<|start_of_role|>assistant<|end_of_role|>' }}\n {%- endif %}\n{%- endfor %}\n{# <tool_call> <tools> #}" , 648/* .expected_output= */ "<|start_of_role|>system<|end_of_role|>You are a helpful assistant<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Hello<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>Hi there<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Who are you<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|> I am an assistant <|end_of_text|>\n<|start_of_role|>user<|end_of_role|>Another question<|end_of_text|>\n<|start_of_role|>user<|end_of_role|>What is the weather?<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|><|tool_call|><tool_call>\n{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}\n</tool_call><|end_of_text|>\n<|start_of_role|>tool_response<|end_of_role|>{\"temperature\": 72}<|end_of_text|>\n<|start_of_role|>assistant<|end_of_role|>" , 649/* .expected_output_jinja= */ "" , 650/* .bos_token= */ "" , 651/* .eos_token= */ "" , 652/* .supported_with_jinja= */ true, 653/* .extra_conversation= */ {{ "user" , "What is the weather?" }, { "assistant_tool_call" , "<tool_call>\n{\"name\": \"get_weather\", \"arguments\": {\"location\": \"NYC\"}}\n</tool_call>" }, { "tool_response" , "{\"temperature\": 72}" }}, 654} 655}; 656std::vector < char > formatted_chat ( 1024 ); 657int32_t res ; 658 659// list all supported templates 660std::vector < const char *> supported_tmpl ; 661res = llama_chat_builtin_templates ( nullptr , 0 ); 662assert ( res > 0 ); 663supported_tmpl . resize ( res ); 664res = llama_chat_builtin_templates ( supported_tmpl . data (), supported_tmpl . size ()); 665std:: cout << "Built-in chat templates:\n" ; 666for ( const auto * tmpl : supported_tmpl ) { 667std:: cout << " " << tmpl << "\n" ; 668} 669 670// test invalid chat template 671res = llama_chat_apply_template ( "INVALID TEMPLATE" , conversation . data (), conversation . size (), true, formatted_chat . data (), formatted_chat . size ()); 672assert ( res < 0 ); 673const auto add_generation_prompt = true; 674 675for ( const auto & test_case : test_cases ) { 676std:: cout << "\n\n=== " << test_case . name << " ===\n\n" ; 677auto conv = conversation ; 678conv . insert ( conv . end (), test_case . extra_conversation . begin (), test_case . extra_conversation . end ()); 679formatted_chat . resize ( 2048 ); 680res = llama_chat_apply_template ( 681test_case . template_str . c_str (), 682conv . data (), 683conv . size (), 684add_generation_prompt , 685formatted_chat . data (), 686formatted_chat . size () 687); 688formatted_chat . resize ( res ); 689std::string output ( formatted_chat . data (), formatted_chat . size ()); 690if ( output != test_case . expected_output ) { 691std:: cout << "Expected:\n" << test_case . expected_output << "\n" ; 692std:: cout << "-------------------------\n" ; 693std:: cout << "Actual:\n" << output << "\n" ; 694std:: cout . flush (); 695assert ( output == test_case . expected_output ); 696} 697} 698 699std::vector < common_chat_msg > messages ; 700messages . reserve ( conversation . size ()); 701for ( const auto & msg : conversation ) { 702messages . push_back ( simple_msg ( msg . role , msg . content )); 703} 704for ( const auto & test_case : test_cases ) { 705if (! test_case . supported_with_jinja ) { 706continue ; 707} 708std:: cout << "\n\n=== " << test_case . name << " (jinja) ===\n\n" ; 709try { 710auto msgs = messages ; 711for ( const auto & msg : test_case . extra_conversation ) { 712msgs . push_back ( simple_msg ( msg . role , msg . content )); 713} 714auto output = format_using_common ( 715test_case . template_str , 716test_case . bos_token , 717test_case . eos_token , 718msgs ); 719auto expected_output = normalize_newlines ( test_case . expected_output_jinja . empty () ? test_case . expected_output : test_case . expected_output_jinja ); 720if ( output != expected_output ) { 721std:: cout << "Template:```\n" << test_case . template_str << "\n```" ; 722std:: cout << "-------------------------\n" ; 723std:: cout << "Expected:```\n" << expected_output << "\n```" ; 724std:: cout << "-------------------------\n" ; 725std:: cout << "Actual:```\n" << output << "\n```" ; 726std:: cout . flush (); 727assert ( output == expected_output ); 728} 729} catch ( const std::exception & e ) { 730std:: cerr << "ERROR: " << e . what () << "\n" ; 731assert (false); 732} 733} 734 735std:: cout << "\nOK: All tests passed successfully.\n" ; 736 737return 0 ; 738}