aleada commited on
Commit
c62c19f
·
verified ·
1 Parent(s): c5ccbb3

Fix chat template: handle system message with multimodal (list) content

Browse files

The template did `"[INST]" + system_message`, assuming string content. OpenAI-compatible servers (vLLM / litellm) normalize content into the content-parts list form for multimodal models, so any request carrying a system message raised: can only concatenate str (not list) to str. Flatten system + assistant list content to their text chunks; the user branch was already list-aware.

Files changed (1) hide show
  1. chat_template.jinja +38 -6
chat_template.jinja CHANGED
@@ -1,5 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  {%- if messages[0]["role"] == "system" %}
2
- {%- set system_message = messages[0]["content"] %}
 
 
 
 
 
 
 
 
 
 
 
3
  {%- set loop_messages = messages[1:] %}
4
  {%- else %}
5
  {%- set loop_messages = messages %}
@@ -12,9 +37,7 @@
12
  {%- endif %}
13
  {%- if message["role"] == "user" %}
14
  {%- if loop.last and system_message is defined %}
15
- {{- "[INST]" + system_message + "
16
-
17
- " }}
18
  {%- else %}
19
  {{- "[INST]" }}
20
  {%- endif %}
@@ -33,8 +56,17 @@
33
  {%- endif %}
34
  {{- "[/INST]" }}
35
  {%- elif message["role"] == "assistant" %}
36
- {{- message["content"] + eos_token}}
 
 
 
 
 
 
 
 
 
37
  {%- else %}
38
  {{- raise_exception("Only user and assistant roles are supported, with the exception of an initial optional system message!") }}
39
  {%- endif %}
40
- {%- endfor %}
 
1
+ {#- Pixtral-12B chat template — patched 2026-07-05.
2
+
3
+ The original template did `"[INST]" + system_message` and
4
+ `message["content"] + eos_token`, assuming `content` is ALWAYS a
5
+ plain string. Pixtral is multimodal, so OpenAI-compatible servers
6
+ (vLLM, litellm, ...) normalize message content into the content-parts
7
+ LIST form (`[{"type": "text", "text": ...}]`) before the template
8
+ runs. A plain system/assistant message then arrives as a list and
9
+ `str + list` raises "can only concatenate str (not list) to str" —
10
+ any request carrying a `system` message 400'd.
11
+
12
+ Fix: flatten system + assistant content to their text chunks when
13
+ they arrive as a list. The user branch already handled both string
14
+ and list content (including [IMG]) correctly and is unchanged. #}
15
  {%- if messages[0]["role"] == "system" %}
16
+ {%- set system_raw = messages[0]["content"] %}
17
+ {%- if system_raw is string %}
18
+ {%- set system_message = system_raw %}
19
+ {%- else %}
20
+ {%- set sys_ns = namespace(text="") %}
21
+ {%- for chunk in system_raw %}
22
+ {%- if chunk["type"] == "text" %}
23
+ {%- set sys_ns.text = sys_ns.text + chunk["text"] %}
24
+ {%- endif %}
25
+ {%- endfor %}
26
+ {%- set system_message = sys_ns.text %}
27
+ {%- endif %}
28
  {%- set loop_messages = messages[1:] %}
29
  {%- else %}
30
  {%- set loop_messages = messages %}
 
37
  {%- endif %}
38
  {%- if message["role"] == "user" %}
39
  {%- if loop.last and system_message is defined %}
40
+ {{- "[INST]" + system_message + "\n\n" }}
 
 
41
  {%- else %}
42
  {{- "[INST]" }}
43
  {%- endif %}
 
56
  {%- endif %}
57
  {{- "[/INST]" }}
58
  {%- elif message["role"] == "assistant" %}
59
+ {%- if message["content"] is string %}
60
+ {{- message["content"] + eos_token }}
61
+ {%- else %}
62
+ {%- for chunk in message["content"] %}
63
+ {%- if chunk["type"] == "text" %}
64
+ {{- chunk["text"] }}
65
+ {%- endif %}
66
+ {%- endfor %}
67
+ {{- eos_token }}
68
+ {%- endif %}
69
  {%- else %}
70
  {{- raise_exception("Only user and assistant roles are supported, with the exception of an initial optional system message!") }}
71
  {%- endif %}
72
+ {%- endfor %}