| 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 -%} |