3using System.Collections.Generic;
22 public static Dictionary<string, ChatTemplate>
templates;
25 public static Dictionary<string, string> templatesDescription;
26 public static Dictionary<string, string> modelTemplates;
27 public static Dictionary<string, string> chatTemplates;
58 templates =
new Dictionary<string, ChatTemplate>();
59 templatesDescription =
new Dictionary<string, string>();
60 modelTemplates =
new Dictionary<string, string>();
61 chatTemplates =
new Dictionary<string, string>();
64 if (
templates.ContainsKey(
template.GetName()))
LLMUnitySetup.LogError($
"{template.GetName()} already in templates");
66 if (templatesDescription.ContainsKey(
template.GetDescription()))
LLMUnitySetup.LogError($
"{template.GetDescription()} already in templatesDescription");
67 templatesDescription[
template.GetDescription()] =
template.GetName();
70 if (modelTemplates.ContainsKey(match))
LLMUnitySetup.LogError($
"Name for {template.GetName()} already in modelTemplates");
71 modelTemplates[match] =
template.GetName();
75 if (chatTemplates.ContainsKey(match))
LLMUnitySetup.LogError($
"Chat template for {template.GetName()} already in chatTemplates");
76 chatTemplates[match] =
template.GetName();
89 if (name ==
null)
return null;
90 string nameLower = name.ToLower();
93 foreach (var pair
in modelTemplates)
95 if (nameLower.Contains(pair.Key) && pair.Key.Length > maxMatch)
97 maxMatch = pair.Key.Length;
111 if (
template ==
null)
return null;
112 string templateTrim =
template.Trim();
113 if (chatTemplates.TryGetValue(templateTrim, out
string value))
137 if (name !=
null)
return name;
140 if (name !=
null)
return name;
142 name =
FromName(Path.GetFileNameWithoutExtension(path));
143 if (name !=
null)
return name;
145 LLMUnitySetup.Log(
"No chat template could be matched, fallback to ChatML");
160 public virtual string GetName() {
return ""; }
168 public virtual string[]
GetStop(
string playerName,
string AIName) {
return new string[] {}; }
170 protected virtual string PromptPrefix() {
return ""; }
171 protected virtual string SystemPrefix() {
return ""; }
172 protected virtual string SystemSuffix() {
return ""; }
173 protected virtual string PlayerPrefix(
string playerName) {
return ""; }
174 protected virtual string AIPrefix(
string AIName) {
return ""; }
175 protected virtual string PrefixMessageSeparator() {
return ""; }
176 protected virtual string RequestPrefix() {
return ""; }
177 protected virtual string RequestSuffix() {
return ""; }
178 protected virtual string PairSuffix() {
return ""; }
180 protected virtual bool SystemPromptSupported() {
return true; }
181 protected virtual bool HasThinkingMode() {
return false; }
188 public virtual string ComputePrompt(List<ChatMessage> chatMessages,
string playerName,
string AIName,
bool endWithPrefix =
true)
190 List<ChatMessage> messages = chatMessages;
191 if (!SystemPromptSupported())
193 if (chatMessages[0].role ==
"system")
195 string firstUserMessage = chatMessages[0].content;
197 if (chatMessages.Count > 1)
199 if (firstUserMessage !=
"") firstUserMessage +=
"\n\n";
200 firstUserMessage += chatMessages[1].content;
203 messages =
new List<ChatMessage>(){
new ChatMessage { role = playerName, content = firstUserMessage }};
204 messages.AddRange(chatMessages.GetRange(newStart, chatMessages.Count - newStart));
208 string chatPrompt = PromptPrefix();
210 if (messages[0].role ==
"system")
212 chatPrompt += RequestPrefix() + SystemPrefix() + messages[0].content + SystemSuffix();
215 for (
int i = start; i < messages.Count; i += 2)
217 if (i > start || start == 0) chatPrompt += RequestPrefix();
218 chatPrompt += PlayerPrefix(messages[i].role) + PrefixMessageSeparator() + messages[i].content + RequestSuffix();
219 if (i < messages.Count - 1)
221 chatPrompt += AIPrefix(messages[i + 1].role) + PrefixMessageSeparator() + messages[i + 1].content + PairSuffix();
226 chatPrompt += AIPrefix(AIName);
227 if (HasThinkingMode()) chatPrompt +=
"<think>\n\n</think>\n\n";
232 protected string[] AddStopNewlines(
string[] stop)
234 List<string> stopWithNewLines =
new List<string>();
235 foreach (
string stopword
in stop)
237 stopWithNewLines.Add(stopword);
238 stopWithNewLines.Add(
"\n" + stopword);
240 return stopWithNewLines.ToArray();
250 public override string GetName() {
return "chatml"; }
252 public override string[]
GetNameMatches() {
return new string[] {
"chatml",
"hermes",
"qwen"}; }
253 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"}; }
255 protected override string SystemPrefix() {
return "<|im_start|>system\n"; }
256 protected override string SystemSuffix() {
return "<|im_end|>\n"; }
257 protected override string PlayerPrefix(
string playerName) {
return $
"<|im_start|>{playerName}\n"; }
258 protected override string AIPrefix(
string AIName) {
return $
"<|im_start|>{AIName}\n"; }
259 protected override string RequestSuffix() {
return "<|im_end|>\n"; }
260 protected override string PairSuffix() {
return "<|im_end|>\n"; }
262 public override string[]
GetStop(
string playerName,
string AIName)
264 return AddStopNewlines(
new string[] {
"<|im_start|>",
"<|im_end|>" });
274 public override string GetName() {
return "llama"; }
277 protected override string SystemPrefix() {
return "<<SYS>>\n"; }
278 protected override string SystemSuffix() {
return "\n<</SYS>> "; }
279 protected override string RequestPrefix() {
return "<s>[INST] "; }
280 protected override string RequestSuffix() {
return " [/INST]"; }
281 protected override string PairSuffix() {
return " </s>"; }
283 public override string[]
GetStop(
string playerName,
string AIName)
285 return AddStopNewlines(
new string[] {
"[INST]",
"[/INST]" });
295 public override string GetName() {
return "llama chat"; }
297 public override string[]
GetNameMatches() {
return new string[] {
"llama-2",
"llama v2"}; }
299 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
300 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
301 protected override string PrefixMessageSeparator() {
return " "; }
303 public override string[]
GetStop(
string playerName,
string AIName)
305 return AddStopNewlines(
new string[] {
"[INST]",
"[/INST]",
"###" });
315 public override string GetName() {
return "llama3 chat"; }
317 public override string[]
GetNameMatches() {
return new string[] {
"llama-3",
"llama v3"}; }
318 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% 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' }}"};}
320 protected override string SystemPrefix() {
return "<|start_header_id|>system<|end_header_id|>\n\n"; }
321 protected override string SystemSuffix() {
return "<|eot_id|>"; }
323 protected override string RequestSuffix() {
return "<|eot_id|>"; }
324 protected override string PairSuffix() {
return "<|eot_id|>"; }
326 protected override string PlayerPrefix(
string playerName) {
return $
"<|start_header_id|>{playerName}<|end_header_id|>\n\n"; }
327 protected override string AIPrefix(
string AIName) {
return $
"<|start_header_id|>{AIName}<|end_header_id|>\n\n"; }
329 public override string[]
GetStop(
string playerName,
string AIName)
331 return AddStopNewlines(
new string[] {
"<|eot_id|>" });
341 public override string GetName() {
return "mistral instruct"; }
344 protected override string SystemPrefix() {
return ""; }
345 protected override string SystemSuffix() {
return "\n\n"; }
346 protected override string RequestPrefix() {
return "[INST] "; }
347 protected override string RequestSuffix() {
return " [/INST]"; }
348 protected override string PairSuffix() {
return "</s>"; }
350 public override string[]
GetStop(
string playerName,
string AIName)
352 return AddStopNewlines(
new string[] {
"</s>",
"[INST]",
"[/INST]" });
362 public override string GetName() {
return "mistral chat"; }
365 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{{ 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 %}"}; }
367 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
368 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
369 protected override string PrefixMessageSeparator() {
return " "; }
371 public override string[]
GetStop(
string playerName,
string AIName)
373 return AddStopNewlines(
new string[] {
"</s>",
"[INST]",
"[/INST]",
"###" });
383 public override string GetName() {
return "gemma"; }
386 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{{ bos_token }}{% 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 %}"}; }
388 protected override string RequestSuffix() {
return "<end_of_turn>\n"; }
389 protected override string PairSuffix() {
return "<end_of_turn>\n"; }
391 protected override string PlayerPrefix(
string playerName) {
return "<start_of_turn>user\n"; }
392 protected override string AIPrefix(
string AIName) {
return "<start_of_turn>model\n"; }
394 protected override bool SystemPromptSupported() {
return false; }
396 public override string[]
GetStop(
string playerName,
string AIName)
398 return AddStopNewlines(
new string[] {
"<start_of_turn>",
"<end_of_turn>" });
408 public override string GetName() {
return "alpaca"; }
412 protected override string SystemSuffix() {
return "\n\n"; }
413 protected override string RequestSuffix() {
return "\n"; }
414 protected override string PlayerPrefix(
string playerName) {
return "### " + playerName +
":"; }
415 protected override string AIPrefix(
string AIName) {
return "### " + AIName +
":"; }
416 protected override string PrefixMessageSeparator() {
return " "; }
417 protected override string PairSuffix() {
return "\n"; }
419 public override string[]
GetStop(
string playerName,
string AIName)
421 return AddStopNewlines(
new string[] {
"###" });
431 public override string GetName() {
return "vicuna"; }
434 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{% if message['role'] == 'system' %}{{message['content'] + ' '}}{% elif message['role'] == 'user' %}{{ 'USER: ' + message['content'] + ' '}}{% elif message['role'] == 'assistant' %}{{ 'ASSISTANT: ' + message['content'] + ' '}}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'ASSISTANT: '}}{% endif %}"}; }
436 protected override string SystemSuffix() {
return "\n"; }
437 protected override string PlayerPrefix(
string playerName) {
return "\n" + playerName +
":"; }
438 protected override string AIPrefix(
string AIName) {
return "\n" + AIName +
":"; }
439 protected override string PrefixMessageSeparator() {
return " "; }
441 public override string[]
GetStop(
string playerName,
string AIName)
443 return AddStopNewlines(
new string[] { playerName +
":", AIName +
":" });
453 public override string GetName() {
return "phi"; }
457 protected override string SystemSuffix() {
return "\n\n"; }
458 protected override string RequestSuffix() {
return "\n"; }
459 protected override string PlayerPrefix(
string playerName) {
return playerName +
":"; }
460 protected override string AIPrefix(
string AIName) {
return AIName +
":"; }
461 protected override string PrefixMessageSeparator() {
return " "; }
462 protected override string PairSuffix() {
return "\n"; }
464 public override string[]
GetStop(
string playerName,
string AIName)
466 return AddStopNewlines(
new string[] { playerName +
":", AIName +
":" });
476 public override string GetName() {
return "phi-3"; }
479 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{{ 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 %}"}; }
481 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
482 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
483 protected override string RequestSuffix() {
return "<|end|>\n"; }
484 protected override string PairSuffix() {
return "<|end|>\n"; }
486 protected override bool SystemPromptSupported() {
return false; }
488 public override string[]
GetStop(
string playerName,
string AIName)
490 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
500 public override string GetName() {
return "phi-3.5"; }
503 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% for message in messages %}{% if message['role'] == 'system' and message['content'] %}{{'<|system|>\n' + message['content'] + '<|end|>\n'}}{% elif message['role'] == 'user' %}{{'<|user|>\n' + message['content'] + '<|end|>\n'}}{% elif message['role'] == 'assistant' %}{{'<|assistant|>\n' + message['content'] + '<|end|>\n'}}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|assistant|>\n' }}{% else %}{{ eos_token }}{% endif %}"};}
505 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
506 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
507 protected override string RequestSuffix() {
return "<|end|>\n"; }
508 protected override string PairSuffix() {
return "<|end|>\n"; }
509 protected override string SystemPrefix() {
return "<|system|>\n"; }
510 protected override string SystemSuffix() {
return "<|end|>\n"; }
512 public override string[]
GetStop(
string playerName,
string AIName)
514 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
524 public override string GetName() {
return "phi-4-mini"; }
526 public override string[]
GetNameMatches() {
return new string[] {
"phi-4-mini"}; }
527 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% for message in messages %}{% if message['role'] == 'system' and 'tools' in message and message['tools'] is not none %}{{ '<|' + message['role'] + '|>' + message['content'] + '<|tool|>' + message['tools'] + '<|/tool|>' + '<|end|>' }}{% else %}{{ '<|' + message['role'] + '|>' + message['content'] + '<|end|>' }}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|assistant|>' }}{% else %}{{ eos_token }}{% endif %}"};}
529 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>"; }
530 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>"; }
531 protected override string RequestSuffix() {
return "<|end|>"; }
532 protected override string PairSuffix() {
return "<|end|>"; }
533 protected override string SystemPrefix() {
return "<|system|>"; }
534 protected override string SystemSuffix() {
return "<|end|>"; }
536 public override string[]
GetStop(
string playerName,
string AIName)
538 return AddStopNewlines(
new string[] {
"<|end|>",
"<|user|>",
"<|assistant|>" });
548 public override string GetName() {
return "phi-4"; }
551 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% 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|>'}}{% elif (message['role'] == 'assistant') %}{{'<|im_start|>assistant<|im_sep|>' + message['content'] + '<|im_end|>'}}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant<|im_sep|>' }}{% endif %}"};}
553 protected override string PlayerPrefix(
string playerName) {
return $
"<|im_start|>user<|im_sep|>"; }
554 protected override string AIPrefix(
string AIName) {
return $
"<|im_start|>assistant<|im_sep|>"; }
555 protected override string RequestSuffix() {
return "<|im_end|>"; }
556 protected override string PairSuffix() {
return "<|im_end|>"; }
557 protected override string SystemPrefix() {
return "<|im_start|>system<|im_sep|>"; }
558 protected override string SystemSuffix() {
return "<|im_end|>"; }
560 public override string[]
GetStop(
string playerName,
string AIName)
562 return AddStopNewlines(
new string[] {
"<|im_end|>",
"<|im_start|>" });
572 public override string GetName() {
return "zephyr"; }
575 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% for message in messages %}\n{% if message['role'] == 'user' %}\n{{ '<|user|>\n' + message['content'] + eos_token }}\n{% elif message['role'] == 'system' %}\n{{ '<|system|>\n' + message['content'] + eos_token }}\n{% elif message['role'] == 'assistant' %}\n{{ '<|assistant|>\n' + message['content'] + eos_token }}\n{% endif %}\n{% if loop.last and add_generation_prompt %}\n{{ '<|assistant|>' }}\n{% endif %}\n{% endfor %}"}; }
577 protected override string SystemPrefix() {
return "<|system|>\n"; }
578 protected override string SystemSuffix() {
return "</s>\n"; }
579 protected override string PlayerPrefix(
string playerName) {
return $
"<|user|>\n"; }
580 protected override string AIPrefix(
string AIName) {
return $
"<|assistant|>\n"; }
581 protected override string RequestSuffix() {
return "</s>\n"; }
582 protected override string PairSuffix() {
return "</s>\n"; }
584 public override string[]
GetStop(
string playerName,
string AIName)
586 return AddStopNewlines(
new string[] { $
"<|user|>", $
"<|assistant|>" });
596 public override string GetName() {
return "deepseek-v2"; }
598 public override string[]
GetNameMatches() {
return new string[] {
"deepseek-v2",
"deepseek-llm"}; }
599 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% 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 %}"}; }
601 protected override string PrefixMessageSeparator() {
return " "; }
602 protected override string PromptPrefix() {
return "<|begin▁of▁sentence|>"; }
603 protected override string PlayerPrefix(
string playerName) {
return "User:"; }
604 protected override string AIPrefix(
string AIName) {
return "Assistant:"; }
605 protected override string PairSuffix() {
return "<|end▁of▁sentence|>"; }
606 protected override string RequestSuffix() {
return "\n\n"; }
607 protected override string SystemSuffix() {
return "\n\n"; }
611 public override string[]
GetStop(
string playerName,
string AIName)
613 return AddStopNewlines(
new string[] {
"<|end▁of▁sentence|>",
"User:",
"Assistant:" });
623 public override string GetName() {
return "deepseek-v3"; }
625 public override string[]
GetNameMatches() {
return new string[] {
"deepseek-v2.5",
"deepseek-v3"}; }
630 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{{'<|Assistant|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|>'}}{% endif %}",
631 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='', is_first_sp=true) %}{%- for message in messages %}{%- if message['role'] == 'system' %}{%- if ns.is_first_sp %}{% set ns.system_prompt = ns.system_prompt + message['content'] %}{% set ns.is_first_sp = false %}{%- else %}{% set ns.system_prompt = ns.system_prompt + '\n\n' + message['content'] %}{%- endif %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{{'<|Assistant|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|>'}}{% endif %}"
635 protected override string PrefixMessageSeparator() {
return ""; }
636 protected override string PlayerPrefix(
string playerName) {
return "<|User|>"; }
637 protected override string AIPrefix(
string AIName) {
return "<|Assistant|>"; }
638 protected override string RequestSuffix() {
return ""; }
640 public override string[]
GetStop(
string playerName,
string AIName)
642 return AddStopNewlines(
new string[] {
"<|end▁of▁sentence|>",
"<|User|>",
"<|Assistant|>" });
652 public override string GetName() {
return "deepseek-r1"; }
654 public override string[]
GetNameMatches() {
return new string[] {
"deepseek-r1"}; }
659 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='', is_first_sp=true) %}{%- for message in messages %}{%- if message['role'] == 'system' %}{%- if ns.is_first_sp %}{% set ns.system_prompt = ns.system_prompt + message['content'] %}{% set ns.is_first_sp = false %}{%- else %}{% set ns.system_prompt = ns.system_prompt + '\\n\\n' + message['content'] %}{%- endif %}{%- endif %}{%- endfor %}{{ bos_token }}{{ ns.system_prompt }}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and 'tool_calls' in message %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls'] %}{%- if not ns.is_first %}{%- if message['content'] is none %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- else %}{{'<|Assistant|>' + message['content'] + '<|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- endif %}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- endif %}{%- endfor %}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- if message['role'] == 'assistant' and 'tool_calls' not in message %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = content.split('</think>')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|><think>\\n'}}{% endif %}",
660 "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\\n' + '<|tool▁call▁begin|>' + tool['type'] + '<|tool▁sep|>' + tool['function']['name'] + '\\n' + '```json' + '\\n' + tool['function']['arguments'] + '\\n' + '```' + '<|tool▁call▁end|>'}}{{'<|tool▁calls▁end|><|end▁of▁sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool▁outputs▁end|>' + message['content'] + '<|end▁of▁sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = content.split('</think>')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end▁of▁sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool▁outputs▁begin|><|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\\n<|tool▁output▁begin|>' + message['content'] + '<|tool▁output▁end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool▁outputs▁end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|><think>\\n'}}{% endif %}"
664 protected override bool HasThinkingMode() {
return true; }
666 public override string[]
GetStop(
string playerName,
string AIName)
668 return AddStopNewlines(
new string[] {
"<|end▁of▁sentence|>",
"<|User|>",
"<|Assistant|>",
"</think>" });
679 public override string GetName() {
return "qwen3"; }
682 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{%- if tools %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].role == 'system' %}\n {{- messages[0].content + '\\n\\n' }}\n {%- endif %}\n {{- \"# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call><|im_end|>\\n\" }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {{- '<|im_start|>system\\n' + messages[0].content + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for forward_message in messages %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- set message = messages[index] %}\n {%- set tool_start = '<tool_response>' %}\n {%- set tool_start_length = tool_start|length %}\n {%- set start_of_message = message.content[:tool_start_length] %}\n {%- set tool_end = '</tool_response>' %}\n {%- set tool_end_length = tool_end|length %}\n {%- set start_pos = (message.content|length) - tool_end_length %}\n {%- if start_pos < 0 %}\n {%- set start_pos = 0 %}\n {%- endif %}\n {%- set end_of_message = message.content[start_pos:] %}\n {%- if ns.multi_step_tool and message.role == \"user\" and not(start_of_message == tool_start and end_of_message == tool_end) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n{%- endfor %}\n{%- for message in messages %}\n {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) %}\n {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set content = message.content %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is defined and message.reasoning_content is not none %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- else %}\n {%- if '</think>' in message.content %}\n {%- set content = (message.content.split('</think>')|last).lstrip('\\n') %}\n {%- set reasoning_content = (message.content.split('</think>')|first).rstrip('\\n') %}\n {%- set reasoning_content = (reasoning_content.split('<think>')|last).lstrip('\\n') %}\n {%- endif %}\n {%- endif %}\n {%- if loop.index0 > ns.last_query_index %}\n {%- if loop.last or (not loop.last and reasoning_content) %}\n {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content.strip('\\n') + '\\n</think>\\n\\n' + content.lstrip('\\n') }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- if message.tool_calls %}\n {%- for tool_call in message.tool_calls %}\n {%- if (loop.first and content) or (not loop.first) %}\n {{- '\\n' }}\n {%- endif %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '<tool_call>\\n{\"name\": \"' }}\n {{- tool_call.name }}\n {{- '\", \"arguments\": ' }}\n {%- if tool_call.arguments is string %}\n {{- tool_call.arguments }}\n {%- else %}\n {{- tool_call.arguments | tojson }}\n {%- endif %}\n {{- '}\\n</tool_call>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- message.content }}\n {{- '\\n</tool_response>' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if enable_thinking is defined and enable_thinking is false %}\n {{- '<think>\\n\\n</think>\\n\\n' }}\n {%- endif %}\n{%- endif %}" }; }
684 protected override bool HasThinkingMode() {
return true; }
693 public override string GetName() {
return "bitnet"; }
696 public override string[]
GetChatTemplateMatches() {
return new string[] {
"{% set loop_messages = messages %}{% for message in loop_messages %}{% set content = message['role'] | capitalize + ': '+ message['content'] | trim + '<|eot_id|>' %}{{ content }}{% endfor %}{% if add_generation_prompt %}{{ 'Assistant: ' }}{% endif %}"};}
698 protected override string PlayerPrefix(
string playerName) {
return "User: "; }
699 protected override string AIPrefix(
string AIName) {
return "Assistant: "; }
700 protected override string RequestSuffix() {
return "<|eot_id|>"; }
701 protected override string PairSuffix() {
return "<|eot_id|>"; }
702 protected override string SystemPrefix() {
return "System: "; }
703 protected override string SystemSuffix() {
return "<|eot_id|>"; }
705 public override string[]
GetStop(
string playerName,
string AIName)
707 return AddStopNewlines(
new string[] {
"<|eot_id|>",
"User",
"Assistant" });
Class implementing the Alpaca template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
Class implementing the BitNet template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetName()
Returns the chat template name.
Class implementing the ChatML template.
override string GetName()
Returns the chat template name.
override string GetDescription()
Returns the chat template description.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the skeleton of a chat template.
static string FromGGUF(string path)
Determines the chat template name from a GGUF file. It reads the GGUF file and then determines the ch...
virtual string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
static Dictionary< string, ChatTemplate > templates
a dictionary from chat template name to chat template type. It can be used to get the chat template n...
virtual string ComputePrompt(List< ChatMessage > chatMessages, string playerName, string AIName, bool endWithPrefix=true)
Constructs the prompt using the template based on a list of ChatMessages.
virtual string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
static string FromName(string name)
Determines the chat template name from a search name. It searches if any of the chat template names i...
virtual string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
static ChatTemplate GetTemplate(string template)
Creates the chat template based on the provided chat template name.
virtual string GetName()
Returns the chat template name.
virtual string GetDescription()
Returns the chat template description.
static string FromTemplate(string template)
Determines the chat template name from a Jinja template.
static string DefaultTemplate
the default template used when it can't be determined ("chatml")
Class implementing the DeepSeek R1 template.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing the DeepSeek V2 template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
Class implementing the DeepSeek V3 template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the GGUF reader.
string GetStringField(string key)
Allows to retrieve a string GGUF field.
Class implementing the Gemma template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing helper functions for setup and process management.
Class implementing a modified version of the LLama2 template for chat.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
Class implementing the LLama2 template.
override string GetName()
Returns the chat template name.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the LLama3 template for chat.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing a modified version of the Mistral Instruct template for chat.
override string GetDescription()
Returns the chat template description.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Mistral Instruct template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Phi-2 template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
Class implementing the Phi-3 template.
override string GetDescription()
Returns the chat template description.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetName()
Returns the chat template name.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
Class implementing the Phi-4 mini template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
Class implementing the Phi-4 mini template.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Phi-4 template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string GetDescription()
Returns the chat template description.
Class implementing the Qwen3 template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetName()
Returns the chat template name.
Class implementing the Vicuna template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
Class implementing the Zephyr template.
override string[] GetChatTemplateMatches()
Returns an array of jinja templates that can be used to match the chat template.
override string GetDescription()
Returns the chat template description.
override string GetName()
Returns the chat template name.
override string[] GetStop(string playerName, string AIName)
Returns an array of the stopwords used by the template.
override string[] GetNameMatches()
Returns an array of names that can be used to match the chat template.