@@ -62,6 +62,7 @@ static const std::map<std::string, llm_chat_template> LLM_CHAT_TEMPLATES = {
6262 { " rwkv-world" , LLM_CHAT_TEMPLATE_RWKV_WORLD },
6363 { " granite" , LLM_CHAT_TEMPLATE_GRANITE_3_X },
6464 { " granite-4.0" , LLM_CHAT_TEMPLATE_GRANITE_4_0 },
65+ { " granite-4.1" , LLM_CHAT_TEMPLATE_GRANITE_4_1 },
6566 { " gigachat" , LLM_CHAT_TEMPLATE_GIGACHAT },
6667 { " megrez" , LLM_CHAT_TEMPLATE_MEGREZ },
6768 { " yandex" , LLM_CHAT_TEMPLATE_YANDEX },
@@ -194,7 +195,10 @@ llm_chat_template llm_chat_detect_template(const std::string & tmpl) {
194195 return LLM_CHAT_TEMPLATE_RWKV_WORLD ;
195196 } else if (tmpl_contains (" <|start_of_role|>" )) {
196197 if (tmpl_contains (" <tool_call>" ) || tmpl_contains (" <tools>" )) {
197- return LLM_CHAT_TEMPLATE_GRANITE_4_0 ;
198+ if (tmpl_contains (" g4_default_system_message" )) {
199+ return LLM_CHAT_TEMPLATE_GRANITE_4_0 ;
200+ }
201+ return LLM_CHAT_TEMPLATE_GRANITE_4_1 ;
198202 }
199203 return LLM_CHAT_TEMPLATE_GRANITE_3_X ;
200204 } else if (tmpl_contains (" message['role'] + additional_special_tokens[0] + message['content'] + additional_special_tokens[1]" )) {
@@ -651,6 +655,20 @@ int32_t llm_chat_apply_template(
651655 if (add_ass) {
652656 ss << " <|start_of_role|>assistant<|end_of_role|>" ;
653657 }
658+ } else if (tmpl == LLM_CHAT_TEMPLATE_GRANITE_4_1 ) {
659+ // IBM Granite 4.1 template
660+ for (const auto & message : chat) {
661+ std::string role (message->role );
662+ if (role == " assistant_tool_call" ) {
663+ ss << " <|start_of_role|>assistant<|end_of_role|><|tool_call|>" ;
664+ } else {
665+ ss << " <|start_of_role|>" << role << " <|end_of_role|>" ;
666+ }
667+ ss << message->content << " <|end_of_text|>\n " ;
668+ }
669+ if (add_ass) {
670+ ss << " <|start_of_role|>assistant<|end_of_role|>" ;
671+ }
654672 } else if (tmpl == LLM_CHAT_TEMPLATE_GIGACHAT ) {
655673 // GigaChat template
656674 bool has_system = !chat.empty () && std::string (chat[0 ]->role ) == " system" ;
0 commit comments