Skip to content

Instantly share code, notes, and snippets.

@mdierolf
Created November 5, 2025 04:57
Show Gist options
  • Select an option

  • Save mdierolf/1f3c43f48f6fbd9b2497e9f538ae42e7 to your computer and use it in GitHub Desktop.

Select an option

Save mdierolf/1f3c43f48f6fbd9b2497e9f538ae42e7 to your computer and use it in GitHub Desktop.
GLM 4.6 Air Chat Template with working tool calling
{%- macro visible_text(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 }}
{%- endif -%}
{%- endfor -%}
{%- else -%}
{{- content }}
{%- endif -%}
{%- endmacro -%}
{#--- SYSTEM + TOOLS (OpenAI-style JSON) ---#}
{%- if tools -%}
<|system|>
You can call functions ("tools") to complete tasks. Tools are provided as JSON below.
Respond NORMALLY unless a tool is needed.
If you decide to call a tool, output EXACTLY ONE LINE containing ONLY this JSON:
{"tool_call":{"name":"<function name>","arguments":{...}}}
Rules:
- The JSON must be strictly valid (double quotes, no trailing commas).
- Put all arguments under "arguments" as an object.
- Do not add commentary or extra text on that line.
TOOLS (OpenAI schema):
{{ tools | tojson }}
{%- endif -%}
{#--- find last user index for think gating ---#}
{%- set ns = namespace(last_user_index=-1) %}
{%- for m in messages %}
{%- if m.role == 'user' %}
{%- set user_content = visible_text(m.content) -%}
{%- if not ("tool_response" in user_content) %}
{%- set ns.last_user_index = loop.index0 -%}
{%- endif -%}
{%- endif %}
{%- endfor %}
{#--- MESSAGE RENDERING ---#}
{%- for m in messages %}
{%- if m.role == 'system' -%}
<|system|>
{{ visible_text(m.content) }}
{%- elif m.role == 'user' -%}
<|user|>
{%- set user_content = visible_text(m.content) -%}
{{ user_content }}
{%- if enable_thinking is defined and not enable_thinking -%}
{%- if not user_content.endswith("/nothink") -%}
/nothink
{%- endif -%}
{%- endif -%}
{%- elif m.role == 'assistant' -%}
<|assistant|>
{%- set content = visible_text(m.content) %}
{%- set reasoning_content = '' %}
{# pull <think> block out of prior assistant messages if present #}
{%- if m.reasoning_content is string %}
{%- set reasoning_content = m.reasoning_content %}
{%- else %}
{%- if '</think>' in content %}
{%- set think_parts = content.split('</think>') %}
{%- if think_parts|length > 1 %}
{%- set before_end_think = think_parts[0] %}
{%- set after_end_think = think_parts[1] %}
{%- set think_start_parts = before_end_think.split('<think>') %}
{%- if think_start_parts|length > 1 %}
{%- set reasoning_content = think_start_parts[-1].lstrip('\n') %}
{%- endif %}
{%- set content = after_end_think.lstrip('\n') %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- if loop.index0 > ns.last_user_index and reasoning_content -%}
<think>{{ reasoning_content.strip() }}</think>
{%- else -%}
<think></think>
{%- endif -%}
{# normal assistant text, if any #}
{%- if content.strip() -%}
{{ '\n' + content.strip() }}
{%- endif -%}
{# tool call ECHO SUPPORT (when upstream passed tool_calls back into history) #}
{%- if m.tool_calls %}
{%- for tc in m.tool_calls %}
{%- set f = tc.function if tc.function else tc %}
{%- set args = f.arguments if f.arguments else {} %}
{{ '\n{"tool_call":{"name":"' ~ f.name ~ '","arguments":' ~ (args if args is string else (args | tojson)) ~ '}}' }}
{%- endfor %}
{%- endif %}
{%- elif m.role == 'tool' -%}
{# Tool outputs are shown as observations for the model to read #}
<|observation|>
{%- if m.content is string -%}
<tool_response>
{{ m.content }}
</tool_response>
{%- else -%}
{%- for tr in m.content %}
<tool_response>
{{ tr.output if tr.output is defined else tr }}
</tool_response>
{%- endfor -%}
{%- endif -%}
{%- endif -%}
{%- endfor %}
{#--- generation prompt ---#}
{%- if add_generation_prompt -%}
<|assistant|>
{%- if enable_thinking is defined and not enable_thinking -%}<think></think>{%- endif -%}
{%- endif -%}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment