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 %}
 6{%- endif %}
 7{%- if not tools is defined %}
 8    {%- set tools = none %}
 9{%- endif %}
10{%- set user_messages = loop_messages | selectattr("role", "equalto", "user") | list %}
11
12{#- This block checks for alternating user/assistant messages, skipping tool calling messages #}
13{%- set ns = namespace() %}
14{%- set ns.index = 0 %}
15{%- for message in loop_messages %}
16    {%- if not (message.role == "tool" or message.role == "tool_results" or (message.tool_calls is defined and message.tool_calls is not none)) %}
17        {%- if (message["role"] == "user") != (ns.index % 2 == 0) %}
18            {{- raise_exception("After the optional system message, conversation roles must alternate user/assistant/user/assistant/...") }}
19        {%- endif %}
20        {%- set ns.index = ns.index + 1 %}
21    {%- endif %}
22{%- endfor %}
23
24{{- bos_token }}
25{%- for message in loop_messages %}
26    {%- if message["role"] == "user" %}
27        {%- if tools is not none and (message == user_messages[-1]) %}
28            {{- "[AVAILABLE_TOOLS][" }}
29            {%- for tool in tools %}
30                {%- set tool = tool.function %}
31                {{- '{"type": "function", "function": {' }}
32                {%- for key, val in tool.items() if key != "return" %}
33                    {%- if val is string %}
34                        {{- '"' + key + '": "' + val + '"' }}
35                    {%- else %}
36                        {{- '"' + key + '": ' + val|tojson }}
37                    {%- endif %}
38                    {%- if not loop.last %}
39                        {{- ", " }}
40                    {%- endif %}
41                {%- endfor %}
42                {{- "}}" }}
43                {%- if not loop.last %}
44                    {{- ", " }}
45                {%- else %}
46                    {{- "]" }}
47                {%- endif %}
48            {%- endfor %}
49            {{- "[/AVAILABLE_TOOLS]" }}
50            {%- endif %}
51        {%- if loop.last and system_message is defined %}
52            {{- "[INST]" + system_message + "\n\n" + message["content"] + "[/INST]" }}
53        {%- else %}
54            {{- "[INST]" + message["content"] + "[/INST]" }}
55        {%- endif %}
56    {%- elif (message.tool_calls is defined and message.tool_calls is not none) %}
57        {{- "[TOOL_CALLS][" }}
58        {%- for tool_call in message.tool_calls %}
59            {%- set out = tool_call.function|tojson %}
60            {{- out[:-1] }}
61            {%- if not tool_call.id is defined or tool_call.id|length != 9 %}
62                {{- raise_exception("Tool call IDs should be alphanumeric strings with length 9!") }}
63            {%- endif %}
64            {{- ', "id": "' + tool_call.id + '"}' }}
65            {%- if not loop.last %}
66                {{- ", " }}
67            {%- else %}
68                {{- "]" + eos_token }}
69            {%- endif %}
70        {%- endfor %}
71    {%- elif message["role"] == "assistant" %}
72        {{- message["content"] + eos_token}}
73    {%- elif message["role"] == "tool_results" or message["role"] == "tool" %}
74        {%- if message.content is defined and message.content.content is defined %}
75            {%- set content = message.content.content %}
76        {%- else %}
77            {%- set content = message.content %}
78        {%- endif %}
79        {{- '[TOOL_RESULTS]{"content": ' + content|string + ", " }}
80        {%- if not message.tool_call_id is defined or message.tool_call_id|length != 9 %}
81            {{- raise_exception("Tool call IDs should be alphanumeric strings with length 9!") }}
82        {%- endif %}
83        {{- '"call_id": "' + message.tool_call_id + '"}[/TOOL_RESULTS]' }}
84    {%- else %}
85        {{- raise_exception("Only user and assistant roles are supported, with the exception of an initial optional system message!") }}
86    {%- endif %}
87{%- endfor %}