char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
bb771cbd2
char/aliceai-t5-moe
1#include "llama-chat.h" 2 3#include "llama.h" 4 5#include <map> 6#include <sstream> 7#include <algorithm> 8 9#if __cplusplus >=202000L 10#define LU8 (x ) (const char*)(u8##x) 11#else 12#define LU8 (x ) u8##x 13#endif 14 15// trim whitespace from the beginning and end of a string 16static std::string trim (const std::string & str ) { 17size_t start = 0 ; 18size_t end = str .size (); 19while (start < end && isspace (static_cast < unsigned char > (str [start ]))) { 20start += 1 ; 21 } 22while (end > start && isspace (static_cast < unsigned char > (str [end - 1 ]))) { 23end -= 1 ; 24 } 25return str .substr (start ,end - start ); 26} 27 28static const std::map < std::string ,llm_chat_template > LLM_CHAT_TEMPLATES = { 29 {"chatml" ,LLM_CHAT_TEMPLATE_CHATML }, 30 {"llama2" ,LLM_CHAT_TEMPLATE_LLAMA_2 }, 31 {"llama2-sys" ,LLM_CHAT_TEMPLATE_LLAMA_2_SYS }, 32 {"llama2-sys-bos" ,LLM_CHAT_TEMPLATE_LLAMA_2_SYS_BOS }, 33 {"llama2-sys-strip" ,LLM_CHAT_TEMPLATE_LLAMA_2_SYS_STRIP }, 34 {"mistral-v1" ,LLM_CHAT_TEMPLATE_MISTRAL_V1 }, 35 {"mistral-v3" ,LLM_CHAT_TEMPLATE_MISTRAL_V3 }, 36 {"mistral-v3-tekken" ,LLM_CHAT_TEMPLATE_MISTRAL_V3_TEKKEN }, 37 {"mistral-v7" ,LLM_CHAT_TEMPLATE_MISTRAL_V7 }, 38 {"mistral-v7-tekken" ,LLM_CHAT_TEMPLATE_MISTRAL_V7_TEKKEN }, 39 {"phi3" ,LLM_CHAT_TEMPLATE_PHI_3 }, 40 {"phi4" ,LLM_CHAT_TEMPLATE_PHI_4 }, 41 {"falcon3" ,LLM_CHAT_TEMPLATE_FALCON_3 }, 42 {"zephyr" ,LLM_CHAT_TEMPLATE_ZEPHYR }, 43 {"monarch" ,LLM_CHAT_TEMPLATE_MONARCH }, 44 {"gemma" ,LLM_CHAT_TEMPLATE_GEMMA }, 45 {"orion" ,LLM_CHAT_TEMPLATE_ORION }, 46 {"openchat" ,LLM_CHAT_TEMPLATE_OPENCHAT }, 47 {"vicuna" ,LLM_CHAT_TEMPLATE_VICUNA }, 48 {"vicuna-orca" ,LLM_CHAT_TEMPLATE_VICUNA_ORCA }, 49 {"deepseek" ,LLM_CHAT_TEMPLATE_DEEPSEEK }, 50 {"deepseek2" ,LLM_CHAT_TEMPLATE_DEEPSEEK_2 }, 51 {"deepseek3" ,LLM_CHAT_TEMPLATE_DEEPSEEK_3 }, 52 {"deepseek-ocr" ,LLM_CHAT_TEMPLATE_DEEPSEEK_OCR }, 53 {"command-r" ,LLM_CHAT_TEMPLATE_COMMAND_R }, 54 {"llama3" ,LLM_CHAT_TEMPLATE_LLAMA_3 }, 55 {"chatglm3" ,LLM_CHAT_TEMPLATE_CHATGLM_3 }, 56 {"chatglm4" ,LLM_CHAT_TEMPLATE_CHATGLM_4 }, 57 {"glmedge" ,LLM_CHAT_TEMPLATE_GLMEDGE }, 58 {"minicpm" ,LLM_CHAT_TEMPLATE_MINICPM }, 59 {"exaone3" ,LLM_CHAT_TEMPLATE_EXAONE_3 }, 60 {"exaone4" ,LLM_CHAT_TEMPLATE_EXAONE_4 }, 61 {"exaone-moe" ,LLM_CHAT_TEMPLATE_EXAONE_MOE }, 62 {"rwkv-world" ,LLM_CHAT_TEMPLATE_RWKV_WORLD }, 63 {"granite" ,LLM_CHAT_TEMPLATE_GRANITE_3_X }, 64 {"granite-4.0" ,LLM_CHAT_TEMPLATE_GRANITE_4_0 }, 65 {"granite-4.1" ,LLM_CHAT_TEMPLATE_GRANITE_4_1 }, 66 {"gigachat" ,LLM_CHAT_TEMPLATE_GIGACHAT }, 67 {"megrez" ,LLM_CHAT_TEMPLATE_MEGREZ }, 68 {"yandex" ,LLM_CHAT_TEMPLATE_YANDEX }, 69 {"bailing" ,LLM_CHAT_TEMPLATE_BAILING }, 70 {"bailing-think" ,LLM_CHAT_TEMPLATE_BAILING_THINK }, 71 {"bailing2" ,LLM_CHAT_TEMPLATE_BAILING2 }, 72 {"llama4" ,LLM_CHAT_TEMPLATE_LLAMA4 }, 73 {"smolvlm" ,LLM_CHAT_TEMPLATE_SMOLVLM }, 74 {"hunyuan-moe" ,LLM_CHAT_TEMPLATE_HUNYUAN_MOE }, 75 {"gpt-oss" ,LLM_CHAT_TEMPLATE_OPENAI_MOE }, 76 {"hunyuan-dense" ,LLM_CHAT_TEMPLATE_HUNYUAN_DENSE }, 77 {"hunyuan-vl" ,LLM_CHAT_TEMPLATE_HUNYUAN_VL }, 78 {"kimi-k2" ,LLM_CHAT_TEMPLATE_KIMI_K2 }, 79 {"seed_oss" ,LLM_CHAT_TEMPLATE_SEED_OSS }, 80 {"grok-2" ,LLM_CHAT_TEMPLATE_GROK_2 }, 81 {"pangu-embedded" ,LLM_CHAT_TEMPLATE_PANGU_EMBED }, 82 {"solar-open" ,LLM_CHAT_TEMPLATE_SOLAR_OPEN }, 83}; 84 85llm_chat_template llm_chat_template_from_str (const std::string & name ) { 86return LLM_CHAT_TEMPLATES .at (name ); 87} 88 89llm_chat_template llm_chat_detect_template (const std::string & tmpl ) { 90try { 91return llm_chat_template_from_str (tmpl ); 92 }catch (const std::out_of_range & ) { 93// ignore 94 } 95 96auto tmpl_contains = [& tmpl ](const char * haystack )-> bool { 97return tmpl .find (haystack )!= std::string::npos ; 98 }; 99if (tmpl_contains ("<|im_start|>" )) { 100return tmpl_contains ("<|im_sep|>" ) 101 ?LLM_CHAT_TEMPLATE_PHI_4 102 :tmpl_contains ("<end_of_utterance>" ) 103 ?LLM_CHAT_TEMPLATE_SMOLVLM // SmolVLM uses <|im_start|> as BOS, but it is NOT chatml 104 :LLM_CHAT_TEMPLATE_CHATML ; 105 }else if (tmpl .find ("mistral" )== 0 || tmpl_contains ("[INST]" )) { 106if (tmpl_contains ("[SYSTEM_PROMPT]" )) { 107return LLM_CHAT_TEMPLATE_MISTRAL_V7 ; 108 }else if ( 109// catches official 'v1' template 110tmpl_contains ("' [INST] ' + system_message" ) 111// catches official 'v3' and 'v3-tekken' templates 112|| tmpl_contains ("[AVAILABLE_TOOLS]" ) 113 ) { 114// Official mistral 'v1', 'v3' and 'v3-tekken' templates 115// See: https://github.com/mistralai/cookbook/blob/main/concept-deep-dive/tokenization/chat_templates.md 116// See: https://github.com/mistralai/cookbook/blob/main/concept-deep-dive/tokenization/templates.md 117if (tmpl_contains (" [INST]" )) { 118return LLM_CHAT_TEMPLATE_MISTRAL_V1 ; 119 }else if (tmpl_contains ("\"[INST]\"" )) { 120return LLM_CHAT_TEMPLATE_MISTRAL_V3_TEKKEN ; 121 } 122return LLM_CHAT_TEMPLATE_MISTRAL_V3 ; 123 }else { 124// llama2 template and its variants 125// [variant] support system message 126// See: https://huggingface.co/blog/llama2#how-to-prompt-llama-2 127bool support_system_message = tmpl_contains ("<<SYS>>" ); 128bool add_bos_inside_history = tmpl_contains ("bos_token + '[INST]" ); 129bool strip_message = tmpl_contains ("content.strip()" ); 130if (strip_message ) { 131return LLM_CHAT_TEMPLATE_LLAMA_2_SYS_STRIP ; 132 }else if (add_bos_inside_history ) { 133return LLM_CHAT_TEMPLATE_LLAMA_2_SYS_BOS ; 134 }else if (support_system_message ) { 135return LLM_CHAT_TEMPLATE_LLAMA_2_SYS ; 136 }else { 137return LLM_CHAT_TEMPLATE_LLAMA_2 ; 138 } 139 } 140 }else if (tmpl_contains ("<|assistant|>" )&& tmpl_contains ("<|end|>" )) { 141return LLM_CHAT_TEMPLATE_PHI_3 ; 142 }else if (tmpl_contains ("[gMASK]<sop>" )) { 143return LLM_CHAT_TEMPLATE_CHATGLM_4 ; 144 }else if (tmpl_contains ("<|assistant|>" )&& tmpl_contains ("<|user|>" )) { 145if (tmpl_contains ("<|tool_declare|>" )) { 146return LLM_CHAT_TEMPLATE_EXAONE_MOE ; 147 } 148return tmpl_contains ("</s>" ) ?LLM_CHAT_TEMPLATE_FALCON_3 :LLM_CHAT_TEMPLATE_GLMEDGE ; 149 }else if (tmpl_contains ("<|{{ item['role'] }}|>" )&& tmpl_contains ("<|begin_of_image|>" )) { 150return LLM_CHAT_TEMPLATE_GLMEDGE ; 151 }else if (tmpl_contains ("<|user|>" )&& tmpl_contains ("<|endoftext|>" )) { 152return LLM_CHAT_TEMPLATE_ZEPHYR ; 153 }else if (tmpl_contains ("bos_token + message['role']" )) { 154return LLM_CHAT_TEMPLATE_MONARCH ; 155 }else if (tmpl_contains ("<start_of_turn>" )) { 156return LLM_CHAT_TEMPLATE_GEMMA ; 157 }else if (tmpl_contains ("'\\n\\nAssistant: ' + eos_token" )) { 158// OrionStarAI/Orion-14B-Chat 159return LLM_CHAT_TEMPLATE_ORION ; 160 }else if (tmpl_contains ("GPT4 Correct " )) { 161// openchat/openchat-3.5-0106 162return LLM_CHAT_TEMPLATE_OPENCHAT ; 163 }else if (tmpl_contains ("USER: " )&& tmpl_contains ("ASSISTANT: " )) { 164// eachadea/vicuna-13b-1.1 (and Orca variant) 165if (tmpl_contains ("SYSTEM: " )) { 166return LLM_CHAT_TEMPLATE_VICUNA_ORCA ; 167 } 168return LLM_CHAT_TEMPLATE_VICUNA ; 169 }else if (tmpl_contains ("### Instruction:" )&& tmpl_contains ("<|EOT|>" )) { 170// deepseek-ai/deepseek-coder-33b-instruct 171return LLM_CHAT_TEMPLATE_DEEPSEEK ; 172 }else if (tmpl_contains ("<|START_OF_TURN_TOKEN|>" )&& tmpl_contains ("<|USER_TOKEN|>" )) { 173// CohereForAI/c4ai-command-r-plus 174return LLM_CHAT_TEMPLATE_COMMAND_R ; 175 }else if (tmpl_contains ("<|start_header_id|>" )&& tmpl_contains ("<|end_header_id|>" )) { 176return LLM_CHAT_TEMPLATE_LLAMA_3 ; 177 }else if (tmpl_contains ("[gMASK]sop" )) { 178// chatglm3-6b 179return LLM_CHAT_TEMPLATE_CHATGLM_3 ; 180 }else if (tmpl_contains (LU8 ("<用户>" ))) { 181// MiniCPM-3B-OpenHermes-2.5-v2-GGUF 182return LLM_CHAT_TEMPLATE_MINICPM ; 183 }else if (tmpl_contains ("'Assistant: ' + message['content'] + eos_token" )) { 184return LLM_CHAT_TEMPLATE_DEEPSEEK_2 ; 185 }else if (tmpl_contains (LU8 ("<|Assistant|>" ))&& tmpl_contains (LU8 ("<|User|>" ))&& tmpl_contains (LU8 ("<|end▁of▁sentence|>" ))) { 186return LLM_CHAT_TEMPLATE_DEEPSEEK_3 ; 187 }else if (tmpl_contains ("[|system|]" )&& tmpl_contains ("[|assistant|]" )&& tmpl_contains ("[|endofturn|]" )) { 188if (tmpl_contains ("[|tool|]" )) { 189return LLM_CHAT_TEMPLATE_EXAONE_4 ; 190 } 191// ref: https://huggingface.co/LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct/discussions/8#66bae61b1893d14ee8ed85bb 192// EXAONE-3.0-7.8B-Instruct 193return LLM_CHAT_TEMPLATE_EXAONE_3 ; 194 }else if (tmpl_contains ("rwkv-world" )|| tmpl_contains ("{{- 'User: ' + message['content']|trim + '\\n\\n' -}}" )) { 195return LLM_CHAT_TEMPLATE_RWKV_WORLD ; 196 }else if (tmpl_contains ("<|start_of_role|>" )) { 197if (tmpl_contains ("<tool_call>" )|| tmpl_contains ("<tools>" )) { 198if (tmpl_contains ("g4_default_system_message" )) { 199return LLM_CHAT_TEMPLATE_GRANITE_4_0 ; 200 } 201return LLM_CHAT_TEMPLATE_GRANITE_4_1 ; 202 } 203return LLM_CHAT_TEMPLATE_GRANITE_3_X ; 204 }else if (tmpl_contains ("message['role'] + additional_special_tokens[0] + message['content'] + additional_special_tokens[1]" )) { 205return LLM_CHAT_TEMPLATE_GIGACHAT ; 206 }else if (tmpl_contains ("<|role_start|>" )) { 207return LLM_CHAT_TEMPLATE_MEGREZ ; 208 }else if (tmpl_contains (" Ассистент:" )) { 209return LLM_CHAT_TEMPLATE_YANDEX ; 210 }else if (tmpl_contains ("<role>ASSISTANT</role>" )&& tmpl_contains ("'HUMAN'" )) { 211return LLM_CHAT_TEMPLATE_BAILING ; 212 }else if (tmpl_contains ("<role>ASSISTANT</role>" )&& tmpl_contains ("\"HUMAN\"" )&& tmpl_contains ("<think>" )) { 213return LLM_CHAT_TEMPLATE_BAILING_THINK ; 214 }else if (tmpl_contains ("<role>ASSISTANT</role>" )&& tmpl_contains ("<role>HUMAN</role>" )&& tmpl_contains ("<|role_end|>" )) { 215return LLM_CHAT_TEMPLATE_BAILING2 ; 216 }else if (tmpl_contains ("<|header_start|>" )&& tmpl_contains ("<|header_end|>" )) { 217return LLM_CHAT_TEMPLATE_LLAMA4 ; 218 }else if (tmpl_contains ("<|endofuserprompt|>" )) { 219return LLM_CHAT_TEMPLATE_DOTS1 ; 220 }else if (tmpl_contains ("<|extra_0|>" )&& tmpl_contains ("<|extra_4|>" )) { 221return LLM_CHAT_TEMPLATE_HUNYUAN_MOE ; 222 }else if (tmpl_contains ("<|start|>" )&& tmpl_contains ("<|channel|>" )) { 223return LLM_CHAT_TEMPLATE_OPENAI_MOE ; 224 }else if (tmpl_contains ("<|hy_Assistant|>" )&& tmpl_contains ("<|hy_begin▁of▁sentence|>" )) { 225return LLM_CHAT_TEMPLATE_HUNYUAN_VL ; 226 }else if (tmpl_contains ("<|hy_Assistant|>" )&& tmpl_contains ("<|hy_place▁holder▁no▁3|>" )) { 227return LLM_CHAT_TEMPLATE_HUNYUAN_DENSE ; 228 }else if (tmpl_contains ("<|im_assistant|>assistant<|im_middle|>" )) { 229return LLM_CHAT_TEMPLATE_KIMI_K2 ; 230 }else if (tmpl_contains ("<seed:bos>" )) { 231return LLM_CHAT_TEMPLATE_SEED_OSS ; 232 }else if (tmpl_contains ("'Assistant: ' + message['content'] + '<|separator|>" )) { 233return LLM_CHAT_TEMPLATE_GROK_2 ; 234 }else if (tmpl_contains (LU8 ("[unused9]系统:[unused10]" ))) { 235return LLM_CHAT_TEMPLATE_PANGU_EMBED ; 236 }else if (tmpl_contains ("<|begin|>" )&& tmpl_contains ("<|end|>" )&& tmpl_contains ("<|content|>" )) { 237return LLM_CHAT_TEMPLATE_SOLAR_OPEN ; 238 } 239return LLM_CHAT_TEMPLATE_UNKNOWN ; 240} 241 242// Simple version of "llama_apply_chat_template" that only works with strings 243// This function uses heuristic checks to determine commonly used template. It is not a jinja parser. 244int32_t llm_chat_apply_template ( 245llm_chat_template tmpl , 246const std::vector < const llama_chat_message *> & chat , 247 std::string & dest ,bool add_ass ) { 248// Taken from the research: https://github.com/ggml-org/llama.cpp/issues/5527 249 std::stringstream ss ; 250if (tmpl == LLM_CHAT_TEMPLATE_CHATML ) { 251// chatml template 252for (auto message :chat ) { 253ss <<"<|im_start|>" <<message -> role <<"\n" <<message -> content <<"<|im_end|>\n" ; 254 } 255if (add_ass ) { 256ss <<"<|im_start|>assistant\n" ; 257 } 258 }else if (tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V7 || tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V7_TEKKEN ) { 259// Official mistral 'v7' template 260// See: https://huggingface.co/mistralai/Mistral-Large-Instruct-2411#basic-instruct-template-v7 261// https://huggingface.co/mistralai/Mistral-Small-3.1-24B-Instruct-2503#basic-instruct-template-v7-tekken 262const char * trailing_space = tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V7 ?" " :"" ; 263for (auto message :chat ) { 264 std::string role (message -> role ); 265 std::string content (message -> content ); 266if (role == "system" ) { 267ss <<"[SYSTEM_PROMPT]" <<trailing_space <<content <<"[/SYSTEM_PROMPT]" ; 268 }else if (role == "user" ) { 269ss <<"[INST]" <<trailing_space <<content <<"[/INST]" ; 270 }else { 271ss <<trailing_space <<content <<"</s>" ; 272 } 273 } 274 }else if (tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V1 275|| tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V3 276|| tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V3_TEKKEN ) { 277// See: https://github.com/mistralai/cookbook/blob/main/concept-deep-dive/tokenization/chat_templates.md 278// See: https://github.com/mistralai/cookbook/blob/main/concept-deep-dive/tokenization/templates.md 279 std::string leading_space = tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V1 ?" " :"" ; 280 std::string trailing_space = tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V3_TEKKEN ?"" :" " ; 281bool trim_assistant_message = tmpl == LLM_CHAT_TEMPLATE_MISTRAL_V3 ; 282bool is_inside_turn = false; 283for (auto message :chat ) { 284if (!is_inside_turn ) { 285ss <<leading_space <<"[INST]" <<trailing_space ; 286is_inside_turn = true; 287 } 288 std::string role (message -> role ); 289 std::string content (message -> content ); 290if (role == "system" ) { 291ss <<content <<"\n\n" ; 292 }else if (role == "user" ) { 293ss <<content <<leading_space <<"[/INST]" ; 294 }else { 295ss <<trailing_space << (trim_assistant_message ?trim (content ) :content ) <<"</s>" ; 296is_inside_turn = false; 297 } 298 } 299 }else if ( 300tmpl == LLM_CHAT_TEMPLATE_LLAMA_2 301|| tmpl == LLM_CHAT_TEMPLATE_LLAMA_2_SYS 302|| tmpl == LLM_CHAT_TEMPLATE_LLAMA_2_SYS_BOS 303|| tmpl == LLM_CHAT_TEMPLATE_LLAMA_2_SYS_STRIP ) { 304// llama2 template and its variants 305// [variant] support system message 306// See: https://huggingface.co/blog/llama2#how-to-prompt-llama-2 307bool support_system_message = tmpl != LLM_CHAT_TEMPLATE_LLAMA_2 ; 308// [variant] add BOS inside history 309bool add_bos_inside_history = tmpl == LLM_CHAT_TEMPLATE_LLAMA_2_SYS_BOS ; 310// [variant] trim spaces from the input message 311bool strip_message = tmpl == LLM_CHAT_TEMPLATE_LLAMA_2_SYS_STRIP ; 312// construct the prompt 313bool is_inside_turn = true;// skip BOS at the beginning 314ss <<"[INST] " ; 315for (auto message :chat ) { 316 std::string content = strip_message ?trim (message -> content ) :message -> content ; 317 std::string role (message -> role ); 318if (!is_inside_turn ) { 319is_inside_turn = true; 320ss << (add_bos_inside_history ?"<s>[INST] " :"[INST] " ); 321 } 322if (role == "system" ) { 323if (support_system_message ) { 324ss <<"<<SYS>>\n" <<content <<"\n<</SYS>>\n\n" ; 325 }else { 326// if the model does not support system message, we still include it in the first message, but without <<SYS>> 327ss <<content <<"\n" ; 328 } 329 }else if (role == "user" ) { 330ss <<content <<" [/INST]" ; 331 }else { 332ss <<content <<"</s>" ; 333is_inside_turn = false; 334 } 335 } 336 }else if (tmpl == LLM_CHAT_TEMPLATE_PHI_3 ) { 337// Phi 3 338for (auto message :chat ) { 339 std::string role (message -> role ); 340ss <<"<|" <<role <<"|>\n" <<message -> content <<"<|end|>\n" ; 341 } 342if (add_ass ) { 343ss <<"<|assistant|>\n" ; 344 } 345 }else if (tmpl == LLM_CHAT_TEMPLATE_PHI_4 ) { 346// chatml template 347for (auto message :chat ) { 348ss <<"<|im_start|>" <<message -> role <<"<|im_sep|>" <<message -> content <<"<|im_end|>" ; 349 } 350if (add_ass ) { 351ss <<"<|im_start|>assistant<|im_sep|>" ; 352 } 353 }else if (tmpl == LLM_CHAT_TEMPLATE_FALCON_3 ) { 354// Falcon 3 355for (auto message :chat ) { 356 std::string role (message -> role ); 357ss <<"<|" <<role <<"|>\n" <<message -> content <<"\n" ; 358 } 359if (add_ass ) { 360ss <<"<|assistant|>\n" ; 361 } 362 }else if (tmpl == LLM_CHAT_TEMPLATE_ZEPHYR ) { 363// zephyr template 364for (auto message :chat ) { 365ss <<"<|" <<message -> role <<"|>" <<"\n" <<message -> content <<"<|endoftext|>\n" ; 366 } 367if (add_ass ) { 368ss <<"<|assistant|>\n" ; 369 } 370 }else if (tmpl == LLM_CHAT_TEMPLATE_MONARCH ) { 371// mlabonne/AlphaMonarch-7B template (the <s> is included inside history) 372for (auto message :chat ) { 373 std::string bos = (message == chat .front ()) ?"" :"<s>" ;// skip BOS for first message 374ss <<bos <<message -> role <<"\n" <<message -> content <<"</s>\n" ; 375 } 376if (add_ass ) { 377ss <<"<s>assistant\n" ; 378 } 379 }else if (tmpl == LLM_CHAT_TEMPLATE_GEMMA ) { 380// google/gemma-7b-it 381 std::string system_prompt = "" ; 382for (auto message :chat ) { 383 std::string role (message -> role ); 384if (role == "system" ) { 385// there is no system message for gemma, but we will merge it with user prompt, so nothing is broken 386system_prompt += trim (message -> content ); 387continue ; 388 } 389// in gemma, "assistant" is "model" 390role = role == "assistant" ?"model" :message -> role ; 391ss <<"<start_of_turn>" <<role <<"\n" ; 392if (!system_prompt .empty ()&& role != "model" ) { 393ss <<system_prompt <<"\n\n" ; 394system_prompt = "" ; 395 } 396ss <<trim (message -> content ) <<"<end_of_turn>\n" ; 397 } 398if (add_ass ) { 399ss <<"<start_of_turn>model\n" ; 400 } 401 }else if (tmpl == LLM_CHAT_TEMPLATE_ORION ) { 402// OrionStarAI/Orion-14B-Chat 403 std::string system_prompt = "" ; 404for (auto message :chat ) { 405 std::string role (message -> role ); 406if (role == "system" ) { 407// there is no system message support, we will merge it with user prompt 408system_prompt += message -> content ; 409continue ; 410 }else if (role == "user" ) { 411ss <<"Human: " ; 412if (!system_prompt .empty ()) { 413ss <<system_prompt <<"\n\n" ; 414system_prompt = "" ; 415 } 416ss <<message -> content <<"\n\nAssistant: </s>" ; 417 }else { 418ss <<message -> content <<"</s>" ; 419 } 420 } 421 }else if (tmpl == LLM_CHAT_TEMPLATE_OPENCHAT ) { 422// openchat/openchat-3.5-0106, 423for (auto message :chat ) { 424 std::string role (message -> role ); 425if (role == "system" ) { 426ss <<message -> content <<"<|end_of_turn|>" ; 427 }else { 428role [0 ]= toupper (role [0 ]); 429ss <<"GPT4 Correct " <<role <<": " <<message -> content <<"<|end_of_turn|>" ; 430 } 431 } 432if (add_ass ) { 433ss <<"GPT4 Correct Assistant:" ; 434 } 435 }else if (tmpl == LLM_CHAT_TEMPLATE_VICUNA || tmpl == LLM_CHAT_TEMPLATE_VICUNA_ORCA ) { 436// eachadea/vicuna-13b-1.1 (and Orca variant) 437for (auto message :chat ) { 438 std::string role (message -> role ); 439if (role == "system" ) { 440// Orca-Vicuna variant uses a system prefix 441if (tmpl == LLM_CHAT_TEMPLATE_VICUNA_ORCA ) { 442ss <<"SYSTEM: " <<message -> content <<"\n" ; 443 }else { 444ss <<message -> content <<"\n\n" ; 445 } 446 }else if (role == "user" ) { 447ss <<"USER: " <<message -> content <<"\n" ; 448 }else if (role == "assistant" ) { 449ss <<"ASSISTANT: " <<message -> content <<"</s>\n" ; 450 } 451 } 452if (add_ass ) { 453ss <<"ASSISTANT:" ; 454 } 455 }else if (tmpl == LLM_CHAT_TEMPLATE_DEEPSEEK ) { 456// deepseek-ai/deepseek-coder-33b-instruct 457for (auto message :chat ) { 458 std::string role (message -> role ); 459if (role == "system" ) { 460ss <<message -> content ; 461 }else if (role == "user" ) { 462ss <<"### Instruction:\n" <<message -> content <<"\n" ; 463 }else if (role == "assistant" ) { 464ss <<"### Response:\n" <<message -> content <<"\n<|EOT|>\n" ; 465 } 466 } 467if (add_ass ) { 468ss <<"### Response:\n" ; 469 } 470 }else if (tmpl == LLM_CHAT_TEMPLATE_COMMAND_R ) { 471// CohereForAI/c4ai-command-r-plus 472for (auto message :chat ) { 473 std::string role (message -> role ); 474if (role == "system" ) { 475ss <<"<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>" <<trim (message -> content ) <<"<|END_OF_TURN_TOKEN|>" ; 476 }else if (role == "user" ) { 477ss <<"<|START_OF_TURN_TOKEN|><|USER_TOKEN|>" <<trim (message -> content ) <<"<|END_OF_TURN_TOKEN|>" ; 478 }else if (role == "assistant" ) { 479ss <<"<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>" <<trim (message -> content ) <<"<|END_OF_TURN_TOKEN|>" ; 480 } 481 } 482if (add_ass ) { 483ss <<"<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>" ; 484 } 485 }else if (tmpl == LLM_CHAT_TEMPLATE_LLAMA_3 ) { 486// Llama 3 487for (auto message :chat ) { 488 std::string role (message -> role ); 489ss <<"<|start_header_id|>" <<role <<"<|end_header_id|>\n\n" <<trim (message -> content ) <<"<|eot_id|>" ; 490 } 491if (add_ass ) { 492ss <<"<|start_header_id|>assistant<|end_header_id|>\n\n" ; 493 } 494 }else if (tmpl == LLM_CHAT_TEMPLATE_CHATGLM_3 ) { 495// chatglm3-6b 496ss <<"[gMASK]" <<"sop" ; 497for (auto message :chat ) { 498 std::string role (message -> role ); 499ss <<"<|" <<role <<"|>" <<"\n " <<message -> content ; 500 } 501if (add_ass ) { 502ss <<"<|assistant|>" ; 503 } 504 }else if (tmpl == LLM_CHAT_TEMPLATE_CHATGLM_4 ) { 505ss <<"[gMASK]" <<"<sop>" ; 506for (auto message :chat ) { 507 std::string role (message -> role ); 508ss <<"<|" <<role <<"|>" <<"\n" <<message -> content ; 509 } 510if (add_ass ) { 511ss <<"<|assistant|>\n" ; 512 } 513 }else if (tmpl == LLM_CHAT_TEMPLATE_GLMEDGE ) { 514for (auto message :chat ) { 515 std::string role (message -> role ); 516ss <<"<|" <<role <<"|>" <<"\n" <<message -> content ; 517 } 518if (add_ass ) { 519ss <<"<|assistant|>" ; 520 } 521 }else if (tmpl == LLM_CHAT_TEMPLATE_MINICPM ) { 522// MiniCPM-3B-OpenHermes-2.5-v2-GGUF 523for (auto message :chat ) { 524 std::string role (message -> role ); 525if (role == "user" ) { 526ss <<LU8 ("<用户>" ); 527ss <<trim (message -> content ); 528ss <<"<AI>" ; 529 }else { 530ss <<trim (message -> content ); 531 } 532 } 533 }else if (tmpl == LLM_CHAT_TEMPLATE_DEEPSEEK_2 ) { 534// DeepSeek-V2 535for (auto message :chat ) { 536 std::string role (message -> role ); 537if (role == "system" ) { 538ss <<message -> content <<"\n\n" ; 539 }else if (role == "user" ) { 540ss <<"User: " <<message -> content <<"\n\n" ; 541 }else if (role == "assistant" ) { 542ss <<"Assistant: " <<message -> content <<LU8 ("<|end▁of▁sentence|>" ); 543 } 544 } 545if (add_ass ) { 546ss <<"Assistant:" ; 547 } 548 }else if (tmpl == LLM_CHAT_TEMPLATE_DEEPSEEK_3 ) { 549// DeepSeek-V3 550for (auto message :chat ) { 551 std::string role (message -> role ); 552if (role == "system" ) { 553ss <<message -> content <<"\n\n" ; 554 }else if (role == "user" ) { 555ss <<LU8 ("<|User|>" ) <<message -> content ; 556 }else if (role == "assistant" ) { 557ss <<LU8 ("<|Assistant|>" ) <<message -> content <<LU8 ("<|end▁of▁sentence|>" ); 558 } 559 } 560if (add_ass ) { 561ss <<LU8 ("<|Assistant|>" ); 562 } 563 }else if (tmpl == LLM_CHAT_TEMPLATE_DEEPSEEK_OCR ) { 564for (auto message :chat ) { 565// no template 566ss <<message -> content ; 567 } 568 }else if (tmpl == LLM_CHAT_TEMPLATE_EXAONE_3 ) { 569// ref: https://huggingface.co/LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct/discussions/8#66bae61b1893d14ee8ed85bb 570// EXAONE-3.0-7.8B-Instruct 571for (auto message :chat ) { 572 std::string role (message -> role ); 573if (role == "system" ) { 574ss <<"[|system|]" <<trim (message -> content ) <<"[|endofturn|]\n" ; 575 }else if (role == "user" ) { 576ss <<"[|user|]" <<trim (message -> content ) <<"\n" ; 577 }else if (role == "assistant" ) { 578ss <<"[|assistant|]" <<trim (message -> content ) <<"[|endofturn|]\n" ; 579 } 580 } 581if (add_ass ) { 582ss <<"[|assistant|]" ; 583 } 584 }else if (tmpl == LLM_CHAT_TEMPLATE_EXAONE_4 ) { 585for (auto message :chat ) { 586 std::string role (message -> role ); 587if (role == "system" ) { 588ss <<"[|system|]" <<trim (message -> content ) <<"[|endofturn|]\n" ; 589 }else if (role == "user" ) { 590ss <<"[|user|]" <<trim (message -> content ) <<"\n" ; 591 }else if (role == "assistant" ) { 592ss <<"[|assistant|]" <<trim (message -> content ) <<"[|endofturn|]\n" ; 593 }else if (role == "tool" ) { 594ss <<"[|tool|]" <<trim (message -> content ) <<"[|endofturn|]\n" ; 595 } 596 } 597if (add_ass ) { 598ss <<"[|assistant|]" ; 599 } 600 }else if (tmpl == LLM_CHAT_TEMPLATE_EXAONE_MOE ) { 601for (auto message :chat ) { 602 std::string role (message -> role ); 603if (role == "system" ) { 604ss <<"<|system|>\n" <<trim (message -> content ) <<"<|endofturn|>\n" ; 605 }else if (role == "user" ) { 606ss <<"<|user|>\n" <<trim (message -> content ) <<"<|endofturn|>\n" ; 607 }else if (role == "assistant" ) { 608ss <<"<|assistant|>\n" <<trim (message -> content ) <<"<|endofturn|>\n" ; 609 }else if (role == "tool" ) { 610ss <<"<|tool|>\n" <<trim (message -> content ) <<"<|endofturn|>\n" ; 611 } 612 } 613if (add_ass ) { 614ss <<"<|assistant|>\n" ; 615 } 616 }else if (tmpl == LLM_CHAT_TEMPLATE_RWKV_WORLD ) { 617// this template requires the model to have "\n\n" as EOT token 618for (size_t i = 0 ;i < chat .size ();i ++ ) { 619 std::string role (chat [i ]-> role ); 620if (role == "system" ) { 621ss <<"System: " <<trim (chat [i ]-> content ) <<"\n\n" ; 622 }else if (role == "user" ) { 623ss <<"User: " <<trim (chat [i ]-> content ) <<"\n\n" ; 624if (i == chat .size ()- 1 ) { 625ss <<"Assistant:" ; 626 } 627 }else if (role == "assistant" ) { 628ss <<"Assistant: " <<trim (chat [i ]-> content ) <<"\n\n" ; 629 } 630 } 631 }else if (tmpl == LLM_CHAT_TEMPLATE_GRANITE_3_X ) { 632// IBM Granite 3.x template 633for (const auto & message :chat ) { 634 std::string role (message -> role ); 635ss <<"<|start_of_role|>" <<role <<"<|end_of_role|>" ; 636if (role == "assistant_tool_call" ) { 637ss <<"<|tool_call|>" ; 638 } 639ss <<message -> content <<"<|end_of_text|>\n" ; 640 } 641if (add_ass ) { 642ss <<"<|start_of_role|>assistant<|end_of_role|>" ; 643 } 644 }else if (tmpl == LLM_CHAT_TEMPLATE_GRANITE_4_0 ) { 645// IBM Granite 4.0 template 646for (const auto & message :chat ) { 647 std::string role (message -> role ); 648if (role == "assistant_tool_call" ) { 649ss <<"<|start_of_role|>assistant<|end_of_role|><|tool_call|>" ; 650 }else { 651ss <<"<|start_of_role|>" <<role <<"<|end_of_role|>" ; 652 } 653ss <<message -> content <<"<|end_of_text|>\n" ; 654 } 655if (add_ass ) { 656ss <<"<|start_of_role|>assistant<|end_of_role|>" ; 657 } 658 }else if (tmpl == LLM_CHAT_TEMPLATE_GRANITE_4_1 ) { 659// IBM Granite 4.1 template 660for (const auto & message :chat ) { 661 std::string role (message -> role ); 662if (role == "assistant_tool_call" ) { 663ss <<"<|start_of_role|>assistant<|end_of_role|><|tool_call|>" ; 664 }else { 665ss <<"<|start_of_role|>" <<role <<"<|end_of_role|>" ; 666 } 667ss <<message -> content <<"<|end_of_text|>\n" ; 668 } 669if (add_ass ) { 670ss <<"<|start_of_role|>assistant<|end_of_role|>" ; 671 } 672 }else if (tmpl == LLM_CHAT_TEMPLATE_GIGACHAT ) { 673// GigaChat template 674bool has_system = !chat .empty ()&& std::string (chat [0 ]-> role )== "system" ; 675 676// Handle system message if present 677if (has_system ) { 678ss <<"<s>" <<chat [0 ]-> content <<"<|message_sep|>" ; 679 }else { 680ss <<"<s>" ; 681 } 682 683// Process remaining messages 684for (size_t i = has_system ?1 :0 ;i < chat .size ();i ++ ) { 685 std::string role (chat [i ]-> role ); 686if (role == "user" ) { 687ss <<"user<|role_sep|>" <<chat [i ]-> content <<"<|message_sep|>" 688 <<"available functions<|role_sep|>[]<|message_sep|>" ; 689 }else if (role == "assistant" ) { 690ss <<"assistant<|role_sep|>" <<chat [i ]-> content <<"<|message_sep|>" ; 691 } 692 } 693 694// Add generation prompt if needed 695if (add_ass ) { 696ss <<"assistant<|role_sep|>" ; 697 } 698 }else if (tmpl == LLM_CHAT_TEMPLATE_MEGREZ ) { 699// Megrez template 700for (auto message :chat ) { 701 std::string role (message -> role ); 702ss <<"<|role_start|>" <<role <<"<|role_end|>" <<message -> content <<"<|turn_end|>" ; 703 } 704 705if (add_ass ) { 706ss <<"<|role_start|>assistant<|role_end|>" ; 707 } 708 }else if (tmpl == LLM_CHAT_TEMPLATE_YANDEX ) { 709// Yandex template ("\n\n" is defined as EOT token) 710 711for (size_t i = 0 ;i < chat .size ();i ++ ) { 712 std::string role (chat [i ]-> role ); 713if (role == "user" ) { 714ss <<" Пользователь: " <<chat [i ]-> content <<"\n\n" ; 715 }else if (role == "assistant" ) { 716ss <<" Ассистент: " <<chat [i ]-> content <<"\n\n" ; 717 } 718 } 719 720// Add generation prompt if needed 721if (add_ass ) { 722ss <<" Ассистент:[SEP]" ; 723 } 724 }else if (tmpl == LLM_CHAT_TEMPLATE_BAILING || tmpl == LLM_CHAT_TEMPLATE_BAILING_THINK ) { 725// Bailing (Ling/Ring) template 726for (auto message :chat ) { 727 std::string role (message -> role ); 728 729if (role == "user" ) { 730role = "HUMAN" ; 731 }else { 732 std::transform (role .begin (),role .end (),role .begin (), ::toupper ); 733 } 734 735ss <<"<role>" <<role <<"</role>" <<message -> content ; 736 } 737 738if (add_ass ) { 739ss <<"<role>ASSISTANT</role>" ; 740 741if (tmpl == LLM_CHAT_TEMPLATE_BAILING_THINK ) { 742ss <<"<think>" ; 743 } 744 } 745 }else if (tmpl == LLM_CHAT_TEMPLATE_BAILING2 ) { 746// Bailing2 (Ling 2.0) template 747bool has_system = !chat .empty ()&& std::string (chat [0 ]-> role )== "system" ; 748 749if (!has_system ) { 750ss <<"<role>SYSTEM</role>detailed thinking off<|role_end|>" ; 751 } 752 753for (auto message :chat ) { 754 std::string role (message -> role ); 755 756if (role == "user" ) { 757role = "HUMAN" ; 758 }else { 759 std::transform (role .begin (),role .end (),role .begin (), ::toupper ); 760 } 761 762ss <<"<role>" <<role <<"</role>" <<message -> content <<"<|role_end|>" ; 763 } 764 765if (add_ass ) { 766ss <<"<role>ASSISTANT</role>" ; 767 } 768 }else if (tmpl == LLM_CHAT_TEMPLATE_LLAMA4 ) { 769// Llama 4 770for (auto message :chat ) { 771 std::string role (message -> role ); 772ss <<"<|header_start|>" <<role <<"<|header_end|>\n\n" <<trim (message -> content ) <<"<|eot|>" ; 773 } 774if (add_ass ) { 775ss <<"<|header_start|>assistant<|header_end|>\n\n" ; 776 } 777 }else if (tmpl == LLM_CHAT_TEMPLATE_SMOLVLM ) { 778// SmolVLM 779ss <<"<|im_start|>" ;// uses <|im_start|> as BOS, but the actual content is NOT chatml 780for (auto message :chat ) { 781 std::string role (message -> role ); 782if (role == "system" ) { 783ss <<message -> content <<"\n\n" ; 784 }else if (role == "user" ) { 785ss <<"User: " <<message -> content <<"<end_of_utterance>\n" ; 786 }else { 787ss <<"Assistant: " <<message -> content <<"<end_of_utterance>\n" ; 788 } 789 } 790if (add_ass ) { 791ss <<"Assistant:" ; 792 } 793 }else if (tmpl == LLM_CHAT_TEMPLATE_DOTS1 ) { 794// dots.llm1.inst (DOTS1) 795for (auto message :chat ) { 796 std::string role (message -> role ); 797if (role == "system" ) { 798ss <<"<|system|>" <<message -> content <<"<|endofsystem|>" ; 799 }else if (role == "user" ) { 800ss <<"<|userprompt|>" <<message -> content <<"<|endofuserprompt|>" ; 801 }else { 802ss <<"<|response|>" <<message -> content <<"<|endofresponse|>" ; 803 } 804 } 805if (add_ass ) { 806ss <<"<|response|>" ; 807 } 808 }else if (tmpl == LLM_CHAT_TEMPLATE_HUNYUAN_MOE ) { 809// tencent/Hunyuan-A13B-Instruct 810for (auto message :chat ) { 811 std::string role (message -> role ); 812if (role == "system" ) { 813ss <<"<|startoftext|>" <<message -> content <<"<|extra_4|>" ; 814 }else if (role == "assistant" ) { 815ss <<message -> content <<"<|eos|>" ; 816 }else { 817ss <<"<|startoftext|>" <<message -> content <<"<|extra_0|>" ; 818 } 819 } 820 }else if (tmpl == LLM_CHAT_TEMPLATE_OPENAI_MOE ) { 821// OpenAI MoE (based on Harmony chat template) 822for (auto message :chat ) { 823 std::string role (message -> role ); 824ss <<"<|start|>" <<role <<"<|message|>" <<message -> content ; 825ss << (role == "assistant" ?"<|return|>" :"<|end|>" ); 826 } 827if (add_ass ) { 828ss <<"<|start|>assistant" ; 829 } 830 }else if (tmpl == LLM_CHAT_TEMPLATE_HUNYUAN_DENSE ) { 831// tencent/Hunyuan-4B-Instruct 832for (size_t i = 0 ;i < chat .size ();i ++ ) { 833 std::string role (chat [i ]-> role ); 834if (i == 0 ) { 835if (role == "system" ) { 836ss <<chat [i ]-> content <<"<|hy_place▁holder▁no▁3|>" ; 837 } 838 } 839 840if (role == "assistant" ) { 841ss <<"<|hy_Assistant|>" <<chat [i ]-> content <<"<|hy_place▁holder▁no▁2|>" ; 842 }else if (role == "user" ) { 843ss <<"<|hy_User|>" <<chat [i ]-> content <<"<|hy_Assistant|>" ; 844 } 845 } 846 }else if (tmpl == LLM_CHAT_TEMPLATE_HUNYUAN_VL ) { 847// tencent/HunyuanOCR & tencent/HunyuanVL 848ss <<"<|hy_begin▁of▁sentence|>" ; 849for (size_t i = 0 ;i < chat .size ();i ++ ) { 850 std::string role (chat [i ]-> role ); 851if (i == 0 && role == "system" ) { 852ss <<chat [i ]-> content <<"<|hy_place▁holder▁no▁3|>" ; 853continue ; 854 } 855 856if (role == "user" ) { 857ss <<chat [i ]-> content <<"<|hy_User|>" ; 858 }else if (role == "assistant" ) { 859ss <<chat [i ]-> content <<"<|hy_Assistant|>" ; 860 } 861 } 862 }else if (tmpl == LLM_CHAT_TEMPLATE_KIMI_K2 ) { 863// moonshotai/Kimi-K2-Instruct 864for (auto message :chat ) { 865 std::string role (message -> role ); 866if (role == "system" ) { 867ss <<"<|im_system|>system<|im_middle|>" ; 868 }else if (role == "user" ) { 869ss <<"<|im_user|>user<|im_middle|>" ; 870 }else if (role == "assistant" ) { 871ss <<"<|im_assistant|>assistant<|im_middle|>" ; 872 }else if (role == "tool" ) { 873ss <<"<|im_system|>tool<|im_middle|>" ; 874 } 875 876ss <<message -> content <<"<|im_end|>" ; 877 } 878if (add_ass ) { 879ss <<"<|im_assistant|>assistant<|im_middle|>" ; 880 } 881 }else if (tmpl == LLM_CHAT_TEMPLATE_SEED_OSS ) { 882for (auto message :chat ) { 883 std::string role (message -> role ); 884ss <<"<seed:bos>" <<role <<"\n" << (role == "assistant" ?trim (message -> content ) :message -> content ) <<"<seed:eos>" ; 885 } 886if (add_ass ) { 887ss <<"<seed:bos>assistant\n" ; 888 } 889 }else if (tmpl == LLM_CHAT_TEMPLATE_GROK_2 ) { 890for (auto message :chat ) { 891 std::string role (message -> role ); 892if (role == "system" ) { 893ss <<"System: " <<trim (message -> content ) <<"<|separator|>\n\n" ; 894 }else if (role == "user" ) { 895ss <<"Human: " <<trim (message -> content ) <<"<|separator|>\n\n" ; 896 }else if (role == "assistant" ) { 897ss <<"Assistant: " <<message -> content <<"<|separator|>\n\n" ; 898 } 899 } 900if (add_ass ) { 901ss <<"Assistant:" ; 902 } 903 }else if (tmpl == LLM_CHAT_TEMPLATE_PANGU_EMBED ) { 904// [unused9]系统:xxx[unused10] 905// [unused9]用户:xxx[unused10] 906// [unused9]助手:xxx[unused10] 907// ... 908for (size_t i = 0 ;i < chat .size ();++ i ) { 909const auto & msg = chat [i ]; 910const std::string & role = msg -> role ; 911const std::string & content = msg -> content ; 912 913if (i == 0 && role != "system" ) { 914ss <<"[unused9]系统:[unused10]" ; 915 } 916 917if (role == "system" ) { 918ss <<"[unused9]系统:" <<content <<"[unused10]" ; 919 }else if (role == "user" ) { 920ss <<"[unused9]用户:" <<content <<"[unused10]" ; 921 }else if (role == "assistant" ) { 922ss <<"[unused9]助手:" <<content <<"[unused10]" ; 923 }else if (role == "tool" ) { 924ss <<"[unused9]工具:" <<content <<"[unused10]" ; 925 }else if (role == "function" ) { 926ss <<"[unused9]方法:" <<content <<"[unused10]" ; 927 } 928 } 929if (add_ass ) { 930ss <<"[unused9]助手:" ; 931 } 932 }else if (tmpl == LLM_CHAT_TEMPLATE_SOLAR_OPEN ) { 933for (auto message :chat ) { 934 std::string role (message -> role ); 935ss <<"<|begin|>" <<role <<"<|content|>" <<message -> content <<"<|end|>" ; 936 } 937if (add_ass ) { 938ss <<"<|begin|>assistant" ; 939 } 940 }else { 941// template not supported 942return -1 ; 943 } 944dest = ss .str (); 945return dest .size (); 946} 947 948// public interface 949 950int32_t llama_chat_builtin_templates (const char ** output ,size_t len ) { 951auto it = LLM_CHAT_TEMPLATES .begin (); 952for (size_t i = 0 ;i < std::min (len ,LLM_CHAT_TEMPLATES .size ());i ++ ) { 953output [i ]= it -> first .c_str (); 954 std::advance (it ,1 ); 955 } 956return (int32_t )LLM_CHAT_TEMPLATES .size (); 957}