main
jinja 384 lines 16.5 KB
Raw
1 {%- macro render_typescript_type(param_spec, required_params, is_nullable=false) -%}
2 {%- if param_spec.type == "array" -%}
3 {%- if param_spec['items'] -%}
4 {%- if param_spec['items']['type'] == "string" -%}
5 {{- "string[]" }}
6 {%- elif param_spec['items']['type'] == "number" -%}
7 {{- "number[]" }}
8 {%- elif param_spec['items']['type'] == "integer" -%}
9 {{- "number[]" }}
10 {%- elif param_spec['items']['type'] == "boolean" -%}
11 {{- "boolean[]" }}
12 {%- else -%}
13 {%- set inner_type = render_typescript_type(param_spec['items'], required_params) -%}
14 {%- if inner_type == "object | object" or inner_type|length > 50 -%}
15 {{- "any[]" }}
16 {%- else -%}
17 {{- inner_type + "[]" }}
18 {%- endif -%}
19 {%- endif -%}
20 {%- if param_spec.nullable -%}
21 {{- " | null" }}
22 {%- endif -%}
23 {%- else -%}
24 {{- "any[]" }}
25 {%- if param_spec.nullable -%}
26 {{- " | null" }}
27 {%- endif -%}
28 {%- endif -%}
29 {%- elif param_spec.type is defined and param_spec.type is iterable and param_spec.type is not string and param_spec.type is not mapping and param_spec.type[0] is defined -%}
30 {#- Handle array of types like ["object", "object"] from Union[dict, list] #}
31 {%- if param_spec.type | length > 1 -%}
32 {{- param_spec.type | join(" | ") }}
33 {%- else -%}
34 {{- param_spec.type[0] }}
35 {%- endif -%}
36 {%- elif param_spec.oneOf -%}
37 {#- Handle oneOf schemas - check for complex unions and fallback to any #}
38 {%- set has_object_variants = false -%}
39 {%- for variant in param_spec.oneOf -%}
40 {%- if variant.type == "object" -%}
41 {%- set has_object_variants = true -%}
42 {%- endif -%}
43 {%- endfor -%}
44 {%- if has_object_variants and param_spec.oneOf|length > 1 -%}
45 {{- "any" }}
46 {%- else -%}
47 {%- for variant in param_spec.oneOf -%}
48 {{- render_typescript_type(variant, required_params) -}}
49 {%- if variant.description %}
50 {{- "// " + variant.description }}
51 {%- endif -%}
52 {%- if variant.default is defined %}
53 {{ "// default: " + variant.default|tojson }}
54 {%- endif -%}
55 {%- if not loop.last %}
56 {{- " | " }}
57 {% endif -%}
58 {%- endfor -%}
59 {%- endif -%}
60 {%- elif param_spec.type == "string" -%}
61 {%- if param_spec.enum -%}
62 {{- '"' + param_spec.enum|join('" | "') + '"' -}}
63 {%- else -%}
64 {{- "string" }}
65 {%- if param_spec.nullable %}
66 {{- " | null" }}
67 {%- endif -%}
68 {%- endif -%}
69 {%- elif param_spec.type == "number" -%}
70 {{- "number" }}
71 {%- elif param_spec.type == "integer" -%}
72 {{- "number" }}
73 {%- elif param_spec.type == "boolean" -%}
74 {{- "boolean" }}
75 {%- elif param_spec.type == "object" -%}
76 {%- if param_spec.properties -%}
77 {{- "{\n" }}
78 {%- for prop_name, prop_spec in param_spec.properties.items() -%}
79 {{- prop_name -}}
80 {%- if prop_name not in (param_spec.required or []) -%}
81 {{- "?" }}
82 {%- endif -%}
83 {{- ": " }}
84 {{ render_typescript_type(prop_spec, param_spec.required or []) }}
85 {%- if not loop.last -%}
86 {{-", " }}
87 {%- endif -%}
88 {%- endfor -%}
89 {{- "}" }}
90 {%- else -%}
91 {{- "object" }}
92 {%- endif -%}
93 {%- else -%}
94 {{- "any" }}
95 {%- endif -%}
96 {%- endmacro -%}
97
98 {%- macro render_tools(tools) -%}
99 {%- for tool in tools %}
100 {%- if tool.function is defined -%}
101 {#- Chat Completions format: {"type": "function", "function": {...}} #}
102 {%- set func = tool.function -%}
103 {%- if func.description is defined -%}
104 {{- "// " + func.description + "\n" }}
105 {%- endif -%}
106 {{- "type "+ func.name + " = " }}
107 {%- if func.parameters and func.parameters.properties %}
108 {{- "(_: {\n" }}
109 {%- for param_name, param_spec in func.parameters.properties.items() %}
110 {%- if param_spec.description is defined %}
111 {{- "// " + param_spec.description + "\n" }}
112 {%- endif %}
113 {{- param_name }}
114 {%- if param_name not in (func.parameters.required or []) -%}
115 {{- "?" }}
116 {%- endif -%}
117 {{- ": " }}
118 {{- render_typescript_type(param_spec, func.parameters.required or []) }}
119 {%- if param_spec.default is defined -%}
120 {%- if param_spec.enum %}
121 {{- ", // default: " + param_spec.default }}
122 {%- elif param_spec.oneOf %}
123 {{- "// default: " + param_spec.default }}
124 {%- else %}
125 {{- ", // default: " + param_spec.default|tojson }}
126 {%- endif -%}
127 {%- endif -%}
128 {%- if not loop.last %}
129 {{- ",\n" }}
130 {%- else %}
131 {{- "\n" }}
132 {%- endif -%}
133 {%- endfor %}
134 {{- "}) => any;" }}
135 {%- else -%}
136 {{- "() => any;" }}
137 {%- endif -%}
138 {%- else -%}
139 {#- Responses format: {"type": "function", "name": "...", ...} #}
140 {%- if tool.description is defined -%}
141 {{- "// " + tool.description + "\n" }}
142 {%- endif -%}
143 {{- "type "+ tool.name + " = " }}
144 {%- if tool.parameters and tool.parameters.properties %}
145 {{- "(_: {\n" }}
146 {%- for param_name, param_spec in tool.parameters.properties.items() %}
147 {%- if param_spec.description is defined %}
148 {{- "// " + param_spec.description + "\n" }}
149 {%- endif %}
150 {{- param_name }}
151 {%- if param_name not in (tool.parameters.required or []) -%}
152 {{- "?" }}
153 {%- endif -%}
154 {{- ": " }}
155 {{- render_typescript_type(param_spec, tool.parameters.required or []) }}
156 {%- if param_spec.default is defined -%}
157 {%- if param_spec.enum %}
158 {{- ", // default: " + param_spec.default }}
159 {%- elif param_spec.oneOf %}
160 {{- "// default: " + param_spec.default }}
161 {%- else %}
162 {{- ", // default: " + param_spec.default|tojson }}
163 {%- endif -%}
164 {%- endif -%}
165 {%- if not loop.last %}
166 {{- ",\n" }}
167 {%- else %}
168 {{- "\n" }}
169 {%- endif -%}
170 {%- endfor %}
171 {{- "}) => any;" }}
172 {%- else -%}
173 {{- "() => any;" }}
174 {%- endif -%}
175 {%- endif -%}
176 {%- if not loop.last -%}
177 {{- "\n" }}
178 {%- endif -%}
179 {%- endfor %}
180 {%- endmacro -%}
181
182 {{ bos_token }}
183
184 {%- set system_token = '<|system_start|>' -%}
185 {%- set end_system_token = '<|system_end|>' -%}
186 {%- set developer_token = '<|developer_start|>' -%}
187 {%- set end_developer_token = '<|developer_end|>' -%}
188 {%- set user_token = '<|user_start|>' -%}
189 {%- set end_user_token = '<|user_end|>' -%}
190 {%- set assistant_token = '<|assistant_start|>' -%}
191 {%- set end_assistant_token = '<|assistant_end|>' -%}
192 {%- set inner_token = '<|inner_prefix|>' -%}
193 {%- set outer_token = '<|inner_suffix|>' -%}
194 {%- set tool_calls_token = '<|tools_prefix|>' -%}
195 {%- set end_tool_calls_token = '<|tools_suffix|>' -%}
196
197 {%- set ns = namespace(in_assistant=false, in_tool=false, in_inner=false, assistant_format=none) -%}
198
199 {%- if messages and messages[0].role == 'system' -%}
200 {%- if "content" in messages[0] -%}
201 {%- if messages[0].content is string -%}
202 {{ system_token + messages[0].content + end_system_token }}
203 {%- elif messages[0].content is mapping and "text" in messages[0].content -%}
204 {{ system_token + messages[0].content.text + end_system_token }}
205 {%- else -%}
206 {{- raise_exception("Invalid system message") -}}
207 {%- endif -%}
208 {%- else -%}
209 {{- raise_exception("Invalid system message") -}}
210 {%- endif -%}
211 {%- set loop_messages = messages[1:] -%}
212 {%- else -%}
213 {{ system_token + 'You are Apertus, a helpful assistant created by the SwissAI initiative.\nKnowledge cutoff: 2024-04\nCurrent date: ' + strftime_now('%Y-%m-%d') + end_system_token }}
214 {%- set loop_messages = messages -%}
215 {%- endif -%}
216
217 {{ developer_token + 'Deliberation: ' }}
218 {%- if enable_thinking is defined and enable_thinking -%}
219 {{ 'enabled\n' }}
220 {%- else -%}
221 {{ 'disabled\n' }}
222 {%- endif -%}
223 {%- if tools is defined and tools -%}
224 {{ 'Tool Capabilities:\n' + render_tools(tools) }}
225 {%- else -%}
226 {{ 'Tool Capabilities: disabled' }}
227 {%- endif -%}
228 {{ end_developer_token }}
229
230 {%- for message in loop_messages -%}
231 {%- if message.role == 'user' -%}
232 {%- set ns.in_inner = false -%}
233 {%- if ns.in_tool -%}
234 {{ ']' }}
235 {%- set ns.in_tool = false -%}
236 {%- endif -%}
237 {%- if ns.in_assistant -%}
238 {{ end_assistant_token }}
239 {%- set ns.in_assistant = false -%}
240 {%- endif -%}
241 {%- if "content" in message -%}
242 {{ user_token }}
243 {%- if message.content is string -%}
244 {{ message.content }}
245 {%- elif message.content is mapping and "parts" in message.content -%}
246 {%- set parts = message.content.parts -%}
247 {%- for part in parts -%}
248 {%- if part.type == "text" -%}
249 {{ part.text }}
250 {%- else -%}
251 {{- raise_exception("Invalid user part: " + part.type) -}}
252 {%- endif -%}
253 {%- endfor -%}
254 {%- else -%}
255 {{- raise_exception("Invalid user message: " + message.role) -}}
256 {%- endif -%}
257 {{ end_user_token }}
258 {%- endif -%}
259 {%- elif message.role == 'assistant' -%}
260 {%- if not ns.in_assistant -%}
261 {{ assistant_token }}
262 {%- set ns.in_assistant = true -%}
263 {%- endif -%}
264 {%- if "content" in message and message.content is not none -%}
265 {%- if message.content is string and (ns.assistant_format is none or ns.assistant_format == "string") -%}
266 {%- if ns.in_tool -%}
267 {{ ']' }}
268 {%- set ns.in_tool = false -%}
269 {%- endif -%}
270 {%- set ns.assistant_format = "string" -%}
271 {{ message.content }}
272 {%- elif message.content is mapping and "blocks" in message.content and (ns.assistant_format is none or ns.assistant_format == "mapping") -%}
273 {%- set ns.assistant_format = "mapping" -%}
274 {%- set blocks = message.content.blocks -%}
275 {%- for block in blocks -%}
276 {%- if block.type == 'thoughts' -%}
277 {%- if ns.in_tool -%}
278 {{ ']' }}
279 {%- set ns.in_tool = false -%}
280 {%- endif -%}
281 {%- if not ns.in_inner -%}
282 {%- set ns.in_inner = true -%}
283 {{ inner_token }}
284 {%- endif -%}
285 {{ block.text }}
286 {%- elif block.type == 'tool_calls' -%}
287 {%- if ns.in_tool -%}
288 {{ ']' }}
289 {%- set ns.in_tool = false -%}
290 {%- endif -%}
291 {%- if ns.in_inner and not loop.first and block.calls|length == 1 and block.calls[0].name == 'display_answers' -%}
292 {%- set ns.in_inner = false -%}
293 {{ outer_token }}
294 {%- endif -%}
295 {{ tool_calls_token + '[' }}
296 {%- for tool_call in block.calls -%}
297 {%- set args = tool_call.arguments -%}
298 {%- if args is string -%}
299 {{- '{"' + tool_call.name + '": ' + args + '}' }}
300 {%- else -%}
301 {{- '{"' + tool_call.name + '": ' + args|tojson + '}' }}
302 {%- endif -%}
303 {%- if not loop.last -%}
304 {{- ", " }}
305 {%- endif -%}
306 {%- endfor -%}
307 {{ ']' + end_tool_calls_token }}
308 {%- elif block.type == 'tool_outputs' -%}
309 {%- if ns.in_tool -%}
310 {{- raise_exception("Cannot have both tool outputs as separate messages and tool outputs as blocks") -}}
311 {%- endif -%}
312 {{ '[' }}
313 {%- for tool_output in block.outputs -%}
314 {{- tool_output.output }}
315 {%- if not loop.last -%}
316 {{- ", " }}
317 {%- endif -%}
318 {%- endfor -%}
319 {{- ']' }}
320 {%- elif block.type == 'response' -%}
321 {%- if ns.in_tool -%}
322 {{ ']' }}
323 {%- set ns.in_tool = false -%}
324 {%- endif -%}
325 {%- if (not loop.first and ns.in_inner) or (ns.in_assistant and ns.in_inner) -%}
326 {%- set ns.in_inner = false -%}
327 {{ outer_token }}
328 {%- endif -%}
329 {{ block.text }}
330 {%- else -%}
331 {{- raise_exception("Invalid assistant block type: " + block.type) -}}
332 {%- endif -%}
333 {%- endfor -%}
334 {%- else -%}
335 {{- raise_exception("Invalid assistant content") -}}
336 {%- endif -%}
337 {%- elif not ("tool_calls" in message and message.tool_calls) -%}
338 {{- raise_exception("Invalid assistant message") -}}
339 {%- endif -%}
340 {%- if "tool_calls" in message and message.tool_calls -%}
341 {{ tool_calls_token + '[' }}
342 {%- for tool_call in message.tool_calls -%}
343 {%- if tool_call.type == 'function' -%}
344 {%- set function = tool_call.function -%}
345 {%- set args = function.arguments -%}
346 {%- if args is string -%}
347 {{- '{"' + function.name + '": ' + args + '}' }}
348 {%- else -%}
349 {{- '{"' + function.name + '": ' + args|tojson + '}' }}
350 {%- endif -%}
351 {%- if not loop.last -%}
352 {{- ", " }}
353 {%- endif -%}
354 {%- else -%}
355 {{- raise_exception("Invalid tool call type: " + tool_call.type) -}}
356 {%- endif -%}
357 {%- endfor -%}
358 {{ ']' + end_tool_calls_token }}
359 {%- endif -%}
360 {%- elif message.role == 'tool' -%}
361 {%- if not ns.in_assistant -%}
362 {{- raise_exception("Tool message outside of assistant") -}}
363 {%- endif -%}
364 {%- if not ns.in_tool -%}
365 {{ '[' }}
366 {%- set ns.in_tool = true -%}
367 {%- else -%}
368 {{ ", "}}
369 {%- endif -%}
370 {%- if message.content is string -%}
371 {{ message.content }}
372 {%- else -%}
373 {{ message.content|tojson }}
374 {%- endif -%}
375 {%- else -%}
376 {{- raise_exception("Invalid message role") -}}
377 {%- endif -%}
378 {%- endfor -%}
379 {%- if ns.in_tool -%}
380 {{ ']' }}
381 {%- endif -%}
382 {%- if add_generation_prompt -%}
383 {{ assistant_token }}
384 {%- endif -%}