char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Piotr Wilkin (ilintar)common/parser: add proper reasoning tag prefill reading (#20424)5e54d51b1

char/aliceai-t5-moe
7.9 KiB171 linesraw
1{# ---------------------------------------------------------------------- #}
2{# ƛƬ Default setup and flags                                             #}
3{# ---------------------------------------------------------------------- #}
4{%- set messages = messages or [] -%}
5{%- set tools = tools or [] -%}
6{%- set add_generation_prompt = add_generation_prompt or false -%}
7{%- set available_tool_string = '' -%}
8{%- set add_tool_id = true -%}
9{%- set add_thoughts = true -%}            {# whether to include <thinking> reasoning blocks #}
10{# Optional token placeholders (safe defaults) #}
11{%- set bos_token = bos_token or '' -%}
12{%- set eos_token = eos_token or '' -%}
13{# ---------------------------------------------------------------------- #}
14{# Core reasoning prompt and assistant reasoning prefix                 #}
15{# ---------------------------------------------------------------------- #}
16{%- set reasoning_prompt -%}
17    You are a thoughtful, systematic AI assistant from ServiceNow Language Models (SLAM) lab.
18    Analyze each question carefully, present your reasoning step-by-step, then provide the final
19    response after the marker [BEGIN FINAL RESPONSE].
20{%- endset -%}
21{%- set reasoning_asst_turn_start = 'Here are my reasoning steps:\n' -%}
22{# ---------------------------------------------------------------------- #}
23{# Tool list and tool call output format                                  #}
24{# ---------------------------------------------------------------------- #}
25{%- if tools|length > 0 -%}
26    {%- set available_tool_string -%}
27        You are provided with function signatures within <available_tools></available_tools> XML tags.
28        You may call one or more functions to assist with the user query.
29        Don't make assumptions about the arguments. You should infer the argument values from previous
30        user responses and the system message.
31        Here are the available tools: 
32        <available_tools>
33        {% for tool in tools %}{{ tool|string }}{% endfor %}
34        
35        </available_tools>.
36
37        Return all function calls as a list of JSON objects within <tool_calls></tool_calls> XML tags.
38        Each JSON object should contain a function name and arguments as follows:
39        <tool_calls>[
40            {"name": <function-name-1>, "arguments": <args-dict-1>},
41            {"name": <function-name-2>, "arguments": <args-dict-2>},
42            ...
43        ]</tool_calls>
44    {%- endset -%}
45{%- endif -%}
46{# ---------------------------------------------------------------------- #}
47{# Start system block if first message is not system                      #}
48{# ---------------------------------------------------------------------- #}
49{%- if messages|length > 0 and messages[0]['role'] != 'system' -%}
50    {%- if tools|length > 0 -%}
51        {{ bos_token + '<|begin_system|>\n' + reasoning_prompt + '\n' + available_tool_string + '\n' }}
52    {%- else -%}
53        {{ bos_token + '<|begin_system|>\n' + reasoning_prompt + '\n' }}
54    {%- endif -%}
55{%- endif -%}
56{# ---------------------------------------------------------------------- #}
57{# Iterate through messages                                             #}
58{# ---------------------------------------------------------------------- #}
59{%- for message in messages -%}
60
61    {# ---------------- USER MESSAGE ---------------- #}
62    {%- if message['role'] == 'user' -%}
63        {{ '<|begin_user|>\n' }}
64        {%- if message['content'] is not string -%}
65            {%- for chunk in message['content'] -%}
66                {%- if chunk['type'] == 'text' -%}
67                    {{ chunk['text'] }}
68                {%- elif chunk['type'] in ['image', 'image_url'] -%}
69                    {{ '[IMG]' }}
70                {%- else -%}
71                    {{ raise_exception('Unrecognized content type!') }}
72                {%- endif -%}
73            {%- endfor -%}
74        {%- else -%}
75            {{ message['content'] }}
76        {%- endif -%}
77
78    {# ---------------- SYSTEM MESSAGE ---------------- #}
79    {%- elif message['role'] == 'system' -%}
80        {%- set sys_content = message.get('content', '') -%}
81        {%- if sys_content and sys_content|length > 0 -%}
82            {%- if sys_content is string -%}
83                {%- set system_message = sys_content -%}
84            {%- else -%}
85                {%- set system_message = sys_content[0]['text'] -%}
86            {%- endif -%}
87        {%- else -%}
88            {%- set system_message = '' -%}
89        {%- endif -%}
90
91        {%- if tools|length > 0 -%}
92            {{ bos_token + '<|begin_system|>\n' + reasoning_prompt + '\n' + system_message + '\n' + available_tool_string + '\n' }}
93        {%- else -%}
94            {{ bos_token + '<|begin_system|>\n' + reasoning_prompt + '\n' + system_message + '\n' }}
95        {%- endif -%}
96
97    {# ---------------- ASSISTANT MESSAGE ---------------- #}
98    {%- elif message['role'] == 'assistant' -%}
99        {%- if loop.last -%}
100            {%- set add_tool_id = false -%}
101        {%- endif -%}
102
103        {{ '\n<|begin_assistant|>\n' }}
104
105        {%- if add_thoughts and message.get('reasoning_content') and loop.last -%}
106            {{ message['reasoning_content'] + '\n[BEGIN FINAL RESPONSE]\n' }}
107        {%- endif -%}
108
109        {%- set asst_content = message.get('content', '') -%}
110        {%- if asst_content and asst_content|length > 0 -%}
111            {%- if asst_content is not string -%}
112                {%- set asst_text = asst_content[0]['text'] -%}
113            {%- else -%}
114                {%- set asst_text = asst_content -%}
115            {%- endif -%}
116            {# For historical turns (not the last), strip reasoning and keep only final response #}
117            {%- if not loop.last and '[BEGIN FINAL RESPONSE]' in asst_text -%}
118                {{- asst_text.split('[BEGIN FINAL RESPONSE]')[-1] | trim -}}
119            {%- else -%}
120                {{- asst_text -}}
121            {%- endif -%}
122        {%- elif message.get('chosen') and message['chosen']|length > 0 -%}
123            {{ message['chosen'][0] }}
124        {%- endif -%}
125
126        {# Tool call output #}
127        {%- set tool_calls = message.get('tool_calls', []) -%}
128        {%- if tool_calls and tool_calls|length > 0 -%}
129            {{ '\n<tool_calls>[' }}
130            {%- for tool_call in tool_calls -%}
131                {{ '{"name": "' + tool_call['function']['name'] + '", "arguments": ' + tool_call['function']['arguments']|tojson }}
132                {%- if add_tool_id == true and 'id' in tool_call -%}
133                    {{ ', "id": "' + tool_call['id'] + '"' }}
134                {%- endif -%}
135                {{ '}' }}
136                {%- if not loop.last -%}{{ ', ' }}{%- endif -%}
137            {%- endfor -%}
138            {{ ']</tool_calls>' }}
139        {%- endif -%}
140
141        {%- set training_prompt = training_prompt if (training_prompt is defined) else false -%}
142        {%- if not loop.last or training_prompt -%}
143            {{ '\n<|end|>\n' }}
144        {%- endif -%}
145
146    {# ---------------- TOOL RESULT MESSAGE ---------------- #}
147    {%- elif message['role'] == 'tool' -%}
148        {%- set tool_content = message.get('content', '') -%}
149        {%- if tool_content is string -%}
150            {%- set tool_message = tool_content -%}
151        {%- else -%}
152            {%- set tool_message = tool_content[0]['text'] if tool_content else '' -%}
153        {%- endif -%}
154        {{ '<|begin_tool_result|>\n' + tool_message|string + '\n' }}
155
156    {# ---------------- CONTENT MESSAGE ---------------- #}
157    {%- elif message['role'] == 'content' -%}
158        {%- set msg_content = message.get('content', '') -%}
159        {%- if msg_content is not string -%}
160            {{ '<|begin_content|>\n' + msg_content[0]['text'] + '\n' }}
161        {%- else -%}
162            {{ '<|begin_content|>\n' + msg_content + '\n' }}
163        {%- endif -%}
164    {%- endif -%}
165
166    {# ---------------- REASONING PROMPT BEFORE NEXT ASSISTANT ---------------- #}
167    {%- if loop.last and add_generation_prompt and message['role'] != 'assistant' -%}
168        {{ '\n<|begin_assistant|>\n' + reasoning_asst_turn_start }}
169    {%- endif -%} 
170
171{%- endfor -%}