Created
November 5, 2025 04:57
-
-
Save mdierolf/1f3c43f48f6fbd9b2497e9f538ae42e7 to your computer and use it in GitHub Desktop.
GLM 4.6 Air Chat Template with working tool calling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {%- 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