SergioPatricio commited on
Commit
f37b59b
·
verified ·
1 Parent(s): 7c785cc

Upload folder using huggingface_hub

Browse files
Qwen3-Coder-Next.jinja ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% macro render_extra_keys(json_dict, handled_keys) %}
2
+ {%- if json_dict is mapping %}
3
+ {%- for json_key in json_dict if json_key not in handled_keys %}
4
+ {%- if json_dict[json_key] is string %}
5
+ {{-'\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | string) ~ '</' ~ json_key ~ '>' }}
6
+ {%- else %}
7
+ {{- '\n<' ~ json_key ~ '>' ~ (json_dict[json_key] | tojson ) ~ '</' ~ json_key ~ '>' }}
8
+ {%- endif %}
9
+ {%- endfor %}
10
+ {%- endif %}
11
+ {%- endmacro %}
12
+
13
+ {%- macro render_content(content) %}
14
+ {%- if content is string %}
15
+ {{- content }}
16
+ {%- elif content is iterable and content is not mapping %}
17
+ {%- for item in content %}
18
+ {%- if item is mapping %}
19
+ {%- if 'text' in item %}
20
+ {{- item.text }}
21
+ {%- elif item.type == 'input_text' or item.type == 'output_text' %}
22
+ {{- item.text | default('', true) }}
23
+ {%- elif item.type == 'image' or item.type == 'image_url' or 'image_url' in item %}
24
+ {{- '<image>' }}
25
+ {%- elif item.type == 'audio' or item.type == 'input_audio' %}
26
+ {{- '<audio>' }}
27
+ {%- elif item.type == 'video' %}
28
+ {{- '<video>' }}
29
+ {%- else %}
30
+ {{- item | tojson }}
31
+ {%- endif %}
32
+ {%- else %}
33
+ {{- item | string }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- content | string }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+
43
+ {%- if messages[0]["role"] == "system" or messages[0]["role"] == "developer" %}
44
+ {%- set system_message = render_content(messages[0]["content"]) %}
45
+ {%- set loop_messages = messages[1:] %}
46
+ {%- else %}
47
+ {%- set loop_messages = messages %}
48
+ {%- endif %}
49
+
50
+ {%- if not tools is defined %}
51
+ {%- set tools = [] %}
52
+ {%- endif %}
53
+
54
+ {%- if system_message is defined %}
55
+ {{- "<|im_start|>system\n" + system_message }}
56
+ {%- else %}
57
+ {%- if tools is iterable and tools | length > 0 %}
58
+ {{- "<|im_start|>system\nYou are Qwen, a helpful AI assistant that can interact with a computer to solve tasks." }}
59
+ {%- endif %}
60
+ {%- endif %}
61
+ {%- if tools is iterable and tools | length > 0 %}
62
+ {{- "\n\n# Tools\n\nYou have access to the following functions:\n\n" }}
63
+ {{- "<tools>" }}
64
+ {%- for tool in tools %}
65
+ {%- if tool.function is defined %}
66
+ {%- set tool = tool.function %}
67
+ {%- endif %}
68
+ {{- "\n<function>\n<name>" ~ tool.name ~ "</name>" }}
69
+ {%- if tool.description is defined %}
70
+ {{- '\n<description>' ~ (tool.description | trim) ~ '</description>' }}
71
+ {%- endif %}
72
+ {{- '\n<parameters>' }}
73
+ {%- if tool.parameters is defined and tool.parameters is mapping and tool.parameters.properties is defined and tool.parameters.properties is mapping %}
74
+ {%- for param_name, param_fields in tool.parameters.properties|items %}
75
+ {{- '\n<parameter>' }}
76
+ {{- '\n<name>' ~ param_name ~ '</name>' }}
77
+ {%- if param_fields.type is defined %}
78
+ {{- '\n<type>' ~ (param_fields.type | string) ~ '</type>' }}
79
+ {%- endif %}
80
+ {%- if param_fields.description is defined %}
81
+ {{- '\n<description>' ~ (param_fields.description | trim) ~ '</description>' }}
82
+ {%- endif %}
83
+ {%- set handled_keys = ['name', 'type', 'description'] %}
84
+ {{- render_extra_keys(param_fields, handled_keys) }}
85
+ {{- '\n</parameter>' }}
86
+ {%- endfor %}
87
+ {%- endif %}
88
+ {%- set handled_keys = ['type', 'properties'] %}
89
+ {{- render_extra_keys(tool.parameters, handled_keys) }}
90
+ {{- '\n</parameters>' }}
91
+ {%- set handled_keys = ['type', 'name', 'description', 'parameters'] %}
92
+ {{- render_extra_keys(tool, handled_keys) }}
93
+ {{- '\n</function>' }}
94
+ {%- endfor %}
95
+ {{- "\n</tools>" }}
96
+ {{- '\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>' }}
97
+ {%- endif %}
98
+ {%- if system_message is defined %}
99
+ {{- '<|im_end|>\n' }}
100
+ {%- else %}
101
+ {%- if tools is iterable and tools | length > 0 %}
102
+ {{- '<|im_end|>\n' }}
103
+ {%- endif %}
104
+ {%- endif %}
105
+ {%- for message in loop_messages %}
106
+ {%- if message.role == "assistant" and message.tool_calls is defined and message.tool_calls is iterable and message.tool_calls | length > 0 %}
107
+ {{- '<|im_start|>' + message.role }}
108
+ {%- set content = render_content(message.content) %}
109
+ {%- if content | trim | length > 0 %}
110
+ {{- '\n' + content | trim + '\n' }}
111
+ {%- endif %}
112
+ {%- for tool_call in message.tool_calls %}
113
+ {%- if tool_call.function is defined %}
114
+ {%- set tool_call = tool_call.function %}
115
+ {%- endif %}
116
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
117
+ {%- if tool_call.arguments is defined and tool_call.arguments is not none %}
118
+ {%- if tool_call.arguments is mapping %}
119
+ {%- for args_name, args_value in tool_call.arguments|items %}
120
+ {{- '<parameter=' + args_name + '>\n' }}
121
+ {%- set args_value = args_value if args_value is string else args_value | tojson %}
122
+ {{- args_value }}
123
+ {{- '\n</parameter>\n' }}
124
+ {%- endfor %}
125
+ {%- elif tool_call.arguments is string %}
126
+ {{- tool_call.arguments }}
127
+ {%- endif %}
128
+ {%- endif %}
129
+ {{- '</function>\n</tool_call>' }}
130
+ {%- endfor %}
131
+ {{- '<|im_end|>\n' }}
132
+ {%- elif message.role == "user" or message.role == "system" or message.role == "developer" or message.role == "assistant" %}
133
+ {%- set role = "system" if message.role == "developer" else message.role %}
134
+ {{- '<|im_start|>' + role + '\n' + render_content(message.content) + '<|im_end|>' + '\n' }}
135
+ {%- elif message.role == "tool" %}
136
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
137
+ {{- '<|im_start|>user' }}
138
+ {%- endif %}
139
+ {{- '\n<tool_response>\n' }}
140
+ {{- render_content(message.content) }}
141
+ {{- '\n</tool_response>' }}
142
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
143
+ {{- '<|im_end|>\n' }}
144
+ {%- elif loop.last %}
145
+ {{- '<|im_end|>\n' }}
146
+ {%- endif %}
147
+ {%- else %}
148
+ {{- '<|im_start|>' + message.role + '\n' + render_content(message.content) + '<|im_end|>\n' }}
149
+ {%- endif %}
150
+ {%- endfor %}
151
+ {%- if add_generation_prompt %}
152
+ {{- '<|im_start|>assistant\n' }}
153
+ {%- endif %}
README.md ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Qwen3-Coder-Next llama.cpp chat template
2
+
3
+ This repository contains a small llama.cpp-oriented patch of the official
4
+ `Qwen/Qwen3-Coder-Next` chat template.
5
+
6
+ It stays close to the upstream Qwen template and only adds compatibility fixes
7
+ that are useful for OpenAI-compatible coding agents such as Codex, Aider,
8
+ OpenCode-style harnesses, and other clients that may send modern message
9
+ shapes.
10
+
11
+ ## Files
12
+
13
+ - `Qwen3-Coder-Next.jinja` - patched llama.cpp Jinja chat template.
14
+ - `smoke_qwen3_coder_next_template.py` - small Jinja2 smoke test.
15
+
16
+ ## Changes from the official template
17
+
18
+ - Accepts `developer` messages and renders them as Qwen `system` messages.
19
+ - Adds `render_content(content)` so string content, typed content arrays,
20
+ `None`, and simple multimodal placeholders do not crash the template.
21
+ - Handles tool responses whose `content` is a typed content array.
22
+ - Handles `tool_call.arguments` as either a mapping or a pre-serialized string.
23
+
24
+ The goal is not to redesign Qwen's tool-calling format. The tool prompt and XML
25
+ tool-call format are intentionally kept close to Qwen's official template.
26
+
27
+ ## llama.cpp usage
28
+
29
+ Example `models.ini` section:
30
+
31
+ ```ini
32
+ [Qwen3-Coder-Next]
33
+ model = /path/to/Qwen3-Coder-Next-UD-IQ3_XXS.gguf
34
+ jinja = on
35
+ chat-template-file = /path/to/Qwen3-Coder-Next.jinja
36
+ chat-template-kwargs = {"enable_thinking": false}
37
+ ```
38
+
39
+ ## Smoke test
40
+
41
+ ```bash
42
+ python -m pip install jinja2
43
+ python smoke_qwen3_coder_next_template.py
44
+ ```
45
+
46
+ Expected result:
47
+
48
+ ```text
49
+ ALL_OK
50
+ ```
51
+
52
+ ## Notes
53
+
54
+ This template is intended for llama.cpp and minijinja-style rendering. The smoke
55
+ test uses Python Jinja2 only to catch obvious template failures and common
56
+ agent-message shapes; final behavior should still be validated with the actual
57
+ serving runtime.
58
+
59
+ Based on the official Apache-2.0 Qwen3-Coder-Next chat template.
smoke_qwen3_coder_next_template.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ from jinja2 import Environment, StrictUndefined
4
+
5
+
6
+ def raise_exception(message: str):
7
+ raise RuntimeError(message)
8
+
9
+
10
+ def main() -> None:
11
+ template = Path("Qwen3-Coder-Next.jinja").read_text()
12
+ env = Environment(undefined=StrictUndefined)
13
+ env.globals.update(raise_exception=raise_exception)
14
+ compiled = env.from_string(template)
15
+
16
+ cases = [
17
+ (
18
+ "plain_developer",
19
+ [
20
+ {"role": "developer", "content": "dev rules"},
21
+ {"role": "user", "content": "hello"},
22
+ ],
23
+ [],
24
+ ),
25
+ (
26
+ "typed_user_and_developer",
27
+ [
28
+ {
29
+ "role": "developer",
30
+ "content": [{"type": "input_text", "text": "dev typed"}],
31
+ },
32
+ {
33
+ "role": "user",
34
+ "content": [
35
+ {"type": "text", "text": "hello"},
36
+ {"type": "image_url", "image_url": {"url": "x"}},
37
+ ],
38
+ },
39
+ ],
40
+ [],
41
+ ),
42
+ (
43
+ "tool_mapping_args_and_typed_tool_response",
44
+ [
45
+ {"role": "user", "content": "run"},
46
+ {
47
+ "role": "assistant",
48
+ "content": "",
49
+ "tool_calls": [
50
+ {
51
+ "function": {
52
+ "name": "bash",
53
+ "arguments": {"cmd": "ls", "limit": 3},
54
+ }
55
+ }
56
+ ],
57
+ },
58
+ {"role": "tool", "content": [{"type": "text", "text": "ok"}]},
59
+ ],
60
+ [
61
+ {
62
+ "type": "function",
63
+ "function": {
64
+ "name": "bash",
65
+ "description": "run shell",
66
+ "parameters": {
67
+ "type": "object",
68
+ "properties": {"cmd": {"type": "string"}},
69
+ },
70
+ },
71
+ }
72
+ ],
73
+ ),
74
+ (
75
+ "tool_string_args_and_typed_assistant_content",
76
+ [
77
+ {"role": "user", "content": "run"},
78
+ {
79
+ "role": "assistant",
80
+ "content": [{"type": "output_text", "text": "I will run it."}],
81
+ "tool_calls": [
82
+ {"function": {"name": "bash", "arguments": '{"cmd":"ls"}'}}
83
+ ],
84
+ },
85
+ ],
86
+ [],
87
+ ),
88
+ (
89
+ "none_content",
90
+ [
91
+ {"role": "developer", "content": None},
92
+ {"role": "user", "content": None},
93
+ ],
94
+ [],
95
+ ),
96
+ ]
97
+
98
+ for name, messages, tools in cases:
99
+ rendered = compiled.render(
100
+ messages=messages,
101
+ tools=tools,
102
+ add_generation_prompt=True,
103
+ )
104
+ assert "<|im_start|>assistant\n" in rendered, name
105
+ print(f"CASE {name}: OK len={len(rendered)}")
106
+
107
+ print("ALL_OK")
108
+
109
+
110
+ if __name__ == "__main__":
111
+ main()