Last active
February 11, 2026 14:55
-
-
Save ugovaretto/828e5e7effcaf034ec6934cb980d3328 to your computer and use it in GitHub Desktop.
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
| # uv venv | |
| # uv pip install gguf | |
| # uv run gguf-jinja-dump.py <gguf ..0001 file> | |
| from gguf import GGUFReader | |
| import sys | |
| def get_jinja_template(file_path): | |
| reader = GGUFReader(file_path) | |
| # The key is standard for tokenizer chat templates | |
| field = reader.fields.get("tokenizer.chat_template") | |
| if field: | |
| # Extract the raw string from the GGUF field parts | |
| parts = field.parts[field.data[0]] | |
| return ''.join(chr(i) for i in parts) | |
| return "Template not found." | |
| def main(): | |
| if len(sys.argv) != 2: | |
| print(f"Prints jinja template to stdout, usage {sys.argv[0]} <gguf file>") | |
| sys.exit(0) | |
| print(get_jinja_template(sys.argv[1])) | |
| if __name__ == "__main__": | |
| main() |
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 render_content(content) %}{% if content is none %}{{- '' }}{% elif content is string %}{{- content }}{% elif content is mapping %}{{- content['value'] if 'value' in content else content['text'] }}{% elif content is iterable %}{% for item in content %}{% if item.type == 'text' %}{{- item['value'] if 'value' in item else item['text'] }}{% elif item.type == 'image' %}<im_patch>{% endif %}{% endfor %}{% endif %}{% endmacro %} | |
| {{bos_token}}{%- if tools %} | |
| {{- '<|im_start|>system\n' }} | |
| {%- if messages[0].role == 'system' %} | |
| {{- render_content(messages[0].content) + '\n\n' }} | |
| {%- endif %} | |
| {{- "# Tools\n\nYou have access to the following functions in JSONSchema format:\n\n<tools>" }} | |
| {%- for tool in tools %} | |
| {{- "\n" }} | |
| {{- tool | tojson(ensure_ascii=False) }} | |
| {%- endfor %} | |
| {{- "\n</tools>\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=...>\n...\n</function> block must be nested within <tool_call>\n...\n</tool_call> XML tags\n- Required parameters MUST be specified\n</IMPORTANT><|im_end|>\n" }} | |
| {%- else %} | |
| {%- if messages[0].role == 'system' %} | |
| {{- '<|im_start|>system\n' + render_content(messages[0].content) + '<|im_end|>\n' }} | |
| {%- endif %} | |
| {%- endif %} | |
| {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %} | |
| {%- for message in messages[::-1] %} | |
| {%- set index = (messages|length - 1) - loop.index0 %} | |
| {%- if ns.multi_step_tool and message.role == "user" and render_content(message.content) is string and not(render_content(message.content).startswith('<tool_response>') and render_content(message.content).endswith('</tool_response>')) %} | |
| {%- set ns.multi_step_tool = false %} | |
| {%- set ns.last_query_index = index %} | |
| {%- endif %} | |
| {%- endfor %} | |
| {%- for message in messages %} | |
| {%- set content = render_content(message.content) %} | |
| {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} | |
| {%- set role_name = 'observation' if (message.role == "system" and not loop.first and message.name == 'observation') else message.role %} | |
| {{- '<|im_start|>' + role_name + '\n' + content + '<|im_end|>' + '\n' }} | |
| {%- elif message.role == "assistant" %} | |
| {%- set reasoning_content = '' %} | |
| {%- if enable_thinking %} | |
| {%- if message.reasoning_content is string %} | |
| {%- set reasoning_content = render_content(message.reasoning_content) %} | |
| {%- else %} | |
| {%- if '</think>' in content %} | |
| {%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %} | |
| {%- set content = content.split('</think>')[-1].lstrip('\n') %} | |
| {%- endif %} | |
| {%- endif %} | |
| {%- else %} | |
| {# If thinking is disabled, strip any inline <think>...</think> from assistant content #} | |
| {%- if '</think>' in content %} | |
| {%- set content = content.split('</think>')[-1].lstrip('\n') %} | |
| {%- endif %} | |
| {%- endif %} | |
| {%- if loop.index0 > ns.last_query_index and enable_thinking %} | |
| {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.rstrip('\n') + '\n</think>\n' + content.lstrip('\n') }} | |
| {%- else %} | |
| {{- '<|im_start|>' + message.role + '\n' + content.lstrip('\n') }} | |
| {%- endif %} | |
| {%- if message.tool_calls %} | |
| {%- for tool_call in message.tool_calls %} | |
| {%- if tool_call.function is defined %} | |
| {%- set tool_call = tool_call.function %} | |
| {%- endif %} | |
| {{- '<tool_call>\n<function=' + tool_call.name + '>\n' }} | |
| {%- if tool_call.arguments is defined %} | |
| {%- if tool_call.arguments is mapping %} | |
| {%- set arguments = tool_call.arguments %} | |
| {%- for args_name, args_value in arguments|items %} | |
| {{- '<parameter=' + args_name + '>\n' }} | |
| {%- set args_value = args_value | tojson(ensure_ascii=False) | safe if args_value is mapping or (args_value is sequence and args_value is not string) else args_value | string %} | |
| {{- args_value }} | |
| {{- '\n</parameter>\n' }} | |
| {%- endfor %} | |
| {%- elif tool_call.arguments is string %} | |
| {# Minja does not support fromjson; preserve raw JSON string as a single parameter #} | |
| {{- '<parameter=arguments>\n' + tool_call.arguments + '\n</parameter>\n' }} | |
| {%- endif %} | |
| {%- endif %} | |
| {{- '</function>\n</tool_call>' }} | |
| {%- endfor %} | |
| {%- endif %} | |
| {{- '<|im_end|>\n' }} | |
| {%- elif message.role == "tool" %} | |
| {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %} | |
| {{- '<|im_start|>tool_response\n' }} | |
| {%- endif %} | |
| {{- '<tool_response>' }} | |
| {{- content }} | |
| {{- '</tool_response>' }} | |
| {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} | |
| {{- '<|im_end|>\n' }} | |
| {%- endif %} | |
| {%- endif %} | |
| {%- endfor %} | |
| {%- if add_generation_prompt %} | |
| {{- '<|im_start|>assistant\n' }} | |
| {%- if enable_thinking %} | |
| {{- '<think>\n' }} | |
| {%- endif %} | |
| {%- endif %} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment