From e079cf16a212711663aa84cd4c2db064e8300922 Mon Sep 17 00:00:00 2001 From: Joaquin Hui <132194176+joaquinhuigomez@users.noreply.github.com> Date: Sun, 12 Apr 2026 05:58:58 +0100 Subject: [PATCH] qwen3_5.jinja: handle list content on system messages (#3595) [skip ci] * qwen3_5.jinja: handle list content on system messages The system message branch used string concatenation on messages[0].content, which breaks when the first system message uses the OpenAI-style list-of-parts format that multimodal datasets require. User and assistant branches already handle both string and list content, but the system branch did not. Check whether content is a string and fall back to iterating over parts when it is a list, matching the pattern used for user messages. Fixes #3590 * Address pr for other content types --------- Co-authored-by: Joaquin Hui Gomez Co-authored-by: Wing Lian --- .../chat_templates/templates/qwen3_5.jinja | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/axolotl/utils/chat_templates/templates/qwen3_5.jinja b/src/axolotl/utils/chat_templates/templates/qwen3_5.jinja index 21f5733ed..c8d0e8da0 100644 --- a/src/axolotl/utils/chat_templates/templates/qwen3_5.jinja +++ b/src/axolotl/utils/chat_templates/templates/qwen3_5.jinja @@ -1,7 +1,19 @@ {%- if tools %} {{- '<|im_start|>system\n' }} {%- if messages[0].role == 'system' %} - {{- messages[0].content + '\n\n' }} + {%- if messages[0].content is string %} + {{- messages[0].content + '\n\n' }} + {%- else %} + {%- for part in messages[0].content %} + {%- if part is mapping %} + {%- set system_text = part.get('text') or part.get('content') or part.get('value') %} + {%- if system_text %}{{- system_text }}{%- endif %} + {%- elif part is string %} + {{- part }} + {%- endif %} + {%- endfor %} + {{- '\n\n' }} + {%- endif %} {%- endif %} {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }} {%- for tool in tools %} @@ -11,7 +23,20 @@ {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }} {%- else %} {%- if messages[0].role == 'system' %} - {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }} + {%- if messages[0].content is string %} + {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }} + {%- else %} + {{- '<|im_start|>system\n' }} + {%- for part in messages[0].content %} + {%- if part is mapping %} + {%- set system_text = part.get('text') or part.get('content') or part.get('value') %} + {%- if system_text %}{{- system_text }}{%- endif %} + {%- elif part is string %} + {{- part }} + {%- endif %} + {%- endfor %} + {{- '<|im_end|>\n' }} + {%- endif %} {%- endif %} {%- endif %} {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}