Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save AVAudioVision/26d732c6dc0081c21b3ebf9b9fc3de9c to your computer and use it in GitHub Desktop.

Select an option

Save AVAudioVision/26d732c6dc0081c21b3ebf9b9fc3de9c to your computer and use it in GitHub Desktop.
{%- set template_version = "qwen3.8-safe-v2" %}
{#- -------------------------------------------------------------------------
Whitespace contract: every tag opener in this file carries a leading minus,
so it strips the whitespace and newlines that precede it. All emitted text
comes from string literals, which makes the rendered prompt byte-exact and
free of incidental newlines. Comment tags need the minus just as much as
block tags do; a plain comment tag breaks the strip chain and leaks the
surrounding indentation into the prompt.
------------------------------------------------------------------------- -#}
{#- The message list has to exist before anything else can inspect it. -#}
{%- if not messages %}
{{- raise_exception('No messages provided.') }}
{%- endif %}
{#- -------------------------------------------------------------------------
Configuration
------------------------------------------------------------------------- -#}
{%- set _requested_tool_format =
tool_call_format if tool_call_format is defined else 'auto'
%}
{%- if _requested_tool_format not in ('auto', 'xml', 'json') %}
{{- raise_exception(
'Unexpected tool_call_format ' ~ _requested_tool_format ~
'. Supported values are auto (default), xml, and json.'
) }}
{%- endif %}
{%- set add_vision_id = add_vision_id if add_vision_id is defined else false %}
{%- set enable_thinking = enable_thinking if enable_thinking is defined else true %}
{%- set auto_disable_thinking_with_tools =
auto_disable_thinking_with_tools
if auto_disable_thinking_with_tools is defined
else false
%}
{%- if preserve_reasoning is defined
and preserve_reasoning is not none
and preserve_thinking is defined
and preserve_thinking is not none
and preserve_reasoning != preserve_thinking %}
{{- raise_exception(
'preserve_reasoning and preserve_thinking were both provided with conflicting values.'
) }}
{%- endif %}
{%- if preserve_reasoning is defined and preserve_reasoning is not none %}
{%- set _preserve_thinking = preserve_reasoning %}
{%- elif preserve_thinking is defined and preserve_thinking is not none %}
{%- set _preserve_thinking = preserve_thinking %}
{%- else %}
{%- set _preserve_thinking = true %}
{%- endif %}
{%- set max_tool_arg_chars =
max_tool_arg_chars if max_tool_arg_chars is defined else 0
%}
{%- set max_tool_response_chars =
max_tool_response_chars if max_tool_response_chars is defined else 0
%}
{%- if max_tool_arg_chars is not number or max_tool_arg_chars < 0 %}
{{- raise_exception('max_tool_arg_chars must be a non-negative number.') }}
{%- endif %}
{%- if max_tool_response_chars is not number or max_tool_response_chars < 0 %}
{{- raise_exception('max_tool_response_chars must be a non-negative number.') }}
{%- endif %}
{%- if tools is defined and tools is not none and tools %}
{%- if tools is string or tools is mapping or tools is not iterable %}
{{- raise_exception('tools must be an iterable list of tool definitions.') }}
{%- endif %}
{%- set _has_tools = true %}
{%- else %}
{%- set _has_tools = false %}
{%- endif %}
{#- -------------------------------------------------------------------------
Resolve the tool-call wire format.
OpenAI-compatible servers hand assistant tool calls back with
`function.arguments` as a JSON *string*, not a mapping. The XML parameter
form needs the individual key/value pairs, and a chat template cannot
decode a JSON string: the standard chat-template environment provides
`tojson` but no inverse, and no codepoint-to-character primitive, so a
hand-rolled scanner could not decode \uXXXX escapes correctly. Guessing
would silently corrupt tool arguments, which is worse than any error.
So when the caller does not pin a format, render the whole prompt in the
JSON tool-call form if any tool call in the history carries string
arguments. That is lossless, needs no decoding, and keeps the system-prompt
instructions and the rendered history in one consistent format. Histories
whose arguments are all mappings still render as XML, byte-identically to
tool_call_format='xml'.
A caller that explicitly pins 'xml' still gets a hard error for string
arguments, because that request cannot be honoured faithfully.
------------------------------------------------------------------------- -#}
{%- set format_scan = namespace(has_json_string_arguments=false) %}
{%- for message in messages %}
{%- if message.role == 'assistant'
and message.tool_calls is defined
and message.tool_calls is not none
and message.tool_calls
and message.tool_calls is not string
and message.tool_calls is not mapping
and message.tool_calls is iterable %}
{%- for tool_call in message.tool_calls %}
{%- if tool_call.function is defined
and tool_call.function is not none %}
{%- set _tc = tool_call.function %}
{%- else %}
{%- set _tc = tool_call %}
{%- endif %}
{%- if _tc.arguments is defined
and _tc.arguments is not none
and _tc.arguments is string
and _tc.arguments | trim
and _tc.arguments | trim != '{}' %}
{%- set format_scan.has_json_string_arguments = true %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endfor %}
{%- if _requested_tool_format == 'auto' %}
{%- if format_scan.has_json_string_arguments %}
{%- set _tool_format = 'json' %}
{%- else %}
{%- set _tool_format = 'xml' %}
{%- endif %}
{%- else %}
{%- set _tool_format = _requested_tool_format %}
{%- endif %}
{%- set _thinking_enabled = enable_thinking %}
{%- if auto_disable_thinking_with_tools and _has_tools %}
{%- set _thinking_enabled = false %}
{%- endif %}
{#- Validate reasoning effort even when thinking is disabled. -#}
{%- set _effort_raw =
reasoning_effort if reasoning_effort is defined else 'xhigh'
%}
{%- if _effort_raw == 'high' or _effort_raw == 'xhigh' %}
{%- set _reasoning_effort = 'xhigh' %}
{%- elif _effort_raw == 'medium' %}
{%- set _reasoning_effort = 'medium' %}
{%- elif _effort_raw == 'low' %}
{%- set _reasoning_effort = 'low' %}
{%- else %}
{{- raise_exception(
'Unexpected reasoning effort ' ~ _effort_raw ~
'. Supported values are high/xhigh, medium, and low.'
) }}
{%- endif %}
{%- set reasoning_instructions = '' %}
{%- if _thinking_enabled %}
{%- if _reasoning_effort == 'xhigh' %}
{%- set reasoning_instructions =
'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.'
%}
{%- elif _reasoning_effort == 'low' %}
{%- set reasoning_instructions =
'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.'
%}
{%- endif %}
{%- endif %}
{#- -------------------------------------------------------------------------
Content rendering
------------------------------------------------------------------------- -#}
{%- set image_count = namespace(value=0) %}
{%- set video_count = namespace(value=0) %}
{%- macro render_content(content, do_vision_count, is_system_content=false) %}
{%- if content is string %}
{{- content }}
{%- elif content is iterable and content is not mapping %}
{%- for item in content %}
{%- if item is not mapping %}
{{- raise_exception(
'Content-list items must be mappings with a supported text, image, or video type.'
) }}
{%- endif %}
{%- set _item_type = item.type if 'type' in item else none %}
{%- if _item_type is not none
and _item_type not in ('text', 'image', 'image_url', 'video') %}
{{- raise_exception(
'Unexpected content item type ' ~ _item_type ~ '.'
) }}
{%- endif %}
{%- set _is_image =
_item_type == 'image'
or _item_type == 'image_url'
or 'image' in item
or 'image_url' in item
%}
{%- set _is_video =
_item_type == 'video'
or 'video' in item
%}
{%- if _is_image and _is_video %}
{{- raise_exception(
'A content item cannot contain both image and video data.'
) }}
{%- elif _item_type == 'text' and (_is_image or _is_video) %}
{{- raise_exception(
'A text content item cannot also contain image or video data.'
) }}
{%- elif _is_image %}
{%- if is_system_content %}
{{- raise_exception(
'System and developer messages cannot contain images.'
) }}
{%- endif %}
{%- if do_vision_count %}
{%- set image_count.value = image_count.value + 1 %}
{%- endif %}
{%- if add_vision_id %}
{{- 'Picture ' ~ image_count.value ~ ': ' }}
{%- endif %}
{{- '<|vision_start|><|image_pad|><|vision_end|>' }}
{%- elif _is_video %}
{%- if is_system_content %}
{{- raise_exception(
'System and developer messages cannot contain videos.'
) }}
{%- endif %}
{%- if do_vision_count %}
{%- set video_count.value = video_count.value + 1 %}
{%- endif %}
{%- if add_vision_id %}
{{- 'Video ' ~ video_count.value ~ ': ' }}
{%- endif %}
{{- '<|vision_start|><|video_pad|><|vision_end|>' }}
{%- elif _item_type == 'text' or 'text' in item %}
{%- if 'text' not in item or item.text is not string %}
{{- raise_exception(
'Text content items must contain a string text field.'
) }}
{%- endif %}
{{- item.text }}
{%- else %}
{{- raise_exception(
'Unexpected item in content list. Expected text, image, or video content.'
) }}
{%- endif %}
{%- endfor %}
{%- elif content is none or content is undefined %}
{{- '' }}
{%- else %}
{{- raise_exception('Unexpected content type.') }}
{%- endif %}
{%- endmacro %}
{#- -------------------------------------------------------------------------
Merge system/developer messages into the system block. They may appear
anywhere in the conversation; all of them are folded into the leading
system prompt. head.count tracks only the leading run, used to slice
_msgs below.
------------------------------------------------------------------------- -#}
{%- set head = namespace(count=0, seen_non_system=false) %}
{%- for message in messages %}
{%- set _is_system =
message.role == 'system' or message.role == 'developer'
%}
{%- if _is_system %}
{%- if not head.seen_non_system %}
{%- set head.count = head.count + 1 %}
{%- endif %}
{%- else %}
{%- set head.seen_non_system = true %}
{%- endif %}
{%- endfor %}
{%- set system_state = namespace(content='') %}
{%- for message in messages %}
{%- if message.role == 'system' or message.role == 'developer' %}
{%- set _part =
render_content(message.content, false, true) | trim
%}
{%- if _part %}
{%- if system_state.content %}
{%- set system_state.content =
system_state.content ~ '\n\n' ~ _part
%}
{%- else %}
{%- set system_state.content = _part %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- set _system_content = system_state.content %}
{%- set _msgs = messages[head.count:] %}
{#- -------------------------------------------------------------------------
System prompt and tool instructions
------------------------------------------------------------------------- -#}
{%- if _has_tools %}
{{- '<|im_start|>system\n' }}
{%- if reasoning_instructions %}
{{- reasoning_instructions ~ '\n\n' }}
{%- endif %}
{{- '# Tools\n\nYou have access to the following functions:\n\n<tools>' }}
{%- for tool in tools %}
{{- '\n' }}
{{- tool | tojson }}
{%- endfor %}
{{- '\n</tools>' }}
{%- if _tool_format == 'json' %}
{{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n{"name": "example_function_name", "arguments": {"example_parameter_1": "value_1", "example_parameter_2": "This is the value for the second parameter"}}\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: a single JSON object with "name" and "arguments" keys must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
{%- else %}
{{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
{%- endif %}
{%- if _system_content %}
{{- '\n\n' ~ _system_content }}
{%- endif %}
{{- '<|im_end|>\n' }}
{%- else %}
{%- if _system_content %}
{{- '<|im_start|>system\n'
~ (reasoning_instructions ~ '\n\n' if reasoning_instructions else '')
~ _system_content
~ '<|im_end|>\n'
}}
{%- elif reasoning_instructions %}
{{- '<|im_start|>system\n'
~ reasoning_instructions
~ '<|im_end|>\n'
}}
{%- endif %}
{%- endif %}
{#- -------------------------------------------------------------------------
Find the last real user query
------------------------------------------------------------------------- -#}
{%- set ns = namespace(
multi_step_tool=true,
last_query_index=(_msgs | length) - 1
) %}
{%- for message in _msgs[::-1] %}
{%- set index = (_msgs | length - 1) - loop.index0 %}
{%- if ns.multi_step_tool and message.role == 'user' %}
{%- set _rendered_user =
render_content(message.content, false) | trim
%}
{%- if not (
_rendered_user.startswith('<tool_response>')
and _rendered_user.endswith('</tool_response>')
) %}
{%- set ns.multi_step_tool = false %}
{%- set ns.last_query_index = index %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- if ns.multi_step_tool %}
{{- raise_exception('No user query found in messages.') }}
{%- endif %}
{#- -------------------------------------------------------------------------
Conversation rendering
------------------------------------------------------------------------- -#}
{%- set history_state = namespace(previous_role='') %}
{#- Pre-scan: role of the next non-system message after each index ('end' if none). System/developer messages are merged into the leading block, so tool grouping must look past them. -#}
{%- set next_ns = namespace(vals=[], current='end') %}
{%- for _i in range(_msgs | length - 1, -1, -1) %}
{%- set next_ns.vals = [next_ns.current] + next_ns.vals %}
{%- if _msgs[_i].role != 'system' and _msgs[_i].role != 'developer' %}
{%- set next_ns.current = _msgs[_i].role %}
{%- endif %}
{%- endfor %}
{%- for message in _msgs %}
{%- if message.role != 'system' and message.role != 'developer' %}
{%- set content =
render_content(message.content, true) | trim
%}
{%- if message.role == 'user' %}
{{- '<|im_start|>user\n'
~ content
~ '<|im_end|>\n'
}}
{%- elif message.role == 'assistant' %}
{%- set reasoning_content = '' %}
{%- if message.reasoning_content is defined
and message.reasoning_content is not none %}
{%- if message.reasoning_content is string %}
{%- set reasoning_content = message.reasoning_content %}
{%- else %}
{%- set reasoning_content =
message.reasoning_content | string
%}
{%- endif %}
{%- elif message.thinking is defined
and message.thinking is not none %}
{%- if message.thinking is string %}
{%- set reasoning_content = message.thinking %}
{%- else %}
{%- set reasoning_content =
message.thinking | string
%}
{%- endif %}
{%- endif %}
{%- set reasoning_content = reasoning_content | trim %}
{#- Preserve the original invariant: when thinking is preserved,
always reconstruct the thinking block, even when it is empty. -#}
{%- if _preserve_thinking
or loop.index0 > ns.last_query_index %}
{{- '<|im_start|>assistant\n<think>\n'
~ reasoning_content
~ '\n</think>\n\n'
~ content
}}
{%- else %}
{{- '<|im_start|>assistant\n' ~ content }}
{%- endif %}
{%- if message.tool_calls is defined
and message.tool_calls is not none
and message.tool_calls %}
{%- if message.tool_calls is string
or message.tool_calls is mapping
or message.tool_calls is not iterable %}
{{- raise_exception(
'assistant.tool_calls must be an iterable list of tool calls.'
) }}
{%- endif %}
{%- for tool_call in message.tool_calls %}
{%- if tool_call.function is defined
and tool_call.function is not none %}
{%- set tc = tool_call.function %}
{%- else %}
{%- set tc = tool_call %}
{%- endif %}
{%- if tc.name is not defined
or tc.name is none
or tc.name is not string
or not tc.name %}
{{- raise_exception(
'Every tool call must have a non-empty string name.'
) }}
{%- endif %}
{%- set tc_name = tc.name %}
{%- if _tool_format == 'json' %}
{%- if loop.first %}
{%- if content | trim %}
{{- '\n\n<tool_call>\n' }}
{%- else %}
{{- '<tool_call>\n' }}
{%- endif %}
{%- else %}
{{- '\n<tool_call>\n' }}
{%- endif %}
{%- set _json_arguments = '{}' %}
{%- if tc.arguments is defined
and tc.arguments is not none %}
{%- if tc.arguments is mapping %}
{%- set _json_arguments =
tc.arguments | tojson
%}
{%- elif tc.arguments is string %}
{%- set _raw_arguments =
tc.arguments | trim
%}
{%- if _raw_arguments %}
{%- if not (
_raw_arguments.startswith('{')
and _raw_arguments.endswith('}')
) %}
{{- raise_exception(
'JSON tool-call arguments must be a JSON object string.'
) }}
{%- endif %}
{%- set _json_arguments =
_raw_arguments
%}
{%- endif %}
{%- else %}
{{- raise_exception(
'JSON tool-call arguments must be a mapping or a JSON object string.'
) }}
{%- endif %}
{%- endif %}
{{- '{"name": ' }}
{{- tc_name | tojson }}
{{- ', "arguments": ' }}
{{- _json_arguments }}
{{- '}\n</tool_call>' }}
{%- else %}
{%- if loop.first %}
{%- if content | trim %}
{{- '\n\n<tool_call>\n<function='
~ tc_name
~ '>\n'
}}
{%- else %}
{{- '<tool_call>\n<function='
~ tc_name
~ '>\n'
}}
{%- endif %}
{%- else %}
{{- '\n<tool_call>\n<function='
~ tc_name
~ '>\n'
}}
{%- endif %}
{%- if tc.arguments is defined
and tc.arguments is not none %}
{%- if tc.arguments is mapping %}
{%- for args_name, args_value
in tc.arguments | items %}
{%- set _argument_name =
args_name | string
%}
{{- '<parameter='
~ _argument_name
~ '>\n'
}}
{#- Preserve strings verbatim. Serialize every
other type as JSON so booleans and null stay
true/false/null instead of True/False/None. -#}
{%- if args_value is string %}
{%- set _argument_value =
args_value
%}
{%- else %}
{%- set _argument_value =
args_value | tojson
%}
{%- endif %}
{%- if max_tool_arg_chars > 0
and _argument_value | length
> max_tool_arg_chars %}
{{- _argument_value[:max_tool_arg_chars] }}
{{- '\n[TRUNCATED — original length '
~ (_argument_value | length | string)
~ ' chars]'
}}
{%- else %}
{{- _argument_value }}
{%- endif %}
{{- '\n</parameter>\n' }}
{%- endfor %}
{%- elif tc.arguments is string %}
{%- set _raw_arguments =
tc.arguments | trim
%}
{%- if _raw_arguments
and _raw_arguments != '{}' %}
{{- raise_exception(
'tool_call_format="xml" requires tool-call arguments to be mappings, but received a JSON string. Parse the JSON string into a mapping before applying the template, or leave tool_call_format unset so the template can select the JSON tool-call format automatically.'
) }}
{%- endif %}
{%- else %}
{{- raise_exception(
'XML tool-call arguments must be a mapping. Parse JSON-string arguments before applying the template.'
) }}
{%- endif %}
{%- endif %}
{{- '</function>\n</tool_call>' }}
{%- endif %}
{%- endfor %}
{%- endif %}
{{- '<|im_end|>\n' }}
{%- elif message.role == 'tool' %}
{%- if history_state.previous_role != 'tool' %}
{{- '<|im_start|>user' }}
{%- endif %}
{%- if max_tool_response_chars > 0
and content | length > max_tool_response_chars %}
{%- set content =
content[:max_tool_response_chars]
~ '\n[TRUNCATED — original length '
~ (content | length | string)
~ ' chars]'
%}
{%- endif %}
{{- '\n<tool_response>\n' }}
{{- content }}
{{- '\n</tool_response>' }}
{%- if next_ns.vals[loop.index0] != 'tool' %}
{{- '<|im_end|>\n' }}
{%- endif %}
{%- else %}
{{- raise_exception(
'Unexpected message role ' ~ message.role ~ '.'
) }}
{%- endif %}
{%- set history_state.previous_role = message.role %}
{%- endif %}
{%- endfor %}
{#- -------------------------------------------------------------------------
Generation prompt
------------------------------------------------------------------------- -#}
{%- if add_generation_prompt %}
{{- '<|im_start|>assistant\n' }}
{%- if not _thinking_enabled %}
{{- '<think>\n\n</think>\n\n' }}
{%- else %}
{{- '<think>\n' }}
{%- endif %}
{%- endif %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment