{#- ----------‑‑‑ special token variables ‑‑‑---------- -#}
{%- set HYTK = ':opensource' %}
{%- set hy_start_token = '<｜hy_start{}｜>'.format(HYTK) %}
{%- set hy_middle_token = '<｜hy_middle{}｜>'.format(HYTK) %}
{%- set hy_end_token = '<｜hy_end{}｜>'.format(HYTK) %}
{%- set think_begin_token = '<think{}>'.format(HYTK) %}
{%- set think_end_token = '</think{}>'.format(HYTK) %}
{%- set toolcalls_begin_token = '<tool_calls{}>'.format(HYTK) %}
{%- set toolcalls_end_token = '</tool_calls{}>'.format(HYTK) %}
{%- set toolcall_begin_token = '<tool_call{}>'.format(HYTK) %}
{%- set toolcall_end_token = '</tool_call{}>'.format(HYTK) %}
{%- set argkey_begin_token = '<arg_key{}>'.format(HYTK) %}
{%- set argkey_end_token = '</arg_key{}>'.format(HYTK) %}
{%- set argvalue_begin_token = '<arg_value{}>'.format(HYTK) %}
{%- set argvalue_end_token = '</arg_value{}>'.format(HYTK) %}
{%- set toolresponse_begin_token = '<tool_response{}>'.format(HYTK) %}
{%- set toolresponse_end_token = '</tool_response{}>'.format(HYTK) %}
{%- set reasoning_mode_token = '<｜reasoning_mode{}｜>'.format(HYTK) %}

{#- ----------‑‑‑ hyperparameters variables ‑‑‑---------- -#}
{%- if not add_generation_prompt is defined %}
    {%- set add_generation_prompt = false %}
{%- endif %}
{%- if not preserved_thinking is defined %}
    {%- if not tools %}
        {%- set preserved_thinking = false %}
    {%- else %}
        {%- set preserved_thinking = true %}
    {%- endif %}
{%- endif %}

{%- if not reasoning_effort is defined %}
    {%- set reasoning_effort = 'high' %}
{%- elif reasoning_effort not in ['high', 'no_think'] %}
    {%- if reasoning_effort is none %}
        {{- raise_exception('reasoning_effort error : None, should be no_think/high') }}
    {%- else %}
        {{- raise_exception('reasoning_effort error : ' + reasoning_effort + ', should be no_think/high') }}
    {%- endif %}
{%- endif %}

{%- if fallback_strategy is defined and fallback_strategy == 'reasoning_toolcall_retry' %}
    {%- set reasoning_effort = 'high' %}
    {%- set add_generation_prompt = false %}
{%- endif %}
{%- if not raw_last_assistant is defined %}
    {%- set raw_last_assistant = false %}
{%- endif %}

{%- macro tool_to_json(tool) -%}
    {%- set ns_tool = namespace(first=true) -%}
    {{- '{' -}}
    {%- for k, v in tool.items() -%}
        {%- if k != 'defer_loading' and k != 'strict' -%}
            {%- if not ns_tool.first -%}{{- ', ' -}}{%- endif -%}
            {%- set ns_tool.first = false -%}
            {{- '"' ~ k ~ '": ' ~ (v | tojson(ensure_ascii=False)) -}}
        {%- endif -%}
    {%- endfor -%}
    {{- '}' -}}
{%- endmacro -%}

{%- macro render_content(content) -%}
    {%- if content is string -%}
        {{- content -}}
    {%- elif content is iterable and content is not mapping -%}
        {%- for item in content -%}
            {%- if item is mapping and item.type == 'text' -%}
                {{- item.text -}}
            {%- elif item is string -%}
                {{- item -}}
            {%- else -%}
                {{- item | string -}}
            {%- endif -%}
        {%- endfor -%}
    {%- elif content is none -%}
        {{- '' -}}
    {%- else -%}
        {{- content | string -}}
    {%- endif -%}
{%- endmacro -%}

{%- macro render_tools_prompt() -%}
    {{- '# Tools\n\nYou may call one or more functions to assist with the user query.' -}}
    {{- '\n\nYou are provided with function signatures within <tools></tools> XML tags:' -}}
    {{- '\n<tools>\n' -}}
    {%- set tool_ns = namespace(first=true) -%}
    {%- for tool in tools -%}
        {%- set t = tool['function'] if tool is mapping and 'function' in tool else tool -%}
        {%- if t.defer_loading is not defined or not t.defer_loading -%}
            {%- if not tool_ns.first -%}{{- '\n' -}}{%- endif -%}
            {%- set tool_ns.first = false -%}
            {{- tool_to_json(t) -}}
        {%- endif -%}
    {%- endfor -%}
    {{- '\n</tools>\n\n' -}}
    {{- 'For function call returns, you should first print ' ~ toolcalls_begin_token -}}
    {{- '\nFor each function call, you should return object like:\n' -}}
    {{- toolcall_begin_token ~ '{function-name}' -}}
    {{- argkey_begin_token ~ '{arg-key-1}' ~ argkey_end_token -}}
    {{- argvalue_begin_token ~ '{arg-value-1}' ~ argvalue_end_token -}}
    {{- argkey_begin_token ~ '{arg-key-2}' ~ argkey_end_token -}}
    {{- argvalue_begin_token ~ '{arg-value-2}' ~ argvalue_end_token -}}
    {{- '...' -}}
    {{- toolcall_end_token -}}
    {{- '\nAt the end of function call returns, you should print ' ~ toolcalls_end_token -}}
{%- endmacro -%}

{%- macro render_tool_response(message) -%}
    {%- set content = message['content'] -%}
    {%- if content is string -%}
        {{- toolresponse_begin_token ~ content ~ toolresponse_end_token -}}
    {%- elif content is iterable and content is not mapping and content and content[0] is mapping and content[0].type == 'tool_reference' -%}
        {{- toolresponse_begin_token -}}
        {{- '<tools>\n' -}}
        {%- for tr in content -%}
            {%- for tool in tools -%}
                {%- set t = tool['function'] if tool is mapping and 'function' in tool else tool -%}
                {%- if t.name == tr.name -%}
                    {{- tool_to_json(t) ~ '\n' -}}
                {%- endif -%}
            {%- endfor -%}
        {%- endfor -%}
        {{- '</tools>' -}}
        {{- toolresponse_end_token -}}
    {%- elif content is iterable and content is not mapping and content and content[0] is mapping and content[0].output is defined -%}
        {%- for tr in content -%}
            {{- toolresponse_begin_token ~ tr.output ~ toolresponse_end_token -}}
        {%- endfor -%}
    {%- else -%}
        {{- toolresponse_begin_token ~ render_content(content) ~ toolresponse_end_token -}}
    {%- endif -%}
{%- endmacro -%}

{#- consecutive tool messages are clustered into a single tool message whose content is the list of the original tool messages; the result is written to merged_ns.messages (a macro cannot return a list) -#}
{%- set merged_ns = namespace(messages=[]) %}
{%- macro merge_tool_responses(messages) -%}
    {%- set merge_ns = namespace(result=[], cluster=[]) -%}
    {%- for message in messages -%}
        {%- if message['role'] == 'tool' -%}
            {%- set merge_ns.cluster = merge_ns.cluster + [message] -%}
        {%- else -%}
            {%- if merge_ns.cluster -%}
                {%- set merge_ns.result = merge_ns.result + [{'role': 'tool', 'content': merge_ns.cluster}] -%}
                {%- set merge_ns.cluster = [] -%}
            {%- endif -%}
            {%- set merge_ns.result = merge_ns.result + [message] -%}
        {%- endif -%}
    {%- endfor -%}
    {%- if merge_ns.cluster -%}
        {%- set merge_ns.result = merge_ns.result + [{'role': 'tool', 'content': merge_ns.cluster}] -%}
    {%- endif -%}
    {%- set merged_ns.messages = merge_ns.result -%}
{%- endmacro -%}

{#- render one tool cluster, reordered to follow the tool_call order of the preceding assistant turn; any missing / ambiguous id falls back to the original tool message order for the whole cluster -#}
{%- macro render_tool_responses(tool_messages, tool_call_ids) -%}
    {%- set order_ns = namespace(ordered=[], matched=true) -%}
    {%- if tool_call_ids and tool_call_ids | length == tool_messages | length -%}
        {%- for tool_call_id in tool_call_ids -%}
            {%- set hit_ns = namespace(count=0, message=none) -%}
            {%- for tool_message in tool_messages -%}
                {%- set message_id = tool_message['tool_call_id'] if tool_message['tool_call_id'] is defined else tool_message['id'] -%}
                {%- if message_id is defined and message_id == tool_call_id -%}
                    {%- set hit_ns.count = hit_ns.count + 1 -%}
                    {%- set hit_ns.message = tool_message -%}
                {%- endif -%}
            {%- endfor -%}
            {%- if hit_ns.count == 1 -%}
                {%- set order_ns.ordered = order_ns.ordered + [hit_ns.message] -%}
            {%- else -%}
                {%- set order_ns.matched = false -%}
            {%- endif -%}
        {%- endfor -%}
    {%- else -%}
        {%- set order_ns.matched = false -%}
    {%- endif -%}
    {%- for tool_message in (order_ns.ordered if order_ns.matched else tool_messages) -%}
        {{- render_tool_response(tool_message) -}}
    {%- endfor -%}
{%- endmacro -%}

{%- set _ = merge_tool_responses(messages) %}
{%- set normed_messages = merged_ns.messages %}

{%- set ns = namespace(last_user_index=-1, has_leading_system=false) %}
{%- if normed_messages and normed_messages[0].role == 'system' %}
    {%- set ns.has_leading_system = true %}
{%- endif %}
{%- for message in normed_messages %}
    {%- if message['role'] == 'user' %}
        {%- set ns.last_user_index = loop.index0 %}
    {%- endif %}
{%- endfor %}

{#- no leading system: synthesize one for tools and/or reasoning_mode -#}
{%- if not ns.has_leading_system %}
    {{- hy_start_token ~ 'system' ~ hy_middle_token -}}
    {%- if tools %}
        {{- render_tools_prompt() -}}
    {%- endif %}
    {{- reasoning_mode_token ~ 'reasoning_effort:' ~ reasoning_effort -}}
    {{- hy_end_token -}}
{%- endif %}

{%- set last_ns = namespace(last_is_assistant=false) %}
{%- set prev_ns = namespace(tool_call_ids=[]) %}
{%- for message in normed_messages %}
    {%- if message['role'] == 'system' %}
        {{- hy_start_token ~ 'system' ~ hy_middle_token -}}
        {#- tools / reasoning_mode only attach to the leading system (messages[0]) -#}
        {%- if loop.first %}
            {%- if tools %}
                {{- render_tools_prompt() -}}
            {%- endif %}
            {%- set content = render_content(message['content']) -%}
            {%- if tools and content -%}
                {{- '\n\n' -}}
            {%- endif -%}
            {{- content -}}
            {{- reasoning_mode_token ~ 'reasoning_effort:' ~ reasoning_effort -}}
        {%- else %}
            {{- render_content(message['content']) -}}
        {%- endif %}
        {{- hy_end_token -}}
    {%- elif message['role'] == 'user' %}
        {{- hy_start_token ~ 'user' ~ hy_middle_token -}}
        {{- render_content(message['content']) -}}
        {{- hy_end_token -}}
    {%- elif message['role'] == 'assistant' %}
        {%- set content_body = render_content(message['content']) -%}
        {#- 'reasoning' takes precedence, fall back to 'reasoning_content' when it is empty -#}
        {%- set reasoning_text = '' %}
        {%- if message['reasoning'] is defined and message['reasoning'] is string and message['reasoning'] %}
            {%- set reasoning_text = message['reasoning'] %}
        {%- elif message['reasoning_content'] is defined and message['reasoning_content'] is string and message['reasoning_content'] %}
            {%- set reasoning_text = message['reasoning_content'] %}
        {%- endif %}
        {#- no_think overrides preserved_thinking: history is always emitted with empty think tags -#}
        {%- if reasoning_effort != 'no_think' and (preserved_thinking or loop.index0 > ns.last_user_index) and reasoning_text %}
            {%- set content = think_begin_token ~ reasoning_text ~ think_end_token ~ content_body %}
        {%- else %}
            {%- set content = think_begin_token ~ think_end_token ~ content_body %}
        {%- endif %}
        {{- hy_start_token ~ 'assistant' ~ hy_middle_token -}}
        {%- if message['tool_calls'] is defined and message['tool_calls'] %}
            {#- remember the tool_call ids of this turn to order the following tool responses; an incomplete id set means "do not reorder" -#}
            {%- set ids_ns = namespace(ids=[], complete=true) %}
            {%- for tool in message['tool_calls'] %}
                {%- set tool_call_id = tool['id'] if tool['id'] is defined and tool['id'] else tool['tool_call_id'] %}
                {%- if tool_call_id is defined and tool_call_id %}
                    {%- set ids_ns.ids = ids_ns.ids + [tool_call_id] %}
                {%- else %}
                    {%- set ids_ns.complete = false %}
                {%- endif %}
            {%- endfor %}
            {%- set prev_ns.tool_call_ids = ids_ns.ids if ids_ns.complete else [] %}
            {{- content -}}
            {{- toolcalls_begin_token -}}
            {%- for tool in message['tool_calls'] -%}
                {%- set func = tool['function'] if tool is mapping and 'function' in tool else tool -%}
                {%- set arguments = func['arguments'] -%}
                {{- toolcall_begin_token ~ func['name'] -}}
                {%- for key, value in arguments.items() -%}
                    {{- argkey_begin_token ~ key ~ argkey_end_token -}}
                    {%- if value is not string -%}
                        {%- set value = value | tojson(ensure_ascii=False) -%}
                    {%- endif -%}
                    {{- argvalue_begin_token ~ value ~ argvalue_end_token -}}
                {%- endfor -%}
                {{- toolcall_end_token -}}
            {%- endfor -%}
            {{- toolcalls_end_token -}}
        {%- else %}
            {%- if loop.last and raw_last_assistant %}
                {{- content_body -}}
            {%- else %}
                {{- content -}}
            {%- endif %}
        {%- endif %}
        {#- continuation / prefill: last assistant is still open, do not close with hy_end -#}
        {%- if not (loop.last and raw_last_assistant) %}
            {{- hy_end_token -}}
        {%- endif %}
    {%- elif message['role'] == 'tool' %}
        {{- hy_start_token ~ 'tool' ~ hy_middle_token -}}
        {{- render_tool_responses(message['content'], prev_ns.tool_call_ids) -}}
        {{- hy_end_token -}}
    {%- else %}
        {{- hy_start_token ~ message['role'] ~ hy_middle_token -}}
        {{- render_content(message['content']) -}}
        {{- hy_end_token -}}
    {%- endif %}
    {%- if message['role'] != 'assistant' or not (message['tool_calls'] is defined and message['tool_calls']) %}
        {%- set prev_ns.tool_call_ids = [] %}
    {%- endif %}
    {%- if loop.last and message['role'] == 'assistant' %}
        {%- set last_ns.last_is_assistant = true %}
    {%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
    {%- if not last_ns.last_is_assistant %}
        {%- if reasoning_effort == 'no_think' %}
            {{- hy_start_token ~ 'assistant' ~ hy_middle_token ~ think_begin_token ~ think_end_token -}}
        {%- else %}
            {{- hy_start_token ~ 'assistant' ~ hy_middle_token ~ think_begin_token -}}
        {%- endif %}
    {%- endif %}
{%- endif %}
