CCSSNE froggeric commited on
Commit
f2faba2
·
0 Parent(s):

Duplicate from froggeric/Qwen-Fixed-Chat-Templates

Browse files

Co-authored-by: froggeric <froggeric@users.noreply.huggingface.co>

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +4 -0
  2. README.md +230 -0
  3. archive/README-v10.md +208 -0
  4. archive/README-v11.md +224 -0
  5. archive/README-v12.md +226 -0
  6. archive/README-v13.md +230 -0
  7. archive/README-v14.md +218 -0
  8. archive/README-v15.md +237 -0
  9. archive/README-v16.md +279 -0
  10. archive/README-v17.md +248 -0
  11. archive/README-v18.md +252 -0
  12. archive/README-v19.md +230 -0
  13. archive/README-v8.md +192 -0
  14. archive/README-v9.md +200 -0
  15. archive/qwen3.5/chat_template-v10.jinja +223 -0
  16. archive/qwen3.5/chat_template-v10_oneline.txt +1 -0
  17. archive/qwen3.5/chat_template-v11.jinja +230 -0
  18. archive/qwen3.5/chat_template-v11_oneline.txt +1 -0
  19. archive/qwen3.5/chat_template-v12.jinja +246 -0
  20. archive/qwen3.5/chat_template-v12_oneline.txt +1 -0
  21. archive/qwen3.5/chat_template-v13.jinja +204 -0
  22. archive/qwen3.5/chat_template-v13_oneline.txt +1 -0
  23. archive/qwen3.5/chat_template-v14.jinja +214 -0
  24. archive/qwen3.5/chat_template-v14_oneline.txt +1 -0
  25. archive/qwen3.5/chat_template-v15.jinja +220 -0
  26. archive/qwen3.5/chat_template-v15_oneline.txt +1 -0
  27. archive/qwen3.5/chat_template-v16.jinja +258 -0
  28. archive/qwen3.5/chat_template-v16_oneline.txt +1 -0
  29. archive/qwen3.5/chat_template-v8.jinja +211 -0
  30. archive/qwen3.5/chat_template-v8_oneline.txt +1 -0
  31. archive/qwen3.5/chat_template-v9.jinja +219 -0
  32. archive/qwen3.5/chat_template-v9_oneline.txt +1 -0
  33. archive/qwen3.6/chat_template-v10.jinja +223 -0
  34. archive/qwen3.6/chat_template-v10_oneline.txt +1 -0
  35. archive/qwen3.6/chat_template-v11.jinja +230 -0
  36. archive/qwen3.6/chat_template-v11_oneline.txt +1 -0
  37. archive/qwen3.6/chat_template-v12.jinja +246 -0
  38. archive/qwen3.6/chat_template-v12_oneline.txt +1 -0
  39. archive/qwen3.6/chat_template-v13.jinja +204 -0
  40. archive/qwen3.6/chat_template-v13_oneline.txt +1 -0
  41. archive/qwen3.6/chat_template-v14.jinja +214 -0
  42. archive/qwen3.6/chat_template-v14_oneline.txt +1 -0
  43. archive/qwen3.6/chat_template-v15.jinja +220 -0
  44. archive/qwen3.6/chat_template-v15_oneline.txt +1 -0
  45. archive/qwen3.6/chat_template-v16.jinja +258 -0
  46. archive/qwen3.6/chat_template-v16_oneline.txt +1 -0
  47. archive/qwen3.6/chat_template-v17.jinja +277 -0
  48. archive/qwen3.6/chat_template-v17_oneline.txt +1 -0
  49. archive/qwen3.6/chat_template-v18.jinja +273 -0
  50. archive/qwen3.6/chat_template-v18_oneline.txt +1 -0
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ .DS_Store
2
+ *.pyc
3
+ __pycache__/
4
+ .env
README.md ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - vllm
13
+ - tool-calling
14
+ - thinking
15
+ ---
16
+
17
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v19)
18
+
19
+ <details open>
20
+ <summary><b>Update History & Changelog (v19)</b></summary>
21
+
22
+ > **2026-05-18 Update (v19): The Agentic Loop Cure.** (1) **Abolished "Empty Think" Poisoning:** Rewrote the AST history rendering to completely remove the injection of empty `<think>\n</think>` blocks. This cures a severe in-context learning bias where the model assumed tools could only be called if it didn't think first, which was causing 80%+ of premature `<|im_end|>` turn aborts. (2) **System Prompt Logic Trap Removed:** Softened the absolute tool mandate in the `<IMPORTANT>` block and restored Universal Synthesis instructions. The model is now explicitly permitted to transition from `</think>` to a conversational answer without panicking. (3) **True 100% KV Cache & Amnesia Fix:** `preserve_thinking` now defaults to `true`. Past thoughts are retained chronologically, permanently curing "amnesia stalls" during multi-step tool loops while mathematically guaranteeing 100% KV Cache prefix matching out-of-the-box.
23
+
24
+ </details>
25
+
26
+ <details>
27
+ <summary><b>Update History & Changelog (v11-v18)</b></summary>
28
+
29
+ > **2026-05-16 Update (v18): Stability & Precision Patch.** (1) **Bulletproof False-Positive Detection:** Shifted agentic error detection from broad substring matching to strict structural formats (e.g., `"error":`, `Exception:`, `Traceback`), completely curing false-positive retry loops when successful JSON returns simply contain the word "error" or "fail". (2) **Legacy Engine Compatibility:** Replaced `loop.previtem` with explicit array indexing, fixing AST crashes on older `llama.cpp` and `minijinja` builds that do not track loop state items. (3) **True Whitespace Normalization:** Fixed a bug where reasoning bypasses and hallucinated tag recovery stacked hidden multi-newlines (`\n\n\n`), strictly fulfilling the 100% KV Cache hit rate claim for all edge cases. (4) **Code Cleanup:** Removed dead conditional branches during XML tool parsing.
30
+ >
31
+ > **2026-05-15 Update (v17):** Major architecture overhaul resolving edge cases in agentic tooling and KV Cache. (1) **Unified Template:** Consolidated Qwen 3.5 and Qwen 3.6 into a single `chat_template.jinja` file that handles all variants seamlessly. (2) **Fixed "Mutually Exclusive" Stopping Bug:** Changed the history-pruning logic from wiping the entire turn to safely array-slicing out just the raw tool tags (`content.split('<tool_call>')[0]`). This preserves the conversational text in the history, which cures the bug where the model would artificially abort its turn (output `<|im_end|>`) when it wanted to talk and use a tool simultaneously. (3) **100% KV Cache Hit Rate Restoration:** Fully normalized internal whitespace logic (`\n\n` -> `\n`) around think blocks and tool calls to exactly match the model's native autoregressive generation spacing. This perfectly synchronizes the template's rendered history with the cached generated tokens, completely eliminating the severe cache invalidation and full-prompt re-processing issues present in v16.
32
+ >
33
+ > **2026-05-14 Update (v16):** Four-part fix addressing community-reported regressions. (1) **Native XML tool format:** reverted from JSON back to the native `<function=name>` / `<parameter=x>` format the model was trained on, restoring full compatibility with vLLM's `qwen3_coder` parser and all inference engines that implement the Qwen tool protocol. (2) **`--reasoning off` respected in error paths:** when thinking is disabled (`enable_thinking=false` / `--reasoning off`), the error escalation directives are now injected as plain text without opening any `<think>` block, preventing degenerate prompts in no-reasoning sessions. (3) **Smarter false-positive detection:** short shell command results (starting with `$ `) and search results with timing footers (`Took X.Xs`) are now correctly excluded from error detection, preventing tool-retry loops when commands succeed but their output happens to contain the word `error`. (4) **`consecutive_failures` counter no longer resets on assistant messages**, allowing Tier 2 escalation to actually fire across multi-turn tool retry chains.
34
+ >
35
+ > **2026-05-13 Update (v15):** Three-part fix for agentic tool-loop failures. (1) **Two-tier error escalation:** replaced the brittle backwards-lookahead error detection with a fully forward-tracking `last_tool_failed` + `consecutive_failures` counter. On the first error the generation prompt is pre-seeded with a correction directive inside `<think>`; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) **Length-gated detection:** error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing `error`, `exception`, etc. in legitimate content. (3) **Static system prompt:** tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.
36
+ >
37
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
38
+ >
39
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
40
+ >
41
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
42
+ >
43
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
44
+
45
+ </details>
46
+
47
+ This is a drop-in Jinja template that fixes rendering errors, KV cache invalidation, token waste, and fatal agentic stalling in the official Qwen chat templates.
48
+
49
+ It is tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
50
+
51
+ ---
52
+
53
+ ## Why you need this
54
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
55
+
56
+ Here are the critical issues this template fixes:
57
+
58
+ | Category | Problem | Impact | Fix |
59
+ |---|---|---|---|
60
+ | **Agentic Loop** | **Premature Stalls (Stopping Bug)** | Model aborts its turn (`<\|im_end\|>`) when trying to combine conversation and a tool call. | Resolved the System Prompt logic trap and cured "Empty Think" poisoning (v19). |
61
+ | **Agentic Loop** | **Retry Stall & Reasoning Spiral** | Model correctly diagnoses a tool error but repeatedly emits the identical failing `<tool_call>`. | Two-tier escalation: seeds `<think>` with correction directive; injects urgent out-of-band directive. |
62
+ | **Agentic Loop** | **Post-Tool Overthinking** | Forced `<think>` block prefilling causes model to panic and debate internal rules after fetching data. | Broadened instructions to define `<think>` as a dual-purpose space for planning *or synthesis*. |
63
+ | **Agentic Loop** | **False-Positive Error Detection** | Short successful API/JSON returns containing the word `error` trigger false retry loops. | Strict structural guards look for exact system failures (`"error":`, `Traceback`, etc.) instead of broad words (v18). |
64
+ | **Performance** | **KV Cache Invalidation** | History pruning dynamically mutates past turns, causing full prompt re-processing every turn. | `preserve_thinking` defaults to `true`, maintaining strict chronological rendering for a 100% KV cache hit rate (v19). |
65
+ | **Performance** | **Empty Think Poisoning** | Stripped past turns leave behind empty `<think></think>` tags, tricking the model into a severe in-context learning bias. | Template completely abolishes the injection of empty think blocks (v19). |
66
+ | **Compatibility** | **Legacy Engine Crashes** | Older C++ parsing engines crash when evaluating `loop.previtem`. | Uses strict chronological array indexing universally supported by all Jinja iterations (v18). |
67
+ | **Compatibility** | **Wrong Tool Call Format** | Qwen-native parsers (like vLLM's `qwen3_coder`) expect XML `<function=name>`. JSON format breaks them. | Restored native XML format while keeping C++ safety. |
68
+ | **Compatibility** | **Jinja C++ Crashes** | Python-specific filters (`map`, `first` on strings) crash on `minijinja`. | All filters replaced with universally compatible equivalents. |
69
+ | **Stability** | **Mid-Conversation System Crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere in the history. |
70
+ | **Stability** | **No-User-Query Crash** | `raise_exception` crashes agentic loops or system-only contexts. | Graceful fallback implemented. |
71
+ | **Stability** | **Unclosed Thinking Before Tool** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely. |
72
+ | **Edge Cases** | **`developer` Role Rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
73
+ | **Edge Cases** | **`--reasoning off` Ignored** | When thinking is disabled, tool error escalation still opened a `<think>` block, corrupting the prompt. | Error escalation branches now fully respect `enable_thinking=false`. |
74
+ | **Edge Cases** | **Reasoning Bypass Hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects a safe boundary to successfully force reasoning bypass without stacking newlines (v18). |
75
+
76
+ ---
77
+
78
+ ## Quick install
79
+
80
+ Choose your environment and update the template:
81
+
82
+ ### LM Studio
83
+ 1. Open your Qwen model in the right-side panel.
84
+ 2. Scroll down to **Prompt Template**.
85
+ 3. Replace the template with the contents of `chat_template.jinja`.
86
+ 4. Click **Save**.
87
+
88
+ ### llama.cpp / koboldcpp
89
+ ```bash
90
+ --jinja --chat-template-file chat_template.jinja
91
+ ```
92
+
93
+ ### vLLM
94
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents. Use the `qwen3_coder` tool parser:
95
+ ```bash
96
+ --tool-call-parser qwen3_coder
97
+ ```
98
+
99
+ ### oMLX
100
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
101
+
102
+ ---
103
+
104
+ ## Which file do I use?
105
+
106
+ Both Qwen 3.5 and Qwen 3.6 variants (including 35B, 32B, 27B, and 14B parameters) have been consolidated. You only need the single `chat_template.jinja` file at the root of the repository.
107
+
108
+ One-line versions (`chat_template_oneline.txt`) are pre-minified for engines that require a single-line template string.
109
+
110
+ ---
111
+
112
+ ## The thinking toggle
113
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
114
+
115
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
116
+
117
+ **Fast answer, no reasoning:**
118
+ ```text
119
+ System: You are a coding assistant. <|think_off|>
120
+ User: What's 2+2?
121
+ ```
122
+
123
+ **Deep reasoning:**
124
+ ```text
125
+ System: You are a coding assistant. <|think_on|>
126
+ User: Implement a red-black tree in Rust.
127
+ ```
128
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
129
+
130
+ ---
131
+
132
+ ## Token Saving: Stripping past thoughts
133
+
134
+ By default in v19, this template **preserves** all past `<think>` blocks in the chat history. This is intentional: it prevents the model from suffering "amnesia stalls" during complex, multi-step agentic loops, and it mathematically guarantees a 100% Prefix KV Cache hit rate on local inference engines.
135
+
136
+ However, if you are running constrained hardware and need to save context tokens, you can explicitly disable this feature in your engine's template kwargs to automatically strip past thoughts:
137
+
138
+ ```json
139
+ {
140
+ "preserve_thinking": false
141
+ }
142
+ ```
143
+ *(Note: Setting this to false will naturally reduce your KV Cache hit rate during multi-turn chats, as the prompt string will dynamically mutate).*
144
+
145
+ ---
146
+
147
+ <details>
148
+ <summary>Technical Details of the Critical Fixes</summary>
149
+
150
+ ### 1. The "Empty Think" Poisoning & Logic Trap Cure (v19)
151
+ Previous versions attempted to save tokens by replacing past thoughts with empty `<think>\n</think>` blocks, combined with an absolute system prompt demanding a tool be called immediately after `</think>`. This created a toxic in-context learning pattern: the model associated empty thoughts with tools, and full thoughts with forbidden conversational text, causing an 80%+ premature `<|im_end|>` stalling rate. v19 abolishes empty think injection and rewrites the `<IMPORTANT>` directives to explicitly authorize conversational synthesis after a thought block.
152
+
153
+ ### 2. KV Cache Safety & Autoregressive Normalization (v18/v19)
154
+ Llama.cpp and vLLM utilize prefix KV caching to speed up generation. Because v19 now preserves historical thoughts chronologically by default, the rendered history perfectly synchronizes with the cached generated tokens. Combined with strict single `\n` normalization at autoregressive boundaries, this achieves a 100% KV Cache hit rate in multi-turn loops.
155
+
156
+ ### 3. Native XML Tool Call Format (v16)
157
+ The model was trained with the XML-based tool call format used by Qwen3-Coder:
158
+ ```xml
159
+ <tool_call>
160
+ <function=tool_name>
161
+ <parameter=param_name>
162
+ value
163
+ </parameter>
164
+ </function>
165
+ </tool_call>
166
+ ```
167
+ v16 restored this format natively, making it compatible with all parsers while bypassing the `|items` crash by using C++ safe key iteration (`for args_name in tool_call.arguments`).
168
+
169
+ ### 4. Two-Tier Agentic Error Escalation (v15)
170
+ When a tool call fails validation repeatedly, the model can enter a degenerate reasoning spiral. This template leverages a two-tier escalation system driven by a forward-tracked `consecutive_failures` counter:
171
+ - **Tier 1 (1st error):** Generation prompt prefix changes to seed reasoning at a different token position, breaking the cached attractor state.
172
+ - **Tier 2 (2nd+ consecutive errors):** Think block bypassed entirely. An urgent out-of-band directive forces an immediate corrected action wrapped safely within the user `tool_response` block.
173
+
174
+ ### 5. Smart False-Positive Detection (v18)
175
+ Instead of broad substring matching that triggers false retry-loops on successful database returns containing words like "error", v18 utilizes strict structural guards looking for `Exception:`, `"error":`, `Traceback`, and `command not found`, combined with length gates and shell-echo exclusions (`$ `).
176
+
177
+ ### 6. minijinja Compatibility Constraints (v18)
178
+ Python-only Jinja2 features crash on `minijinja` (the C++ runtime used by llama.cpp, LM Studio, and MLX). All instances have been refactored for universal support:
179
+ - `\| items` -> `for key in mapping`
180
+ - `loop.previtem` -> `messages[loop.index0 - 1]` (v18)
181
+ - `map('string')` -> `join('|')`
182
+ - `\| first` -> `'$ ' in content`
183
+
184
+ </details>
185
+
186
+ <details>
187
+ <summary>Comparison Matrix: Official vs Fixed vs Community</summary>
188
+
189
+ | Feature | Official Qwen Templates | LuffyTheFox | mod-ellary | Pneuny | **This Fixed Template (v19)** |
190
+ |---------|----------|-------------|------------|--------|----------------|
191
+ | Tool call format | XML (native) | JSON | JSON | JSON | **XML (native, qwen3_coder compatible)** |
192
+ | Tool arguments | Fails (`\|items`) | Fixed | Missing | Fixed | **Fixed (C++ safe XML)** |
193
+ | Premature Stalls (Stopping Bug) | Stalls | Stalls | Stalls | Stalls | **Fixed via Logic Trap / Poisoning removal (v19)** |
194
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | Stalls | Stalls | Stalls | **Two-tier escalation system** |
195
+ | False-positive tool errors | N/A | N/A | N/A | N/A | **Guarded (Strict structural matching)** |
196
+ | Post-Tool Overthinking | Spams/Stalls | Broken | Broken | Broken | **Universal Synthesis** |
197
+ | `--reasoning off` on tool errors | N/A | N/A | N/A | N/A | **Fully respected** |
198
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
199
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
200
+ | Empty think in history | Spams empty blocks | Broken | Tags omitted | Broken | **Abolished completely (v19)** |
201
+ | KV prefix caching | Breaks on dynamic history | Breaks | Breaks | Breaks | **100% stable out-of-the-box (v19)** |
202
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
203
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
204
+ | Legacy AST support | Fails (`previtem`) | Fails | Fails | Fails | **Fixed (`index0`)** |
205
+ | `</thinking>` hallucination | Fails | N/A | N/A | N/A | **Detected and safely trimmed** |
206
+
207
+ </details>
208
+
209
+ ---
210
+
211
+ ## Running the test suite
212
+
213
+ ```bash
214
+ python3 scripts/test_v18.py
215
+ ```
216
+
217
+ Tests cover: XML tool format, tool instructions, thinking bypass, `<|think_off|>` / `<|think_on|>`, Tier 1 & 2 escalation, length-gated detection, shell/search false positives, `--reasoning off` + errors, counter reset, historical think stripping, `preserve_thinking`, developer role, mid-conversation system, tool response wrapping, and string argument passthrough.
218
+
219
+ ---
220
+
221
+ ## Authorship
222
+
223
+ | Role | Author |
224
+ |------|--------|
225
+ | Original models | Alibaba Cloud (Qwen team) |
226
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
227
+
228
+ ## License
229
+
230
+ Apache-2.0, inherited from Qwen.
archive/README-v10.md ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v10)
17
+
18
+ > **2026-05-09 Update (v10):** Massive stability and performance overhaul! Halved tool prompt tokens via compaction, eliminated C++ engine `UndefinedValue` crashes by removing brittle string slices, fixed prefix cache invalidation in llama.cpp by ensuring chronological state tracking, resolved vLLM crashes with `<|think_off|>`, and fixed tool parameter omission over long contexts via dynamic instruction reinforcement.
19
+ >
20
+ > **2026-05-08 Update (v9):** Fixed 9th bug: Thinking-tool-call hallucination. Refactored system prompt parsing to enable dynamic tool instructions. The template now actively teaches the model how to safely combine `<think>` blocks and `<tool_call>` boundaries.
21
+ >
22
+ > **2026-05-07 Update (v8):** Fixed 8th bug: Mid-conversation system messages no longer crash the template. Compatibility restored for agent frameworks (OpenCode, Docker Agent, oh-my-pi). Re-engineered Jinja string parsing for C++ engine stability.
23
+
24
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
25
+
26
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
27
+
28
+ ---
29
+
30
+ ## Why you need this
31
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
32
+
33
+ Here are the 14 bugs this template fixes:
34
+
35
+ | Problem | Impact | Fix |
36
+ |---|---|---|
37
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility. |
38
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
39
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
40
+ | **4. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
41
+ | **5. No way to toggle thinking** | The user is restricted to the model defaults. | Intercepts `<\|think_off\|>` and `<\|think_on\|>` tags natively. |
42
+ | **6. Qwen 3.6 `</thinking>` hallucination** | Model sometimes generates `</thinking>` instead of `</think>`, permanently breaking the parser. | Advanced tag detection and stream recovery. |
43
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
44
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries. |
45
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
46
+ | **10. Massive token waste on tools** | The template dumps raw JSON schemas for tools, wasting ~50% of the prompt context and increasing TTFT. | Tools are now compacted into typed one-line signatures, saving hundreds of tokens. |
47
+ | **11. Cache invalidation on llama.cpp** | Conditionally hiding past `<think>` blocks based on future messages breaks KV cache. | Refactored history rendering to strictly chronological forward state tracking. |
48
+ | **12. vLLM generation crash** | Hardcoded empty `<think></think>` blocks when thinking is disabled break vLLM stop parsing. | Removed fake closed blocks; relies on natural `<\|im_start\|>assistant` without primer. |
49
+ | **13. Jinja C++ crashes (UndefinedValue)** | Python negative indexing `[-1]` when closing tags fails on `minijinja` engines. | Replaced all string slicing with safe Jinja `replace()` operations. |
50
+ | **14. Tool parameter omission** | Model forgets the strict XML format over long contexts and drops required parameters. | Implemented Dynamic Reinforcement: format reminder is injected right before the final response. |
51
+
52
+ ---
53
+
54
+ ## Quick install
55
+
56
+ Choose your environment and update the template:
57
+
58
+ ### LM Studio
59
+ 1. Open your Qwen model in the right-side panel.
60
+ 2. Scroll down to **Prompt Template**.
61
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
62
+ 4. Click **Save**.
63
+
64
+ ### llama.cpp / koboldcpp
65
+ ```bash
66
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
67
+ ```
68
+
69
+ ### vLLM / TextGen
70
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
71
+
72
+ ### oMLX
73
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
74
+
75
+ ---
76
+
77
+ ## Which file do I use?
78
+
79
+ | Template File | Supported Models |
80
+ |------|-----------|
81
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
82
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
83
+
84
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
85
+
86
+ ---
87
+
88
+ ## The thinking toggle
89
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
90
+
91
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
92
+
93
+ **Fast answer, no reasoning:**
94
+ ```text
95
+ System: You are a coding assistant. <|think_off|>
96
+ User: What's 2+2?
97
+ ```
98
+
99
+ **Deep reasoning:**
100
+ ```text
101
+ System: You are a coding assistant. <|think_on|>
102
+ User: Implement a red-black tree in Rust.
103
+ ```
104
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
105
+
106
+ ---
107
+
108
+ ## Pre-installed models
109
+
110
+ If you are using one of the following models, you already have an older version of this template installed.
111
+
112
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
113
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
114
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
115
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
116
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
117
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
118
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
119
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
120
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
121
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
122
+
123
+ ---
124
+
125
+ <details>
126
+ <summary>Technical Details of the 9 Fixes</summary>
127
+
128
+ ### 1. Tool calls on C++ engines
129
+ The official template iterates tool call arguments with `|items`:
130
+ `{%- for key, value in tool_call.arguments|items %}`
131
+
132
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses direct dictionary key lookups instead. It also replaces `is sequence` with `is iterable`, removes Python-only `|safe` wrappers, and handles arguments returned as raw strings.
133
+
134
+ ### 2. Mid-conversation system messages crash
135
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
136
+
137
+ ### 3. `developer` role
138
+ The OpenAI-compatible API spec sends `message.role == "developer"` for system-level instructions. The official Qwen template throws an exception. Both templates here accept `"developer"` and map it properly.
139
+
140
+ ### 4. Empty thinking blocks
141
+ The official template wraps every past assistant turn in thinking tags, even when empty. When there is no reasoning content, those tags waste context tokens and break prefix caching. The 3.5 template checks `reasoning_content` before emitting. The 3.6 template checks `reasoning_content|trim|length > 0` and ties history visibility to the `<|think_off|>` override.
142
+
143
+ ### 5. `</thinking>` hallucination (Qwen 3.6 only)
144
+ The Qwen 3.6 model sometimes generates `</thinking>` instead of the expected `</think>`. The official parser splits on `</think >` only and fails. The 3.6 template detects which closing tag was actually used and splits dynamically. It also handles interrupted generation by rescuing incomplete streams.
145
+
146
+ ### 6. Arguments serialization
147
+ The official template serializes argument values with `|tojson` unconditionally, failing when the value is already a string. The fixed templates check the type first. Strings pass through as-is, and everything else goes through `|tojson`.
148
+
149
+ ### 7. Auto-close unclosed thinking before tool calls
150
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
151
+
152
+ ### 8. No-user-query exception
153
+ The official template scans the message list in reverse. If all messages are tool results, or there are no user messages, it fires `raise_exception('No user query found...')` and hard-crashes. The fix replaces the exception with a graceful fallback `{%- set ns.last_query_index = messages|length - 1 %}`, enabling agentic tool-calling chains to function perfectly.
154
+
155
+ ### 9. Thinking tool_call hallucination
156
+ The official template appends `<think>\n` to the end of the generation prompt to initiate reasoning. However, its system instructions rigidly demand the model to output *only* `<tool_call>` with no suffix. This contradictory state causes the model to improperly nest its tool call inside the thinking block. This template utilizes a global pre-scan to evaluate the final `enable_thinking` state across the entire conversation history, guaranteeing it can dynamically inject a proper `<think>...</think>` usage example into the tool instructions exactly when reasoning is enabled.
157
+ </details>
158
+
159
+ <details>
160
+ <summary>Comparison: Qwen 3.5 templates</summary>
161
+
162
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v10)** |
163
+ |---------|----------|-------------|------------|--------|----------------|
164
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed** |
165
+ | `\|safe` removed | Fails | Fixed | Missing | Fixed | **Fixed** |
166
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
167
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
168
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
169
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
170
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
171
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
172
+ | Tool token optimization | None | None | None | None | **~50% reduction** |
173
+ | Long-context tool adherence | Fails | Fails | Fails | Fails | **Dynamic reinforcement** |
174
+
175
+ </details>
176
+
177
+ <details>
178
+ <summary>Comparison: Qwen 3.6 template</summary>
179
+
180
+ | Feature | Official | **This (v10)** |
181
+ |---------|----------|----------------|
182
+ | Tool arguments | Fails (`\|items`) | **Fixed** |
183
+ | `\|safe` removed | Fails | **Fixed** |
184
+ | `developer` role | Missing | **Added** |
185
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
186
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
187
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Chronological)** |
188
+ | Mid-conversation system | Crashes | **Fixed** |
189
+ | `</thinking>` hallucination | Fails | **Detected and handled** |
190
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
191
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
192
+ | Tool token optimization | None | **~50% reduction** |
193
+ | Long-context tool adherence | Fails | **Dynamic reinforcement** |
194
+
195
+ </details>
196
+
197
+ ---
198
+
199
+ ## Authorship
200
+
201
+ | Role | Author |
202
+ |------|--------|
203
+ | Original models | Alibaba Cloud (Qwen team) |
204
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
205
+
206
+ ## License
207
+
208
+ Apache-2.0, inherited from Qwen.
archive/README-v11.md ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v11)
17
+
18
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`) when `enable_thinking` is false to prevent the model from hallucinating reasoning tags. Also removed the redundant end-of-prompt system message.
19
+ >
20
+ > **2026-05-09 Update (v10):** Massive stability and performance overhaul! Halved tool prompt tokens via compaction, eliminated C++ engine `UndefinedValue` crashes by removing brittle string slices, fixed prefix cache invalidation in llama.cpp by ensuring chronological state tracking, resolved vLLM crashes with `<|think_off|>`, and fixed tool parameter omission over long contexts via dynamic instruction reinforcement.
21
+ >
22
+ > **2026-05-08 Update (v9):** Fixed 9th bug: Thinking-tool-call hallucination. Refactored system prompt parsing to enable dynamic tool instructions. The template now actively teaches the model how to safely combine `<think>` blocks and `<tool_call>` boundaries.
23
+ >
24
+ > **2026-05-07 Update (v8):** Fixed 8th bug: Mid-conversation system messages no longer crash the template. Compatibility restored for agent frameworks (OpenCode, Docker Agent, oh-my-pi). Re-engineered Jinja string parsing for C++ engine stability.
25
+
26
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
27
+
28
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
29
+
30
+ ---
31
+
32
+ ## Why you need this
33
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
34
+
35
+ Here are the 14 bugs this template fixes:
36
+
37
+ | Problem | Impact | Fix |
38
+ |---|---|---|
39
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility. |
40
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
41
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
42
+ | **4. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
43
+ | **5. No way to toggle thinking** | The user is restricted to the model defaults. | Intercepts `<\|think_off\|>` and `<\|think_on\|>` tags natively. |
44
+ | **6. Qwen 3.6 `</thinking>` hallucination** | Model sometimes generates `</thinking>` instead of `</think>`, permanently breaking the parser. | Advanced tag detection and stream recovery. |
45
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
46
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries. |
47
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
48
+ | **10. Massive token waste on tools** | The template dumps raw JSON schemas for tools, wasting ~50% of the prompt context and increasing TTFT. | Tools are now compacted into typed one-line signatures, saving hundreds of tokens. |
49
+ | **11. Cache invalidation on llama.cpp** | Conditionally hiding past `<think>` blocks based on future messages breaks KV cache. | Refactored history rendering to strictly chronological forward state tracking. |
50
+ | **12. vLLM generation crash** | Hardcoded empty `<think></think>` blocks when thinking is disabled break vLLM stop parsing. | Removed fake closed blocks; relies on natural `<\|im_start\|>assistant` without primer. |
51
+ | **13. Jinja C++ crashes (UndefinedValue)** | Python negative indexing `[-1]` when closing tags fails on `minijinja` engines. | Replaced all string slicing with safe Jinja `replace()` operations. |
52
+ | **14. Tool parameter omission** | Model forgets the strict XML format over long contexts and drops required parameters. | Implemented Dynamic Reinforcement: format reminder is injected right before the final response. |
53
+
54
+ ---
55
+
56
+ ## Quick install
57
+
58
+ Choose your environment and update the template:
59
+
60
+ ### LM Studio
61
+ 1. Open your Qwen model in the right-side panel.
62
+ 2. Scroll down to **Prompt Template**.
63
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
64
+ 4. Click **Save**.
65
+
66
+ ### llama.cpp / koboldcpp
67
+ ```bash
68
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
69
+ ```
70
+
71
+ ### vLLM / TextGen
72
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
73
+
74
+ ### oMLX
75
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
76
+
77
+ ---
78
+
79
+ ## Which file do I use?
80
+
81
+ | Template File | Supported Models |
82
+ |------|-----------|
83
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
84
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
85
+
86
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
87
+
88
+ ---
89
+
90
+ ## The thinking toggle
91
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
92
+
93
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
94
+
95
+ **Fast answer, no reasoning:**
96
+ ```text
97
+ System: You are a coding assistant. <|think_off|>
98
+ User: What's 2+2?
99
+ ```
100
+
101
+ **Deep reasoning:**
102
+ ```text
103
+ System: You are a coding assistant. <|think_on|>
104
+ User: Implement a red-black tree in Rust.
105
+ ```
106
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
107
+
108
+ ---
109
+
110
+ ## Preserving past thoughts
111
+
112
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
113
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
114
+
115
+ ```json
116
+ {
117
+ "preserve_thinking": true
118
+ }
119
+ ```
120
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
121
+
122
+ ---
123
+
124
+ ## Pre-installed models
125
+
126
+ If you are using one of the following models, you already have an older version of this template installed.
127
+
128
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
129
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
130
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
131
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
132
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
133
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
134
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
135
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
136
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
137
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
138
+
139
+ ---
140
+
141
+ <details>
142
+ <summary>Technical Details of the 9 Fixes</summary>
143
+
144
+ ### 1. Tool calls on C++ engines
145
+ The official template iterates tool call arguments with `|items`:
146
+ `{%- for key, value in tool_call.arguments|items %}`
147
+
148
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses direct dictionary key lookups instead. It also replaces `is sequence` with `is iterable`, removes Python-only `|safe` wrappers, and handles arguments returned as raw strings.
149
+
150
+ ### 2. Mid-conversation system messages crash
151
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
152
+
153
+ ### 3. `developer` role
154
+ The OpenAI-compatible API spec sends `message.role == "developer"` for system-level instructions. The official Qwen template throws an exception. Both templates here accept `"developer"` and map it properly.
155
+
156
+ ### 4. Empty thinking blocks
157
+ The official template wraps every past assistant turn in thinking tags, even when empty. When there is no reasoning content, those tags waste context tokens and break prefix caching. The 3.5 template checks `reasoning_content` before emitting. The 3.6 template checks `reasoning_content|trim|length > 0` and ties history visibility to the `<|think_off|>` override.
158
+
159
+ ### 5. `</thinking>` hallucination (Qwen 3.6 only)
160
+ The Qwen 3.6 model sometimes generates `</thinking>` instead of the expected `</think>`. The official parser splits on `</think >` only and fails. The 3.6 template detects which closing tag was actually used and splits dynamically. It also handles interrupted generation by rescuing incomplete streams.
161
+
162
+ ### 6. Arguments serialization
163
+ The official template serializes argument values with `|tojson` unconditionally, failing when the value is already a string. The fixed templates check the type first. Strings pass through as-is, and everything else goes through `|tojson`.
164
+
165
+ ### 7. Auto-close unclosed thinking before tool calls
166
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
167
+
168
+ ### 8. No-user-query exception
169
+ The official template scans the message list in reverse. If all messages are tool results, or there are no user messages, it fires `raise_exception('No user query found...')` and hard-crashes. The fix replaces the exception with a graceful fallback `{%- set ns.last_query_index = messages|length - 1 %}`, enabling agentic tool-calling chains to function perfectly.
170
+
171
+ ### 9. Thinking tool_call hallucination
172
+ The official template appends `<think>\n` to the end of the generation prompt to initiate reasoning. However, its system instructions rigidly demand the model to output *only* `<tool_call>` with no suffix. This contradictory state causes the model to improperly nest its tool call inside the thinking block. This template utilizes a global pre-scan to evaluate the final `enable_thinking` state across the entire conversation history, guaranteeing it can dynamically inject a proper `<think>...</think>` usage example into the tool instructions exactly when reasoning is enabled.
173
+ </details>
174
+
175
+ <details>
176
+ <summary>Comparison: Qwen 3.5 templates</summary>
177
+
178
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v11)** |
179
+ |---------|----------|-------------|------------|--------|----------------|
180
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed** |
181
+ | `\|safe` removed | Fails | Fixed | Missing | Fixed | **Fixed** |
182
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
183
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
184
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
185
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
186
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
187
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
188
+ | Tool token optimization | None | None | None | None | **~50% reduction** |
189
+ | Long-context tool adherence | Fails | Fails | Fails | Fails | **Dynamic reinforcement** |
190
+
191
+ </details>
192
+
193
+ <details>
194
+ <summary>Comparison: Qwen 3.6 template</summary>
195
+
196
+ | Feature | Official | **This (v11)** |
197
+ |---------|----------|----------------|
198
+ | Tool arguments | Fails (`\|items`) | **Fixed** |
199
+ | `\|safe` removed | Fails | **Fixed** |
200
+ | `developer` role | Missing | **Added** |
201
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
202
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
203
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Chronological)** |
204
+ | Mid-conversation system | Crashes | **Fixed** |
205
+ | `</thinking>` hallucination | Fails | **Detected and handled** |
206
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
207
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
208
+ | Tool token optimization | None | **~50% reduction** |
209
+ | Long-context tool adherence | Fails | **Dynamic reinforcement** |
210
+
211
+ </details>
212
+
213
+ ---
214
+
215
+ ## Authorship
216
+
217
+ | Role | Author |
218
+ |------|--------|
219
+ | Original models | Alibaba Cloud (Qwen team) |
220
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
221
+
222
+ ## License
223
+
224
+ Apache-2.0, inherited from Qwen.
archive/README-v12.md ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v12)
17
+
18
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes. Fixed a massive semantic data-loss bug in v10 by restoring parameter descriptions to the compacted tool schemas. Implemented a robust Pre-Parse Tag Normalization Pipeline to neutralize whitespace tag hallucinations (e.g., `</ think>`), preventing conversational text from being permanently trapped or deleted.
19
+ >
20
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`) when `enable_thinking` is false to prevent the model from hallucinating reasoning tags. Also removed the redundant end-of-prompt system message.
21
+ >
22
+ > **2026-05-09 Update (v10):** Massive stability and performance overhaul! Halved tool prompt tokens via compaction, eliminated C++ engine `UndefinedValue` crashes by removing brittle string slices, fixed prefix cache invalidation in llama.cpp by ensuring chronological state tracking, resolved vLLM crashes with `<|think_off|>`, and fixed tool parameter omission over long contexts via dynamic instruction reinforcement.
23
+ >
24
+ > **2026-05-08 Update (v9):** Fixed 9th bug: Thinking-tool-call hallucination. Refactored system prompt parsing to enable dynamic tool instructions. The template now actively teaches the model how to safely combine `<think>` blocks and `<tool_call>` boundaries.
25
+ >
26
+ > **2026-05-07 Update (v8):** Fixed 8th bug: Mid-conversation system messages no longer crash the template. Compatibility restored for agent frameworks (OpenCode, Docker Agent, oh-my-pi). Re-engineered Jinja string parsing for C++ engine stability.
27
+
28
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
29
+
30
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
31
+
32
+ ---
33
+
34
+ ## Why you need this
35
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
36
+
37
+ Here are the 14 bugs this template fixes:
38
+
39
+ | Problem | Impact | Fix |
40
+ |---|---|---|
41
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility. |
42
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
43
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
44
+ | **4. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
45
+ | **5. No way to toggle thinking** | The user is restricted to the model defaults. | Intercepts `<\|think_off\|>` and `<\|think_on\|>` tags natively. |
46
+ | **6. Whitespace tag hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | Pre-Parse Tag Normalization Pipeline natively neutralizes variants. |
47
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
48
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries. |
49
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
50
+ | **10. Massive token waste on tools** | The template dumps raw JSON schemas for tools, wasting ~50% of the prompt context and increasing TTFT. | Tools are now compacted into typed one-line signatures while preserving semantic parameter descriptions. |
51
+ | **11. Cache invalidation on llama.cpp** | Conditionally hiding past `<think>` blocks based on future messages breaks KV cache. | Refactored history rendering to strictly chronological forward state tracking. |
52
+ | **12. Reasoning bypass hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
53
+ | **13. Jinja C++ crashes (UndefinedValue)** | Python negative indexing `[-1]` when closing tags fails on `minijinja` engines. | Replaced all string slicing with safe Jinja `replace()` operations. |
54
+ | **14. Tool format drift & stalls** | Model leaks conversational text between reasoning and tool calls, stalling strict parsers. | Re-engineered dynamic instructions and restored `<IMPORTANT>` formatting reminder to the initial system prompt. |
55
+
56
+ ---
57
+
58
+ ## Quick install
59
+
60
+ Choose your environment and update the template:
61
+
62
+ ### LM Studio
63
+ 1. Open your Qwen model in the right-side panel.
64
+ 2. Scroll down to **Prompt Template**.
65
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
66
+ 4. Click **Save**.
67
+
68
+ ### llama.cpp / koboldcpp
69
+ ```bash
70
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
71
+ ```
72
+
73
+ ### vLLM / TextGen
74
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
75
+
76
+ ### oMLX
77
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
78
+
79
+ ---
80
+
81
+ ## Which file do I use?
82
+
83
+ | Template File | Supported Models |
84
+ |------|-----------|
85
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
86
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
87
+
88
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
89
+
90
+ ---
91
+
92
+ ## The thinking toggle
93
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
94
+
95
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
96
+
97
+ **Fast answer, no reasoning:**
98
+ ```text
99
+ System: You are a coding assistant. <|think_off|>
100
+ User: What's 2+2?
101
+ ```
102
+
103
+ **Deep reasoning:**
104
+ ```text
105
+ System: You are a coding assistant. <|think_on|>
106
+ User: Implement a red-black tree in Rust.
107
+ ```
108
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
109
+
110
+ ---
111
+
112
+ ## Preserving past thoughts
113
+
114
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
115
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
116
+
117
+ ```json
118
+ {
119
+ "preserve_thinking": true
120
+ }
121
+ ```
122
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
123
+
124
+ ---
125
+
126
+ ## Pre-installed models
127
+
128
+ If you are using one of the following models, you already have an older version of this template installed.
129
+
130
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
131
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
132
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
133
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
134
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
135
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
136
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
137
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
138
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
139
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
140
+
141
+ ---
142
+
143
+ <details>
144
+ <summary>Technical Details of the 9 Fixes</summary>
145
+
146
+ ### 1. Tool calls on C++ engines
147
+ The official template iterates tool call arguments with `|items`:
148
+ `{%- for key, value in tool_call.arguments|items %}`
149
+
150
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses direct dictionary key lookups instead. It also replaces `is sequence` with `is iterable`, removes Python-only `|safe` wrappers, and handles arguments returned as raw strings.
151
+
152
+ ### 2. Mid-conversation system messages crash
153
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
154
+
155
+ ### 3. `developer` role
156
+ The OpenAI-compatible API spec sends `message.role == "developer"` for system-level instructions. The official Qwen template throws an exception. Both templates here accept `"developer"` and map it properly.
157
+
158
+ ### 4. Empty thinking blocks
159
+ The official template wraps every past assistant turn in thinking tags, even when empty. When there is no reasoning content, those tags waste context tokens and break prefix caching. The 3.5 template checks `reasoning_content` before emitting. The 3.6 template checks `reasoning_content|trim|length > 0` and ties history visibility to the `<|think_off|>` override.
160
+
161
+ ### 5. `</thinking>` hallucination (Qwen 3.6 only)
162
+ The Qwen 3.6 model sometimes generates `</thinking>` instead of the expected `</think>`. The official parser splits on `</think >` only and fails. The 3.6 template detects which closing tag was actually used and splits dynamically. It also handles interrupted generation by rescuing incomplete streams.
163
+
164
+ ### 6. Arguments serialization
165
+ The official template serializes argument values with `|tojson` unconditionally, failing when the value is already a string. The fixed templates check the type first. Strings pass through as-is, and everything else goes through `|tojson`.
166
+
167
+ ### 7. Auto-close unclosed thinking before tool calls
168
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
169
+
170
+ ### 8. No-user-query exception
171
+ The official template scans the message list in reverse. If all messages are tool results, or there are no user messages, it fires `raise_exception('No user query found...')` and hard-crashes. The fix replaces the exception with a graceful fallback `{%- set ns.last_query_index = messages|length - 1 %}`, enabling agentic tool-calling chains to function perfectly.
172
+
173
+ ### 9. Thinking tool_call hallucination
174
+ The official template appends `<think>\n` to the end of the generation prompt to initiate reasoning. However, its system instructions rigidly demand the model to output *only* `<tool_call>` with no suffix. This contradictory state causes the model to improperly nest its tool call inside the thinking block. This template utilizes a global pre-scan to evaluate the final `enable_thinking` state across the entire conversation history, guaranteeing it can dynamically inject a proper `<think>...</think>` usage example into the tool instructions exactly when reasoning is enabled.
175
+ </details>
176
+
177
+ <details>
178
+ <summary>Comparison: Qwen 3.5 templates</summary>
179
+
180
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v12)** |
181
+ |---------|----------|-------------|------------|--------|----------------|
182
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed** |
183
+ | `\|safe` removed | Fails | Fixed | Missing | Fixed | **Fixed** |
184
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
185
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
186
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
187
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
188
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
189
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
190
+ | Tool token optimization | None | None | None | None | **~50% reduction** |
191
+ | Long-context tool adherence | Fails | Fails | Fails | Fails | **Dynamic reinforcement** |
192
+
193
+ </details>
194
+
195
+ <details>
196
+ <summary>Comparison: Qwen 3.6 template</summary>
197
+
198
+ | Feature | Official | **This (v12)** |
199
+ |---------|----------|----------------|
200
+ | Tool arguments | Fails (`\|items`) | **Fixed** |
201
+ | `\|safe` removed | Fails | **Fixed** |
202
+ | `developer` role | Missing | **Added** |
203
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
204
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
205
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Chronological)** |
206
+ | Mid-conversation system | Crashes | **Fixed** |
207
+ | `</thinking>` hallucination | Fails | **Detected and handled** |
208
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
209
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
210
+ | Tool token optimization | None | **~50% reduction** |
211
+ | Long-context tool adherence | Fails | **Dynamic reinforcement** |
212
+
213
+ </details>
214
+
215
+ ---
216
+
217
+ ## Authorship
218
+
219
+ | Role | Author |
220
+ |------|--------|
221
+ | Original models | Alibaba Cloud (Qwen team) |
222
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
223
+
224
+ ## License
225
+
226
+ Apache-2.0, inherited from Qwen.
archive/README-v13.md ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v13)
17
+
18
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
19
+ >
20
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
21
+ >
22
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
23
+ >
24
+ > **2026-05-09 Update (v10):** Massive stability and performance overhaul! Fixed prefix cache invalidation in llama.cpp by ensuring chronological state tracking, resolved vLLM crashes with `<|think_off|>`.
25
+
26
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
27
+
28
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
29
+
30
+ ---
31
+
32
+ ## Why you need this
33
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
34
+
35
+ Here are the 14 bugs this template fixes:
36
+
37
+ | Problem | Impact | Fix |
38
+ |---|---|---|
39
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility, natively dumping JSON schemas safely. |
40
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
41
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
42
+ | **4. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
43
+ | **5. No way to toggle thinking** | The user is restricted to the model defaults. | Intercepts `<\|think_off\|>` and `<\|think_on\|>` tags natively. |
44
+ | **6. Whitespace tag hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | C++ safe array-slicing isolates the reasoning block without corrupting user code snippets. |
45
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
46
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely using array slicing. |
47
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
48
+ | **10. MCP Tool parsing crashes** | Downstream coding agents crash because tool parameters contain unescaped newlines inside custom XML wrappers. | Restored 100% standard JSON formatted tool calls (`{"name": "...", "arguments": {...}}`) natively. |
49
+ | **11. Cache invalidation on llama.cpp** | Mutating the initial system prompt based on future user toggles breaks the prefix KV cache. | Replaced history mutation with structural bypass generation (`<think>\n\n</think>\n\n`), keeping the system prompt 100% immutable. |
50
+ | **12. Reasoning bypass hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
51
+ | **13. Jinja C++ crashes (UndefinedValue)** | Python negative indexing `[-1]` or implicit enum coercions crash on `minijinja`. | Replaced all brittle logic with native JSON iteration and safe Jinja strings. |
52
+ | **14. Tool format drift & stalls** | Model leaks conversational text between reasoning and tool calls, stalling strict parsers. | Cleanly refactored dynamic tool instructions block with a standard JSON example. |
53
+
54
+ ---
55
+
56
+ ## Quick install
57
+
58
+ Choose your environment and update the template:
59
+
60
+ ### LM Studio
61
+ 1. Open your Qwen model in the right-side panel.
62
+ 2. Scroll down to **Prompt Template**.
63
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
64
+ 4. Click **Save**.
65
+
66
+ ### llama.cpp / koboldcpp
67
+ ```bash
68
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
69
+ ```
70
+
71
+ ### vLLM / TextGen
72
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
73
+
74
+ ### oMLX
75
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
76
+
77
+ ---
78
+
79
+ ## Which file do I use?
80
+
81
+ | Template File | Supported Models |
82
+ |------|-----------|
83
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
84
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
85
+
86
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
87
+
88
+ ---
89
+
90
+ ## The thinking toggle
91
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
92
+
93
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
94
+
95
+ **Fast answer, no reasoning:**
96
+ ```text
97
+ System: You are a coding assistant. <|think_off|>
98
+ User: What's 2+2?
99
+ ```
100
+
101
+ **Deep reasoning:**
102
+ ```text
103
+ System: You are a coding assistant. <|think_on|>
104
+ User: Implement a red-black tree in Rust.
105
+ ```
106
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
107
+
108
+ ---
109
+
110
+ ## Preserving past thoughts
111
+
112
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
113
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
114
+
115
+ ```json
116
+ {
117
+ "preserve_thinking": true
118
+ }
119
+ ```
120
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
121
+
122
+ ---
123
+
124
+ ## Pre-installed models
125
+
126
+ If you are using one of the following models, you already have an older version of this template installed.
127
+
128
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
129
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
130
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
131
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
132
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
133
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
134
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
135
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
136
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
137
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
138
+
139
+ ---
140
+
141
+ <details>
142
+ <summary>Technical Details of the 14 Fixes</summary>
143
+
144
+ ### 1. Tool calls on C++ engines
145
+ The official template iterates tool call arguments with `|items`:
146
+ `{%- for key, value in tool_call.arguments|items %}`
147
+
148
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses native JSON serialization to safely inject tools.
149
+
150
+ ### 2. Mid-conversation system messages crash
151
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
152
+
153
+ ### 3. `developer` role
154
+ The OpenAI-compatible API spec sends `message.role == "developer"` for system-level instructions. The official Qwen template throws an exception. Both templates here accept `"developer"` and map it properly.
155
+
156
+ ### 4. Empty thinking blocks
157
+ The official template wraps every past assistant turn in thinking tags, even when empty. When there is no reasoning content, those tags waste context tokens and break prefix caching. The 3.5 and 3.6 templates check `reasoning_content|trim|length > 0` and tie history visibility to the `<|think_off|>` override.
158
+
159
+ ### 5. `</thinking>` hallucination
160
+ Qwen models sometimes generate `</thinking>` instead of the expected `</think>`. The official parser splits on `</think >` only and fails. This template dynamically detects the exact hallucinated variant used and structurally isolates it safely.
161
+
162
+ ### 6. Whitespace Tag Hallucination Isolation
163
+ Using global `.replace('</ think>', '</think>')` silently corrupts code blocks if the user queries about XML formatting. This template employs an entirely C++ safe array-slicing method (`content.split('<think>')`) to securely extract the reasoning content at strict boundaries without ever modifying user text.
164
+
165
+ ### 7. Auto-close unclosed thinking before tool calls
166
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
167
+
168
+ ### 8. No-user-query exception
169
+ The official template scans the message list in reverse. If all messages are tool results, or there are no user messages, it fires `raise_exception('No user query found...')` and hard-crashes. The fix replaces the exception with a graceful fallback `{%- set ns.last_query_index = messages|length - 1 %}`, enabling agentic tool-calling chains to function perfectly.
170
+
171
+ ### 9. Thinking tool_call hallucination
172
+ The official template appends `<think>\n` to the end of the generation prompt to initiate reasoning. However, its system instructions rigidly demand the model to output *only* `<tool_call>` with no suffix. This contradictory state causes the model to improperly nest its tool call inside the thinking block. This template utilizes a cleanly formatted instruction block that properly guides the model.
173
+
174
+ ### 10. Downstream MCP Tool parsing crashes
175
+ Using a custom XML formatting for arguments (`<parameter=key>value</parameter>`) breaks downstream standard JSON parsers when values contain newlines. This template natively supports and enforces standard JSON formatting (`{"name": "...", "arguments": {...}}`) exactly as Llama.cpp and MCP frameworks expect.
176
+
177
+ ### 11. KV Cache preservation (Immutable System Prompt)
178
+ Dynamically parsing `<|think_off|>` in the conversation history and altering the *initial* system prompt's instructions completely drops the LLM KV prefix cache. This template isolates the system prompt entirely, preserving the cache, and relies strictly on generation bypass formatting (`<think>\n\n</think>\n\n`) to toggle thinking mid-conversation.
179
+ </details>
180
+
181
+ <details>
182
+ <summary>Comparison: Qwen 3.5 templates</summary>
183
+
184
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v13)** |
185
+ |---------|----------|-------------|------------|--------|----------------|
186
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed (JSON native)** |
187
+ | `\|safe` removed | Fails | Fixed | Missing | Fixed | **Fixed** |
188
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
189
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
190
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
191
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
192
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
193
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
194
+ | Tool token optimization | None | None | None | None | **JSON-native simplification** |
195
+ | Long-context tool adherence | Fails | Fails | Fails | Fails | **Dynamic reinforcement** |
196
+
197
+ </details>
198
+
199
+ <details>
200
+ <summary>Comparison: Qwen 3.6 template</summary>
201
+
202
+ | Feature | Official | **This (v13)** |
203
+ |---------|----------|----------------|
204
+ | Tool arguments | Fails (`\|items`) | **Fixed (JSON native)** |
205
+ | `\|safe` removed | Fails | **Fixed** |
206
+ | `developer` role | Missing | **Added** |
207
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
208
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
209
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Immutable)** |
210
+ | Mid-conversation system | Crashes | **Fixed** |
211
+ | `</thinking>` hallucination | Fails | **Detected and handled (C++ safe)** |
212
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
213
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
214
+ | Tool token optimization | None | **JSON-native simplification** |
215
+ | Long-context tool adherence | Fails | **Dynamic reinforcement** |
216
+
217
+ </details>
218
+
219
+ ---
220
+
221
+ ## Authorship
222
+
223
+ | Role | Author |
224
+ |------|--------|
225
+ | Original models | Alibaba Cloud (Qwen team) |
226
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
227
+
228
+ ## License
229
+
230
+ Apache-2.0, inherited from Qwen.
archive/README-v14.md ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v14)
17
+
18
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
19
+ >
20
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
21
+ >
22
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
23
+ >
24
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
25
+
26
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
27
+
28
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
29
+
30
+ ---
31
+
32
+ ## Why you need this
33
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
34
+
35
+ Here are the critical issues this template fixes:
36
+
37
+ | Problem | Impact | Fix |
38
+ |---|---|---|
39
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility, natively dumping JSON schemas safely. |
40
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
41
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
42
+ | **4. Multi-turn Tool Amnesia Loops** | Pruning historical `<think>` blocks causes the model to lose its train of thought when retrying failed calls, getting stuck retrying identical invalid parameters. | **Smart Loop Preservation** conditionally preserves reasoning context during active tool errors to cure amnesia loops. |
43
+ | **5. Post-Tool Indecisive Overthinking** | Forced `<think>` block prefilling combined with narrow instructions causes the model to panic and debate internal prompt rules after fetching tool data. | Refactored instructions to define `<think>` as a dual-purpose space for planning **or synthesis**. |
44
+ | **6. Whitespace tag hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | C++ safe array-slicing isolates the reasoning block without corrupting user code snippets. |
45
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
46
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely using array slicing. |
47
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
48
+ | **10. MCP Tool parsing crashes** | Downstream coding agents crash because tool parameters contain unescaped newlines inside custom XML wrappers. | Restored 100% standard JSON formatted tool calls (`{"name": "...", "arguments": {...}}`) natively. |
49
+ | **11. Cache invalidation on llama.cpp** | Mutating the initial system prompt based on future user toggles breaks the prefix KV cache. | Replaced history mutation with structural bypass generation (`<think>\n\n</think>\n\n`), keeping the system prompt 100% immutable. |
50
+ | **12. Reasoning bypass hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
51
+ | **13. Jinja C++ crashes (UndefinedValue)** | Python negative indexing `[-1]` or implicit enum coercions crash on `minijinja`. | Replaced all brittle logic with native JSON iteration and safe Jinja strings. |
52
+ | **14. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
53
+
54
+ ---
55
+
56
+ ## Quick install
57
+
58
+ Choose your environment and update the template:
59
+
60
+ ### LM Studio
61
+ 1. Open your Qwen model in the right-side panel.
62
+ 2. Scroll down to **Prompt Template**.
63
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
64
+ 4. Click **Save**.
65
+
66
+ ### llama.cpp / koboldcpp
67
+ ```bash
68
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
69
+ ```
70
+
71
+ ### vLLM / TextGen
72
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
73
+
74
+ ### oMLX
75
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
76
+
77
+ ---
78
+
79
+ ## Which file do I use?
80
+
81
+ | Template File | Supported Models |
82
+ |------|-----------|
83
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
84
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
85
+
86
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
87
+
88
+ ---
89
+
90
+ ## The thinking toggle
91
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
92
+
93
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
94
+
95
+ **Fast answer, no reasoning:**
96
+ ```text
97
+ System: You are a coding assistant. <|think_off|>
98
+ User: What's 2+2?
99
+ ```
100
+
101
+ **Deep reasoning:**
102
+ ```text
103
+ System: You are a coding assistant. <|think_on|>
104
+ User: Implement a red-black tree in Rust.
105
+ ```
106
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
107
+
108
+ ---
109
+
110
+ ## Preserving past thoughts
111
+
112
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
113
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
114
+
115
+ ```json
116
+ {
117
+ "preserve_thinking": true
118
+ }
119
+ ```
120
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
121
+
122
+ ---
123
+
124
+ ## Pre-installed models
125
+
126
+ If you are using one of the following models, you already have an older version of this template installed.
127
+
128
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
129
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
130
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
131
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
132
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
133
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
134
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
135
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
136
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
137
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
138
+
139
+ ---
140
+
141
+ <details>
142
+ <summary>Technical Details of the Critical Fixes</summary>
143
+
144
+ ### 1. Smart Loop Preservation (Curing Multi-turn Tool Amnesia)
145
+ When a tool call fails parameter validation, the model uses its reasoning block to plan adjustments. By unconditionally deleting past `<think>` blocks, earlier template iterations induced multi-turn state amnesia, trapping the model in ungrounded loops retrying identical mistakes. This template scans subsequent tool responses for error markers (`'error'`, `'fail'`, `'exceeds'`, etc.) and dynamically preserves the relevant reasoning blocks precisely when correcting errors.
146
+
147
+ ### 2. Universal Synthesis Guidance (Curing Overthinking)
148
+ By prefilling `<think>\n`, earlier templates forced reasoning post-tool retrieval, but strict guidelines demanding reasoning *only before tool calls* caused internal logic conflicts. This template seamlessly widens the operational scope of `<think>` to cover planning **or synthesis**, completely stabilizing post-tool behavior.
149
+
150
+ ### 3. Tool calls on C++ engines
151
+ The official template iterates tool call arguments with `|items`:
152
+ `{%- for key, value in tool_call.arguments|items %}`
153
+
154
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses native JSON serialization to safely inject tools.
155
+
156
+ ### 4. Mid-conversation system messages crash
157
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
158
+
159
+ ### 5. Whitespace Tag Hallucination Isolation
160
+ Using global `.replace('</ think>', '</think>')` silently corrupts code blocks if the user queries about XML formatting. This template employs an entirely C++ safe array-slicing method (`content.split('<think>')`) to securely extract the reasoning content at strict boundaries without ever modifying user text.
161
+
162
+ ### 6. Auto-close unclosed thinking before tool calls
163
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
164
+
165
+ ### 7. KV Cache preservation (Immutable System Prompt)
166
+ Alteration of the *initial* system prompt's instructions completely drops the LLM KV prefix cache. This template isolates the system prompt entirely, preserving the cache, and relies strictly on generation bypass formatting (`<think>\n\n</think>\n\n`) to toggle thinking mid-conversation.
167
+ </details>
168
+
169
+ <details>
170
+ <summary>Comparison: Qwen 3.5 templates</summary>
171
+
172
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v14)** |
173
+ |---------|----------|-------------|------------|--------|----------------|
174
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed (JSON native)** |
175
+ | Tool Amnesia Prevention | None | None | None | None | **Smart Loop Preservation** |
176
+ | Post-Tool Overthinking | Broken | Broken | Broken | Broken | **Universal Synthesis** |
177
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
178
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
179
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
180
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
181
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
182
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
183
+ | Long-context tool adherence | Fails | Fails | Fails | Fails | **Dynamic reinforcement** |
184
+
185
+ </details>
186
+
187
+ <details>
188
+ <summary>Comparison: Qwen 3.6 template</summary>
189
+
190
+ | Feature | Official | **This (v14)** |
191
+ |---------|----------|----------------|
192
+ | Tool arguments | Fails (`\|items`) | **Fixed (JSON native)** |
193
+ | Tool Amnesia Prevention | None | **Smart Loop Preservation** |
194
+ | Post-Tool Overthinking | Spams/Stalls | **Universal Synthesis** |
195
+ | `developer` role | Missing | **Added** |
196
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
197
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
198
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Immutable)** |
199
+ | Mid-conversation system | Crashes | **Fixed** |
200
+ | `</thinking>` hallucination | Fails | **Detected and handled (C++ safe)** |
201
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
202
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
203
+ | Long-context tool adherence | Fails | **Dynamic reinforcement** |
204
+
205
+ </details>
206
+
207
+ ---
208
+
209
+ ## Authorship
210
+
211
+ | Role | Author |
212
+ |------|--------|
213
+ | Original models | Alibaba Cloud (Qwen team) |
214
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
215
+
216
+ ## License
217
+
218
+ Apache-2.0, inherited from Qwen.
archive/README-v15.md ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v15)
17
+
18
+ > **2026-05-13 Update (v15):** Three-part fix for agentic tool-loop failures. (1) **Two-tier error escalation:** replaced the brittle backwards-lookahead error detection with a fully forward-tracking `last_tool_failed` + `consecutive_failures` counter. On the first error the generation prompt is pre-seeded with a correction directive inside `<think>`; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) **Length-gated detection:** error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing `error`, `exception`, etc. in legitimate content. (3) **Static system prompt:** tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.
19
+ >
20
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
21
+ >
22
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
23
+ >
24
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
25
+ >
26
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
27
+
28
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
29
+
30
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
31
+
32
+ ---
33
+
34
+ ## Why you need this
35
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
36
+
37
+ Here are the critical issues this template fixes:
38
+
39
+ | Problem | Impact | Fix |
40
+ |---|---|---|
41
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility, natively dumping JSON schemas safely. |
42
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
43
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
44
+ | **4. Agentic retry stall & reasoning spiral** | Model correctly diagnoses a tool error in `<think>` but repeatedly emits the identical failing `<tool_call>`. At long context (60k+ tokens), the reasoning block degenerates into a 2000+ token repetition loop. | Two-tier escalation: (1) first error pre-seeds `<think>` with a correction directive; (2) on 2nd+ consecutive error, bypasses thinking entirely and injects an urgent out-of-band directive, making the degenerate loop physically impossible. |
45
+ | **5. Post-Tool Indecisive Overthinking** | Forced `<think>` block prefilling combined with narrow instructions causes the model to panic and debate internal prompt rules after fetching tool data. | Refactored instructions to define `<think>` as a dual-purpose space for planning **or synthesis**. |
46
+ | **6. Whitespace tag hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | C++ safe array-slicing isolates the reasoning block without corrupting user code snippets. |
47
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
48
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely using array slicing. |
49
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
50
+ | **10. MCP Tool parsing crashes** | Downstream coding agents crash because tool parameters contain unescaped newlines inside custom XML wrappers. | Restored 100% standard JSON formatted tool calls (`{"name": "...", "arguments": {...}}`) natively. |
51
+ | **11. Cache invalidation on llama.cpp** | Mutating the initial system prompt based on future user toggles or thinking state breaks the prefix KV cache. | System prompt tool instructions are now fully unconditional and static. Thinking state is controlled exclusively via the generation prompt bypass. |
52
+ | **12. Reasoning bypass hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
53
+ | **13. Jinja C++ crashes (UndefinedValue)** | Python negative indexing `[-1]` or implicit enum coercions crash on `minijinja`. | Replaced all brittle logic with native JSON iteration and safe Jinja strings. |
54
+ | **14. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
55
+
56
+ ---
57
+
58
+ ## Quick install
59
+
60
+ Choose your environment and update the template:
61
+
62
+ ### LM Studio
63
+ 1. Open your Qwen model in the right-side panel.
64
+ 2. Scroll down to **Prompt Template**.
65
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
66
+ 4. Click **Save**.
67
+
68
+ ### llama.cpp / koboldcpp
69
+ ```bash
70
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
71
+ ```
72
+
73
+ ### vLLM / TextGen
74
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
75
+
76
+ ### oMLX
77
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
78
+
79
+ ---
80
+
81
+ ## Which file do I use?
82
+
83
+ | Template File | Supported Models |
84
+ |------|-----------|
85
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
86
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
87
+
88
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
89
+
90
+ ---
91
+
92
+ ## The thinking toggle
93
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
94
+
95
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
96
+
97
+ **Fast answer, no reasoning:**
98
+ ```text
99
+ System: You are a coding assistant. <|think_off|>
100
+ User: What's 2+2?
101
+ ```
102
+
103
+ **Deep reasoning:**
104
+ ```text
105
+ System: You are a coding assistant. <|think_on|>
106
+ User: Implement a red-black tree in Rust.
107
+ ```
108
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
109
+
110
+ ---
111
+
112
+ ## Preserving past thoughts
113
+
114
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
115
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
116
+
117
+ ```json
118
+ {
119
+ "preserve_thinking": true
120
+ }
121
+ ```
122
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
123
+
124
+ ---
125
+
126
+ ## Pre-installed models
127
+
128
+ If you are using one of the following models, you already have an older version of this template installed.
129
+
130
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
131
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
132
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
133
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
134
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
135
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
136
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
137
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
138
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
139
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
140
+
141
+ ---
142
+
143
+ <details>
144
+ <summary>Technical Details of the Critical Fixes</summary>
145
+
146
+ ### 1. Two-Tier Agentic Error Escalation & Length-Gated Detection
147
+ When a tool call fails validation, the model's `<think>` block correctly diagnoses the problem. However, because the generation prompt was always identical (`<|im_start|>assistant\n<think>\n`), the model's attention was biased towards the cached token sequence for the previous (failing) tool call. At long context lengths (60k+ tokens), this compounds into a catastrophic **degenerate reasoning spiral** — the model loops inside `<think>` generating thousands of repetitive tokens without ever producing a corrected action.
148
+
149
+ A naive keyword-based error detector (`'error' in content`) also causes false positives when reading code files: JavaScript with `throw new Error(...)`, `catch(e)` blocks, or any file mentioning error-handling would incorrectly trigger the correction directive on a perfectly successful read, confusing the model into thinking its call failed.
150
+
151
+ v15 fixes this with two mechanisms:
152
+
153
+ **Detection:** Error signals are only read from **short** tool responses (`content | length < 500`). Framework error messages are always compact (30–300 chars). Any response large enough to contain file content is never flagged as an error, regardless of keywords present.
154
+
155
+ **Escalation:** A forward-tracked `consecutive_failures` counter drives a two-tier response:
156
+ - **Tier 1 (1st error):** Generation prompt prefix changes to `<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n`. Seeds reasoning at a different token position, breaking the cached attractor state.
157
+ - **Tier 2 (2nd+ consecutive errors):** Think block bypassed entirely (`<think>\n\n</think>\n\n`), preventing the degenerate spiral. An urgent out-of-band directive is injected into the output stream, forcing an immediate corrected tool call without intermediate reasoning.
158
+
159
+ The `consecutive_failures` counter resets to zero whenever a user message, assistant message, or successful (short, error-free) tool response is rendered.
160
+
161
+ ### 2. Static System Prompt (KV Cache Safety)
162
+ v14 contained a conditional inside the `tool_instructions` set block: `{%- if ns_flags.enable_thinking %}`. Because `ns_flags.enable_thinking` is evaluated at system prompt render time (before the message loop), any `<|think_off|>` in a later message would change the value of the flag on the next inference call, producing a different system prompt prefix. Inference engines detect the changed prefix and invalidate the entire KV cache.
163
+
164
+ v15 removes this conditional entirely. The `<think>` instruction is now always present in the system prompt. Thinking state is controlled exclusively via the generation prompt bypass (`<think>\n\n</think>\n\n`), which is outside the KV-cached prefix and has no cache impact.
165
+
166
+ ### 3. Universal Synthesis Guidance (Curing Overthinking)
167
+ By prefilling `<think>\n`, earlier templates forced reasoning post-tool retrieval, but strict guidelines demanding reasoning *only before tool calls* caused internal logic conflicts. This template seamlessly widens the operational scope of `<think>` to cover planning **or synthesis**, completely stabilizing post-tool behavior.
168
+
169
+ ### 4. Tool calls on C++ engines
170
+ The official template iterates tool call arguments with `|items`:
171
+ `{%- for key, value in tool_call.arguments|items %}`
172
+
173
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses native JSON serialization to safely inject tools.
174
+
175
+ ### 5. Mid-conversation system messages crash
176
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
177
+
178
+ ### 6. Whitespace Tag Hallucination Isolation
179
+ Using global `.replace('</ think>', '</think>')` silently corrupts code blocks if the user queries about XML formatting. This template employs an entirely C++ safe array-slicing method (`content.split('<think>')`) to securely extract the reasoning content at strict boundaries without ever modifying user text.
180
+
181
+ ### 7. Auto-close unclosed thinking before tool calls
182
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
183
+
184
+ ### 8. KV Cache preservation (Immutable System Prompt)
185
+ Alteration of the *initial* system prompt's instructions completely drops the LLM KV prefix cache. This template isolates the system prompt entirely, preserving the cache, and relies strictly on generation bypass formatting (`<think>\n\n</think>\n\n`) to toggle thinking mid-conversation.
186
+ </details>
187
+
188
+ <details>
189
+ <summary>Comparison: Qwen 3.5 templates</summary>
190
+
191
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v15)** |
192
+ |---------|----------|-------------|------------|--------|----------------|
193
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed (JSON native)** |
194
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | Stalls | Stalls | Stalls | **Two-tier escalation system** |
195
+ | Post-Tool Overthinking | Broken | Broken | Broken | Broken | **Universal Synthesis** |
196
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
197
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
198
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
199
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
200
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
201
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
202
+ | KV cache stability | Breaks | Breaks | Breaks | Breaks | **Fully immutable prefix** |
203
+
204
+ </details>
205
+
206
+ <details>
207
+ <summary>Comparison: Qwen 3.6 template</summary>
208
+
209
+ | Feature | Official | **This (v15)** |
210
+ |---------|----------|----------------|
211
+ | Tool arguments | Fails (`\|items`) | **Fixed (JSON native)** |
212
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | **Two-tier escalation system** |
213
+ | Post-Tool Overthinking | Spams/Stalls | **Universal Synthesis** |
214
+ | `developer` role | Missing | **Added** |
215
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
216
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
217
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Immutable)** |
218
+ | Mid-conversation system | Crashes | **Fixed** |
219
+ | `</thinking>` hallucination | Fails | **Detected and handled (C++ safe)** |
220
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
221
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
222
+ | Long-context tool adherence | Fails | **Dynamic reinforcement** |
223
+
224
+ </details>
225
+
226
+ ---
227
+
228
+ ## Authorship
229
+
230
+ | Role | Author |
231
+ |------|--------|
232
+ | Original models | Alibaba Cloud (Qwen team) |
233
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
234
+
235
+ ## License
236
+
237
+ Apache-2.0, inherited from Qwen.
archive/README-v16.md ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - vllm
13
+ - tool-calling
14
+ - thinking
15
+ ---
16
+
17
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v16)
18
+
19
+ > **2026-05-14 Update (v16):** Four-part fix addressing community-reported regressions. (1) **Native XML tool format:** reverted from JSON back to the native `<function=name>` / `<parameter=x>` format the model was trained on, restoring full compatibility with vLLM's `qwen3_coder` parser and all inference engines that implement the Qwen tool protocol. (2) **`--reasoning off` respected in error paths:** when thinking is disabled (`enable_thinking=false` / `--reasoning off`), the error escalation directives are now injected as plain text without opening any `<think>` block, preventing degenerate prompts in no-reasoning sessions. (3) **Smarter false-positive detection:** short shell command results (starting with `$ `) and search results with timing footers (`Took X.Xs`) are now correctly excluded from error detection, preventing tool-retry loops when commands succeed but their output happens to contain the word `error`. (4) **`consecutive_failures` counter no longer resets on assistant messages**, allowing Tier 2 escalation to actually fire across multi-turn tool retry chains.
20
+ >
21
+ > **2026-05-13 Update (v15):** Three-part fix for agentic tool-loop failures. (1) **Two-tier error escalation:** replaced the brittle backwards-lookahead error detection with a fully forward-tracking `last_tool_failed` + `consecutive_failures` counter. On the first error the generation prompt is pre-seeded with a correction directive inside `<think>`; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) **Length-gated detection:** error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing `error`, `exception`, etc. in legitimate content. (3) **Static system prompt:** tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.
22
+ >
23
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
24
+ >
25
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
26
+ >
27
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
28
+ >
29
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
30
+
31
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
32
+
33
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
34
+
35
+ ---
36
+
37
+ ## Why you need this
38
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
39
+
40
+ Here are the critical issues this template fixes:
41
+
42
+ | Problem | Impact | Fix |
43
+ |---|---|---|
44
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility. |
45
+ | **2. Wrong tool call format** | vLLM `qwen3_coder` parser and other Qwen-native parsers expect `<function=name>` XML format. JSON format breaks them. | Restored native XML `<function=name>` / `<parameter=x>` format. |
46
+ | **3. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
47
+ | **4. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
48
+ | **5. Agentic retry stall & reasoning spiral** | Model correctly diagnoses a tool error in `<think>` but repeatedly emits the identical failing `<tool_call>`. At long context (60k+ tokens), the reasoning block degenerates into a 2000+ token repetition loop. | Two-tier escalation: (1) first error pre-seeds `<think>` with a correction directive; (2) on 2nd+ consecutive error, bypasses thinking entirely and injects an urgent out-of-band directive. |
49
+ | **6. `--reasoning off` ignored on tool errors** | When thinking is disabled, tool error escalation still opened a `<think>` block, corrupting the generation prompt. | Error escalation branches now fully respect `enable_thinking=false`. |
50
+ | **7. False-positive error detection** | Short shell command results (`$ grep …`) and search outputs (`Took 0.1s`) containing `error` in code identifiers trigger incorrect retry loops. | Added guards: responses starting with `$ ` or containing `Took ` footer are never flagged as errors. |
51
+ | **8. Post-Tool Indecisive Overthinking** | Forced `<think>` block prefilling combined with narrow instructions causes the model to panic and debate internal prompt rules after fetching tool data. | Refactored instructions to define `<think>` as a dual-purpose space for planning **or synthesis**. |
52
+ | **9. Whitespace tag hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | C++ safe array-slicing isolates the reasoning block without corrupting user code snippets. |
53
+ | **10. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Removed backwards history scanning entirely. |
54
+ | **11. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely using array slicing. |
55
+ | **12. Cache invalidation on llama.cpp** | Mutating the initial system prompt based on future user toggles or thinking state breaks the prefix KV cache. | System prompt tool instructions are now fully unconditional and static. |
56
+ | **13. Reasoning bypass hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
57
+ | **14. Jinja C++ crashes** | Python-specific filters (`|items`, `map('string')`, `| first` on strings) crash on `minijinja`. | All filters replaced with universally compatible equivalents. |
58
+ | **15. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
59
+
60
+ ---
61
+
62
+ ## Quick install
63
+
64
+ Choose your environment and update the template:
65
+
66
+ ### LM Studio
67
+ 1. Open your Qwen model in the right-side panel.
68
+ 2. Scroll down to **Prompt Template**.
69
+ 3. Replace the template with the contents of `qwen3.5/chat_template-v16.jinja` or `qwen3.6/chat_template-v16.jinja`.
70
+ 4. Click **Save**.
71
+
72
+ ### llama.cpp / koboldcpp
73
+ ```bash
74
+ --jinja --chat-template-file qwen3.6/chat_template-v16.jinja
75
+ ```
76
+
77
+ ### vLLM
78
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents. Use the `qwen3_coder` tool parser:
79
+ ```bash
80
+ --tool-call-parser qwen3_coder
81
+ ```
82
+
83
+ ### oMLX
84
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
85
+
86
+ ---
87
+
88
+ ## Which file do I use?
89
+
90
+ | Template File | Supported Models |
91
+ |------|-----------|
92
+ | [`qwen3.5/chat_template-v16.jinja`](qwen3.5/chat_template-v16.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
93
+ | [`qwen3.6/chat_template-v16.jinja`](qwen3.6/chat_template-v16.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
94
+
95
+ One-line versions (`*_oneline.txt`) are pre-minified for engines that require a single-line template string.
96
+
97
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
98
+
99
+ ---
100
+
101
+ ## The thinking toggle
102
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
103
+
104
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
105
+
106
+ **Fast answer, no reasoning:**
107
+ ```text
108
+ System: You are a coding assistant. <|think_off|>
109
+ User: What's 2+2?
110
+ ```
111
+
112
+ **Deep reasoning:**
113
+ ```text
114
+ System: You are a coding assistant. <|think_on|>
115
+ User: Implement a red-black tree in Rust.
116
+ ```
117
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
118
+
119
+ ---
120
+
121
+ ## Preserving past thoughts
122
+
123
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
124
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
125
+
126
+ ```json
127
+ {
128
+ "preserve_thinking": true
129
+ }
130
+ ```
131
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
132
+
133
+ ---
134
+
135
+ ## Pre-installed models
136
+
137
+ If you are using one of the following models, you already have an older version of this template installed.
138
+
139
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
140
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
141
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
142
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
143
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
144
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
145
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
146
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
147
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
148
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
149
+
150
+ ---
151
+
152
+ <details>
153
+ <summary>Technical Details of the Critical Fixes</summary>
154
+
155
+ ### 1. Native XML Tool Call Format (v16)
156
+ The model was trained with the XML-based tool call format used by Qwen3-Coder:
157
+ ```
158
+ <tool_call>
159
+ <function=tool_name>
160
+ <parameter=param_name>
161
+ value
162
+ </parameter>
163
+ </function>
164
+ </tool_call>
165
+ ```
166
+
167
+ v13 changed this to JSON (`{"name": "tool_name", "arguments": {...}}`) to fix MCP parser crashes. However, this broke vLLM's native `qwen3_coder` tool parser and all inference engines that implement the Qwen protocol natively. v16 restores the original XML format, making it compatible with all parsers again while retaining the JSON output for the tool schema presentation (which was always separate).
168
+
169
+ The key insight: the v12 XML renderer already used `for args_name in tool_call.arguments` (key iteration), which **is** supported by `minijinja`. The `|items` crash never required a JSON fallback — it only required avoiding that specific filter.
170
+
171
+ ### 2. Two-Tier Agentic Error Escalation (v15, refined in v16)
172
+ When a tool call fails validation, the model's `<think>` block correctly diagnoses the problem. However, because the generation prompt was always identical, the model's attention was biased towards the cached token sequence for the previous (failing) tool call. At long context lengths (60k+ tokens), this compounds into a catastrophic **degenerate reasoning spiral**.
173
+
174
+ v15 introduced a two-tier escalation system driven by a forward-tracked `consecutive_failures` counter:
175
+ - **Tier 1 (1st error):** Generation prompt prefix changes to seed reasoning at a different token position, breaking the cached attractor state.
176
+ - **Tier 2 (2nd+ consecutive errors):** Think block bypassed entirely, preventing the degenerate spiral. An urgent out-of-band directive forces an immediate corrected action.
177
+
178
+ v16 fixes a bug where `consecutive_failures` was incorrectly reset on every **assistant** message, preventing Tier 2 from ever firing across a multi-turn retry chain. Now only **user messages** and **successful tool responses** reset the counter.
179
+
180
+ ### 3. `enable_thinking=false` in Error Paths (v16)
181
+ The original error escalation always emitted `<think>\n...` regardless of whether thinking was enabled. When users set `--reasoning off` in llama.cpp (which passes `enable_thinking=false`), the Tier 1 hint still opened a `<think>` block, creating a degenerate prompt the model couldn't resolve while in no-reasoning mode.
182
+
183
+ v16 wraps all `<think>` emissions in the error path with `{%- if ns_flags.enable_thinking is not false %}`. When thinking is off:
184
+ - Tier 1 injects the correction directive as plain text (no `<think>` wrapper)
185
+ - Tier 2 skips the `<think>\n\n</think>\n\n` bypass prefix entirely
186
+
187
+ ### 4. Smart False-Positive Detection (v15/v16)
188
+ A naive keyword detector (`'error' in content`) triggers on perfectly successful tool results that happen to contain error-related identifiers in code:
189
+ - `$ grep -n "error_message" file.go` → contains `error`
190
+ - Search results returning `661: "error_message": ""` → contains `error`
191
+
192
+ v15 added a length gate (`content | length < 500`). v16 adds two more guards:
193
+ - **`'$ ' not in content`**: Shell command echoes always start with `$ ` (dollar-space). This single check correctly identifies and excludes all shell tool output.
194
+ - **`'took ' not in content_lower`**: Search tools like `grep`, `ripgrep`, and CLI tools append `Took X.Xs` timing footers. This excludes them regardless of content.
195
+
196
+ Together these three guards produce zero false positives on all observed real-world tool output patterns.
197
+
198
+ ### 5. Static System Prompt (KV Cache Safety, v15)
199
+ Tool instructions are fully unconditional and static, permanently eliminating the KV cache invalidation vector introduced in v14. Thinking state is controlled exclusively via the generation prompt bypass, which is outside the KV-cached prefix.
200
+
201
+ ### 6. minijinja Compatibility Constraints
202
+ Three Python-only Jinja2 filters crash on `minijinja` (the C++ runtime used by llama.cpp, LM Studio, and MLX):
203
+
204
+ | Filter | Python Jinja2 | minijinja | Safe alternative |
205
+ |---|---|---|---|
206
+ | `\| items` | ✅ | ❌ | `for key in mapping` + `mapping[key]` |
207
+ | `map('string')` | ✅ | ❌ | `join('|')` directly |
208
+ | `\| first` on strings | ✅ | ❌ | `'$ ' in content` substring check |
209
+
210
+ All three are avoided in v16. The `| first` filter works for arrays in minijinja but not for strings; the replacement uses a simple `in` operator substring check which is universally supported.
211
+
212
+ </details>
213
+
214
+ <details>
215
+ <summary>Comparison: Qwen 3.5 templates</summary>
216
+
217
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This (v16)** |
218
+ |---------|----------|-------------|------------|--------|----------------|
219
+ | Tool call format | XML (native) | JSON | JSON | JSON | **XML (native, qwen3_coder compatible)** |
220
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed (C++ safe XML)** |
221
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | Stalls | Stalls | Stalls | **Two-tier escalation system** |
222
+ | Post-Tool Overthinking | Broken | Broken | Broken | Broken | **Universal Synthesis** |
223
+ | `--reasoning off` on tool errors | N/A | N/A | N/A | N/A | **Fully respected** |
224
+ | Shell/search false positives | N/A | N/A | N/A | N/A | **Guarded** |
225
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
226
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
227
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Pruned dynamically** |
228
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
229
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
230
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
231
+ | KV cache stability | Breaks | Breaks | Breaks | Breaks | **Fully immutable prefix** |
232
+
233
+ </details>
234
+
235
+ <details>
236
+ <summary>Comparison: Qwen 3.6 template</summary>
237
+
238
+ | Feature | Official | **This (v16)** |
239
+ |---------|----------|----------------|
240
+ | Tool call format | XML (native) | **XML (native, qwen3_coder compatible)** |
241
+ | Tool arguments | Fails (`\|items`) | **Fixed (C++ safe XML)** |
242
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | **Two-tier escalation system** |
243
+ | Post-Tool Overthinking | Spams/Stalls | **Universal Synthesis** |
244
+ | `--reasoning off` on tool errors | N/A | **Fully respected** |
245
+ | Shell/search false positives | N/A | **Guarded** |
246
+ | `developer` role | Missing | **Added** |
247
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
248
+ | Empty think in history | Spams empty blocks | **Pruned dynamically** |
249
+ | KV prefix caching | Breaks on dynamic history | **100% stable (Immutable)** |
250
+ | Mid-conversation system | Crashes | **Fixed** |
251
+ | `</thinking>` hallucination | Fails | **Detected and handled (C++ safe)** |
252
+ | Auto-close thinking before tool | Not handled | **Engine-safe auto-inject** |
253
+ | vLLM stop parsing | Crashes if thinking disabled | **Fixed natively** |
254
+
255
+ </details>
256
+
257
+ ---
258
+
259
+ ## Running the test suite
260
+
261
+ ```bash
262
+ python3 scripts/test_v15.py # test both variants
263
+ python3 scripts/test_v15.py qwen3.6 # test one variant
264
+ ```
265
+
266
+ Tests cover: XML tool format, tool instructions, thinking bypass, `<|think_off|>` / `<|think_on|>`, Tier 1 & 2 escalation, length-gated detection, shell/search false positives, `--reasoning off` + errors, counter reset, historical think stripping, `preserve_thinking`, developer role, mid-conversation system, tool response wrapping, and string argument passthrough.
267
+
268
+ ---
269
+
270
+ ## Authorship
271
+
272
+ | Role | Author |
273
+ |------|--------|
274
+ | Original models | Alibaba Cloud (Qwen team) |
275
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
276
+
277
+ ## License
278
+
279
+ Apache-2.0, inherited from Qwen.
archive/README-v17.md ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - vllm
13
+ - tool-calling
14
+ - thinking
15
+ ---
16
+
17
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v17)
18
+
19
+ <details open>
20
+ <summary><b>Update History & Changelog (v17)</b></summary>
21
+
22
+ > **2026-05-15 Update (v17):** Major architecture overhaul resolving edge cases in agentic tooling and KV Cache. (1) **Unified Template:** Consolidated Qwen 3.5 and Qwen 3.6 into a single `chat_template.jinja` file that handles all variants seamlessly. (2) **Fixed "Mutually Exclusive" Stopping Bug:** Changed the history-pruning logic from wiping the entire turn to safely array-slicing out just the raw tool tags (`content.split('<tool_call>')[0]`). This preserves the conversational text in the history, which cures the bug where the model would artificially abort its turn (output `<|im_end|>`) when it wanted to talk and use a tool simultaneously. (3) **100% KV Cache Hit Rate Restoration:** Fully normalized internal whitespace logic (`\n\n` -> `\n`) around think blocks and tool calls to exactly match the model's native autoregressive generation spacing. This perfectly synchronizes the template's rendered history with the cached generated tokens, completely eliminating the severe cache invalidation and full-prompt re-processing issues present in v16.
23
+
24
+ </details>
25
+
26
+ <details>
27
+ <summary><b>Update History & Changelog (v11-v16)</b></summary>
28
+
29
+ > **2026-05-14 Update (v16):** Four-part fix addressing community-reported regressions. (1) **Native XML tool format:** reverted from JSON back to the native `<function=name>` / `<parameter=x>` format the model was trained on, restoring full compatibility with vLLM's `qwen3_coder` parser and all inference engines that implement the Qwen tool protocol. (2) **`--reasoning off` respected in error paths:** when thinking is disabled (`enable_thinking=false` / `--reasoning off`), the error escalation directives are now injected as plain text without opening any `<think>` block, preventing degenerate prompts in no-reasoning sessions. (3) **Smarter false-positive detection:** short shell command results (starting with `$ `) and search results with timing footers (`Took X.Xs`) are now correctly excluded from error detection, preventing tool-retry loops when commands succeed but their output happens to contain the word `error`. (4) **`consecutive_failures` counter no longer resets on assistant messages**, allowing Tier 2 escalation to actually fire across multi-turn tool retry chains.
30
+ >
31
+ > **2026-05-13 Update (v15):** Three-part fix for agentic tool-loop failures. (1) **Two-tier error escalation:** replaced the brittle backwards-lookahead error detection with a fully forward-tracking `last_tool_failed` + `consecutive_failures` counter. On the first error the generation prompt is pre-seeded with a correction directive inside `<think>`; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) **Length-gated detection:** error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing `error`, `exception`, etc. in legitimate content. (3) **Static system prompt:** tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.
32
+ >
33
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
34
+ >
35
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
36
+ >
37
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
38
+ >
39
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
40
+
41
+ </details>
42
+
43
+ This is a drop-in Jinja template that fixes rendering errors, KV cache invalidation, token waste, and missing features in the official Qwen chat templates.
44
+
45
+ It is tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
46
+
47
+ ---
48
+
49
+ ## Why you need this
50
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
51
+
52
+ Here are the critical issues this template fixes:
53
+
54
+ | Category | Problem | Impact | Fix |
55
+ |---|---|---|---|
56
+ | **Agentic Loop** | **Premature Stalls (Stopping Bug)** | Model aborts its turn (`<\|im_end\|>`) when trying to combine conversation and a tool call. | Safely prunes history to preserve conversational text without duplicating tool calls. (v17) |
57
+ | **Agentic Loop** | **Retry Stall & Reasoning Spiral** | Model correctly diagnoses a tool error but repeatedly emits the identical failing `<tool_call>`. | Two-tier escalation: seeds `<think>` with correction directive; injects urgent out-of-band directive. |
58
+ | **Agentic Loop** | **Post-Tool Overthinking** | Forced `<think>` block prefilling causes model to panic and debate internal rules after fetching data. | Broadened instructions to define `<think>` as a dual-purpose space for planning *or synthesis*. |
59
+ | **Agentic Loop** | **False-Positive Error Detection** | Short shell commands (`$ grep`) or search outputs containing the word `error` trigger retry loops. | Strict guards exclude shell echoes and timing footers from error detection. |
60
+ | **Performance** | **KV Cache Invalidation** | History pruning and whitespace mismatch invalidates KV cache, causing full prompt re-processing every turn. | Strict `\n` whitespace normalization mirrors autoregressive outputs for a 100% KV Cache hit rate. (v17) |
61
+ | **Performance** | **Empty Thinking Blocks Spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
62
+ | **Compatibility** | **Tool Calls Fail on C++ Engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). | Rewritten for strict C++ engine compatibility using natively supported key iteration. |
63
+ | **Compatibility** | **Wrong Tool Call Format** | Qwen-native parsers (like vLLM's `qwen3_coder`) expect XML `<function=name>`. JSON format breaks them. | Restored native XML format while keeping C++ safety. |
64
+ | **Compatibility** | **Jinja C++ Crashes** | Python-specific filters (`map`, `first` on strings) crash on `minijinja`. | All filters replaced with universally compatible equivalents. |
65
+ | **Stability** | **Mid-Conversation System Crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere in the history. |
66
+ | **Stability** | **No-User-Query Crash** | `raise_exception` crashes agentic loops or system-only contexts. | Removed backwards history scanning entirely. |
67
+ | **Stability** | **Unclosed Thinking Before Tool** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely. |
68
+ | **Edge Cases** | **`developer` Role Rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
69
+ | **Edge Cases** | **`--reasoning off` Ignored** | When thinking is disabled, tool error escalation still opened a `<think>` block, corrupting the prompt. | Error escalation branches now fully respect `enable_thinking=false`. |
70
+ | **Edge Cases** | **Reasoning Bypass Hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
71
+ | **Edge Cases** | **Whitespace Tag Hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | C++ safe array-slicing isolates the reasoning block without corrupting user code snippets. |
72
+
73
+ ---
74
+
75
+ ## Quick install
76
+
77
+ Choose your environment and update the template:
78
+
79
+ ### LM Studio
80
+ 1. Open your Qwen model in the right-side panel.
81
+ 2. Scroll down to **Prompt Template**.
82
+ 3. Replace the template with the contents of `chat_template.jinja`.
83
+ 4. Click **Save**.
84
+
85
+ ### llama.cpp / koboldcpp
86
+ ```bash
87
+ --jinja --chat-template-file chat_template.jinja
88
+ ```
89
+
90
+ ### vLLM
91
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents. Use the `qwen3_coder` tool parser:
92
+ ```bash
93
+ --tool-call-parser qwen3_coder
94
+ ```
95
+
96
+ ### oMLX
97
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
98
+
99
+ ---
100
+
101
+ ## Which file do I use?
102
+
103
+ Both Qwen 3.5 and Qwen 3.6 variants (including 35B, 32B, 27B, and 14B parameters) have been consolidated. You only need the single `chat_template.jinja` file at the root of the repository.
104
+
105
+ One-line versions (`chat_template_oneline.txt`) are pre-minified for engines that require a single-line template string.
106
+
107
+ ---
108
+
109
+ ## The thinking toggle
110
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
111
+
112
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
113
+
114
+ **Fast answer, no reasoning:**
115
+ ```text
116
+ System: You are a coding assistant. <|think_off|>
117
+ User: What's 2+2?
118
+ ```
119
+
120
+ **Deep reasoning:**
121
+ ```text
122
+ System: You are a coding assistant. <|think_on|>
123
+ User: Implement a red-black tree in Rust.
124
+ ```
125
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
126
+
127
+ ---
128
+
129
+ ## Preserving past thoughts
130
+
131
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
132
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
133
+
134
+ ```json
135
+ {
136
+ "preserve_thinking": true
137
+ }
138
+ ```
139
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
140
+
141
+ ---
142
+
143
+ ## Pre-installed models
144
+
145
+ If you are using one of the following models, you already have an older version of this template installed.
146
+
147
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
148
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
149
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
150
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
151
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
152
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
153
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
154
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
155
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
156
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
157
+
158
+ ---
159
+
160
+ <details>
161
+ <summary>Technical Details of the Critical Fixes</summary>
162
+
163
+ ### 1. KV Cache Safety & Autoregressive Whitespace Normalization (v17)
164
+ Llama.cpp and vLLM utilize prefix KV caching to speed up generation. Previous template versions wiped conversational text from tool-call turns and injected `\n\n` before tool boundaries. These manipulations created a mismatch between the strings generated autoregressively by the model and the history rendered by the template, forcing a complete cache invalidation and full prompt re-processing on every turn. v17 normalizes all whitespace injections to strict single `\n` boundaries and safely prunes tool tags without dropping conversation, achieving a 100% KV cache hit rate in multi-turn loops.
165
+
166
+ ### 2. "Mutually Exclusive" Stopping Bug Resolution (v17)
167
+ By preserving conversational text alongside tool calls in the history (rather than aggressively wiping it), the model unlearns the artificial limitation that conversing and using a tool are mutually exclusive. It no longer aborts its turn with an early `<|im_end|>` when explaining its tool actions.
168
+
169
+ ### 3. Native XML Tool Call Format (v16)
170
+ The model was trained with the XML-based tool call format used by Qwen3-Coder:
171
+ ```xml
172
+ <tool_call>
173
+ <function=tool_name>
174
+ <parameter=param_name>
175
+ value
176
+ </parameter>
177
+ </function>
178
+ </tool_call>
179
+ ```
180
+ v16 restored this format natively, making it compatible with all parsers while bypassing the `|items` crash by using C++ safe key iteration (`for args_name in tool_call.arguments`).
181
+
182
+ ### 4. Two-Tier Agentic Error Escalation (v15)
183
+ When a tool call fails validation repeatedly, the model can enter a degenerate reasoning spiral. v15 leverages a two-tier escalation system driven by a forward-tracked `consecutive_failures` counter:
184
+ - **Tier 1 (1st error):** Generation prompt prefix changes to seed reasoning at a different token position, breaking the cached attractor state.
185
+ - **Tier 2 (2nd+ consecutive errors):** Think block bypassed entirely. An urgent out-of-band directive forces an immediate corrected action wrapped safely within the user `tool_response` block.
186
+
187
+ ### 5. Universal Synthesis (v14)
188
+ Forced `<think>` block prefilling combined with narrow system instructions causes the model to panic and debate its own internal rules after fetching tool data. v14 broadens the system instruction scope to define `<think>` as a dual-purpose space for planning **or synthesis**, completely eliminating indecisiveness post-tool retrieval.
189
+
190
+ ### 6. `enable_thinking=false` in Error Paths (v16)
191
+ When users set `--reasoning off` in llama.cpp, error escalation directives are now injected as plain text (no `<think>` wrapper) to prevent creating degenerate prompts the model couldn't resolve in no-reasoning mode.
192
+
193
+ ### 7. Smart False-Positive Detection (v15/v16)
194
+ Added strict guards: responses starting with `$ ` (shell echoes) or containing `Took X.Xs` footers (search tools) are excluded from error detection, preventing successful terminal executions from triggering false-positive retry loops when their text contains "error".
195
+
196
+ ### 8. minijinja Compatibility Constraints
197
+ Three Python-only Jinja2 filters crash on `minijinja` (the C++ runtime used by llama.cpp, LM Studio, and MLX). They have been completely removed and replaced with universally compatible equivalents:
198
+ - `\| items` -> `for key in mapping`
199
+ - `map('string')` -> `join('|')`
200
+ - `\| first` -> `'$ ' in content`
201
+
202
+ </details>
203
+
204
+ <details>
205
+ <summary>Comparison Matrix: Official vs Fixed vs Community</summary>
206
+
207
+ | Feature | Official Qwen Templates | LuffyTheFox | mod-ellary | Pneuny | **This Fixed Template (v17)** |
208
+ |---------|----------|-------------|------------|--------|----------------|
209
+ | Tool call format | XML (native) | JSON | JSON | JSON | **XML (native, qwen3_coder compatible)** |
210
+ | Tool arguments | Fails (`\|items`) | Fixed | Missing | Fixed | **Fixed (C++ safe XML)** |
211
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | Stalls | Stalls | Stalls | **Two-tier escalation system** |
212
+ | Post-Tool Overthinking | Spams/Stalls | Broken | Broken | Broken | **Universal Synthesis** |
213
+ | Premature Stalls (Stopping Bug) | Stalls | Stalls | Stalls | Stalls | **Fixed via conversation preservation (v17)** |
214
+ | `--reasoning off` on tool errors | N/A | N/A | N/A | N/A | **Fully respected** |
215
+ | Shell/search false positives | N/A | N/A | N/A | N/A | **Guarded** |
216
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
217
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
218
+ | Empty think in history | Spams empty blocks | Broken | Tags omitted | Broken | **Pruned dynamically** |
219
+ | KV prefix caching | Breaks on dynamic history | Breaks | Breaks | Breaks | **100% stable (Immutable \n spacing) (v17)** |
220
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
221
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
222
+ | `</thinking>` hallucination | Fails | N/A | N/A | N/A | **Detected and handled (C++ safe)** |
223
+ | Auto-close thinking before tool | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
224
+
225
+ </details>
226
+
227
+ ---
228
+
229
+ ## Running the test suite
230
+
231
+ ```bash
232
+ python3 scripts/test_v17.py
233
+ ```
234
+
235
+ Tests cover: XML tool format, tool instructions, thinking bypass, `<|think_off|>` / `<|think_on|>`, Tier 1 & 2 escalation, length-gated detection, shell/search false positives, `--reasoning off` + errors, counter reset, historical think stripping, `preserve_thinking`, developer role, mid-conversation system, tool response wrapping, and string argument passthrough.
236
+
237
+ ---
238
+
239
+ ## Authorship
240
+
241
+ | Role | Author |
242
+ |------|--------|
243
+ | Original models | Alibaba Cloud (Qwen team) |
244
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
245
+
246
+ ## License
247
+
248
+ Apache-2.0, inherited from Qwen.
archive/README-v18.md ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - vllm
13
+ - tool-calling
14
+ - thinking
15
+ ---
16
+
17
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v18)
18
+
19
+ <details open>
20
+ <summary><b>Update History & Changelog (v18)</b></summary>
21
+
22
+ > **2026-05-16 Update (v18): Stability & Precision Patch.** (1) **Bulletproof False-Positive Detection:** Shifted agentic error detection from broad substring matching to strict structural formats (e.g., `"error":`, `Exception:`, `Traceback`), completely curing false-positive retry loops when successful JSON returns simply contain the word "error" or "fail". (2) **Legacy Engine Compatibility:** Replaced `loop.previtem` with explicit array indexing, fixing AST crashes on older `llama.cpp` and `minijinja` builds that do not track loop state items. (3) **True Whitespace Normalization:** Fixed a bug where reasoning bypasses and hallucinated tag recovery stacked hidden multi-newlines (`\n\n\n`), strictly fulfilling the 100% KV Cache hit rate claim for all edge cases. (4) **Code Cleanup:** Removed dead conditional branches during XML tool parsing.
23
+
24
+
25
+ </details>
26
+
27
+ <details>
28
+ <summary><b>Update History & Changelog (v11-v17)</b></summary>
29
+
30
+ > **2026-05-15 Update (v17):** Major architecture overhaul resolving edge cases in agentic tooling and KV Cache. (1) **Unified Template:** Consolidated Qwen 3.5 and Qwen 3.6 into a single `chat_template.jinja` file that handles all variants seamlessly. (2) **Fixed "Mutually Exclusive" Stopping Bug:** Changed the history-pruning logic from wiping the entire turn to safely array-slicing out just the raw tool tags (`content.split('<tool_call>')[0]`). This preserves the conversational text in the history, which cures the bug where the model would artificially abort its turn (output `<|im_end|>`) when it wanted to talk and use a tool simultaneously. (3) **100% KV Cache Hit Rate Restoration:** Fully normalized internal whitespace logic (`\n\n` -> `\n`) around think blocks and tool calls to exactly match the model's native autoregressive generation spacing. This perfectly synchronizes the template's rendered history with the cached generated tokens, completely eliminating the severe cache invalidation and full-prompt re-processing issues present in v16.
31
+ >
32
+ > **2026-05-14 Update (v16):** Four-part fix addressing community-reported regressions. (1) **Native XML tool format:** reverted from JSON back to the native `<function=name>` / `<parameter=x>` format the model was trained on, restoring full compatibility with vLLM's `qwen3_coder` parser and all inference engines that implement the Qwen tool protocol. (2) **`--reasoning off` respected in error paths:** when thinking is disabled (`enable_thinking=false` / `--reasoning off`), the error escalation directives are now injected as plain text without opening any `<think>` block, preventing degenerate prompts in no-reasoning sessions. (3) **Smarter false-positive detection:** short shell command results (starting with `$ `) and search results with timing footers (`Took X.Xs`) are now correctly excluded from error detection, preventing tool-retry loops when commands succeed but their output happens to contain the word `error`. (4) **`consecutive_failures` counter no longer resets on assistant messages**, allowing Tier 2 escalation to actually fire across multi-turn tool retry chains.
33
+ >
34
+ > **2026-05-13 Update (v15):** Three-part fix for agentic tool-loop failures. (1) **Two-tier error escalation:** replaced the brittle backwards-lookahead error detection with a fully forward-tracking `last_tool_failed` + `consecutive_failures` counter. On the first error the generation prompt is pre-seeded with a correction directive inside `<think>`; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) **Length-gated detection:** error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing `error`, `exception`, etc. in legitimate content. (3) **Static system prompt:** tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.
35
+ >
36
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
37
+ >
38
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
39
+ >
40
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
41
+ >
42
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
43
+
44
+ </details>
45
+
46
+ This is a drop-in Jinja template that fixes rendering errors, KV cache invalidation, token waste, and missing features in the official Qwen chat templates.
47
+
48
+ It is tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
49
+
50
+ ---
51
+
52
+ ## Why you need this
53
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
54
+
55
+ Here are the critical issues this template fixes:
56
+
57
+ | Category | Problem | Impact | Fix |
58
+ |---|---|---|---|
59
+ | **Agentic Loop** | **Premature Stalls (Stopping Bug)** | Model aborts its turn (`<\|im_end\|>`) when trying to combine conversation and a tool call. | Safely prunes history to preserve conversational text without duplicating tool calls. (v17) |
60
+ | **Agentic Loop** | **Retry Stall & Reasoning Spiral** | Model correctly diagnoses a tool error but repeatedly emits the identical failing `<tool_call>`. | Two-tier escalation: seeds `<think>` with correction directive; injects urgent out-of-band directive. |
61
+ | **Agentic Loop** | **Post-Tool Overthinking** | Forced `<think>` block prefilling causes model to panic and debate internal rules after fetching data. | Broadened instructions to define `<think>` as a dual-purpose space for planning *or synthesis*. |
62
+ | **Agentic Loop** | **False-Positive Error Detection** | Short shell commands or API/JSON returns containing the word `error` trigger false retry loops. | Strict structural guards look for exact system failures (`"error":`, `Traceback`, etc.) instead of broad words. |
63
+ | **Performance** | **KV Cache Invalidation** | History pruning and whitespace mismatch invalidates KV cache, causing full prompt re-processing every turn. | Strict `\n` whitespace normalization mirrors autoregressive outputs for a 100% KV Cache hit rate. (v17) |
64
+ | **Performance** | **Empty Thinking Blocks Spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Strictly skips empty blocks unconditionally. |
65
+ | **Compatibility** | **Legacy Engine Crashes** | Older C++ parsing engines crash when evaluating `loop.previtem`. | Uses strict chronological array indexing (`messages[loop.index0 - 1]`) universally supported by all Jinja iterations. |
66
+ | **Compatibility** | **Tool Calls Fail on C++ Engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). | Rewritten for strict C++ engine compatibility using natively supported key iteration. |
67
+ | **Compatibility** | **Wrong Tool Call Format** | Qwen-native parsers (like vLLM's `qwen3_coder`) expect XML `<function=name>`. JSON format breaks them. | Restored native XML format while keeping C++ safety. |
68
+ | **Compatibility** | **Jinja C++ Crashes** | Python-specific filters (`map`, `first` on strings) crash on `minijinja`. | All filters replaced with universally compatible equivalents. |
69
+ | **Stability** | **Mid-Conversation System Crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere in the history. |
70
+ | **Stability** | **No-User-Query Crash** | `raise_exception` crashes agentic loops or system-only contexts. | Removed backwards history scanning entirely. |
71
+ | **Stability** | **Unclosed Thinking Before Tool** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely. |
72
+ | **Edge Cases** | **`developer` Role Rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
73
+ | **Edge Cases** | **`--reasoning off` Ignored** | When thinking is disabled, tool error escalation still opened a `<think>` block, corrupting the prompt. | Error escalation branches now fully respect `enable_thinking=false`. |
74
+ | **Edge Cases** | **Reasoning Bypass Hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects an empty closed `<think>\n\n</think>\n\n` block to successfully force reasoning bypass. |
75
+ | **Edge Cases** | **Whitespace Tag Hallucinations** | Model hallucinates invalid boundaries (e.g., `</ think>`), swallowing conversational text. | C++ safe array-slicing isolates the reasoning block without corrupting user code snippets. |
76
+
77
+ ---
78
+
79
+ ## Quick install
80
+
81
+ Choose your environment and update the template:
82
+
83
+ ### LM Studio
84
+ 1. Open your Qwen model in the right-side panel.
85
+ 2. Scroll down to **Prompt Template**.
86
+ 3. Replace the template with the contents of `chat_template.jinja`.
87
+ 4. Click **Save**.
88
+
89
+ ### llama.cpp / koboldcpp
90
+ ```bash
91
+ --jinja --chat-template-file chat_template.jinja
92
+ ```
93
+
94
+ ### vLLM
95
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents. Use the `qwen3_coder` tool parser:
96
+ ```bash
97
+ --tool-call-parser qwen3_coder
98
+ ```
99
+
100
+ ### oMLX
101
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
102
+
103
+ ---
104
+
105
+ ## Which file do I use?
106
+
107
+ Both Qwen 3.5 and Qwen 3.6 variants (including 35B, 32B, 27B, and 14B parameters) have been consolidated. You only need the single `chat_template.jinja` file at the root of the repository.
108
+
109
+ One-line versions (`chat_template_oneline.txt`) are pre-minified for engines that require a single-line template string.
110
+
111
+ ---
112
+
113
+ ## The thinking toggle
114
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
115
+
116
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
117
+
118
+ **Fast answer, no reasoning:**
119
+ ```text
120
+ System: You are a coding assistant. <|think_off|>
121
+ User: What's 2+2?
122
+ ```
123
+
124
+ **Deep reasoning:**
125
+ ```text
126
+ System: You are a coding assistant. <|think_on|>
127
+ User: Implement a red-black tree in Rust.
128
+ ```
129
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
130
+
131
+ ---
132
+
133
+ ## Preserving past thoughts
134
+
135
+ By default, Qwen models "forget" their previous `<think>` blocks in the chat history to prevent repetitive looping and save context tokens.
136
+ If you are running an agentic workflow where the model *needs* to reference its past reasoning, you can enable the `preserve_thinking` flag in your engine's template kwargs:
137
+
138
+ ```json
139
+ {
140
+ "preserve_thinking": true
141
+ }
142
+ ```
143
+ *(If your engine does not support passing kwargs, the template will default to standard Qwen behavior and strip past thoughts).*
144
+
145
+ ---
146
+
147
+ ## Pre-installed models
148
+
149
+ If you are using one of the following models, you already have an older version of this template installed.
150
+
151
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
152
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
153
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
154
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
155
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
156
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
157
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
158
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
159
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
160
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
161
+
162
+ ---
163
+
164
+ <details>
165
+ <summary>Technical Details of the Critical Fixes</summary>
166
+
167
+ ### 1. KV Cache Safety & Autoregressive Whitespace Normalization (v17)
168
+ Llama.cpp and vLLM utilize prefix KV caching to speed up generation. Previous template versions wiped conversational text from tool-call turns and injected `\n\n` before tool boundaries. These manipulations created a mismatch between the strings generated autoregressively by the model and the history rendered by the template, forcing a complete cache invalidation and full prompt re-processing on every turn. v17 normalizes all whitespace injections to strict single `\n` boundaries and safely prunes tool tags without dropping conversation, achieving a 100% KV cache hit rate in multi-turn loops.
169
+
170
+ ### 2. "Mutually Exclusive" Stopping Bug Resolution (v17)
171
+ By preserving conversational text alongside tool calls in the history (rather than aggressively wiping it), the model unlearns the artificial limitation that conversing and using a tool are mutually exclusive. It no longer aborts its turn with an early `<|im_end|>` when explaining its tool actions.
172
+
173
+ ### 3. Native XML Tool Call Format (v16)
174
+ The model was trained with the XML-based tool call format used by Qwen3-Coder:
175
+ ```xml
176
+ <tool_call>
177
+ <function=tool_name>
178
+ <parameter=param_name>
179
+ value
180
+ </parameter>
181
+ </function>
182
+ </tool_call>
183
+ ```
184
+ v16 restored this format natively, making it compatible with all parsers while bypassing the `|items` crash by using C++ safe key iteration (`for args_name in tool_call.arguments`).
185
+
186
+ ### 4. Two-Tier Agentic Error Escalation (v15)
187
+ When a tool call fails validation repeatedly, the model can enter a degenerate reasoning spiral. v15 leverages a two-tier escalation system driven by a forward-tracked `consecutive_failures` counter:
188
+ - **Tier 1 (1st error):** Generation prompt prefix changes to seed reasoning at a different token position, breaking the cached attractor state.
189
+ - **Tier 2 (2nd+ consecutive errors):** Think block bypassed entirely. An urgent out-of-band directive forces an immediate corrected action wrapped safely within the user `tool_response` block.
190
+
191
+ ### 5. Universal Synthesis (v14)
192
+ Forced `<think>` block prefilling combined with narrow system instructions causes the model to panic and debate its own internal rules after fetching tool data. v14 broadens the system instruction scope to define `<think>` as a dual-purpose space for planning **or synthesis**, completely eliminating indecisiveness post-tool retrieval.
193
+
194
+ ### 6. `enable_thinking=false` in Error Paths (v16)
195
+ When users set `--reasoning off` in llama.cpp, error escalation directives are now injected as plain text (no `<think>` wrapper) to prevent creating degenerate prompts the model couldn't resolve in no-reasoning mode.
196
+
197
+ ### 7. Smart False-Positive Detection (v18)
198
+ Previous versions relied on broad substring matching, which caused successful API/database returns containing the word "error" (e.g., `{"status": 200, "msg": "cleared error logs"}`) to trigger agentic retry loops. v18 replaces this with strict structural matching, looking specifically for code-level failure patterns (`"error":`, `Exception:`, `Traceback`, `command not found`, `invalid syntax`) alongside length gates and bash-echo exclusions.
199
+
200
+ ### 8. minijinja Compatibility Constraints
201
+ Three Python-only Jinja2 filters crash on `minijinja` (the C++ runtime used by llama.cpp, LM Studio, and MLX). They have been completely removed and replaced with universally compatible equivalents:
202
+ - `\| items` -> `for key in mapping`
203
+ - `map('string')` -> `join('|')`
204
+ - `\| first` -> `'$ ' in content`
205
+
206
+ </details>
207
+
208
+ <details>
209
+ <summary>Comparison Matrix: Official vs Fixed vs Community</summary>
210
+
211
+ | Feature | Official Qwen Templates | LuffyTheFox | mod-ellary | Pneuny | **This Fixed Template (v18)** |
212
+ |---------|----------|-------------|------------|--------|----------------|
213
+ | Tool call format | XML (native) | JSON | JSON | JSON | **XML (native, qwen3_coder compatible)** |
214
+ | Tool arguments | Fails (`\|items`) | Fixed | Missing | Fixed | **Fixed (C++ safe XML)** |
215
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | Stalls | Stalls | Stalls | **Two-tier escalation system** |
216
+ | Post-Tool Overthinking | Spams/Stalls | Broken | Broken | Broken | **Universal Synthesis** |
217
+ | Premature Stalls (Stopping Bug) | Stalls | Stalls | Stalls | Stalls | **Fixed via conversation preservation (v17)** |
218
+ | `--reasoning off` on tool errors | N/A | N/A | N/A | N/A | **Fully respected** |
219
+ | Shell/search false positives | N/A | N/A | N/A | N/A | **Guarded** |
220
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
221
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
222
+ | Empty think in history | Spams empty blocks | Broken | Tags omitted | Broken | **Pruned dynamically** |
223
+ | KV prefix caching | Breaks on dynamic history | Breaks | Breaks | Breaks | **100% stable (Immutable \n spacing) (v17)** |
224
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
225
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
226
+ | `</thinking>` hallucination | Fails | N/A | N/A | N/A | **Detected and handled (C++ safe)** |
227
+ | Auto-close thinking before tool | Not handled | Not handled | Not handled | Not handled | **Engine-safe auto-inject** |
228
+
229
+ </details>
230
+
231
+ ---
232
+
233
+ ## Running the test suite
234
+
235
+ ```bash
236
+ python3 scripts/test_v18.py
237
+ ```
238
+
239
+ Tests cover: XML tool format, tool instructions, thinking bypass, `<|think_off|>` / `<|think_on|>`, Tier 1 & 2 escalation, length-gated detection, shell/search false positives, `--reasoning off` + errors, counter reset, historical think stripping, `preserve_thinking`, developer role, mid-conversation system, tool response wrapping, and string argument passthrough.
240
+
241
+ ---
242
+
243
+ ## Authorship
244
+
245
+ | Role | Author |
246
+ |------|--------|
247
+ | Original models | Alibaba Cloud (Qwen team) |
248
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
249
+
250
+ ## License
251
+
252
+ Apache-2.0, inherited from Qwen.
archive/README-v19.md ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - vllm
13
+ - tool-calling
14
+ - thinking
15
+ ---
16
+
17
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6 (v19)
18
+
19
+ <details open>
20
+ <summary><b>Update History & Changelog (v19)</b></summary>
21
+
22
+ > **2026-05-18 Update (v19): The Agentic Loop Cure.** (1) **Abolished "Empty Think" Poisoning:** Rewrote the AST history rendering to completely remove the injection of empty `<think>\n</think>` blocks. This cures a severe in-context learning bias where the model assumed tools could only be called if it didn't think first, which was causing 80%+ of premature `<|im_end|>` turn aborts. (2) **System Prompt Logic Trap Removed:** Softened the absolute tool mandate in the `<IMPORTANT>` block and restored Universal Synthesis instructions. The model is now explicitly permitted to transition from `</think>` to a conversational answer without panicking. (3) **True 100% KV Cache & Amnesia Fix:** `preserve_thinking` now defaults to `true`. Past thoughts are retained chronologically, permanently curing "amnesia stalls" during multi-step tool loops while mathematically guaranteeing 100% KV Cache prefix matching out-of-the-box.
23
+
24
+ </details>
25
+
26
+ <details>
27
+ <summary><b>Update History & Changelog (v11-v18)</b></summary>
28
+
29
+ > **2026-05-16 Update (v18): Stability & Precision Patch.** (1) **Bulletproof False-Positive Detection:** Shifted agentic error detection from broad substring matching to strict structural formats (e.g., `"error":`, `Exception:`, `Traceback`), completely curing false-positive retry loops when successful JSON returns simply contain the word "error" or "fail". (2) **Legacy Engine Compatibility:** Replaced `loop.previtem` with explicit array indexing, fixing AST crashes on older `llama.cpp` and `minijinja` builds that do not track loop state items. (3) **True Whitespace Normalization:** Fixed a bug where reasoning bypasses and hallucinated tag recovery stacked hidden multi-newlines (`\n\n\n`), strictly fulfilling the 100% KV Cache hit rate claim for all edge cases. (4) **Code Cleanup:** Removed dead conditional branches during XML tool parsing.
30
+ >
31
+ > **2026-05-15 Update (v17):** Major architecture overhaul resolving edge cases in agentic tooling and KV Cache. (1) **Unified Template:** Consolidated Qwen 3.5 and Qwen 3.6 into a single `chat_template.jinja` file that handles all variants seamlessly. (2) **Fixed "Mutually Exclusive" Stopping Bug:** Changed the history-pruning logic from wiping the entire turn to safely array-slicing out just the raw tool tags (`content.split('<tool_call>')[0]`). This preserves the conversational text in the history, which cures the bug where the model would artificially abort its turn (output `<|im_end|>`) when it wanted to talk and use a tool simultaneously. (3) **100% KV Cache Hit Rate Restoration:** Fully normalized internal whitespace logic (`\n\n` -> `\n`) around think blocks and tool calls to exactly match the model's native autoregressive generation spacing. This perfectly synchronizes the template's rendered history with the cached generated tokens, completely eliminating the severe cache invalidation and full-prompt re-processing issues present in v16.
32
+ >
33
+ > **2026-05-14 Update (v16):** Four-part fix addressing community-reported regressions. (1) **Native XML tool format:** reverted from JSON back to the native `<function=name>` / `<parameter=x>` format the model was trained on, restoring full compatibility with vLLM's `qwen3_coder` parser and all inference engines that implement the Qwen tool protocol. (2) **`--reasoning off` respected in error paths:** when thinking is disabled (`enable_thinking=false` / `--reasoning off`), the error escalation directives are now injected as plain text without opening any `<think>` block, preventing degenerate prompts in no-reasoning sessions. (3) **Smarter false-positive detection:** short shell command results (starting with `$ `) and search results with timing footers (`Took X.Xs`) are now correctly excluded from error detection, preventing tool-retry loops when commands succeed but their output happens to contain the word `error`. (4) **`consecutive_failures` counter no longer resets on assistant messages**, allowing Tier 2 escalation to actually fire across multi-turn tool retry chains.
34
+ >
35
+ > **2026-05-13 Update (v15):** Three-part fix for agentic tool-loop failures. (1) **Two-tier error escalation:** replaced the brittle backwards-lookahead error detection with a fully forward-tracking `last_tool_failed` + `consecutive_failures` counter. On the first error the generation prompt is pre-seeded with a correction directive inside `<think>`; on the 2nd+ consecutive error the think block is bypassed and an out-of-band directive forces an immediate corrected action. (2) **Length-gated detection:** error signals are only read from short tool responses (< 500 chars), preventing false positives when reading code files containing `error`, `exception`, etc. in legitimate content. (3) **Static system prompt:** tool instructions are now fully unconditional, permanently eliminating the KV cache invalidation vector introduced in v14.
36
+ >
37
+ > **2026-05-12 Update (v14):** Cured tool amnesia loops and post-tool overthinking friction! Implemented **Smart Loop Preservation** to dynamically scan subsequent tool returns for error markers and conditionally preserve historical reasoning context during active tool failures. Broadened the system instruction scope to define `<think>` as a dual-purpose planning **or synthesis** space, completely eliminating indecisiveness post-tool retrieval.
38
+ >
39
+ > **2026-05-11 Update (v13):** Radical simplification and compatibility overhaul! Reverted tool schemas and assistant output formatting to standard JSON to natively fix downstream MCP parser crashes and C++ implicit enum coercion bugs. Removed the `ns_scan` history loop to permanently fix KV cache invalidation mid-conversation. Replaced global string replacement for hallucinated tags with a C++ safe, localized array-slicing method to prevent data-corruption on user code blocks.
40
+ >
41
+ > **2026-05-10 Update (v12):** Fixed agent stalls, parameter data-loss, and hallucination bugs! Restored dynamic tool instructions and the `<IMPORTANT>` formatting reminder block to stop grammar parser crashes.
42
+ >
43
+ > **2026-05-10 Update (v11):** Fixed agent looping and overthinking! Re-implemented `preserve_thinking` kwarg to properly strip reasoning blocks from history by default, and restored the reasoning bypass (`<think>\n\n</think>\n\n`).
44
+
45
+ </details>
46
+
47
+ This is a drop-in Jinja template that fixes rendering errors, KV cache invalidation, token waste, and fatal agentic stalling in the official Qwen chat templates.
48
+
49
+ It is tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
50
+
51
+ ---
52
+
53
+ ## Why you need this
54
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
55
+
56
+ Here are the critical issues this template fixes:
57
+
58
+ | Category | Problem | Impact | Fix |
59
+ |---|---|---|---|
60
+ | **Agentic Loop** | **Premature Stalls (Stopping Bug)** | Model aborts its turn (`<\|im_end\|>`) when trying to combine conversation and a tool call. | Resolved the System Prompt logic trap and cured "Empty Think" poisoning (v19). |
61
+ | **Agentic Loop** | **Retry Stall & Reasoning Spiral** | Model correctly diagnoses a tool error but repeatedly emits the identical failing `<tool_call>`. | Two-tier escalation: seeds `<think>` with correction directive; injects urgent out-of-band directive. |
62
+ | **Agentic Loop** | **Post-Tool Overthinking** | Forced `<think>` block prefilling causes model to panic and debate internal rules after fetching data. | Broadened instructions to define `<think>` as a dual-purpose space for planning *or synthesis*. |
63
+ | **Agentic Loop** | **False-Positive Error Detection** | Short successful API/JSON returns containing the word `error` trigger false retry loops. | Strict structural guards look for exact system failures (`"error":`, `Traceback`, etc.) instead of broad words (v18). |
64
+ | **Performance** | **KV Cache Invalidation** | History pruning dynamically mutates past turns, causing full prompt re-processing every turn. | `preserve_thinking` defaults to `true`, maintaining strict chronological rendering for a 100% KV cache hit rate (v19). |
65
+ | **Performance** | **Empty Think Poisoning** | Stripped past turns leave behind empty `<think></think>` tags, tricking the model into a severe in-context learning bias. | Template completely abolishes the injection of empty think blocks (v19). |
66
+ | **Compatibility** | **Legacy Engine Crashes** | Older C++ parsing engines crash when evaluating `loop.previtem`. | Uses strict chronological array indexing universally supported by all Jinja iterations (v18). |
67
+ | **Compatibility** | **Wrong Tool Call Format** | Qwen-native parsers (like vLLM's `qwen3_coder`) expect XML `<function=name>`. JSON format breaks them. | Restored native XML format while keeping C++ safety. |
68
+ | **Compatibility** | **Jinja C++ Crashes** | Python-specific filters (`map`, `first` on strings) crash on `minijinja`. | All filters replaced with universally compatible equivalents. |
69
+ | **Stability** | **Mid-Conversation System Crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere in the history. |
70
+ | **Stability** | **No-User-Query Crash** | `raise_exception` crashes agentic loops or system-only contexts. | Graceful fallback implemented. |
71
+ | **Stability** | **Unclosed Thinking Before Tool** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries securely. |
72
+ | **Edge Cases** | **`developer` Role Rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
73
+ | **Edge Cases** | **`--reasoning off` Ignored** | When thinking is disabled, tool error escalation still opened a `<think>` block, corrupting the prompt. | Error escalation branches now fully respect `enable_thinking=false`. |
74
+ | **Edge Cases** | **Reasoning Bypass Hallucinations** | When thinking is disabled, Qwen models inherently hallucinate reasoning tags anyway. | Injects a safe boundary to successfully force reasoning bypass without stacking newlines (v18). |
75
+
76
+ ---
77
+
78
+ ## Quick install
79
+
80
+ Choose your environment and update the template:
81
+
82
+ ### LM Studio
83
+ 1. Open your Qwen model in the right-side panel.
84
+ 2. Scroll down to **Prompt Template**.
85
+ 3. Replace the template with the contents of `chat_template.jinja`.
86
+ 4. Click **Save**.
87
+
88
+ ### llama.cpp / koboldcpp
89
+ ```bash
90
+ --jinja --chat-template-file chat_template.jinja
91
+ ```
92
+
93
+ ### vLLM
94
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents. Use the `qwen3_coder` tool parser:
95
+ ```bash
96
+ --tool-call-parser qwen3_coder
97
+ ```
98
+
99
+ ### oMLX
100
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
101
+
102
+ ---
103
+
104
+ ## Which file do I use?
105
+
106
+ Both Qwen 3.5 and Qwen 3.6 variants (including 35B, 32B, 27B, and 14B parameters) have been consolidated. You only need the single `chat_template.jinja` file at the root of the repository.
107
+
108
+ One-line versions (`chat_template_oneline.txt`) are pre-minified for engines that require a single-line template string.
109
+
110
+ ---
111
+
112
+ ## The thinking toggle
113
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
114
+
115
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
116
+
117
+ **Fast answer, no reasoning:**
118
+ ```text
119
+ System: You are a coding assistant. <|think_off|>
120
+ User: What's 2+2?
121
+ ```
122
+
123
+ **Deep reasoning:**
124
+ ```text
125
+ System: You are a coding assistant. <|think_on|>
126
+ User: Implement a red-black tree in Rust.
127
+ ```
128
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
129
+
130
+ ---
131
+
132
+ ## Token Saving: Stripping past thoughts
133
+
134
+ By default in v19, this template **preserves** all past `<think>` blocks in the chat history. This is intentional: it prevents the model from suffering "amnesia stalls" during complex, multi-step agentic loops, and it mathematically guarantees a 100% Prefix KV Cache hit rate on local inference engines.
135
+
136
+ However, if you are running constrained hardware and need to save context tokens, you can explicitly disable this feature in your engine's template kwargs to automatically strip past thoughts:
137
+
138
+ ```json
139
+ {
140
+ "preserve_thinking": false
141
+ }
142
+ ```
143
+ *(Note: Setting this to false will naturally reduce your KV Cache hit rate during multi-turn chats, as the prompt string will dynamically mutate).*
144
+
145
+ ---
146
+
147
+ <details>
148
+ <summary>Technical Details of the Critical Fixes</summary>
149
+
150
+ ### 1. The "Empty Think" Poisoning & Logic Trap Cure (v19)
151
+ Previous versions attempted to save tokens by replacing past thoughts with empty `<think>\n</think>` blocks, combined with an absolute system prompt demanding a tool be called immediately after `</think>`. This created a toxic in-context learning pattern: the model associated empty thoughts with tools, and full thoughts with forbidden conversational text, causing an 80%+ premature `<|im_end|>` stalling rate. v19 abolishes empty think injection and rewrites the `<IMPORTANT>` directives to explicitly authorize conversational synthesis after a thought block.
152
+
153
+ ### 2. KV Cache Safety & Autoregressive Normalization (v18/v19)
154
+ Llama.cpp and vLLM utilize prefix KV caching to speed up generation. Because v19 now preserves historical thoughts chronologically by default, the rendered history perfectly synchronizes with the cached generated tokens. Combined with strict single `\n` normalization at autoregressive boundaries, this achieves a 100% KV Cache hit rate in multi-turn loops.
155
+
156
+ ### 3. Native XML Tool Call Format (v16)
157
+ The model was trained with the XML-based tool call format used by Qwen3-Coder:
158
+ ```xml
159
+ <tool_call>
160
+ <function=tool_name>
161
+ <parameter=param_name>
162
+ value
163
+ </parameter>
164
+ </function>
165
+ </tool_call>
166
+ ```
167
+ v16 restored this format natively, making it compatible with all parsers while bypassing the `|items` crash by using C++ safe key iteration (`for args_name in tool_call.arguments`).
168
+
169
+ ### 4. Two-Tier Agentic Error Escalation (v15)
170
+ When a tool call fails validation repeatedly, the model can enter a degenerate reasoning spiral. This template leverages a two-tier escalation system driven by a forward-tracked `consecutive_failures` counter:
171
+ - **Tier 1 (1st error):** Generation prompt prefix changes to seed reasoning at a different token position, breaking the cached attractor state.
172
+ - **Tier 2 (2nd+ consecutive errors):** Think block bypassed entirely. An urgent out-of-band directive forces an immediate corrected action wrapped safely within the user `tool_response` block.
173
+
174
+ ### 5. Smart False-Positive Detection (v18)
175
+ Instead of broad substring matching that triggers false retry-loops on successful database returns containing words like "error", v18 utilizes strict structural guards looking for `Exception:`, `"error":`, `Traceback`, and `command not found`, combined with length gates and shell-echo exclusions (`$ `).
176
+
177
+ ### 6. minijinja Compatibility Constraints (v18)
178
+ Python-only Jinja2 features crash on `minijinja` (the C++ runtime used by llama.cpp, LM Studio, and MLX). All instances have been refactored for universal support:
179
+ - `\| items` -> `for key in mapping`
180
+ - `loop.previtem` -> `messages[loop.index0 - 1]` (v18)
181
+ - `map('string')` -> `join('|')`
182
+ - `\| first` -> `'$ ' in content`
183
+
184
+ </details>
185
+
186
+ <details>
187
+ <summary>Comparison Matrix: Official vs Fixed vs Community</summary>
188
+
189
+ | Feature | Official Qwen Templates | LuffyTheFox | mod-ellary | Pneuny | **This Fixed Template (v19)** |
190
+ |---------|----------|-------------|------------|--------|----------------|
191
+ | Tool call format | XML (native) | JSON | JSON | JSON | **XML (native, qwen3_coder compatible)** |
192
+ | Tool arguments | Fails (`\|items`) | Fixed | Missing | Fixed | **Fixed (C++ safe XML)** |
193
+ | Premature Stalls (Stopping Bug) | Stalls | Stalls | Stalls | Stalls | **Fixed via Logic Trap / Poisoning removal (v19)** |
194
+ | Agentic Retry Stall & Reasoning Spiral | Stalls | Stalls | Stalls | Stalls | **Two-tier escalation system** |
195
+ | False-positive tool errors | N/A | N/A | N/A | N/A | **Guarded (Strict structural matching)** |
196
+ | Post-Tool Overthinking | Spams/Stalls | Broken | Broken | Broken | **Universal Synthesis** |
197
+ | `--reasoning off` on tool errors | N/A | N/A | N/A | N/A | **Fully respected** |
198
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
199
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
200
+ | Empty think in history | Spams empty blocks | Broken | Tags omitted | Broken | **Abolished completely (v19)** |
201
+ | KV prefix caching | Breaks on dynamic history | Breaks | Breaks | Breaks | **100% stable out-of-the-box (v19)** |
202
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
203
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
204
+ | Legacy AST support | Fails (`previtem`) | Fails | Fails | Fails | **Fixed (`index0`)** |
205
+ | `</thinking>` hallucination | Fails | N/A | N/A | N/A | **Detected and safely trimmed** |
206
+
207
+ </details>
208
+
209
+ ---
210
+
211
+ ## Running the test suite
212
+
213
+ ```bash
214
+ python3 scripts/test_v18.py
215
+ ```
216
+
217
+ Tests cover: XML tool format, tool instructions, thinking bypass, `<|think_off|>` / `<|think_on|>`, Tier 1 & 2 escalation, length-gated detection, shell/search false positives, `--reasoning off` + errors, counter reset, historical think stripping, `preserve_thinking`, developer role, mid-conversation system, tool response wrapping, and string argument passthrough.
218
+
219
+ ---
220
+
221
+ ## Authorship
222
+
223
+ | Role | Author |
224
+ |------|--------|
225
+ | Original models | Alibaba Cloud (Qwen team) |
226
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
227
+
228
+ ## License
229
+
230
+ Apache-2.0, inherited from Qwen.
archive/README-v8.md ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6
17
+
18
+ > **2026-05-07 Update:** Fixed 8th bug: Mid-conversation system messages no longer crash the template. Compatibility restored for agent frameworks (OpenCode, Docker Agent, oh-my-pi). Re-engineered Jinja string parsing for C++ engine stability.
19
+
20
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
21
+
22
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
23
+
24
+ ---
25
+
26
+ ## Why you need this
27
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
28
+
29
+ Here are the 8 bugs this template fixes:
30
+
31
+ | Problem | Impact | Fix |
32
+ |---|---|---|
33
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility. |
34
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
35
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
36
+ | **4. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Dynamic length checks and history visibility logic. |
37
+ | **5. No way to toggle thinking** | The user is restricted to the model defaults. | Intercepts `<\|think_off\|>` and `<\|think_on\|>` tags natively. |
38
+ | **6. Qwen 3.6 `</thinking>` hallucination** | Model sometimes generates `</thinking>` instead of `</think>`, permanently breaking the parser. | Advanced tag detection and stream recovery. |
39
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Graceful fallback scanning mechanism. |
40
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries. |
41
+
42
+ ---
43
+
44
+ ## Quick install
45
+
46
+ Choose your environment and update the template:
47
+
48
+ ### LM Studio
49
+ 1. Open your Qwen model in the right-side panel.
50
+ 2. Scroll down to **Prompt Template**.
51
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
52
+ 4. Click **Save**.
53
+
54
+ ### llama.cpp / koboldcpp
55
+ ```bash
56
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
57
+ ```
58
+
59
+ ### vLLM / TextGen
60
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
61
+
62
+ ### oMLX
63
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
64
+
65
+ ---
66
+
67
+ ## Which file do I use?
68
+
69
+ | Template File | Supported Models |
70
+ |------|-----------|
71
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
72
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
73
+
74
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
75
+
76
+ ---
77
+
78
+ ## The thinking toggle
79
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
80
+
81
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
82
+
83
+ **Fast answer, no reasoning:**
84
+ ```text
85
+ System: You are a coding assistant. <|think_off|>
86
+ User: What's 2+2?
87
+ ```
88
+
89
+ **Deep reasoning:**
90
+ ```text
91
+ System: You are a coding assistant. <|think_on|>
92
+ User: Implement a red-black tree in Rust.
93
+ ```
94
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
95
+
96
+ ---
97
+
98
+ ## Pre-installed models
99
+
100
+ If you are using one of the following models, you already have an older version of this template installed.
101
+
102
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
103
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
104
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
105
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
106
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
107
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
108
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
109
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
110
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
111
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
112
+
113
+ ---
114
+
115
+ <details>
116
+ <summary>Technical Details of the 8 Fixes</summary>
117
+
118
+ ### 1. Tool calls on C++ engines
119
+ The official template iterates tool call arguments with `|items`:
120
+ `{%- for key, value in tool_call.arguments|items %}`
121
+
122
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses direct dictionary key lookups instead. It also replaces `is sequence` with `is iterable`, removes Python-only `|safe` wrappers, and handles arguments returned as raw strings.
123
+
124
+ ### 2. Mid-conversation system messages crash
125
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
126
+
127
+ ### 3. `developer` role
128
+ The OpenAI-compatible API spec sends `message.role == "developer"` for system-level instructions. The official Qwen template throws an exception. Both templates here accept `"developer"` and map it properly.
129
+
130
+ ### 4. Empty thinking blocks
131
+ The official template wraps every past assistant turn in thinking tags, even when empty. When there is no reasoning content, those tags waste context tokens and break prefix caching. The 3.5 template checks `reasoning_content` before emitting. The 3.6 template checks `reasoning_content|trim|length > 0` and ties history visibility to the `<|think_off|>` override.
132
+
133
+ ### 5. `</thinking>` hallucination (Qwen 3.6 only)
134
+ The Qwen 3.6 model sometimes generates `</thinking>` instead of the expected `</think>`. The official parser splits on `</think >` only and fails. The 3.6 template detects which closing tag was actually used and splits dynamically. It also handles interrupted generation by rescuing incomplete streams.
135
+
136
+ ### 6. Arguments serialization
137
+ The official template serializes argument values with `|tojson` unconditionally, failing when the value is already a string. The fixed templates check the type first. Strings pass through as-is, and everything else goes through `|tojson`.
138
+
139
+ ### 7. Auto-close unclosed thinking before tool calls
140
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
141
+
142
+ ### 8. No-user-query exception
143
+ The official template scans the message list in reverse. If all messages are tool results, or there are no user messages, it fires `raise_exception('No user query found...')` and hard-crashes. The fix replaces the exception with a graceful fallback `{%- set ns.last_query_index = messages|length - 1 %}`, enabling agentic tool-calling chains to function perfectly.
144
+ </details>
145
+
146
+ <details>
147
+ <summary>Comparison: Qwen 3.5 templates</summary>
148
+
149
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This** |
150
+ |---------|----------|-------------|------------|--------|----------|
151
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed** |
152
+ | `\|safe` removed | Fails | Fixed | Missing | Fixed | **Fixed** |
153
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
154
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
155
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Fixed** |
156
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
157
+ | Clean instructions | Yes | Yes | Yes | Injects text | **Yes** |
158
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
159
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Auto-injects close tag** |
160
+
161
+ </details>
162
+
163
+ <details>
164
+ <summary>Comparison: Qwen 3.6 template</summary>
165
+
166
+ | Feature | Official | **This** |
167
+ |---------|----------|----------|
168
+ | Tool arguments | Fails (`\|items`) | **Fixed** |
169
+ | `\|safe` removed | Fails | **Fixed** |
170
+ | `developer` role | Missing | **Added** |
171
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
172
+ | `preserve_thinking` | Spams empty blocks | **Dynamic length checks** |
173
+ | Mid-conversation system | Crashes | **Fixed** |
174
+ | `</thinking>` hallucination | Fails | **Detected and handled** |
175
+ | Interrupted streams | Broken tags | **Rescued** |
176
+ | Auto-close thinking before tool | Not handled | **Auto-injects close tag** |
177
+ | No-user-query crash | Crashes | **Graceful fallback** |
178
+
179
+ </details>
180
+
181
+ ---
182
+
183
+ ## Authorship
184
+
185
+ | Role | Author |
186
+ |------|--------|
187
+ | Original models | Alibaba Cloud (Qwen team) |
188
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
189
+
190
+ ## License
191
+
192
+ Apache-2.0, inherited from Qwen.
archive/README-v9.md ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - jinja
5
+ - chat-template
6
+ - qwen
7
+ - qwen3.5
8
+ - qwen3.6
9
+ - lm-studio
10
+ - mlx
11
+ - llama.cpp
12
+ - tool-calling
13
+ - thinking
14
+ ---
15
+
16
+ # Fixed jinja chat templates for Qwen 3.5 & 3.6
17
+
18
+ > **2026-05-08 Update:** Fixed 9th bug: Thinking-tool-call hallucination. Refactored system prompt parsing to enable dynamic tool instructions. The template now actively teaches the model how to safely combine `<think>` blocks and `<tool_call>` boundaries.
19
+ >
20
+ > **2026-05-07 Update:** Fixed 8th bug: Mid-conversation system messages no longer crash the template. Compatibility restored for agent frameworks (OpenCode, Docker Agent, oh-my-pi). Re-engineered Jinja string parsing for C++ engine stability.
21
+
22
+ These are drop-in Jinja templates that fix rendering errors, token waste, and missing features in the official Qwen chat templates.
23
+
24
+ They are tested to work across LM Studio, llama.cpp, vLLM, MLX, oMLX, and any engine that supports HuggingFace Jinja templates.
25
+
26
+ ---
27
+
28
+ ## Why you need this
29
+ The official Qwen templates contain restrictions and Python-specific Jinja logic that break usage on many inference engines and agent frameworks.
30
+
31
+ Here are the 9 bugs this template fixes:
32
+
33
+ | Problem | Impact | Fix |
34
+ |---|---|---|
35
+ | **1. Tool calls fail on C++ engines** | The `\|items` filter doesn't exist in `minijinja` (LM Studio, llama.cpp, MLX). Tool calls instantly crash the template. | Rewritten for strict C++ engine compatibility. |
36
+ | **2. Mid-conversation system crash** | Frameworks injecting mid-conversation steering instructions trigger a hard crash. | Native, chronological rendering for system messages anywhere. |
37
+ | **3. `developer` role rejected** | Modern APIs send the developer role; the official template rejects it. | Added full support for `"developer"`. |
38
+ | **4. Empty thinking blocks spam** | Every past turn gets wrapped in empty `<think></think>` tags, wasting context and breaking caching. | Dynamic length checks and history visibility logic. |
39
+ | **5. No way to toggle thinking** | The user is restricted to the model defaults. | Intercepts `<\|think_off\|>` and `<\|think_on\|>` tags natively. |
40
+ | **6. Qwen 3.6 `</thinking>` hallucination** | Model sometimes generates `</thinking>` instead of `</think>`, permanently breaking the parser. | Advanced tag detection and stream recovery. |
41
+ | **7. No-user-query crash** | `raise_exception` crashes agentic loops, system-only contexts, or `/reset` flows. | Graceful fallback scanning mechanism. |
42
+ | **8. Unclosed thinking before tool call** | Model calls a tool without closing its reasoning, bleeding XML tags into tool parsers. | Auto-injects closing tags before tool boundaries. |
43
+ | **9. Thinking tool_call hallucination** | Model places `<tool_call>` inside `<think>` block because prompt forces `<think>\n` before a strict tool instruction. | Hoists system toggle to inject `<think>` natively into tool instructions. |
44
+
45
+ ---
46
+
47
+ ## Quick install
48
+
49
+ Choose your environment and update the template:
50
+
51
+ ### LM Studio
52
+ 1. Open your Qwen model in the right-side panel.
53
+ 2. Scroll down to **Prompt Template**.
54
+ 3. Replace the template with the contents of `qwen3.5/chat_template.jinja` or `qwen3.6/chat_template.jinja`.
55
+ 4. Click **Save**.
56
+
57
+ ### llama.cpp / koboldcpp
58
+ ```bash
59
+ --jinja --chat-template-file qwen3.6/chat_template.jinja
60
+ ```
61
+
62
+ ### vLLM / TextGen
63
+ Replace the `"chat_template"` string in your `tokenizer_config.json` with the raw file contents.
64
+
65
+ ### oMLX
66
+ Overwrite `chat_template.jinja` in your local model directory. Load with `--jinja`. Remove any `chat_template_kwargs` overrides because the template handles everything internally.
67
+
68
+ ---
69
+
70
+ ## Which file do I use?
71
+
72
+ | Template File | Supported Models |
73
+ |------|-----------|
74
+ | [`qwen3.5/chat_template.jinja`](qwen3.5/chat_template.jinja) | Qwen3.5-35B-A3B, Qwen3.5-32B, Qwen3.5-14B, and all Qwen 3.5 variants. |
75
+ | [`qwen3.6/chat_template.jinja`](qwen3.6/chat_template.jinja) | Qwen3.6-27B, Qwen3.6-35B-A3B, and all Qwen 3.6 variants. |
76
+
77
+ > **Note:** The 3.6 template is a superset. It additionally handles `preserve_thinking`, `</thinking>` hallucination recovery, and interrupted thought streams. If you are on 3.6, always use the 3.6 file.
78
+
79
+ ---
80
+
81
+ ## The thinking toggle
82
+ You can control the model reasoning behavior. Insert `<|think_on|>` or `<|think_off|>` anywhere in your system or user prompt.
83
+
84
+ The template natively intercepts the tag, removes it from the final context so the model never sees it, and flips the reasoning mode instantly.
85
+
86
+ **Fast answer, no reasoning:**
87
+ ```text
88
+ System: You are a coding assistant. <|think_off|>
89
+ User: What's 2+2?
90
+ ```
91
+
92
+ **Deep reasoning:**
93
+ ```text
94
+ System: You are a coding assistant. <|think_on|>
95
+ User: Implement a red-black tree in Rust.
96
+ ```
97
+ *(The tag syntax uses Qwen's control-token delimiters to guarantee it will never collide with legitimate text or file paths, unlike earlier community templates that used `/think`)*
98
+
99
+ ---
100
+
101
+ ## Pre-installed models
102
+
103
+ If you are using one of the following models, you already have an older version of this template installed.
104
+
105
+ - [froggeric/Qwen3.6-27B-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-8bit)
106
+ - [froggeric/Qwen3.6-27B-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-MLX-4bit)
107
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-8bit)
108
+ - [froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit](https://huggingface.co/froggeric/Qwen3.5-35B-A3B-Uncensored-FernflowerAI-MLX-4bit)
109
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-8bit)
110
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-6bit)
111
+ - [froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-27B-Uncensored-Heretic-v2-MLX-4bit)
112
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-8bit)
113
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-6bit)
114
+ - [froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit](https://huggingface.co/froggeric/Qwen3.6-35B-A3B-Uncensored-Heretic-MLX-4bit)
115
+
116
+ ---
117
+
118
+ <details>
119
+ <summary>Technical Details of the 9 Fixes</summary>
120
+
121
+ ### 1. Tool calls on C++ engines
122
+ The official template iterates tool call arguments with `|items`:
123
+ `{%- for key, value in tool_call.arguments|items %}`
124
+
125
+ Python's Jinja supports `|items`. C++ runtimes (LM Studio, llama.cpp, MLX) do not, which produces a rendering error. This template uses direct dictionary key lookups instead. It also replaces `is sequence` with `is iterable`, removes Python-only `|safe` wrappers, and handles arguments returned as raw strings.
126
+
127
+ ### 2. Mid-conversation system messages crash
128
+ The official template hard-crashes if a `system` or `developer` message appears anywhere except the first position. This breaks agentic frameworks (Codex CLI, Docker Agent, oh-my-pi, OpenCode) that inject steering instructions mid-conversation. The fix natively renders these messages chronologically to preserve LLM recency bias while enforcing strict image-blocking checks.
129
+
130
+ ### 3. `developer` role
131
+ The OpenAI-compatible API spec sends `message.role == "developer"` for system-level instructions. The official Qwen template throws an exception. Both templates here accept `"developer"` and map it properly.
132
+
133
+ ### 4. Empty thinking blocks
134
+ The official template wraps every past assistant turn in thinking tags, even when empty. When there is no reasoning content, those tags waste context tokens and break prefix caching. The 3.5 template checks `reasoning_content` before emitting. The 3.6 template checks `reasoning_content|trim|length > 0` and ties history visibility to the `<|think_off|>` override.
135
+
136
+ ### 5. `</thinking>` hallucination (Qwen 3.6 only)
137
+ The Qwen 3.6 model sometimes generates `</thinking>` instead of the expected `</think>`. The official parser splits on `</think >` only and fails. The 3.6 template detects which closing tag was actually used and splits dynamically. It also handles interrupted generation by rescuing incomplete streams.
138
+
139
+ ### 6. Arguments serialization
140
+ The official template serializes argument values with `|tojson` unconditionally, failing when the value is already a string. The fixed templates check the type first. Strings pass through as-is, and everything else goes through `|tojson`.
141
+
142
+ ### 7. Auto-close unclosed thinking before tool calls
143
+ The model sometimes starts a thinking block and immediately calls a tool without emitting the closing tag. The official template lets the unclosed thinking tag bleed into the tool call. The fixed templates detect this pattern and safely auto-inject the closing tag using standard Jinja `split` operations to guarantee 100% C++ compatibility.
144
+
145
+ ### 8. No-user-query exception
146
+ The official template scans the message list in reverse. If all messages are tool results, or there are no user messages, it fires `raise_exception('No user query found...')` and hard-crashes. The fix replaces the exception with a graceful fallback `{%- set ns.last_query_index = messages|length - 1 %}`, enabling agentic tool-calling chains to function perfectly.
147
+
148
+ ### 9. Thinking tool_call hallucination
149
+ The official template appends `<think>\n` to the end of the generation prompt to initiate reasoning. However, its system instructions rigidly demand the model to output *only* `<tool_call>` with no suffix. This contradictory state causes the model to improperly nest its tool call inside the thinking block. This template utilizes a global pre-scan to evaluate the final `enable_thinking` state across the entire conversation history, guaranteeing it can dynamically inject a proper `<think>...</think>` usage example into the tool instructions exactly when reasoning is enabled.
150
+ </details>
151
+
152
+ <details>
153
+ <summary>Comparison: Qwen 3.5 templates</summary>
154
+
155
+ | Feature | Official | LuffyTheFox | mod-ellary | Pneuny | **This** |
156
+ |---------|----------|-------------|------------|--------|----------|
157
+ | Tool arguments | Fails | Fixed | Missing | Fixed | **Fixed** |
158
+ | `\|safe` removed | Fails | Fixed | Missing | Fixed | **Fixed** |
159
+ | `developer` role | Missing | Missing | Missing | Missing | **Added** |
160
+ | Thinking toggle | None | None | `/think` (system only) | None | **`<\|think_off\|>` anywhere** |
161
+ | Empty think in history | Broken | Broken | Tags omitted | Broken | **Fixed** |
162
+ | Mid-conversation system | Crashes | Crashes | Crashes | Crashes | **Fixed** |
163
+ | Clean instructions | Yes | Yes | Yes | Injects text | **Yes** |
164
+ | No-user-query crash | Crashes | Crashes | Crashes | Crashes | **Graceful fallback** |
165
+ | Auto-close thinking | Not handled | Not handled | Not handled | Not handled | **Auto-injects close tag** |
166
+ | Dynamic tool format | Static | Static | Static | Static | **Yes** |
167
+
168
+ </details>
169
+
170
+ <details>
171
+ <summary>Comparison: Qwen 3.6 template</summary>
172
+
173
+ | Feature | Official | **This** |
174
+ |---------|----------|----------|
175
+ | Tool arguments | Fails (`\|items`) | **Fixed** |
176
+ | `\|safe` removed | Fails | **Fixed** |
177
+ | `developer` role | Missing | **Added** |
178
+ | Thinking toggle | None | **`<\|think_off\|>` anywhere** |
179
+ | `preserve_thinking` | Spams empty blocks | **Dynamic length checks** |
180
+ | Mid-conversation system | Crashes | **Fixed** |
181
+ | `</thinking>` hallucination | Fails | **Detected and handled** |
182
+ | Interrupted streams | Broken tags | **Rescued** |
183
+ | Auto-close thinking before tool | Not handled | **Auto-injects close tag** |
184
+ | No-user-query crash | Crashes | **Graceful fallback** |
185
+ | Dynamic tool format | Static | **Yes** |
186
+
187
+ </details>
188
+
189
+ ---
190
+
191
+ ## Authorship
192
+
193
+ | Role | Author |
194
+ |------|--------|
195
+ | Original models | Alibaba Cloud (Qwen team) |
196
+ | Template fixes | [froggeric](https://huggingface.co/froggeric) |
197
+
198
+ ## License
199
+
200
+ Apache-2.0, inherited from Qwen.
archive/qwen3.5/chat_template-v10.jinja ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {%- set fn = tool.function if tool.function is defined else tool %}
70
+ {%- set props = {} %}
71
+ {%- set req = [] %}
72
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
73
+ {%- if fn.parameters.properties is defined %}
74
+ {%- set props = fn.parameters.properties %}
75
+ {%- endif %}
76
+ {%- if fn.parameters.required is defined %}
77
+ {%- set req = fn.parameters.required %}
78
+ {%- endif %}
79
+ {%- endif %}
80
+ {%- set ns_p = namespace(sig='') %}
81
+ {%- for pname in props %}
82
+ {%- set pdef = props[pname] %}
83
+ {%- set ptype = 'any' %}
84
+ {%- if pdef.type is defined %}
85
+ {%- if pdef.type == 'array' or pdef.type == 'object' %}
86
+ {%- set ptype = 'array|object' %}
87
+ {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %}
88
+ {%- set ptype = pdef.enum | join('|') %}
89
+ {%- else %}
90
+ {%- set ptype = pdef.type %}
91
+ {%- endif %}
92
+ {%- endif %}
93
+ {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %}
94
+ {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %}
95
+ {%- endfor %}
96
+ {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }}
97
+ {%- if fn.description is defined %}
98
+ {{- ' — ' ~ fn.description }}
99
+ {%- endif %}
100
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
101
+ {%- for pname in props %}
102
+ {%- set pdef = props[pname] %}
103
+ {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %}
104
+ {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }}
105
+ {%- endif %}
106
+ {%- endfor %}
107
+ {%- endif %}
108
+ {%- endfor %}
109
+ {{- "\n</tools>" }}
110
+ {{- '\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>' }}
111
+ {%- if has_system and system_content %}
112
+ {{- '\n\n' + system_content }}
113
+ {%- endif %}
114
+ {{- '<|im_end|>\n' }}
115
+ {%- elif has_system and system_content %}
116
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
117
+ {%- endif %}
118
+ {%- for message in messages %}
119
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
120
+ {%- set content = render_content(message.content, true, is_system)|trim %}
121
+ {%- if '<|think_off|>' in content %}
122
+ {%- set ns_flags.enable_thinking = false %}
123
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
124
+ {%- elif '<|think_on|>' in content %}
125
+ {%- set ns_flags.enable_thinking = true %}
126
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
127
+ {%- endif %}
128
+ {%- if is_system %}
129
+ {%- if not loop.first and content %}
130
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
131
+ {%- endif %}
132
+ {%- elif message.role == "user" %}
133
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
134
+ {%- elif message.role == "assistant" %}
135
+ {%- set reasoning_content = '' %}
136
+ {%- if message.reasoning_content is string %}
137
+ {%- set reasoning_content = message.reasoning_content %}
138
+ {%- else %}
139
+ {%- if '</think>' in content or '</thinking>' in content %}
140
+ {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %}
141
+ {%- set reasoning_parts = content.split(think_end_token) %}
142
+ {%- set reasoning_content = reasoning_parts[0] %}
143
+ {%- set content = reasoning_parts[1] %}
144
+ {%- if '<think>' in reasoning_content %}
145
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
146
+ {%- endif %}
147
+ {%- elif '<think>' in content %}
148
+ {%- if '<tool_call>' in content %}
149
+ {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %}
150
+ {%- set reasoning_parts = content.split('</think>') %}
151
+ {%- set reasoning_content = reasoning_parts[0] %}
152
+ {%- set content = reasoning_parts[1] %}
153
+ {%- if '<think>' in reasoning_content %}
154
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
155
+ {%- endif %}
156
+ {%- else %}
157
+ {%- set reasoning_content = content.split('<think>')[1] %}
158
+ {%- set content = '' %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+ {%- endif %}
162
+ {%- set reasoning_content = reasoning_content | trim %}
163
+ {%- set content = content | trim %}
164
+ {%- if reasoning_content %}
165
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
166
+ {%- else %}
167
+ {{- '<|im_start|>' + message.role + '\n' + content }}
168
+ {%- endif %}
169
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
170
+ {%- for tool_call in message.tool_calls %}
171
+ {%- if tool_call.function is defined %}
172
+ {%- set tool_call = tool_call.function %}
173
+ {%- endif %}
174
+ {%- if loop.first and content %}
175
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
176
+ {%- else %}
177
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
178
+ {%- endif %}
179
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
180
+ {%- if tool_call.arguments|length > 0 %}
181
+ {%- for args_name in tool_call.arguments %}
182
+ {%- set args_value = tool_call.arguments[args_name] %}
183
+ {{- '<parameter=' + args_name + '>\n' }}
184
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
185
+ {{- args_value }}
186
+ {{- '\n</parameter>\n' }}
187
+ {%- endfor %}
188
+ {%- endif %}
189
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
190
+ {%- if tool_call.arguments|trim|length > 0 %}
191
+ {{- tool_call.arguments }}
192
+ {{- '\n' }}
193
+ {%- endif %}
194
+ {%- endif %}
195
+ {{- '</function>\n</tool_call>' }}
196
+ {%- endfor %}
197
+ {%- endif %}
198
+ {{- '<|im_end|>\n' }}
199
+ {%- elif message.role == "tool" %}
200
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
201
+ {{- '<|im_start|>user' }}
202
+ {%- endif %}
203
+ {{- '\n<tool_response>\n' }}
204
+ {{- content }}
205
+ {{- '\n</tool_response>' }}
206
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
207
+ {{- '<|im_end|>\n' }}
208
+ {%- elif loop.last %}
209
+ {{- '<|im_end|>\n' }}
210
+ {%- endif %}
211
+ {%- else %}
212
+ {{- raise_exception('Unexpected message role.') }}
213
+ {%- endif %}
214
+ {%- endfor %}
215
+ {%- if add_generation_prompt %}
216
+ {%- if ns_flags.has_tools %}
217
+ {{- '<|im_start|>system\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- 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><|im_end|>\n' }}
218
+ {%- endif %}
219
+ {{- '<|im_start|>assistant\n' }}
220
+ {%- if ns_flags.enable_thinking %}
221
+ {{- '<think>\n' }}
222
+ {%- endif %}
223
+ {%- endif %}
archive/qwen3.5/chat_template-v10_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {%- set fn = tool.function if tool.function is defined else tool %} {%- set props = {} %} {%- set req = [] %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- if fn.parameters.properties is defined %} {%- set props = fn.parameters.properties %} {%- endif %} {%- if fn.parameters.required is defined %} {%- set req = fn.parameters.required %} {%- endif %} {%- endif %} {%- set ns_p = namespace(sig='') %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- set ptype = 'any' %} {%- if pdef.type is defined %} {%- if pdef.type == 'array' or pdef.type == 'object' %} {%- set ptype = 'array|object' %} {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %} {%- set ptype = pdef.enum | join('|') %} {%- else %} {%- set ptype = pdef.type %} {%- endif %} {%- endif %} {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %} {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %} {%- endfor %} {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }} {%- if fn.description is defined %} {{- ' — ' ~ fn.description }} {%- endif %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %} {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }} {%- endif %} {%- endfor %} {%- endif %} {%- 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>' }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- if '</think>' in content or '</thinking>' in content %} {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- elif '<think>' in content %} {%- if '<tool_call>' in content %} {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %} {%- set reasoning_parts = content.split('</think>') %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- else %} {%- set reasoning_content = content.split('<think>')[1] %} {%- set content = '' %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- else %} {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- endif %} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments|length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' + args_name + '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments|trim|length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v11.jinja ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {%- set fn = tool.function if tool.function is defined else tool %}
70
+ {%- set props = {} %}
71
+ {%- set req = [] %}
72
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
73
+ {%- if fn.parameters.properties is defined %}
74
+ {%- set props = fn.parameters.properties %}
75
+ {%- endif %}
76
+ {%- if fn.parameters.required is defined %}
77
+ {%- set req = fn.parameters.required %}
78
+ {%- endif %}
79
+ {%- endif %}
80
+ {%- set ns_p = namespace(sig='') %}
81
+ {%- for pname in props %}
82
+ {%- set pdef = props[pname] %}
83
+ {%- set ptype = 'any' %}
84
+ {%- if pdef.type is defined %}
85
+ {%- if pdef.type == 'array' or pdef.type == 'object' %}
86
+ {%- set ptype = 'array|object' %}
87
+ {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %}
88
+ {%- set ptype = pdef.enum | join('|') %}
89
+ {%- else %}
90
+ {%- set ptype = pdef.type %}
91
+ {%- endif %}
92
+ {%- endif %}
93
+ {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %}
94
+ {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %}
95
+ {%- endfor %}
96
+ {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }}
97
+ {%- if fn.description is defined %}
98
+ {{- ' — ' ~ fn.description }}
99
+ {%- endif %}
100
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
101
+ {%- for pname in props %}
102
+ {%- set pdef = props[pname] %}
103
+ {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %}
104
+ {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }}
105
+ {%- endif %}
106
+ {%- endfor %}
107
+ {%- endif %}
108
+ {%- endfor %}
109
+ {{- "\n</tools>" }}
110
+ {{- '\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>' }}
111
+ {%- if has_system and system_content %}
112
+ {{- '\n\n' + system_content }}
113
+ {%- endif %}
114
+ {{- '<|im_end|>\n' }}
115
+ {%- elif has_system and system_content %}
116
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
117
+ {%- endif %}
118
+ {%- for message in messages %}
119
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
120
+ {%- set content = render_content(message.content, true, is_system)|trim %}
121
+ {%- if '<|think_off|>' in content %}
122
+ {%- set ns_flags.enable_thinking = false %}
123
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
124
+ {%- elif '<|think_on|>' in content %}
125
+ {%- set ns_flags.enable_thinking = true %}
126
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
127
+ {%- endif %}
128
+ {%- if is_system %}
129
+ {%- if not loop.first and content %}
130
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
131
+ {%- endif %}
132
+ {%- elif message.role == "user" %}
133
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
134
+ {%- elif message.role == "assistant" %}
135
+ {%- set reasoning_content = '' %}
136
+ {%- if message.reasoning_content is string %}
137
+ {%- set reasoning_content = message.reasoning_content %}
138
+ {%- else %}
139
+ {%- if '</think>' in content or '</thinking>' in content %}
140
+ {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %}
141
+ {%- set reasoning_parts = content.split(think_end_token) %}
142
+ {%- set reasoning_content = reasoning_parts[0] %}
143
+ {%- set content = reasoning_parts[1] %}
144
+ {%- if '<think>' in reasoning_content %}
145
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
146
+ {%- endif %}
147
+ {%- elif '<think>' in content %}
148
+ {%- if '<tool_call>' in content %}
149
+ {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %}
150
+ {%- set reasoning_parts = content.split('</think>') %}
151
+ {%- set reasoning_content = reasoning_parts[0] %}
152
+ {%- set content = reasoning_parts[1] %}
153
+ {%- if '<think>' in reasoning_content %}
154
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
155
+ {%- endif %}
156
+ {%- else %}
157
+ {%- set reasoning_content = content.split('<think>')[1] %}
158
+ {%- set content = '' %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+ {%- endif %}
162
+ {%- set reasoning_content = reasoning_content | trim %}
163
+ {%- set content = content | trim %}
164
+ {%- set show_think = false %}
165
+ {%- if reasoning_content %}
166
+ {%- if preserve_thinking is defined and preserve_thinking %}
167
+ {%- set show_think = true %}
168
+ {%- elif loop.last %}
169
+ {%- set show_think = true %}
170
+ {%- endif %}
171
+ {%- endif %}
172
+ {%- if show_think %}
173
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
174
+ {%- else %}
175
+ {{- '<|im_start|>' + message.role + '\n' + content }}
176
+ {%- endif %}
177
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
178
+ {%- for tool_call in message.tool_calls %}
179
+ {%- if tool_call.function is defined %}
180
+ {%- set tool_call = tool_call.function %}
181
+ {%- endif %}
182
+ {%- if loop.first and content %}
183
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
184
+ {%- else %}
185
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
186
+ {%- endif %}
187
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
188
+ {%- if tool_call.arguments|length > 0 %}
189
+ {%- for args_name in tool_call.arguments %}
190
+ {%- set args_value = tool_call.arguments[args_name] %}
191
+ {{- '<parameter=' + args_name + '>\n' }}
192
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
193
+ {{- args_value }}
194
+ {{- '\n</parameter>\n' }}
195
+ {%- endfor %}
196
+ {%- endif %}
197
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
198
+ {%- if tool_call.arguments|trim|length > 0 %}
199
+ {{- tool_call.arguments }}
200
+ {{- '\n' }}
201
+ {%- endif %}
202
+ {%- endif %}
203
+ {{- '</function>\n</tool_call>' }}
204
+ {%- endfor %}
205
+ {%- endif %}
206
+ {{- '<|im_end|>\n' }}
207
+ {%- elif message.role == "tool" %}
208
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
209
+ {{- '<|im_start|>user' }}
210
+ {%- endif %}
211
+ {{- '\n<tool_response>\n' }}
212
+ {{- content }}
213
+ {{- '\n</tool_response>' }}
214
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
215
+ {{- '<|im_end|>\n' }}
216
+ {%- elif loop.last %}
217
+ {{- '<|im_end|>\n' }}
218
+ {%- endif %}
219
+ {%- else %}
220
+ {{- raise_exception('Unexpected message role.') }}
221
+ {%- endif %}
222
+ {%- endfor %}
223
+ {%- if add_generation_prompt %}
224
+ {{- '<|im_start|>assistant\n' }}
225
+ {%- if ns_flags.enable_thinking is false %}
226
+ {{- '<think>\n\n</think>\n\n' }}
227
+ {%- else %}
228
+ {{- '<think>\n' }}
229
+ {%- endif %}
230
+ {%- endif %}
archive/qwen3.5/chat_template-v11_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {%- set fn = tool.function if tool.function is defined else tool %} {%- set props = {} %} {%- set req = [] %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- if fn.parameters.properties is defined %} {%- set props = fn.parameters.properties %} {%- endif %} {%- if fn.parameters.required is defined %} {%- set req = fn.parameters.required %} {%- endif %} {%- endif %} {%- set ns_p = namespace(sig='') %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- set ptype = 'any' %} {%- if pdef.type is defined %} {%- if pdef.type == 'array' or pdef.type == 'object' %} {%- set ptype = 'array|object' %} {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %} {%- set ptype = pdef.enum | join('|') %} {%- else %} {%- set ptype = pdef.type %} {%- endif %} {%- endif %} {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %} {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %} {%- endfor %} {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }} {%- if fn.description is defined %} {{- ' — ' ~ fn.description }} {%- endif %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %} {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }} {%- endif %} {%- endfor %} {%- endif %} {%- 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>' }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- if '</think>' in content or '</thinking>' in content %} {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- elif '<think>' in content %} {%- if '<tool_call>' in content %} {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %} {%- set reasoning_parts = content.split('</think>') %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- else %} {%- set reasoning_content = content.split('<think>')[1] %} {%- set content = '' %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- else %} {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- endif %} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments|length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' + args_name + '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments|trim|length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v12.jinja ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {%- set fn = tool.function if tool.function is defined else tool %}
70
+ {%- set props = {} %}
71
+ {%- set req = [] %}
72
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
73
+ {%- if fn.parameters.properties is defined %}
74
+ {%- set props = fn.parameters.properties %}
75
+ {%- endif %}
76
+ {%- if fn.parameters.required is defined %}
77
+ {%- set req = fn.parameters.required %}
78
+ {%- endif %}
79
+ {%- endif %}
80
+ {%- set ns_p = namespace(sig='') %}
81
+ {%- for pname in props %}
82
+ {%- set pdef = props[pname] %}
83
+ {%- set ptype = 'any' %}
84
+ {%- if pdef.type is defined %}
85
+ {%- if pdef.type == 'array' or pdef.type == 'object' %}
86
+ {%- set ptype = 'array|object' %}
87
+ {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %}
88
+ {%- set ptype = pdef.enum | join('|') %}
89
+ {%- else %}
90
+ {%- set ptype = pdef.type %}
91
+ {%- endif %}
92
+ {%- endif %}
93
+ {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %}
94
+ {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %}
95
+ {%- endfor %}
96
+ {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }}
97
+ {%- if fn.description is defined %}
98
+ {{- ' — ' ~ fn.description }}
99
+ {%- endif %}
100
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
101
+ {%- for pname in props %}
102
+ {%- set pdef = props[pname] %}
103
+ {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %}
104
+ {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }}
105
+ {%- elif pdef.description is defined and pdef.description is string %}
106
+ {{- '\n - ' ~ pname ~ ' description: ' ~ pdef.description }}
107
+ {%- endif %}
108
+ {%- endfor %}
109
+ {%- endif %}
110
+ {%- endfor %}
111
+ {{- "\n</tools>" }}
112
+ {%- set ns_scan = namespace(final_enable=ns_flags.enable_thinking) %}
113
+ {%- for message in messages %}
114
+ {%- set content_str = message.content | string %}
115
+ {%- if '<|think_off|>' in content_str %}
116
+ {%- set ns_scan.final_enable = false %}
117
+ {%- elif '<|think_on|>' in content_str %}
118
+ {%- set ns_scan.final_enable = true %}
119
+ {%- endif %}
120
+ {%- endfor %}
121
+ {%- if ns_scan.final_enable %}
122
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<think>\nBrief explanation of tool call\n</think>\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 MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>\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>' }}
123
+ {%- else %}
124
+ {{- '\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- 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>' }}
125
+ {%- endif %}
126
+ {%- if has_system and system_content %}
127
+ {{- '\n\n' + system_content }}
128
+ {%- endif %}
129
+ {{- '<|im_end|>\n' }}
130
+ {%- elif has_system and system_content %}
131
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
132
+ {%- endif %}
133
+ {%- for message in messages %}
134
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
135
+ {%- set content = render_content(message.content, true, is_system)|trim %}
136
+ {%- if '<|think_off|>' in content %}
137
+ {%- set ns_flags.enable_thinking = false %}
138
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
139
+ {%- elif '<|think_on|>' in content %}
140
+ {%- set ns_flags.enable_thinking = true %}
141
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
142
+ {%- endif %}
143
+ {%- if is_system %}
144
+ {%- if not loop.first and content %}
145
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
146
+ {%- endif %}
147
+ {%- elif message.role == "user" %}
148
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
149
+ {%- elif message.role == "assistant" %}
150
+ {%- set content = content | replace('</ think>', '</think>') | replace('< /think>', '</think>') | replace('</think >', '</think>') | replace('<think >', '<think>') | replace('< think>', '<think>') %}
151
+ {%- set reasoning_content = '' %}
152
+ {%- if message.reasoning_content is string %}
153
+ {%- set reasoning_content = message.reasoning_content %}
154
+ {%- else %}
155
+ {%- if '</think>' in content or '</thinking>' in content %}
156
+ {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %}
157
+ {%- set reasoning_parts = content.split(think_end_token) %}
158
+ {%- set reasoning_content = reasoning_parts[0] %}
159
+ {%- set content = reasoning_parts[1] %}
160
+ {%- if '<think>' in reasoning_content %}
161
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
162
+ {%- endif %}
163
+ {%- elif '<think>' in content %}
164
+ {%- if '<tool_call>' in content %}
165
+ {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %}
166
+ {%- set reasoning_parts = content.split('</think>') %}
167
+ {%- set reasoning_content = reasoning_parts[0] %}
168
+ {%- set content = reasoning_parts[1] %}
169
+ {%- if '<think>' in reasoning_content %}
170
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
171
+ {%- endif %}
172
+ {%- else %}
173
+ {%- set reasoning_content = content.split('<think>')[1] %}
174
+ {%- set content = '' %}
175
+ {%- endif %}
176
+ {%- endif %}
177
+ {%- endif %}
178
+ {%- set reasoning_content = reasoning_content | trim %}
179
+ {%- set content = content | trim %}
180
+ {%- set show_think = false %}
181
+ {%- if reasoning_content %}
182
+ {%- if preserve_thinking is defined and preserve_thinking %}
183
+ {%- set show_think = true %}
184
+ {%- elif loop.last %}
185
+ {%- set show_think = true %}
186
+ {%- endif %}
187
+ {%- endif %}
188
+ {%- if show_think %}
189
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
190
+ {%- else %}
191
+ {{- '<|im_start|>' + message.role + '\n' + content }}
192
+ {%- endif %}
193
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
194
+ {%- for tool_call in message.tool_calls %}
195
+ {%- if tool_call.function is defined %}
196
+ {%- set tool_call = tool_call.function %}
197
+ {%- endif %}
198
+ {%- if loop.first and content %}
199
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
200
+ {%- else %}
201
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
202
+ {%- endif %}
203
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
204
+ {%- if tool_call.arguments|length > 0 %}
205
+ {%- for args_name in tool_call.arguments %}
206
+ {%- set args_value = tool_call.arguments[args_name] %}
207
+ {{- '<parameter=' + args_name + '>\n' }}
208
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
209
+ {{- args_value }}
210
+ {{- '\n</parameter>\n' }}
211
+ {%- endfor %}
212
+ {%- endif %}
213
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
214
+ {%- if tool_call.arguments|trim|length > 0 %}
215
+ {{- tool_call.arguments }}
216
+ {{- '\n' }}
217
+ {%- endif %}
218
+ {%- endif %}
219
+ {{- '</function>\n</tool_call>' }}
220
+ {%- endfor %}
221
+ {%- endif %}
222
+ {{- '<|im_end|>\n' }}
223
+ {%- elif message.role == "tool" %}
224
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
225
+ {{- '<|im_start|>user' }}
226
+ {%- endif %}
227
+ {{- '\n<tool_response>\n' }}
228
+ {{- content }}
229
+ {{- '\n</tool_response>' }}
230
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
231
+ {{- '<|im_end|>\n' }}
232
+ {%- elif loop.last %}
233
+ {{- '<|im_end|>\n' }}
234
+ {%- endif %}
235
+ {%- else %}
236
+ {{- raise_exception('Unexpected message role.') }}
237
+ {%- endif %}
238
+ {%- endfor %}
239
+ {%- if add_generation_prompt %}
240
+ {{- '<|im_start|>assistant\n' }}
241
+ {%- if ns_flags.enable_thinking is false %}
242
+ {{- '<think>\n\n</think>\n\n' }}
243
+ {%- else %}
244
+ {{- '<think>\n' }}
245
+ {%- endif %}
246
+ {%- endif %}
archive/qwen3.5/chat_template-v12_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {%- set fn = tool.function if tool.function is defined else tool %} {%- set props = {} %} {%- set req = [] %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- if fn.parameters.properties is defined %} {%- set props = fn.parameters.properties %} {%- endif %} {%- if fn.parameters.required is defined %} {%- set req = fn.parameters.required %} {%- endif %} {%- endif %} {%- set ns_p = namespace(sig='', schema_blocks='') %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- set ptype = 'any' %} {%- if pdef.type is defined %} {%- if pdef.type == 'array' or pdef.type == 'object' %} {%- set ptype = 'array|object' %} {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %} {%- set ptype = pdef.enum | map('string') | join('|') %} {%- else %} {%- set ptype = pdef.type %} {%- endif %} {%- endif %} {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %} {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %} {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %} {%- set ns_p.schema_blocks = ns_p.schema_blocks ~ '\n - ' ~ pname ~ ' schema: ' ~ (pdef | tojson) %} {%- elif pdef.description is defined and pdef.description is string %} {%- set ns_p.schema_blocks = ns_p.schema_blocks ~ '\n - ' ~ pname ~ ' description: ' ~ pdef.description %} {%- endif %} {%- endfor %} {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }} {%- if fn.description is defined %} {{- ' — ' ~ fn.description }} {%- endif %} {{- ns_p.schema_blocks }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<think>Brief explanation of tool call</think><tool_call><function=example_function_name><parameter=example_parameter_1>value_1</parameter><parameter=example_parameter_2>This is the value for the second parameterthat can spanmultiple lines</parameter></function></tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- You MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '< /think>' in content %} {%- set think_end_token = '< /think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token, 1) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] if reasoning_parts | length > 1 else '' %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- elif '<think>' in content %} {%- if '<tool_call>' in content %} {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %} {%- set reasoning_parts = content.split('</think>') %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- else %} {%- set reasoning_content = content.split('<think>')[1] %} {%- set content = '' %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- else %} {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- endif %} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments|length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' + args_name + '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments|trim|length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v13.jinja ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <tool_call>
78
+ {"name": "tool_name", "arguments": {"arg_name": "value"}}
79
+ </tool_call>
80
+
81
+ <IMPORTANT>
82
+ Reminder:
83
+ - Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags
84
+ - Required parameters MUST be specified
85
+ {%- if ns_flags.enable_thinking %}
86
+ - You MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>
87
+ {%- endif %}
88
+ - 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
89
+ </IMPORTANT>
90
+ {%- endset %}
91
+ {{- '\n\n' ~ tool_instructions | trim }}
92
+ {%- if has_system and system_content %}
93
+ {{- '\n\n' + system_content }}
94
+ {%- endif %}
95
+ {{- '<|im_end|>\n' }}
96
+ {%- elif has_system and system_content %}
97
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
98
+ {%- endif %}
99
+ {%- for message in messages %}
100
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
101
+ {%- set content = render_content(message.content, true, is_system)|trim %}
102
+ {%- if '<|think_off|>' in content %}
103
+ {%- set ns_flags.enable_thinking = false %}
104
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
105
+ {%- elif '<|think_on|>' in content %}
106
+ {%- set ns_flags.enable_thinking = true %}
107
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
108
+ {%- endif %}
109
+ {%- if is_system %}
110
+ {%- if not loop.first and content %}
111
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
112
+ {%- endif %}
113
+ {%- elif message.role == "user" %}
114
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set reasoning_content = '' %}
117
+ {%- if message.reasoning_content is string %}
118
+ {%- set reasoning_content = message.reasoning_content %}
119
+ {%- else %}
120
+ {%- set think_end_token = '' %}
121
+ {%- if '</think>' in content %}
122
+ {%- set think_end_token = '</think>' %}
123
+ {%- elif '</thinking>' in content %}
124
+ {%- set think_end_token = '</thinking>' %}
125
+ {%- elif '</ think>' in content %}
126
+ {%- set think_end_token = '</ think>' %}
127
+ {%- elif '</think >' in content %}
128
+ {%- set think_end_token = '</think >' %}
129
+ {%- endif %}
130
+ {%- if think_end_token %}
131
+ {%- set reasoning_parts = content.split(think_end_token) %}
132
+ {%- set reasoning_content = reasoning_parts[0] %}
133
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
134
+ {%- if '<think>' in reasoning_content %}
135
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
136
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
137
+ {%- set content = r_prefix ~ '\n' ~ content %}
138
+ {%- endif %}
139
+ {%- elif '<think>' in content %}
140
+ {%- set prefix = content.split('<think>')[0] %}
141
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
142
+ {%- if '<tool_call>' in think_part %}
143
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
144
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
145
+ {%- else %}
146
+ {%- set reasoning_content = think_part %}
147
+ {%- set content = prefix %}
148
+ {%- endif %}
149
+ {%- endif %}
150
+ {%- endif %}
151
+ {%- set reasoning_content = reasoning_content | trim %}
152
+ {%- set content = content | trim %}
153
+ {%- set show_think = false %}
154
+ {%- if reasoning_content %}
155
+ {%- if preserve_thinking is defined and preserve_thinking %}
156
+ {%- set show_think = true %}
157
+ {%- elif loop.last %}
158
+ {%- set show_think = true %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+ {%- if show_think %}
162
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
163
+ {%- else %}
164
+ {{- '<|im_start|>' + message.role + '\n' + content }}
165
+ {%- endif %}
166
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
167
+ {%- for tool_call in message.tool_calls %}
168
+ {%- if tool_call.function is defined %}
169
+ {%- set tool_call = tool_call.function %}
170
+ {%- endif %}
171
+ {%- if loop.first and content %}
172
+ {{- '\n\n<tool_call>\n' }}
173
+ {%- else %}
174
+ {{- '\n<tool_call>\n' }}
175
+ {%- endif %}
176
+ {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }}
177
+ {{- '</tool_call>' }}
178
+ {%- endfor %}
179
+ {%- endif %}
180
+ {{- '<|im_end|>\n' }}
181
+ {%- elif message.role == "tool" %}
182
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
183
+ {{- '<|im_start|>user' }}
184
+ {%- endif %}
185
+ {{- '\n<tool_response>\n' }}
186
+ {{- content }}
187
+ {{- '\n</tool_response>' }}
188
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
189
+ {{- '<|im_end|>\n' }}
190
+ {%- elif loop.last %}
191
+ {{- '<|im_end|>\n' }}
192
+ {%- endif %}
193
+ {%- else %}
194
+ {{- raise_exception('Unexpected message role.') }}
195
+ {%- endif %}
196
+ {%- endfor %}
197
+ {%- if add_generation_prompt %}
198
+ {{- '<|im_start|>assistant\n' }}
199
+ {%- if ns_flags.enable_thinking is false %}
200
+ {{- '<think>\n\n</think>\n\n' }}
201
+ {%- else %}
202
+ {{- '<think>\n' }}
203
+ {%- endif %}
204
+ {%- endif %}
archive/qwen3.5/chat_template-v13_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified{%- if ns_flags.enable_thinking %}- You MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>{%- endif %}- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v14.jinja ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <tool_call>
78
+ {"name": "tool_name", "arguments": {"arg_name": "value"}}
79
+ </tool_call>
80
+
81
+ <IMPORTANT>
82
+ Reminder:
83
+ - Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags
84
+ - Required parameters MUST be specified
85
+ {%- if ns_flags.enable_thinking %}
86
+ - You MUST use the <think></think> block to reason about your actions, plan function calls, or synthesize results before providing your final response
87
+ {%- endif %}
88
+ - 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
89
+ </IMPORTANT>
90
+ {%- endset %}
91
+ {{- '\n\n' ~ tool_instructions | trim }}
92
+ {%- if has_system and system_content %}
93
+ {{- '\n\n' + system_content }}
94
+ {%- endif %}
95
+ {{- '<|im_end|>\n' }}
96
+ {%- elif has_system and system_content %}
97
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
98
+ {%- endif %}
99
+ {%- for message in messages %}
100
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
101
+ {%- set content = render_content(message.content, true, is_system)|trim %}
102
+ {%- if '<|think_off|>' in content %}
103
+ {%- set ns_flags.enable_thinking = false %}
104
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
105
+ {%- elif '<|think_on|>' in content %}
106
+ {%- set ns_flags.enable_thinking = true %}
107
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
108
+ {%- endif %}
109
+ {%- if is_system %}
110
+ {%- if not loop.first and content %}
111
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
112
+ {%- endif %}
113
+ {%- elif message.role == "user" %}
114
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set reasoning_content = '' %}
117
+ {%- if message.reasoning_content is string %}
118
+ {%- set reasoning_content = message.reasoning_content %}
119
+ {%- else %}
120
+ {%- set think_end_token = '' %}
121
+ {%- if '</think>' in content %}
122
+ {%- set think_end_token = '</think>' %}
123
+ {%- elif '</thinking>' in content %}
124
+ {%- set think_end_token = '</thinking>' %}
125
+ {%- elif '</ think>' in content %}
126
+ {%- set think_end_token = '</ think>' %}
127
+ {%- elif '</think >' in content %}
128
+ {%- set think_end_token = '</think >' %}
129
+ {%- endif %}
130
+ {%- if think_end_token %}
131
+ {%- set reasoning_parts = content.split(think_end_token) %}
132
+ {%- set reasoning_content = reasoning_parts[0] %}
133
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
134
+ {%- if '<think>' in reasoning_content %}
135
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
136
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
137
+ {%- set content = r_prefix ~ '\n' ~ content %}
138
+ {%- endif %}
139
+ {%- elif '<think>' in content %}
140
+ {%- set prefix = content.split('<think>')[0] %}
141
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
142
+ {%- if '<tool_call>' in think_part %}
143
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
144
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
145
+ {%- else %}
146
+ {%- set reasoning_content = think_part %}
147
+ {%- set content = prefix %}
148
+ {%- endif %}
149
+ {%- endif %}
150
+ {%- endif %}
151
+ {%- set reasoning_content = reasoning_content | trim %}
152
+ {%- set content = content | trim %}
153
+ {%- set is_tool_error = false %}
154
+ {%- if message.tool_calls and not loop.last and loop.nextitem is defined %}
155
+ {%- set next_role = loop.nextitem.role %}
156
+ {%- set next_content = loop.nextitem.content | string | lower %}
157
+ {%- if next_role == 'tool' or '<tool_response>' in next_content %}
158
+ {%- if 'error' in next_content or 'fail' in next_content or 'invalid' in next_content or 'exceeds' in next_content or 'retry loop' in next_content %}
159
+ {%- set is_tool_error = true %}
160
+ {%- endif %}
161
+ {%- endif %}
162
+ {%- endif %}
163
+ {%- set show_think = false %}
164
+ {%- if reasoning_content %}
165
+ {%- if preserve_thinking is defined and preserve_thinking %}
166
+ {%- set show_think = true %}
167
+ {%- elif loop.last or is_tool_error %}
168
+ {%- set show_think = true %}
169
+ {%- endif %}
170
+ {%- endif %}
171
+ {%- if show_think %}
172
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
173
+ {%- else %}
174
+ {{- '<|im_start|>' + message.role + '\n' + content }}
175
+ {%- endif %}
176
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
177
+ {%- for tool_call in message.tool_calls %}
178
+ {%- if tool_call.function is defined %}
179
+ {%- set tool_call = tool_call.function %}
180
+ {%- endif %}
181
+ {%- if loop.first and content %}
182
+ {{- '\n\n<tool_call>\n' }}
183
+ {%- else %}
184
+ {{- '\n<tool_call>\n' }}
185
+ {%- endif %}
186
+ {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }}
187
+ {{- '</tool_call>' }}
188
+ {%- endfor %}
189
+ {%- endif %}
190
+ {{- '<|im_end|>\n' }}
191
+ {%- elif message.role == "tool" %}
192
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
193
+ {{- '<|im_start|>user' }}
194
+ {%- endif %}
195
+ {{- '\n<tool_response>\n' }}
196
+ {{- content }}
197
+ {{- '\n</tool_response>' }}
198
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
199
+ {{- '<|im_end|>\n' }}
200
+ {%- elif loop.last %}
201
+ {{- '<|im_end|>\n' }}
202
+ {%- endif %}
203
+ {%- else %}
204
+ {{- raise_exception('Unexpected message role.') }}
205
+ {%- endif %}
206
+ {%- endfor %}
207
+ {%- if add_generation_prompt %}
208
+ {{- '<|im_start|>assistant\n' }}
209
+ {%- if ns_flags.enable_thinking is false %}
210
+ {{- '<think>\n\n</think>\n\n' }}
211
+ {%- else %}
212
+ {{- '<think>\n' }}
213
+ {%- endif %}
214
+ {%- endif %}
archive/qwen3.5/chat_template-v14_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified{%- if ns_flags.enable_thinking %}- You MUST use the <think></think> block to reason about your actions, plan function calls, or synthesize results before providing your final response{%- endif %}- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set is_tool_error = false %} {%- if message.tool_calls and not loop.last and loop.nextitem is defined %} {%- set next_role = loop.nextitem.role %} {%- set next_content = loop.nextitem.content | string | lower %} {%- if next_role == 'tool' or '<tool_response>' in next_content %} {%- if 'error' in next_content or 'fail' in next_content or 'invalid' in next_content or 'exceeds' in next_content or 'retry loop' in next_content %} {%- set is_tool_error = true %} {%- endif %} {%- endif %} {%- endif %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last or is_tool_error %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v15.jinja ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <tool_call>
78
+ {"name": "tool_name", "arguments": {"arg_name": "value"}}
79
+ </tool_call>
80
+
81
+ <IMPORTANT>
82
+ Reminder:
83
+ - Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags
84
+ - Required parameters MUST be specified
85
+ - Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response
86
+ - 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
87
+ </IMPORTANT>
88
+ {%- endset %}
89
+ {{- '\n\n' ~ tool_instructions | trim }}
90
+ {%- if has_system and system_content %}
91
+ {{- '\n\n' + system_content }}
92
+ {%- endif %}
93
+ {{- '<|im_end|>\n' }}
94
+ {%- elif has_system and system_content %}
95
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
96
+ {%- endif %}
97
+ {%- for message in messages %}
98
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
99
+ {%- set content = render_content(message.content, true, is_system)|trim %}
100
+ {%- if '<|think_off|>' in content %}
101
+ {%- set ns_flags.enable_thinking = false %}
102
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
103
+ {%- elif '<|think_on|>' in content %}
104
+ {%- set ns_flags.enable_thinking = true %}
105
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
106
+ {%- endif %}
107
+ {%- if is_system %}
108
+ {%- if not loop.first and content %}
109
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
110
+ {%- endif %}
111
+ {%- elif message.role == "user" %}
112
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
113
+ {%- set ns_flags.last_tool_failed = false %}
114
+ {%- set ns_flags.consecutive_failures = 0 %}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set ns_flags.last_tool_failed = false %}
117
+ {%- set ns_flags.consecutive_failures = 0 %}
118
+ {%- set reasoning_content = '' %}
119
+ {%- if message.reasoning_content is string %}
120
+ {%- set reasoning_content = message.reasoning_content %}
121
+ {%- else %}
122
+ {%- set think_end_token = '' %}
123
+ {%- if '</think>' in content %}
124
+ {%- set think_end_token = '</think>' %}
125
+ {%- elif '</thinking>' in content %}
126
+ {%- set think_end_token = '</thinking>' %}
127
+ {%- elif '</ think>' in content %}
128
+ {%- set think_end_token = '</ think>' %}
129
+ {%- elif '</think >' in content %}
130
+ {%- set think_end_token = '</think >' %}
131
+ {%- endif %}
132
+ {%- if think_end_token %}
133
+ {%- set reasoning_parts = content.split(think_end_token) %}
134
+ {%- set reasoning_content = reasoning_parts[0] %}
135
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
136
+ {%- if '<think>' in reasoning_content %}
137
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
138
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
139
+ {%- set content = r_prefix ~ '\n' ~ content %}
140
+ {%- endif %}
141
+ {%- elif '<think>' in content %}
142
+ {%- set prefix = content.split('<think>')[0] %}
143
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
144
+ {%- if '<tool_call>' in think_part %}
145
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
146
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
147
+ {%- else %}
148
+ {%- set reasoning_content = think_part %}
149
+ {%- set content = prefix %}
150
+ {%- endif %}
151
+ {%- endif %}
152
+ {%- endif %}
153
+ {%- set reasoning_content = reasoning_content | trim %}
154
+ {%- set content = content | trim %}
155
+ {%- set show_think = false %}
156
+ {%- if reasoning_content %}
157
+ {%- if preserve_thinking is defined and preserve_thinking %}
158
+ {%- set show_think = true %}
159
+ {%- elif loop.last %}
160
+ {%- set show_think = true %}
161
+ {%- endif %}
162
+ {%- endif %}
163
+ {%- if show_think %}
164
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
165
+ {%- else %}
166
+ {{- '<|im_start|>' + message.role + '\n' + content }}
167
+ {%- endif %}
168
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
169
+ {%- for tool_call in message.tool_calls %}
170
+ {%- if tool_call.function is defined %}
171
+ {%- set tool_call = tool_call.function %}
172
+ {%- endif %}
173
+ {%- if loop.first and content %}
174
+ {{- '\n\n<tool_call>\n' }}
175
+ {%- else %}
176
+ {{- '\n<tool_call>\n' }}
177
+ {%- endif %}
178
+ {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }}
179
+ {{- '</tool_call>' }}
180
+ {%- endfor %}
181
+ {%- endif %}
182
+ {{- '<|im_end|>\n' }}
183
+ {%- elif message.role == "tool" %}
184
+ {%- set content_lower = content | lower %}
185
+ {%- if content | length < 500 and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %}
186
+ {%- set ns_flags.last_tool_failed = true %}
187
+ {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}
188
+ {%- else %}
189
+ {%- set ns_flags.last_tool_failed = false %}
190
+ {%- set ns_flags.consecutive_failures = 0 %}
191
+ {%- endif %}
192
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
193
+ {{- '<|im_start|>user' }}
194
+ {%- endif %}
195
+ {{- '\n<tool_response>\n' }}
196
+ {{- content }}
197
+ {{- '\n</tool_response>' }}
198
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
199
+ {{- '<|im_end|>\n' }}
200
+ {%- elif loop.last %}
201
+ {{- '<|im_end|>\n' }}
202
+ {%- endif %}
203
+ {%- else %}
204
+ {{- raise_exception('Unexpected message role.') }}
205
+ {%- endif %}
206
+ {%- endfor %}
207
+ {%- if add_generation_prompt %}
208
+ {{- '<|im_start|>assistant\n' }}
209
+ {%- if ns_flags.last_tool_failed %}
210
+ {%- if ns_flags.consecutive_failures >= 2 %}
211
+ {{- '<think>\n\n</think>\n\n⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }}
212
+ {%- else %}
213
+ {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }}
214
+ {%- endif %}
215
+ {%- elif ns_flags.enable_thinking is false %}
216
+ {{- '<think>\n\n</think>\n\n' }}
217
+ {%- else %}
218
+ {{- '<think>\n' }}
219
+ {%- endif %}
220
+ {%- endif %}
archive/qwen3.5/chat_template-v15_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- elif message.role == "assistant" %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- set content_lower = content | lower %} {%- if content | length < 500 and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %} {%- set ns_flags.last_tool_failed = true %} {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %} {%- else %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- endif %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.last_tool_failed %} {%- if ns_flags.consecutive_failures >= 2 %} {{- '<think>\n\n</think>\n\n⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }} {%- else %} {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }} {%- endif %} {%- elif ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v16.jinja ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <think>
78
+ Brief explanation of tool call
79
+ </think>
80
+
81
+ <tool_call>
82
+ <function=example_function_name>
83
+ <parameter=example_parameter_1>
84
+ value_1
85
+ </parameter>
86
+ <parameter=example_parameter_2>
87
+ This is the value for the second parameter
88
+ that can span
89
+ multiple lines
90
+ </parameter>
91
+ </function>
92
+ </tool_call>
93
+
94
+ <IMPORTANT>
95
+ Reminder:
96
+ - Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags
97
+ - Required parameters MUST be specified
98
+ - Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response
99
+ - 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
100
+ </IMPORTANT>
101
+ {%- endset %}
102
+ {{- '\n\n' ~ tool_instructions | trim }}
103
+ {%- if has_system and system_content %}
104
+ {{- '\n\n' + system_content }}
105
+ {%- endif %}
106
+ {{- '<|im_end|>\n' }}
107
+ {%- elif has_system and system_content %}
108
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
109
+ {%- endif %}
110
+ {%- for message in messages %}
111
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
112
+ {%- set content = render_content(message.content, true, is_system)|trim %}
113
+ {%- if '<|think_off|>' in content %}
114
+ {%- set ns_flags.enable_thinking = false %}
115
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
116
+ {%- elif '<|think_on|>' in content %}
117
+ {%- set ns_flags.enable_thinking = true %}
118
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
119
+ {%- endif %}
120
+ {%- if is_system %}
121
+ {%- if not loop.first and content %}
122
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
123
+ {%- endif %}
124
+ {%- elif message.role == "user" %}
125
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
126
+ {%- set ns_flags.last_tool_failed = false %}
127
+ {%- set ns_flags.consecutive_failures = 0 %}
128
+ {%- elif message.role == "assistant" %}
129
+ {%- set ns_flags.last_tool_failed = false %}
130
+ {%- set reasoning_content = '' %}
131
+ {%- if message.reasoning_content is string %}
132
+ {%- set reasoning_content = message.reasoning_content %}
133
+ {%- else %}
134
+ {%- set think_end_token = '' %}
135
+ {%- if '</think>' in content %}
136
+ {%- set think_end_token = '</think>' %}
137
+ {%- elif '</thinking>' in content %}
138
+ {%- set think_end_token = '</thinking>' %}
139
+ {%- elif '</ think>' in content %}
140
+ {%- set think_end_token = '</ think>' %}
141
+ {%- elif '</think >' in content %}
142
+ {%- set think_end_token = '</think >' %}
143
+ {%- endif %}
144
+ {%- if think_end_token %}
145
+ {%- set reasoning_parts = content.split(think_end_token) %}
146
+ {%- set reasoning_content = reasoning_parts[0] %}
147
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
148
+ {%- if '<think>' in reasoning_content %}
149
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
150
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
151
+ {%- set content = r_prefix ~ '\n' ~ content %}
152
+ {%- endif %}
153
+ {%- elif '<think>' in content %}
154
+ {%- set prefix = content.split('<think>')[0] %}
155
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
156
+ {%- if '<tool_call>' in think_part %}
157
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
158
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
159
+ {%- else %}
160
+ {%- set reasoning_content = think_part %}
161
+ {%- set content = prefix %}
162
+ {%- endif %}
163
+ {%- endif %}
164
+ {%- endif %}
165
+ {%- set reasoning_content = reasoning_content | trim %}
166
+ {%- set content = content | trim %}
167
+ {%- set show_think = false %}
168
+ {%- if reasoning_content %}
169
+ {%- if preserve_thinking is defined and preserve_thinking %}
170
+ {%- set show_think = true %}
171
+ {%- elif loop.last %}
172
+ {%- set show_think = true %}
173
+ {%- endif %}
174
+ {%- endif %}
175
+ {%- if show_think %}
176
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
177
+ {%- else %}
178
+ {{- '<|im_start|>' + message.role + '\n' + content }}
179
+ {%- endif %}
180
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
181
+ {%- for tool_call in message.tool_calls %}
182
+ {%- if tool_call.function is defined %}
183
+ {%- set tool_call = tool_call.function %}
184
+ {%- endif %}
185
+ {%- if loop.first and content %}
186
+ {{- '\n\n<tool_call>\n' }}
187
+ {%- else %}
188
+ {{- '\n<tool_call>\n' }}
189
+ {%- endif %}
190
+ {{- '<function=' ~ tool_call.name ~ '>\n' }}
191
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
192
+ {%- if tool_call.arguments | length > 0 %}
193
+ {%- for args_name in tool_call.arguments %}
194
+ {%- set args_value = tool_call.arguments[args_name] %}
195
+ {{- '<parameter=' ~ args_name ~ '>\n' }}
196
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
197
+ {{- args_value }}
198
+ {{- '\n</parameter>\n' }}
199
+ {%- endfor %}
200
+ {%- endif %}
201
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
202
+ {%- if tool_call.arguments | trim | length > 0 %}
203
+ {{- tool_call.arguments }}
204
+ {{- '\n' }}
205
+ {%- endif %}
206
+ {%- endif %}
207
+ {{- '</function>\n</tool_call>' }}
208
+ {%- endfor %}
209
+ {%- endif %}
210
+ {{- '<|im_end|>\n' }}
211
+ {%- elif message.role == "tool" %}
212
+ {%- set content_lower = content | lower %}
213
+ {%- if content | length < 500
214
+ and '$ ' not in content
215
+ and 'took ' not in content_lower
216
+ and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %}
217
+ {%- set ns_flags.last_tool_failed = true %}
218
+ {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}
219
+ {%- else %}
220
+ {%- set ns_flags.last_tool_failed = false %}
221
+ {%- set ns_flags.consecutive_failures = 0 %}
222
+ {%- endif %}
223
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
224
+ {{- '<|im_start|>user' }}
225
+ {%- endif %}
226
+ {{- '\n<tool_response>\n' }}
227
+ {{- content }}
228
+ {{- '\n</tool_response>' }}
229
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
230
+ {{- '<|im_end|>\n' }}
231
+ {%- elif loop.last %}
232
+ {{- '<|im_end|>\n' }}
233
+ {%- endif %}
234
+ {%- else %}
235
+ {{- raise_exception('Unexpected message role.') }}
236
+ {%- endif %}
237
+ {%- endfor %}
238
+ {%- if add_generation_prompt %}
239
+ {{- '<|im_start|>assistant\n' }}
240
+ {%- if ns_flags.last_tool_failed %}
241
+ {%- if ns_flags.consecutive_failures >= 2 %}
242
+ {%- if ns_flags.enable_thinking is not false %}
243
+ {{- '<think>\n\n</think>\n\n' }}
244
+ {%- endif %}
245
+ {{- '⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }}
246
+ {%- else %}
247
+ {%- if ns_flags.enable_thinking is not false %}
248
+ {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }}
249
+ {%- else %}
250
+ {{- 'The previous tool call returned an error. I must retry with completely corrected arguments:\n\n' }}
251
+ {%- endif %}
252
+ {%- endif %}
253
+ {%- elif ns_flags.enable_thinking is false %}
254
+ {{- '<think>\n\n</think>\n\n' }}
255
+ {%- else %}
256
+ {{- '<think>\n' }}
257
+ {%- endif %}
258
+ {%- endif %}
archive/qwen3.5/chat_template-v16_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- elif message.role == "assistant" %} {%- set ns_flags.last_tool_failed = false %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- set content_lower = content | lower %} {%- if content | length < 500 and '$ ' not in content and 'took ' not in content_lower and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %} {%- set ns_flags.last_tool_failed = true %} {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %} {%- else %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- endif %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.last_tool_failed %} {%- if ns_flags.consecutive_failures >= 2 %} {%- if ns_flags.enable_thinking is not false %} {{- '<think>\n\n</think>\n\n' }} {%- endif %} {{- '⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }} {%- else %} {%- if ns_flags.enable_thinking is not false %} {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }} {%- else %} {{- 'The previous tool call returned an error. I must retry with completely corrected arguments:\n\n' }} {%- endif %} {%- endif %} {%- elif ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.5/chat_template-v8.jinja ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- if tools and tools is iterable and tools is not mapping %}
50
+ {{- '<|im_start|>system\n' }}
51
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
52
+ {%- for tool in tools %}
53
+ {{- "\n" }}
54
+ {{- tool | tojson }}
55
+ {%- endfor %}
56
+ {{- "\n</tools>" }}
57
+ {{- '\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>' }}
58
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
59
+ {%- set content = render_content(messages[0].content, false, true)|trim %}
60
+ {%- if '<|think_off|>' in content %}
61
+ {%- set ns_flags.enable_thinking = false %}
62
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
63
+ {%- elif '<|think_on|>' in content %}
64
+ {%- set ns_flags.enable_thinking = true %}
65
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
66
+ {%- endif %}
67
+ {%- if content %}
68
+ {{- '\n\n' + content }}
69
+ {%- endif %}
70
+ {%- endif %}
71
+ {{- '<|im_end|>\n' }}
72
+ {%- else %}
73
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
74
+ {%- set content = render_content(messages[0].content, false, true)|trim %}
75
+ {%- if '<|think_off|>' in content %}
76
+ {%- set ns_flags.enable_thinking = false %}
77
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
78
+ {%- elif '<|think_on|>' in content %}
79
+ {%- set ns_flags.enable_thinking = true %}
80
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
81
+ {%- endif %}
82
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
83
+ {%- endif %}
84
+ {%- endif %}
85
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
86
+ {%- for message in messages[::-1] %}
87
+ {%- set index = (messages|length - 1) - loop.index0 %}
88
+ {%- if ns.multi_step_tool and message.role == "user" %}
89
+ {%- set content = render_content(message.content, false)|trim %}
90
+ {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
91
+ {%- set ns.multi_step_tool = false %}
92
+ {%- set ns.last_query_index = index %}
93
+ {%- endif %}
94
+ {%- endif %}
95
+ {%- endfor %}
96
+ {%- if ns.multi_step_tool %}
97
+ {%- set ns.last_query_index = messages|length - 1 %}
98
+ {%- endif %}
99
+ {%- for message in messages %}
100
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
101
+ {%- set content = render_content(message.content, true, is_system)|trim %}
102
+ {%- if '<|think_off|>' in content %}
103
+ {%- set ns_flags.enable_thinking = false %}
104
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
105
+ {%- elif '<|think_on|>' in content %}
106
+ {%- set ns_flags.enable_thinking = true %}
107
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
108
+ {%- endif %}
109
+ {%- if is_system %}
110
+ {%- if not loop.first and content %}
111
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
112
+ {%- endif %}
113
+ {%- elif message.role == "user" %}
114
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set reasoning_content = '' %}
117
+ {%- if message.reasoning_content is string %}
118
+ {%- set reasoning_content = message.reasoning_content %}
119
+ {%- else %}
120
+ {%- if '</think>' in content %}
121
+ {%- set reasoning_content = content.split('</think>')[0].split('<think>')[-1] %}
122
+ {%- set content = content.split('</think>')[-1] %}
123
+ {%- if reasoning_content.endswith('\n') %}
124
+ {%- set reasoning_content = reasoning_content[:-1] %}
125
+ {%- endif %}
126
+ {%- if reasoning_content.startswith('\n') %}
127
+ {%- set reasoning_content = reasoning_content[1:] %}
128
+ {%- endif %}
129
+ {%- if content.startswith('\n') %}
130
+ {%- set content = content[1:] %}
131
+ {%- endif %}
132
+ {%- elif '<think>' in content %}
133
+ {#- Auto-close unclosed think before tool_call (compatibility-safe: no rfind/slice) -#}
134
+ {%- set think_part = content.split('<think>')[-1] %}
135
+ {%- if '<tool_call>' in think_part %}
136
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
137
+ {%- set content = '<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
138
+ {%- else %}
139
+ {%- set reasoning_content = think_part %}
140
+ {%- set content = '' %}
141
+ {%- endif %}
142
+ {#- Ensure reasoning_content doesn't have leading whitespace like newlines -#}
143
+ {%- if reasoning_content.startswith('\n') %}
144
+ {%- set reasoning_content = reasoning_content[1:] %}
145
+ {%- endif %}
146
+ {%- endif %}
147
+ {%- endif %}
148
+ {%- set reasoning_content = reasoning_content|trim %}
149
+ {%- if loop.index0 > ns.last_query_index %}
150
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
151
+ {%- else %}
152
+ {{- '<|im_start|>' + message.role + '\n' + content }}
153
+ {%- endif %}
154
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
155
+ {%- for tool_call in message.tool_calls %}
156
+ {%- if tool_call.function is defined %}
157
+ {%- set tool_call = tool_call.function %}
158
+ {%- endif %}
159
+ {%- if loop.first %}
160
+ {%- if content|trim %}
161
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
162
+ {%- else %}
163
+ {{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
164
+ {%- endif %}
165
+ {%- else %}
166
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
167
+ {%- endif %}
168
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
169
+ {%- if tool_call.arguments|length > 0 %}
170
+ {%- for args_name in tool_call.arguments %}
171
+ {%- set args_value = tool_call.arguments[args_name] %}
172
+ {{- '<parameter=' + args_name + '>\n' }}
173
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
174
+ {{- args_value }}
175
+ {{- '\n</parameter>\n' }}
176
+ {%- endfor %}
177
+ {%- endif %}
178
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
179
+ {%- if tool_call.arguments|trim|length > 0 %}
180
+ {{- tool_call.arguments }}
181
+ {{- '\n' }}
182
+ {%- endif %}
183
+ {%- endif %}
184
+ {{- '</function>\n</tool_call>' }}
185
+ {%- endfor %}
186
+ {%- endif %}
187
+ {{- '<|im_end|>\n' }}
188
+ {%- elif message.role == "tool" %}
189
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
190
+ {{- '<|im_start|>user' }}
191
+ {%- endif %}
192
+ {{- '\n<tool_response>\n' }}
193
+ {{- content }}
194
+ {{- '\n</tool_response>' }}
195
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
196
+ {{- '<|im_end|>\n' }}
197
+ {%- elif loop.last %}
198
+ {{- '<|im_end|>\n' }}
199
+ {%- endif %}
200
+ {%- else %}
201
+ {{- raise_exception('Unexpected message role.') }}
202
+ {%- endif %}
203
+ {%- endfor %}
204
+ {%- if add_generation_prompt %}
205
+ {{- '<|im_start|>assistant\n' }}
206
+ {%- if ns_flags.enable_thinking is false %}
207
+ {{- '<think>\n\n</think>\n\n' }}
208
+ {%- else %}
209
+ {{- '<think>\n' }}
210
+ {%- endif %}
211
+ {%- endif %}
archive/qwen3.5/chat_template-v8_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ "{%- set image_count = namespace(value=0) %}\n{%- set video_count = namespace(value=0) %}\n{%- macro render_content(content, do_vision_count, is_system_content=false) %}\n {%- if content is string %}\n {{- content }}\n {%- elif content is iterable and content is not mapping %}\n {%- for item in content %}\n {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain images.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id is defined and add_vision_id %}\n {{- 'Picture ' ~ image_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|image_pad|><|vision_end|>' }}\n {%- elif 'video' in item or item.type == 'video' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain videos.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id is defined and add_vision_id %}\n {{- 'Video ' ~ video_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|video_pad|><|vision_end|>' }}\n {%- elif 'text' in item %}\n {{- item.text }}\n {%- else %}\n {{- raise_exception('Unexpected item type in content.') }}\n {%- endif %}\n {%- endfor %}\n {%- elif content is none or content is undefined %}\n {{- '' }}\n {%- else %}\n {{- raise_exception('Unexpected content type.') }}\n {%- endif %}\n{%- endmacro %}\n{%- set ns_flags = namespace(enable_thinking=true) %}\n{%- if enable_thinking is defined %}\n {%- set ns_flags.enable_thinking = enable_thinking %}\n{%- endif %}\n{%- if not messages %}\n {{- raise_exception('No messages provided.') }}\n{%- endif %}\n{%- if tools and tools is iterable and tools is not mapping %}\n {{- '<|im_start|>system\\n' }}\n {{- \"# Tools\\n\\nYou have access to the following functions:\\n\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n</tools>\" }}\n {{- '\\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>' }}\n {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}\n {%- set content = render_content(messages[0].content, false, true)|trim %}\n {%- if '<|think_off|>' in content %}\n {%- set ns_flags.enable_thinking = false %}\n {%- set content = content | replace('<|think_off|>', '') | trim %}\n {%- elif '<|think_on|>' in content %}\n {%- set ns_flags.enable_thinking = true %}\n {%- set content = content | replace('<|think_on|>', '') | trim %}\n {%- endif %}\n {%- if content %}\n {{- '\\n\\n' + content }}\n {%- endif %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n{%- else %}\n {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}\n {%- set content = render_content(messages[0].content, false, true)|trim %}\n {%- if '<|think_off|>' in content %}\n {%- set ns_flags.enable_thinking = false %}\n {%- set content = content | replace('<|think_off|>', '') | trim %}\n {%- elif '<|think_on|>' in content %}\n {%- set ns_flags.enable_thinking = true %}\n {%- set content = content | replace('<|think_on|>', '') | trim %}\n {%- endif %}\n {{- '<|im_start|>system\\n' + content + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- if ns.multi_step_tool and message.role == \"user\" %}\n {%- set content = render_content(message.content, false)|trim %}\n {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if ns.multi_step_tool %}\n {%- set ns.last_query_index = messages|length - 1 %}\n{%- endif %}\n{%- for message in messages %}\n {%- set is_system = (message.role == \"system\" or message.role == \"developer\") %}\n {%- set content = render_content(message.content, true, is_system)|trim %}\n {%- if '<|think_off|>' in content %}\n {%- set ns_flags.enable_thinking = false %}\n {%- set content = content | replace('<|think_off|>', '') | trim %}\n {%- elif '<|think_on|>' in content %}\n {%- set ns_flags.enable_thinking = true %}\n {%- set content = content | replace('<|think_on|>', '') | trim %}\n {%- endif %}\n {%- if is_system %}\n {%- if not loop.first and content %}\n {{- '<|im_start|>system\\n' + content + '<|im_end|>\\n' }}\n {%- endif %}\n {%- elif message.role == \"user\" %}\n {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is string %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- else %}\n {%- if '</think>' in content %}\n {%- set reasoning_content = content.split('</think>')[0].split('<think>')[-1] %}\n {%- set content = content.split('</think>')[-1] %}\n {%- if reasoning_content.endswith('\\n') %}\n {%- set reasoning_content = reasoning_content[:-1] %}\n {%- endif %}\n {%- if reasoning_content.startswith('\\n') %}\n {%- set reasoning_content = reasoning_content[1:] %}\n {%- endif %}\n {%- if content.startswith('\\n') %}\n {%- set content = content[1:] %}\n {%- endif %}\n {%- elif '<think>' in content %}\n {#- Auto-close unclosed think before tool_call (compatibility-safe: no rfind/slice) -#}\n {%- set think_part = content.split('<think>')[-1] %}\n {%- if '<tool_call>' in think_part %}\n {%- set reasoning_content = think_part.split('<tool_call>')[0] %}\n {%- set content = '<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}\n {%- else %}\n {%- set reasoning_content = think_part %}\n {%- set content = '' %}\n {%- endif %}\n {#- Ensure reasoning_content doesn't have leading whitespace like newlines -#}\n {%- if reasoning_content.startswith('\\n') %}\n {%- set reasoning_content = reasoning_content[1:] %}\n {%- endif %}\n {%- endif %}\n {%- endif %}\n {%- set reasoning_content = reasoning_content|trim %}\n {%- if loop.index0 > ns.last_query_index %}\n {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content + '\\n</think>\\n\\n' + content }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {%- if loop.first %}\n {%- if content|trim %}\n {{- '\\n\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- else %}\n {{- '<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- endif %}\n {%- else %}\n {{- '\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- endif %}\n {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}\n {%- if tool_call.arguments|length > 0 %}\n {%- for args_name in tool_call.arguments %}\n {%- set args_value = tool_call.arguments[args_name] %}\n {{- '<parameter=' + args_name + '>\\n' }}\n {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}\n {{- args_value }}\n {{- '\\n</parameter>\\n' }}\n {%- endfor %}\n {%- endif %}\n {%- elif tool_call.arguments is defined and tool_call.arguments is string %}\n {%- if tool_call.arguments|trim|length > 0 %}\n {{- tool_call.arguments }}\n {{- '\\n' }}\n {%- endif %}\n {%- endif %}\n {{- '</function>\\n</tool_call>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- content }}\n {{- '\\n</tool_response>' }}\n {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n {{- '<|im_end|>\\n' }}\n {%- elif loop.last %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- else %}\n {{- raise_exception('Unexpected message role.') }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if ns_flags.enable_thinking is false %}\n {{- '<think>\\n\\n</think>\\n\\n' }}\n {%- else %}\n {{- '<think>\\n' }}\n {%- endif %}\n{%- endif %}"
archive/qwen3.5/chat_template-v9.jinja ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {{- '<|im_start|>system\n' }}
66
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
67
+ {%- for tool in tools %}
68
+ {{- "\n" }}
69
+ {{- tool | tojson }}
70
+ {%- endfor %}
71
+ {{- "\n</tools>" }}
72
+ {%- set ns_scan = namespace(final_enable=ns_flags.enable_thinking) %}
73
+ {%- for message in messages %}
74
+ {%- set content_str = message.content | string %}
75
+ {%- if '<|think_off|>' in content_str %}
76
+ {%- set ns_scan.final_enable = false %}
77
+ {%- elif '<|think_on|>' in content_str %}
78
+ {%- set ns_scan.final_enable = true %}
79
+ {%- endif %}
80
+ {%- endfor %}
81
+ {%- if ns_scan.final_enable %}
82
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<think>\nBrief explanation of tool call\n</think>\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 MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>\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>' }}
83
+ {%- else %}
84
+ {{- '\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- 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>' }}
85
+ {%- endif %}
86
+ {%- if has_system and system_content %}
87
+ {{- '\n\n' + system_content }}
88
+ {%- endif %}
89
+ {{- '<|im_end|>\n' }}
90
+ {%- elif has_system and system_content %}
91
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
92
+ {%- endif %}
93
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
94
+ {%- for message in messages[::-1] %}
95
+ {%- set index = (messages|length - 1) - loop.index0 %}
96
+ {%- if ns.multi_step_tool and message.role == "user" %}
97
+ {%- set content = render_content(message.content, false)|trim %}
98
+ {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}
99
+ {%- set ns.multi_step_tool = false %}
100
+ {%- set ns.last_query_index = index %}
101
+ {%- endif %}
102
+ {%- endif %}
103
+ {%- endfor %}
104
+ {%- if ns.multi_step_tool %}
105
+ {%- set ns.last_query_index = messages|length - 1 %}
106
+ {%- endif %}
107
+ {%- for message in messages %}
108
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
109
+ {%- set content = render_content(message.content, true, is_system)|trim %}
110
+ {%- if '<|think_off|>' in content %}
111
+ {%- set ns_flags.enable_thinking = false %}
112
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
113
+ {%- elif '<|think_on|>' in content %}
114
+ {%- set ns_flags.enable_thinking = true %}
115
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
116
+ {%- endif %}
117
+ {%- if is_system %}
118
+ {%- if not loop.first and content %}
119
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
120
+ {%- endif %}
121
+ {%- elif message.role == "user" %}
122
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
123
+ {%- elif message.role == "assistant" %}
124
+ {%- set reasoning_content = '' %}
125
+ {%- if message.reasoning_content is string %}
126
+ {%- set reasoning_content = message.reasoning_content %}
127
+ {%- else %}
128
+ {%- if '</think>' in content %}
129
+ {%- set reasoning_content = content.split('</think>')[0].split('<think>')[-1] %}
130
+ {%- set content = content.split('</think>')[-1] %}
131
+ {%- if reasoning_content.endswith('\n') %}
132
+ {%- set reasoning_content = reasoning_content[:-1] %}
133
+ {%- endif %}
134
+ {%- if reasoning_content.startswith('\n') %}
135
+ {%- set reasoning_content = reasoning_content[1:] %}
136
+ {%- endif %}
137
+ {%- if content.startswith('\n') %}
138
+ {%- set content = content[1:] %}
139
+ {%- endif %}
140
+ {%- elif '<think>' in content %}
141
+ {#- Auto-close unclosed think before tool_call (compatibility-safe: no rfind/slice) -#}
142
+ {%- set think_part = content.split('<think>')[-1] %}
143
+ {%- if '<tool_call>' in think_part %}
144
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
145
+ {%- set content = '<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
146
+ {%- else %}
147
+ {%- set reasoning_content = think_part %}
148
+ {%- set content = '' %}
149
+ {%- endif %}
150
+ {#- Ensure reasoning_content doesn't have leading whitespace like newlines -#}
151
+ {%- if reasoning_content.startswith('\n') %}
152
+ {%- set reasoning_content = reasoning_content[1:] %}
153
+ {%- endif %}
154
+ {%- endif %}
155
+ {%- endif %}
156
+ {%- set reasoning_content = reasoning_content|trim %}
157
+ {%- if loop.index0 > ns.last_query_index %}
158
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
159
+ {%- else %}
160
+ {{- '<|im_start|>' + message.role + '\n' + content }}
161
+ {%- endif %}
162
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
163
+ {%- for tool_call in message.tool_calls %}
164
+ {%- if tool_call.function is defined %}
165
+ {%- set tool_call = tool_call.function %}
166
+ {%- endif %}
167
+ {%- if loop.first %}
168
+ {%- if content|trim %}
169
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
170
+ {%- else %}
171
+ {{- '<tool_call>\n<function=' + tool_call.name + '>\n' }}
172
+ {%- endif %}
173
+ {%- else %}
174
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
175
+ {%- endif %}
176
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
177
+ {%- if tool_call.arguments|length > 0 %}
178
+ {%- for args_name in tool_call.arguments %}
179
+ {%- set args_value = tool_call.arguments[args_name] %}
180
+ {{- '<parameter=' + args_name + '>\n' }}
181
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
182
+ {{- args_value }}
183
+ {{- '\n</parameter>\n' }}
184
+ {%- endfor %}
185
+ {%- endif %}
186
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
187
+ {%- if tool_call.arguments|trim|length > 0 %}
188
+ {{- tool_call.arguments }}
189
+ {{- '\n' }}
190
+ {%- endif %}
191
+ {%- endif %}
192
+ {{- '</function>\n</tool_call>' }}
193
+ {%- endfor %}
194
+ {%- endif %}
195
+ {{- '<|im_end|>\n' }}
196
+ {%- elif message.role == "tool" %}
197
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
198
+ {{- '<|im_start|>user' }}
199
+ {%- endif %}
200
+ {{- '\n<tool_response>\n' }}
201
+ {{- content }}
202
+ {{- '\n</tool_response>' }}
203
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
204
+ {{- '<|im_end|>\n' }}
205
+ {%- elif loop.last %}
206
+ {{- '<|im_end|>\n' }}
207
+ {%- endif %}
208
+ {%- else %}
209
+ {{- raise_exception('Unexpected message role.') }}
210
+ {%- endif %}
211
+ {%- endfor %}
212
+ {%- if add_generation_prompt %}
213
+ {{- '<|im_start|>assistant\n' }}
214
+ {%- if ns_flags.enable_thinking is false %}
215
+ {{- '<think>\n\n</think>\n\n' }}
216
+ {%- else %}
217
+ {{- '<think>\n' }}
218
+ {%- endif %}
219
+ {%- endif %}
archive/qwen3.5/chat_template-v9_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}\n{%- set video_count = namespace(value=0) %}\n{%- macro render_content(content, do_vision_count, is_system_content=false) %}\n {%- if content is string %}\n {{- content }}\n {%- elif content is iterable and content is not mapping %}\n {%- for item in content %}\n {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain images.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id is defined and add_vision_id %}\n {{- 'Picture ' ~ image_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|image_pad|><|vision_end|>' }}\n {%- elif 'video' in item or item.type == 'video' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain videos.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id is defined and add_vision_id %}\n {{- 'Video ' ~ video_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|video_pad|><|vision_end|>' }}\n {%- elif 'text' in item %}\n {{- item.text }}\n {%- else %}\n {{- raise_exception('Unexpected item type in content.') }}\n {%- endif %}\n {%- endfor %}\n {%- elif content is none or content is undefined %}\n {{- '' }}\n {%- else %}\n {{- raise_exception('Unexpected content type.') }}\n {%- endif %}\n{%- endmacro %}\n{%- set ns_flags = namespace(enable_thinking=true) %}\n{%- if enable_thinking is defined %}\n {%- set ns_flags.enable_thinking = enable_thinking %}\n{%- endif %}\n{%- if not messages %}\n {{- raise_exception('No messages provided.') }}\n{%- endif %}\n{%- set system_content = '' %}\n{%- set has_system = false %}\n{%- if messages[0].role == 'system' or messages[0].role == 'developer' %}\n {%- set has_system = true %}\n {%- set system_content = render_content(messages[0].content, false, true)|trim %}\n {%- if '<|think_off|>' in system_content %}\n {%- set ns_flags.enable_thinking = false %}\n {%- set system_content = system_content | replace('<|think_off|>', '') %}\n {%- endif %}\n {%- if '<|think_on|>' in system_content %}\n {%- set ns_flags.enable_thinking = true %}\n {%- set system_content = system_content | replace('<|think_on|>', '') %}\n {%- endif %}\n {%- set system_content = system_content | trim %}\n{%- endif %}\n{%- if tools and tools is iterable and tools is not mapping %}\n {{- '<|im_start|>system\\n' }}\n {{- \"# Tools\\n\\nYou have access to the following functions:\\n\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n</tools>\" }}\n {%- set ns_scan = namespace(final_enable=ns_flags.enable_thinking) %}\n {%- for message in messages %}\n {%- set content_str = message.content | string %}\n {%- if '<|think_off|>' in content_str %}\n {%- set ns_scan.final_enable = false %}\n {%- elif '<|think_on|>' in content_str %}\n {%- set ns_scan.final_enable = true %}\n {%- endif %}\n {%- endfor %}\n {%- if ns_scan.final_enable %}\n {{- '\\n\\nIf you choose to call a function ONLY reply in the following format with NO suffix:\\n\\n<think>\\nBrief explanation of tool call\\n</think>\\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 MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>\\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>' }}\n {%- else %}\n {{- '\\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- 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>' }}\n {%- endif %}\n {%- if has_system and system_content %}\n {{- '\\n\\n' + system_content }}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n{%- elif has_system and system_content %}\n {{- '<|im_start|>system\\n' + system_content + '<|im_end|>\\n' }}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- if ns.multi_step_tool and message.role == \"user\" %}\n {%- set content = render_content(message.content, false)|trim %}\n {%- if not(content.startswith('<tool_response>') and content.endswith('</tool_response>')) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if ns.multi_step_tool %}\n {%- set ns.last_query_index = messages|length - 1 %}\n{%- endif %}\n{%- for message in messages %}\n {%- set is_system = (message.role == \"system\" or message.role == \"developer\") %}\n {%- set content = render_content(message.content, true, is_system)|trim %}\n {%- if '<|think_off|>' in content %}\n {%- set ns_flags.enable_thinking = false %}\n {%- set content = content | replace('<|think_off|>', '') | trim %}\n {%- elif '<|think_on|>' in content %}\n {%- set ns_flags.enable_thinking = true %}\n {%- set content = content | replace('<|think_on|>', '') | trim %}\n {%- endif %}\n {%- if is_system %}\n {%- if not loop.first and content %}\n {{- '<|im_start|>system\\n' + content + '<|im_end|>\\n' }}\n {%- endif %}\n {%- elif message.role == \"user\" %}\n {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is string %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- else %}\n {%- if '</think>' in content %}\n {%- set reasoning_content = content.split('</think>')[0].split('<think>')[-1] %}\n {%- set content = content.split('</think>')[-1] %}\n {%- if reasoning_content.endswith('\\n') %}\n {%- set reasoning_content = reasoning_content[:-1] %}\n {%- endif %}\n {%- if reasoning_content.startswith('\\n') %}\n {%- set reasoning_content = reasoning_content[1:] %}\n {%- endif %}\n {%- if content.startswith('\\n') %}\n {%- set content = content[1:] %}\n {%- endif %}\n {%- elif '<think>' in content %}\n {#- Auto-close unclosed think before tool_call (compatibility-safe: no rfind/slice) -#}\n {%- set think_part = content.split('<think>')[-1] %}\n {%- if '<tool_call>' in think_part %}\n {%- set reasoning_content = think_part.split('<tool_call>')[0] %}\n {%- set content = '<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}\n {%- else %}\n {%- set reasoning_content = think_part %}\n {%- set content = '' %}\n {%- endif %}\n {#- Ensure reasoning_content doesn't have leading whitespace like newlines -#}\n {%- if reasoning_content.startswith('\\n') %}\n {%- set reasoning_content = reasoning_content[1:] %}\n {%- endif %}\n {%- endif %}\n {%- endif %}\n {%- set reasoning_content = reasoning_content|trim %}\n {%- if loop.index0 > ns.last_query_index %}\n {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content + '\\n</think>\\n\\n' + content }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {%- if loop.first %}\n {%- if content|trim %}\n {{- '\\n\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- else %}\n {{- '<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- endif %}\n {%- else %}\n {{- '\\n<tool_call>\\n<function=' + tool_call.name + '>\\n' }}\n {%- endif %}\n {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}\n {%- if tool_call.arguments|length > 0 %}\n {%- for args_name in tool_call.arguments %}\n {%- set args_value = tool_call.arguments[args_name] %}\n {{- '<parameter=' + args_name + '>\\n' }}\n {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}\n {{- args_value }}\n {{- '\\n</parameter>\\n' }}\n {%- endfor %}\n {%- endif %}\n {%- elif tool_call.arguments is defined and tool_call.arguments is string %}\n {%- if tool_call.arguments|trim|length > 0 %}\n {{- tool_call.arguments }}\n {{- '\\n' }}\n {%- endif %}\n {%- endif %}\n {{- '</function>\\n</tool_call>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- content }}\n {{- '\\n</tool_response>' }}\n {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n {{- '<|im_end|>\\n' }}\n {%- elif loop.last %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- else %}\n {{- raise_exception('Unexpected message role.') }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if ns_flags.enable_thinking is false %}\n {{- '<think>\\n\\n</think>\\n\\n' }}\n {%- else %}\n {{- '<think>\\n' }}\n {%- endif %}\n{%- endif %}
archive/qwen3.6/chat_template-v10.jinja ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {%- set fn = tool.function if tool.function is defined else tool %}
70
+ {%- set props = {} %}
71
+ {%- set req = [] %}
72
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
73
+ {%- if fn.parameters.properties is defined %}
74
+ {%- set props = fn.parameters.properties %}
75
+ {%- endif %}
76
+ {%- if fn.parameters.required is defined %}
77
+ {%- set req = fn.parameters.required %}
78
+ {%- endif %}
79
+ {%- endif %}
80
+ {%- set ns_p = namespace(sig='') %}
81
+ {%- for pname in props %}
82
+ {%- set pdef = props[pname] %}
83
+ {%- set ptype = 'any' %}
84
+ {%- if pdef.type is defined %}
85
+ {%- if pdef.type == 'array' or pdef.type == 'object' %}
86
+ {%- set ptype = 'array|object' %}
87
+ {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %}
88
+ {%- set ptype = pdef.enum | join('|') %}
89
+ {%- else %}
90
+ {%- set ptype = pdef.type %}
91
+ {%- endif %}
92
+ {%- endif %}
93
+ {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %}
94
+ {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %}
95
+ {%- endfor %}
96
+ {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }}
97
+ {%- if fn.description is defined %}
98
+ {{- ' — ' ~ fn.description }}
99
+ {%- endif %}
100
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
101
+ {%- for pname in props %}
102
+ {%- set pdef = props[pname] %}
103
+ {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %}
104
+ {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }}
105
+ {%- endif %}
106
+ {%- endfor %}
107
+ {%- endif %}
108
+ {%- endfor %}
109
+ {{- "\n</tools>" }}
110
+ {{- '\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>' }}
111
+ {%- if has_system and system_content %}
112
+ {{- '\n\n' + system_content }}
113
+ {%- endif %}
114
+ {{- '<|im_end|>\n' }}
115
+ {%- elif has_system and system_content %}
116
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
117
+ {%- endif %}
118
+ {%- for message in messages %}
119
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
120
+ {%- set content = render_content(message.content, true, is_system)|trim %}
121
+ {%- if '<|think_off|>' in content %}
122
+ {%- set ns_flags.enable_thinking = false %}
123
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
124
+ {%- elif '<|think_on|>' in content %}
125
+ {%- set ns_flags.enable_thinking = true %}
126
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
127
+ {%- endif %}
128
+ {%- if is_system %}
129
+ {%- if not loop.first and content %}
130
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
131
+ {%- endif %}
132
+ {%- elif message.role == "user" %}
133
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
134
+ {%- elif message.role == "assistant" %}
135
+ {%- set reasoning_content = '' %}
136
+ {%- if message.reasoning_content is string %}
137
+ {%- set reasoning_content = message.reasoning_content %}
138
+ {%- else %}
139
+ {%- if '</think>' in content or '</thinking>' in content %}
140
+ {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %}
141
+ {%- set reasoning_parts = content.split(think_end_token) %}
142
+ {%- set reasoning_content = reasoning_parts[0] %}
143
+ {%- set content = reasoning_parts[1] %}
144
+ {%- if '<think>' in reasoning_content %}
145
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
146
+ {%- endif %}
147
+ {%- elif '<think>' in content %}
148
+ {%- if '<tool_call>' in content %}
149
+ {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %}
150
+ {%- set reasoning_parts = content.split('</think>') %}
151
+ {%- set reasoning_content = reasoning_parts[0] %}
152
+ {%- set content = reasoning_parts[1] %}
153
+ {%- if '<think>' in reasoning_content %}
154
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
155
+ {%- endif %}
156
+ {%- else %}
157
+ {%- set reasoning_content = content.split('<think>')[1] %}
158
+ {%- set content = '' %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+ {%- endif %}
162
+ {%- set reasoning_content = reasoning_content | trim %}
163
+ {%- set content = content | trim %}
164
+ {%- if reasoning_content %}
165
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
166
+ {%- else %}
167
+ {{- '<|im_start|>' + message.role + '\n' + content }}
168
+ {%- endif %}
169
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
170
+ {%- for tool_call in message.tool_calls %}
171
+ {%- if tool_call.function is defined %}
172
+ {%- set tool_call = tool_call.function %}
173
+ {%- endif %}
174
+ {%- if loop.first and content %}
175
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
176
+ {%- else %}
177
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
178
+ {%- endif %}
179
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
180
+ {%- if tool_call.arguments|length > 0 %}
181
+ {%- for args_name in tool_call.arguments %}
182
+ {%- set args_value = tool_call.arguments[args_name] %}
183
+ {{- '<parameter=' + args_name + '>\n' }}
184
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
185
+ {{- args_value }}
186
+ {{- '\n</parameter>\n' }}
187
+ {%- endfor %}
188
+ {%- endif %}
189
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
190
+ {%- if tool_call.arguments|trim|length > 0 %}
191
+ {{- tool_call.arguments }}
192
+ {{- '\n' }}
193
+ {%- endif %}
194
+ {%- endif %}
195
+ {{- '</function>\n</tool_call>' }}
196
+ {%- endfor %}
197
+ {%- endif %}
198
+ {{- '<|im_end|>\n' }}
199
+ {%- elif message.role == "tool" %}
200
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
201
+ {{- '<|im_start|>user' }}
202
+ {%- endif %}
203
+ {{- '\n<tool_response>\n' }}
204
+ {{- content }}
205
+ {{- '\n</tool_response>' }}
206
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
207
+ {{- '<|im_end|>\n' }}
208
+ {%- elif loop.last %}
209
+ {{- '<|im_end|>\n' }}
210
+ {%- endif %}
211
+ {%- else %}
212
+ {{- raise_exception('Unexpected message role.') }}
213
+ {%- endif %}
214
+ {%- endfor %}
215
+ {%- if add_generation_prompt %}
216
+ {%- if ns_flags.has_tools %}
217
+ {{- '<|im_start|>system\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- 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><|im_end|>\n' }}
218
+ {%- endif %}
219
+ {{- '<|im_start|>assistant\n' }}
220
+ {%- if ns_flags.enable_thinking %}
221
+ {{- '<think>\n' }}
222
+ {%- endif %}
223
+ {%- endif %}
archive/qwen3.6/chat_template-v10_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {%- set fn = tool.function if tool.function is defined else tool %} {%- set props = {} %} {%- set req = [] %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- if fn.parameters.properties is defined %} {%- set props = fn.parameters.properties %} {%- endif %} {%- if fn.parameters.required is defined %} {%- set req = fn.parameters.required %} {%- endif %} {%- endif %} {%- set ns_p = namespace(sig='') %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- set ptype = 'any' %} {%- if pdef.type is defined %} {%- if pdef.type == 'array' or pdef.type == 'object' %} {%- set ptype = 'array|object' %} {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %} {%- set ptype = pdef.enum | join('|') %} {%- else %} {%- set ptype = pdef.type %} {%- endif %} {%- endif %} {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %} {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %} {%- endfor %} {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }} {%- if fn.description is defined %} {{- ' — ' ~ fn.description }} {%- endif %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %} {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }} {%- endif %} {%- endfor %} {%- endif %} {%- 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>' }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- if '</think>' in content or '</thinking>' in content %} {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- elif '<think>' in content %} {%- if '<tool_call>' in content %} {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %} {%- set reasoning_parts = content.split('</think>') %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- else %} {%- set reasoning_content = content.split('<think>')[1] %} {%- set content = '' %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- else %} {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- endif %} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments|length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' + args_name + '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments|trim|length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v11.jinja ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {%- set fn = tool.function if tool.function is defined else tool %}
70
+ {%- set props = {} %}
71
+ {%- set req = [] %}
72
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
73
+ {%- if fn.parameters.properties is defined %}
74
+ {%- set props = fn.parameters.properties %}
75
+ {%- endif %}
76
+ {%- if fn.parameters.required is defined %}
77
+ {%- set req = fn.parameters.required %}
78
+ {%- endif %}
79
+ {%- endif %}
80
+ {%- set ns_p = namespace(sig='') %}
81
+ {%- for pname in props %}
82
+ {%- set pdef = props[pname] %}
83
+ {%- set ptype = 'any' %}
84
+ {%- if pdef.type is defined %}
85
+ {%- if pdef.type == 'array' or pdef.type == 'object' %}
86
+ {%- set ptype = 'array|object' %}
87
+ {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %}
88
+ {%- set ptype = pdef.enum | join('|') %}
89
+ {%- else %}
90
+ {%- set ptype = pdef.type %}
91
+ {%- endif %}
92
+ {%- endif %}
93
+ {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %}
94
+ {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %}
95
+ {%- endfor %}
96
+ {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }}
97
+ {%- if fn.description is defined %}
98
+ {{- ' — ' ~ fn.description }}
99
+ {%- endif %}
100
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
101
+ {%- for pname in props %}
102
+ {%- set pdef = props[pname] %}
103
+ {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %}
104
+ {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }}
105
+ {%- endif %}
106
+ {%- endfor %}
107
+ {%- endif %}
108
+ {%- endfor %}
109
+ {{- "\n</tools>" }}
110
+ {{- '\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>' }}
111
+ {%- if has_system and system_content %}
112
+ {{- '\n\n' + system_content }}
113
+ {%- endif %}
114
+ {{- '<|im_end|>\n' }}
115
+ {%- elif has_system and system_content %}
116
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
117
+ {%- endif %}
118
+ {%- for message in messages %}
119
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
120
+ {%- set content = render_content(message.content, true, is_system)|trim %}
121
+ {%- if '<|think_off|>' in content %}
122
+ {%- set ns_flags.enable_thinking = false %}
123
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
124
+ {%- elif '<|think_on|>' in content %}
125
+ {%- set ns_flags.enable_thinking = true %}
126
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
127
+ {%- endif %}
128
+ {%- if is_system %}
129
+ {%- if not loop.first and content %}
130
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
131
+ {%- endif %}
132
+ {%- elif message.role == "user" %}
133
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
134
+ {%- elif message.role == "assistant" %}
135
+ {%- set reasoning_content = '' %}
136
+ {%- if message.reasoning_content is string %}
137
+ {%- set reasoning_content = message.reasoning_content %}
138
+ {%- else %}
139
+ {%- if '</think>' in content or '</thinking>' in content %}
140
+ {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %}
141
+ {%- set reasoning_parts = content.split(think_end_token) %}
142
+ {%- set reasoning_content = reasoning_parts[0] %}
143
+ {%- set content = reasoning_parts[1] %}
144
+ {%- if '<think>' in reasoning_content %}
145
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
146
+ {%- endif %}
147
+ {%- elif '<think>' in content %}
148
+ {%- if '<tool_call>' in content %}
149
+ {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %}
150
+ {%- set reasoning_parts = content.split('</think>') %}
151
+ {%- set reasoning_content = reasoning_parts[0] %}
152
+ {%- set content = reasoning_parts[1] %}
153
+ {%- if '<think>' in reasoning_content %}
154
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
155
+ {%- endif %}
156
+ {%- else %}
157
+ {%- set reasoning_content = content.split('<think>')[1] %}
158
+ {%- set content = '' %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+ {%- endif %}
162
+ {%- set reasoning_content = reasoning_content | trim %}
163
+ {%- set content = content | trim %}
164
+ {%- set show_think = false %}
165
+ {%- if reasoning_content %}
166
+ {%- if preserve_thinking is defined and preserve_thinking %}
167
+ {%- set show_think = true %}
168
+ {%- elif loop.last %}
169
+ {%- set show_think = true %}
170
+ {%- endif %}
171
+ {%- endif %}
172
+ {%- if show_think %}
173
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
174
+ {%- else %}
175
+ {{- '<|im_start|>' + message.role + '\n' + content }}
176
+ {%- endif %}
177
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
178
+ {%- for tool_call in message.tool_calls %}
179
+ {%- if tool_call.function is defined %}
180
+ {%- set tool_call = tool_call.function %}
181
+ {%- endif %}
182
+ {%- if loop.first and content %}
183
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
184
+ {%- else %}
185
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
186
+ {%- endif %}
187
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
188
+ {%- if tool_call.arguments|length > 0 %}
189
+ {%- for args_name in tool_call.arguments %}
190
+ {%- set args_value = tool_call.arguments[args_name] %}
191
+ {{- '<parameter=' + args_name + '>\n' }}
192
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
193
+ {{- args_value }}
194
+ {{- '\n</parameter>\n' }}
195
+ {%- endfor %}
196
+ {%- endif %}
197
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
198
+ {%- if tool_call.arguments|trim|length > 0 %}
199
+ {{- tool_call.arguments }}
200
+ {{- '\n' }}
201
+ {%- endif %}
202
+ {%- endif %}
203
+ {{- '</function>\n</tool_call>' }}
204
+ {%- endfor %}
205
+ {%- endif %}
206
+ {{- '<|im_end|>\n' }}
207
+ {%- elif message.role == "tool" %}
208
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
209
+ {{- '<|im_start|>user' }}
210
+ {%- endif %}
211
+ {{- '\n<tool_response>\n' }}
212
+ {{- content }}
213
+ {{- '\n</tool_response>' }}
214
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
215
+ {{- '<|im_end|>\n' }}
216
+ {%- elif loop.last %}
217
+ {{- '<|im_end|>\n' }}
218
+ {%- endif %}
219
+ {%- else %}
220
+ {{- raise_exception('Unexpected message role.') }}
221
+ {%- endif %}
222
+ {%- endfor %}
223
+ {%- if add_generation_prompt %}
224
+ {{- '<|im_start|>assistant\n' }}
225
+ {%- if ns_flags.enable_thinking is false %}
226
+ {{- '<think>\n\n</think>\n\n' }}
227
+ {%- else %}
228
+ {{- '<think>\n' }}
229
+ {%- endif %}
230
+ {%- endif %}
archive/qwen3.6/chat_template-v11_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {%- set fn = tool.function if tool.function is defined else tool %} {%- set props = {} %} {%- set req = [] %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- if fn.parameters.properties is defined %} {%- set props = fn.parameters.properties %} {%- endif %} {%- if fn.parameters.required is defined %} {%- set req = fn.parameters.required %} {%- endif %} {%- endif %} {%- set ns_p = namespace(sig='') %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- set ptype = 'any' %} {%- if pdef.type is defined %} {%- if pdef.type == 'array' or pdef.type == 'object' %} {%- set ptype = 'array|object' %} {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %} {%- set ptype = pdef.enum | join('|') %} {%- else %} {%- set ptype = pdef.type %} {%- endif %} {%- endif %} {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %} {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %} {%- endfor %} {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }} {%- if fn.description is defined %} {{- ' — ' ~ fn.description }} {%- endif %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %} {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }} {%- endif %} {%- endfor %} {%- endif %} {%- 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>' }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- if '</think>' in content or '</thinking>' in content %} {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- elif '<think>' in content %} {%- if '<tool_call>' in content %} {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %} {%- set reasoning_parts = content.split('</think>') %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- else %} {%- set reasoning_content = content.split('<think>')[1] %} {%- set content = '' %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- else %} {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- endif %} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments|length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' + args_name + '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments|trim|length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v12.jinja ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {%- set fn = tool.function if tool.function is defined else tool %}
70
+ {%- set props = {} %}
71
+ {%- set req = [] %}
72
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
73
+ {%- if fn.parameters.properties is defined %}
74
+ {%- set props = fn.parameters.properties %}
75
+ {%- endif %}
76
+ {%- if fn.parameters.required is defined %}
77
+ {%- set req = fn.parameters.required %}
78
+ {%- endif %}
79
+ {%- endif %}
80
+ {%- set ns_p = namespace(sig='') %}
81
+ {%- for pname in props %}
82
+ {%- set pdef = props[pname] %}
83
+ {%- set ptype = 'any' %}
84
+ {%- if pdef.type is defined %}
85
+ {%- if pdef.type == 'array' or pdef.type == 'object' %}
86
+ {%- set ptype = 'array|object' %}
87
+ {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %}
88
+ {%- set ptype = pdef.enum | join('|') %}
89
+ {%- else %}
90
+ {%- set ptype = pdef.type %}
91
+ {%- endif %}
92
+ {%- endif %}
93
+ {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %}
94
+ {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %}
95
+ {%- endfor %}
96
+ {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }}
97
+ {%- if fn.description is defined %}
98
+ {{- ' — ' ~ fn.description }}
99
+ {%- endif %}
100
+ {%- if fn.parameters is defined and fn.parameters is mapping %}
101
+ {%- for pname in props %}
102
+ {%- set pdef = props[pname] %}
103
+ {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %}
104
+ {{- '\n - ' ~ pname ~ ' schema: ' ~ pdef | tojson }}
105
+ {%- elif pdef.description is defined and pdef.description is string %}
106
+ {{- '\n - ' ~ pname ~ ' description: ' ~ pdef.description }}
107
+ {%- endif %}
108
+ {%- endfor %}
109
+ {%- endif %}
110
+ {%- endfor %}
111
+ {{- "\n</tools>" }}
112
+ {%- set ns_scan = namespace(final_enable=ns_flags.enable_thinking) %}
113
+ {%- for message in messages %}
114
+ {%- set content_str = message.content | string %}
115
+ {%- if '<|think_off|>' in content_str %}
116
+ {%- set ns_scan.final_enable = false %}
117
+ {%- elif '<|think_on|>' in content_str %}
118
+ {%- set ns_scan.final_enable = true %}
119
+ {%- endif %}
120
+ {%- endfor %}
121
+ {%- if ns_scan.final_enable %}
122
+ {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<think>\nBrief explanation of tool call\n</think>\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 MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>\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>' }}
123
+ {%- else %}
124
+ {{- '\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- 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>' }}
125
+ {%- endif %}
126
+ {%- if has_system and system_content %}
127
+ {{- '\n\n' + system_content }}
128
+ {%- endif %}
129
+ {{- '<|im_end|>\n' }}
130
+ {%- elif has_system and system_content %}
131
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
132
+ {%- endif %}
133
+ {%- for message in messages %}
134
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
135
+ {%- set content = render_content(message.content, true, is_system)|trim %}
136
+ {%- if '<|think_off|>' in content %}
137
+ {%- set ns_flags.enable_thinking = false %}
138
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
139
+ {%- elif '<|think_on|>' in content %}
140
+ {%- set ns_flags.enable_thinking = true %}
141
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
142
+ {%- endif %}
143
+ {%- if is_system %}
144
+ {%- if not loop.first and content %}
145
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
146
+ {%- endif %}
147
+ {%- elif message.role == "user" %}
148
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
149
+ {%- elif message.role == "assistant" %}
150
+ {%- set content = content | replace('</ think>', '</think>') | replace('< /think>', '</think>') | replace('</think >', '</think>') | replace('<think >', '<think>') | replace('< think>', '<think>') %}
151
+ {%- set reasoning_content = '' %}
152
+ {%- if message.reasoning_content is string %}
153
+ {%- set reasoning_content = message.reasoning_content %}
154
+ {%- else %}
155
+ {%- if '</think>' in content or '</thinking>' in content %}
156
+ {%- set think_end_token = '</think>' if '</think>' in content else '</thinking>' %}
157
+ {%- set reasoning_parts = content.split(think_end_token) %}
158
+ {%- set reasoning_content = reasoning_parts[0] %}
159
+ {%- set content = reasoning_parts[1] %}
160
+ {%- if '<think>' in reasoning_content %}
161
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
162
+ {%- endif %}
163
+ {%- elif '<think>' in content %}
164
+ {%- if '<tool_call>' in content %}
165
+ {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %}
166
+ {%- set reasoning_parts = content.split('</think>') %}
167
+ {%- set reasoning_content = reasoning_parts[0] %}
168
+ {%- set content = reasoning_parts[1] %}
169
+ {%- if '<think>' in reasoning_content %}
170
+ {%- set reasoning_content = reasoning_content.split('<think>')[1] %}
171
+ {%- endif %}
172
+ {%- else %}
173
+ {%- set reasoning_content = content.split('<think>')[1] %}
174
+ {%- set content = '' %}
175
+ {%- endif %}
176
+ {%- endif %}
177
+ {%- endif %}
178
+ {%- set reasoning_content = reasoning_content | trim %}
179
+ {%- set content = content | trim %}
180
+ {%- set show_think = false %}
181
+ {%- if reasoning_content %}
182
+ {%- if preserve_thinking is defined and preserve_thinking %}
183
+ {%- set show_think = true %}
184
+ {%- elif loop.last %}
185
+ {%- set show_think = true %}
186
+ {%- endif %}
187
+ {%- endif %}
188
+ {%- if show_think %}
189
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
190
+ {%- else %}
191
+ {{- '<|im_start|>' + message.role + '\n' + content }}
192
+ {%- endif %}
193
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
194
+ {%- for tool_call in message.tool_calls %}
195
+ {%- if tool_call.function is defined %}
196
+ {%- set tool_call = tool_call.function %}
197
+ {%- endif %}
198
+ {%- if loop.first and content %}
199
+ {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
200
+ {%- else %}
201
+ {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
202
+ {%- endif %}
203
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
204
+ {%- if tool_call.arguments|length > 0 %}
205
+ {%- for args_name in tool_call.arguments %}
206
+ {%- set args_value = tool_call.arguments[args_name] %}
207
+ {{- '<parameter=' + args_name + '>\n' }}
208
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
209
+ {{- args_value }}
210
+ {{- '\n</parameter>\n' }}
211
+ {%- endfor %}
212
+ {%- endif %}
213
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
214
+ {%- if tool_call.arguments|trim|length > 0 %}
215
+ {{- tool_call.arguments }}
216
+ {{- '\n' }}
217
+ {%- endif %}
218
+ {%- endif %}
219
+ {{- '</function>\n</tool_call>' }}
220
+ {%- endfor %}
221
+ {%- endif %}
222
+ {{- '<|im_end|>\n' }}
223
+ {%- elif message.role == "tool" %}
224
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
225
+ {{- '<|im_start|>user' }}
226
+ {%- endif %}
227
+ {{- '\n<tool_response>\n' }}
228
+ {{- content }}
229
+ {{- '\n</tool_response>' }}
230
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
231
+ {{- '<|im_end|>\n' }}
232
+ {%- elif loop.last %}
233
+ {{- '<|im_end|>\n' }}
234
+ {%- endif %}
235
+ {%- else %}
236
+ {{- raise_exception('Unexpected message role.') }}
237
+ {%- endif %}
238
+ {%- endfor %}
239
+ {%- if add_generation_prompt %}
240
+ {{- '<|im_start|>assistant\n' }}
241
+ {%- if ns_flags.enable_thinking is false %}
242
+ {{- '<think>\n\n</think>\n\n' }}
243
+ {%- else %}
244
+ {{- '<think>\n' }}
245
+ {%- endif %}
246
+ {%- endif %}
archive/qwen3.6/chat_template-v12_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {%- set fn = tool.function if tool.function is defined else tool %} {%- set props = {} %} {%- set req = [] %} {%- if fn.parameters is defined and fn.parameters is mapping %} {%- if fn.parameters.properties is defined %} {%- set props = fn.parameters.properties %} {%- endif %} {%- if fn.parameters.required is defined %} {%- set req = fn.parameters.required %} {%- endif %} {%- endif %} {%- set ns_p = namespace(sig='', schema_blocks='') %} {%- for pname in props %} {%- set pdef = props[pname] %} {%- set ptype = 'any' %} {%- if pdef.type is defined %} {%- if pdef.type == 'array' or pdef.type == 'object' %} {%- set ptype = 'array|object' %} {%- elif pdef.enum is defined and pdef.enum is iterable and pdef.enum is not string and pdef.enum is not mapping %} {%- set ptype = pdef.enum | map('string') | join('|') %} {%- else %} {%- set ptype = pdef.type %} {%- endif %} {%- endif %} {%- set part = pname ~ ('' if pname in req else '?') ~ ': ' ~ ptype %} {%- set ns_p.sig = ns_p.sig ~ ', ' ~ part if ns_p.sig else part %} {%- if pdef.type is defined and (pdef.type == 'array' or pdef.type == 'object') %} {%- set ns_p.schema_blocks = ns_p.schema_blocks ~ '\n - ' ~ pname ~ ' schema: ' ~ (pdef | tojson) %} {%- elif pdef.description is defined and pdef.description is string %} {%- set ns_p.schema_blocks = ns_p.schema_blocks ~ '\n - ' ~ pname ~ ' description: ' ~ pdef.description %} {%- endif %} {%- endfor %} {{- '\n- ' ~ fn.name ~ '(' ~ ns_p.sig ~ ')' }} {%- if fn.description is defined %} {{- ' — ' ~ fn.description }} {%- endif %} {{- ns_p.schema_blocks }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<think>Brief explanation of tool call</think><tool_call><function=example_function_name><parameter=example_parameter_1>value_1</parameter><parameter=example_parameter_2>This is the value for the second parameterthat can spanmultiple lines</parameter></function></tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- You MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '< /think>' in content %} {%- set think_end_token = '< /think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token, 1) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] if reasoning_parts | length > 1 else '' %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- elif '<think>' in content %} {%- if '<tool_call>' in content %} {%- set content = content | replace('<tool_call>', '</think>\n<tool_call>', 1) %} {%- set reasoning_parts = content.split('</think>') %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1] %} {%- if '<think>' in reasoning_content %} {%- set reasoning_content = reasoning_content.split('<think>')[1] %} {%- endif %} {%- else %} {%- set reasoning_content = content.split('<think>')[1] %} {%- set content = '' %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- else %} {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }} {%- endif %} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments|length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' + args_name + '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments|trim|length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v13.jinja ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <tool_call>
78
+ {"name": "tool_name", "arguments": {"arg_name": "value"}}
79
+ </tool_call>
80
+
81
+ <IMPORTANT>
82
+ Reminder:
83
+ - Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags
84
+ - Required parameters MUST be specified
85
+ {%- if ns_flags.enable_thinking %}
86
+ - You MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>
87
+ {%- endif %}
88
+ - 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
89
+ </IMPORTANT>
90
+ {%- endset %}
91
+ {{- '\n\n' ~ tool_instructions | trim }}
92
+ {%- if has_system and system_content %}
93
+ {{- '\n\n' + system_content }}
94
+ {%- endif %}
95
+ {{- '<|im_end|>\n' }}
96
+ {%- elif has_system and system_content %}
97
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
98
+ {%- endif %}
99
+ {%- for message in messages %}
100
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
101
+ {%- set content = render_content(message.content, true, is_system)|trim %}
102
+ {%- if '<|think_off|>' in content %}
103
+ {%- set ns_flags.enable_thinking = false %}
104
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
105
+ {%- elif '<|think_on|>' in content %}
106
+ {%- set ns_flags.enable_thinking = true %}
107
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
108
+ {%- endif %}
109
+ {%- if is_system %}
110
+ {%- if not loop.first and content %}
111
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
112
+ {%- endif %}
113
+ {%- elif message.role == "user" %}
114
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set reasoning_content = '' %}
117
+ {%- if message.reasoning_content is string %}
118
+ {%- set reasoning_content = message.reasoning_content %}
119
+ {%- else %}
120
+ {%- set think_end_token = '' %}
121
+ {%- if '</think>' in content %}
122
+ {%- set think_end_token = '</think>' %}
123
+ {%- elif '</thinking>' in content %}
124
+ {%- set think_end_token = '</thinking>' %}
125
+ {%- elif '</ think>' in content %}
126
+ {%- set think_end_token = '</ think>' %}
127
+ {%- elif '</think >' in content %}
128
+ {%- set think_end_token = '</think >' %}
129
+ {%- endif %}
130
+ {%- if think_end_token %}
131
+ {%- set reasoning_parts = content.split(think_end_token) %}
132
+ {%- set reasoning_content = reasoning_parts[0] %}
133
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
134
+ {%- if '<think>' in reasoning_content %}
135
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
136
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
137
+ {%- set content = r_prefix ~ '\n' ~ content %}
138
+ {%- endif %}
139
+ {%- elif '<think>' in content %}
140
+ {%- set prefix = content.split('<think>')[0] %}
141
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
142
+ {%- if '<tool_call>' in think_part %}
143
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
144
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
145
+ {%- else %}
146
+ {%- set reasoning_content = think_part %}
147
+ {%- set content = prefix %}
148
+ {%- endif %}
149
+ {%- endif %}
150
+ {%- endif %}
151
+ {%- set reasoning_content = reasoning_content | trim %}
152
+ {%- set content = content | trim %}
153
+ {%- set show_think = false %}
154
+ {%- if reasoning_content %}
155
+ {%- if preserve_thinking is defined and preserve_thinking %}
156
+ {%- set show_think = true %}
157
+ {%- elif loop.last %}
158
+ {%- set show_think = true %}
159
+ {%- endif %}
160
+ {%- endif %}
161
+ {%- if show_think %}
162
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
163
+ {%- else %}
164
+ {{- '<|im_start|>' + message.role + '\n' + content }}
165
+ {%- endif %}
166
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
167
+ {%- for tool_call in message.tool_calls %}
168
+ {%- if tool_call.function is defined %}
169
+ {%- set tool_call = tool_call.function %}
170
+ {%- endif %}
171
+ {%- if loop.first and content %}
172
+ {{- '\n\n<tool_call>\n' }}
173
+ {%- else %}
174
+ {{- '\n<tool_call>\n' }}
175
+ {%- endif %}
176
+ {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }}
177
+ {{- '</tool_call>' }}
178
+ {%- endfor %}
179
+ {%- endif %}
180
+ {{- '<|im_end|>\n' }}
181
+ {%- elif message.role == "tool" %}
182
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
183
+ {{- '<|im_start|>user' }}
184
+ {%- endif %}
185
+ {{- '\n<tool_response>\n' }}
186
+ {{- content }}
187
+ {{- '\n</tool_response>' }}
188
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
189
+ {{- '<|im_end|>\n' }}
190
+ {%- elif loop.last %}
191
+ {{- '<|im_end|>\n' }}
192
+ {%- endif %}
193
+ {%- else %}
194
+ {{- raise_exception('Unexpected message role.') }}
195
+ {%- endif %}
196
+ {%- endfor %}
197
+ {%- if add_generation_prompt %}
198
+ {{- '<|im_start|>assistant\n' }}
199
+ {%- if ns_flags.enable_thinking is false %}
200
+ {{- '<think>\n\n</think>\n\n' }}
201
+ {%- else %}
202
+ {{- '<think>\n' }}
203
+ {%- endif %}
204
+ {%- endif %}
archive/qwen3.6/chat_template-v13_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified{%- if ns_flags.enable_thinking %}- You MUST provide reasoning for your function call within a <think></think> block BEFORE the <tool_call>{%- endif %}- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v14.jinja ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <tool_call>
78
+ {"name": "tool_name", "arguments": {"arg_name": "value"}}
79
+ </tool_call>
80
+
81
+ <IMPORTANT>
82
+ Reminder:
83
+ - Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags
84
+ - Required parameters MUST be specified
85
+ {%- if ns_flags.enable_thinking %}
86
+ - You MUST use the <think></think> block to reason about your actions, plan function calls, or synthesize results before providing your final response
87
+ {%- endif %}
88
+ - 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
89
+ </IMPORTANT>
90
+ {%- endset %}
91
+ {{- '\n\n' ~ tool_instructions | trim }}
92
+ {%- if has_system and system_content %}
93
+ {{- '\n\n' + system_content }}
94
+ {%- endif %}
95
+ {{- '<|im_end|>\n' }}
96
+ {%- elif has_system and system_content %}
97
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
98
+ {%- endif %}
99
+ {%- for message in messages %}
100
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
101
+ {%- set content = render_content(message.content, true, is_system)|trim %}
102
+ {%- if '<|think_off|>' in content %}
103
+ {%- set ns_flags.enable_thinking = false %}
104
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
105
+ {%- elif '<|think_on|>' in content %}
106
+ {%- set ns_flags.enable_thinking = true %}
107
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
108
+ {%- endif %}
109
+ {%- if is_system %}
110
+ {%- if not loop.first and content %}
111
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
112
+ {%- endif %}
113
+ {%- elif message.role == "user" %}
114
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set reasoning_content = '' %}
117
+ {%- if message.reasoning_content is string %}
118
+ {%- set reasoning_content = message.reasoning_content %}
119
+ {%- else %}
120
+ {%- set think_end_token = '' %}
121
+ {%- if '</think>' in content %}
122
+ {%- set think_end_token = '</think>' %}
123
+ {%- elif '</thinking>' in content %}
124
+ {%- set think_end_token = '</thinking>' %}
125
+ {%- elif '</ think>' in content %}
126
+ {%- set think_end_token = '</ think>' %}
127
+ {%- elif '</think >' in content %}
128
+ {%- set think_end_token = '</think >' %}
129
+ {%- endif %}
130
+ {%- if think_end_token %}
131
+ {%- set reasoning_parts = content.split(think_end_token) %}
132
+ {%- set reasoning_content = reasoning_parts[0] %}
133
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
134
+ {%- if '<think>' in reasoning_content %}
135
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
136
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
137
+ {%- set content = r_prefix ~ '\n' ~ content %}
138
+ {%- endif %}
139
+ {%- elif '<think>' in content %}
140
+ {%- set prefix = content.split('<think>')[0] %}
141
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
142
+ {%- if '<tool_call>' in think_part %}
143
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
144
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
145
+ {%- else %}
146
+ {%- set reasoning_content = think_part %}
147
+ {%- set content = prefix %}
148
+ {%- endif %}
149
+ {%- endif %}
150
+ {%- endif %}
151
+ {%- set reasoning_content = reasoning_content | trim %}
152
+ {%- set content = content | trim %}
153
+ {%- set is_tool_error = false %}
154
+ {%- if message.tool_calls and not loop.last and loop.nextitem is defined %}
155
+ {%- set next_role = loop.nextitem.role %}
156
+ {%- set next_content = loop.nextitem.content | string | lower %}
157
+ {%- if next_role == 'tool' or '<tool_response>' in next_content %}
158
+ {%- if 'error' in next_content or 'fail' in next_content or 'invalid' in next_content or 'exceeds' in next_content or 'retry loop' in next_content %}
159
+ {%- set is_tool_error = true %}
160
+ {%- endif %}
161
+ {%- endif %}
162
+ {%- endif %}
163
+ {%- set show_think = false %}
164
+ {%- if reasoning_content %}
165
+ {%- if preserve_thinking is defined and preserve_thinking %}
166
+ {%- set show_think = true %}
167
+ {%- elif loop.last or is_tool_error %}
168
+ {%- set show_think = true %}
169
+ {%- endif %}
170
+ {%- endif %}
171
+ {%- if show_think %}
172
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
173
+ {%- else %}
174
+ {{- '<|im_start|>' + message.role + '\n' + content }}
175
+ {%- endif %}
176
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
177
+ {%- for tool_call in message.tool_calls %}
178
+ {%- if tool_call.function is defined %}
179
+ {%- set tool_call = tool_call.function %}
180
+ {%- endif %}
181
+ {%- if loop.first and content %}
182
+ {{- '\n\n<tool_call>\n' }}
183
+ {%- else %}
184
+ {{- '\n<tool_call>\n' }}
185
+ {%- endif %}
186
+ {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }}
187
+ {{- '</tool_call>' }}
188
+ {%- endfor %}
189
+ {%- endif %}
190
+ {{- '<|im_end|>\n' }}
191
+ {%- elif message.role == "tool" %}
192
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
193
+ {{- '<|im_start|>user' }}
194
+ {%- endif %}
195
+ {{- '\n<tool_response>\n' }}
196
+ {{- content }}
197
+ {{- '\n</tool_response>' }}
198
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
199
+ {{- '<|im_end|>\n' }}
200
+ {%- elif loop.last %}
201
+ {{- '<|im_end|>\n' }}
202
+ {%- endif %}
203
+ {%- else %}
204
+ {{- raise_exception('Unexpected message role.') }}
205
+ {%- endif %}
206
+ {%- endfor %}
207
+ {%- if add_generation_prompt %}
208
+ {{- '<|im_start|>assistant\n' }}
209
+ {%- if ns_flags.enable_thinking is false %}
210
+ {{- '<think>\n\n</think>\n\n' }}
211
+ {%- else %}
212
+ {{- '<think>\n' }}
213
+ {%- endif %}
214
+ {%- endif %}
archive/qwen3.6/chat_template-v14_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified{%- if ns_flags.enable_thinking %}- You MUST use the <think></think> block to reason about your actions, plan function calls, or synthesize results before providing your final response{%- endif %}- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- elif message.role == "assistant" %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set is_tool_error = false %} {%- if message.tool_calls and not loop.last and loop.nextitem is defined %} {%- set next_role = loop.nextitem.role %} {%- set next_content = loop.nextitem.content | string | lower %} {%- if next_role == 'tool' or '<tool_response>' in next_content %} {%- if 'error' in next_content or 'fail' in next_content or 'invalid' in next_content or 'exceeds' in next_content or 'retry loop' in next_content %} {%- set is_tool_error = true %} {%- endif %} {%- endif %} {%- endif %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last or is_tool_error %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v15.jinja ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <tool_call>
78
+ {"name": "tool_name", "arguments": {"arg_name": "value"}}
79
+ </tool_call>
80
+
81
+ <IMPORTANT>
82
+ Reminder:
83
+ - Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags
84
+ - Required parameters MUST be specified
85
+ - Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response
86
+ - 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
87
+ </IMPORTANT>
88
+ {%- endset %}
89
+ {{- '\n\n' ~ tool_instructions | trim }}
90
+ {%- if has_system and system_content %}
91
+ {{- '\n\n' + system_content }}
92
+ {%- endif %}
93
+ {{- '<|im_end|>\n' }}
94
+ {%- elif has_system and system_content %}
95
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
96
+ {%- endif %}
97
+ {%- for message in messages %}
98
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
99
+ {%- set content = render_content(message.content, true, is_system)|trim %}
100
+ {%- if '<|think_off|>' in content %}
101
+ {%- set ns_flags.enable_thinking = false %}
102
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
103
+ {%- elif '<|think_on|>' in content %}
104
+ {%- set ns_flags.enable_thinking = true %}
105
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
106
+ {%- endif %}
107
+ {%- if is_system %}
108
+ {%- if not loop.first and content %}
109
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
110
+ {%- endif %}
111
+ {%- elif message.role == "user" %}
112
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
113
+ {%- set ns_flags.last_tool_failed = false %}
114
+ {%- set ns_flags.consecutive_failures = 0 %}
115
+ {%- elif message.role == "assistant" %}
116
+ {%- set ns_flags.last_tool_failed = false %}
117
+ {%- set ns_flags.consecutive_failures = 0 %}
118
+ {%- set reasoning_content = '' %}
119
+ {%- if message.reasoning_content is string %}
120
+ {%- set reasoning_content = message.reasoning_content %}
121
+ {%- else %}
122
+ {%- set think_end_token = '' %}
123
+ {%- if '</think>' in content %}
124
+ {%- set think_end_token = '</think>' %}
125
+ {%- elif '</thinking>' in content %}
126
+ {%- set think_end_token = '</thinking>' %}
127
+ {%- elif '</ think>' in content %}
128
+ {%- set think_end_token = '</ think>' %}
129
+ {%- elif '</think >' in content %}
130
+ {%- set think_end_token = '</think >' %}
131
+ {%- endif %}
132
+ {%- if think_end_token %}
133
+ {%- set reasoning_parts = content.split(think_end_token) %}
134
+ {%- set reasoning_content = reasoning_parts[0] %}
135
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
136
+ {%- if '<think>' in reasoning_content %}
137
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
138
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
139
+ {%- set content = r_prefix ~ '\n' ~ content %}
140
+ {%- endif %}
141
+ {%- elif '<think>' in content %}
142
+ {%- set prefix = content.split('<think>')[0] %}
143
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
144
+ {%- if '<tool_call>' in think_part %}
145
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
146
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
147
+ {%- else %}
148
+ {%- set reasoning_content = think_part %}
149
+ {%- set content = prefix %}
150
+ {%- endif %}
151
+ {%- endif %}
152
+ {%- endif %}
153
+ {%- set reasoning_content = reasoning_content | trim %}
154
+ {%- set content = content | trim %}
155
+ {%- set show_think = false %}
156
+ {%- if reasoning_content %}
157
+ {%- if preserve_thinking is defined and preserve_thinking %}
158
+ {%- set show_think = true %}
159
+ {%- elif loop.last %}
160
+ {%- set show_think = true %}
161
+ {%- endif %}
162
+ {%- endif %}
163
+ {%- if show_think %}
164
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
165
+ {%- else %}
166
+ {{- '<|im_start|>' + message.role + '\n' + content }}
167
+ {%- endif %}
168
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
169
+ {%- for tool_call in message.tool_calls %}
170
+ {%- if tool_call.function is defined %}
171
+ {%- set tool_call = tool_call.function %}
172
+ {%- endif %}
173
+ {%- if loop.first and content %}
174
+ {{- '\n\n<tool_call>\n' }}
175
+ {%- else %}
176
+ {{- '\n<tool_call>\n' }}
177
+ {%- endif %}
178
+ {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }}
179
+ {{- '</tool_call>' }}
180
+ {%- endfor %}
181
+ {%- endif %}
182
+ {{- '<|im_end|>\n' }}
183
+ {%- elif message.role == "tool" %}
184
+ {%- set content_lower = content | lower %}
185
+ {%- if content | length < 500 and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %}
186
+ {%- set ns_flags.last_tool_failed = true %}
187
+ {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}
188
+ {%- else %}
189
+ {%- set ns_flags.last_tool_failed = false %}
190
+ {%- set ns_flags.consecutive_failures = 0 %}
191
+ {%- endif %}
192
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
193
+ {{- '<|im_start|>user' }}
194
+ {%- endif %}
195
+ {{- '\n<tool_response>\n' }}
196
+ {{- content }}
197
+ {{- '\n</tool_response>' }}
198
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
199
+ {{- '<|im_end|>\n' }}
200
+ {%- elif loop.last %}
201
+ {{- '<|im_end|>\n' }}
202
+ {%- endif %}
203
+ {%- else %}
204
+ {{- raise_exception('Unexpected message role.') }}
205
+ {%- endif %}
206
+ {%- endfor %}
207
+ {%- if add_generation_prompt %}
208
+ {{- '<|im_start|>assistant\n' }}
209
+ {%- if ns_flags.last_tool_failed %}
210
+ {%- if ns_flags.consecutive_failures >= 2 %}
211
+ {{- '<think>\n\n</think>\n\n⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }}
212
+ {%- else %}
213
+ {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }}
214
+ {%- endif %}
215
+ {%- elif ns_flags.enable_thinking is false %}
216
+ {{- '<think>\n\n</think>\n\n' }}
217
+ {%- else %}
218
+ {{- '<think>\n' }}
219
+ {%- endif %}
220
+ {%- endif %}
archive/qwen3.6/chat_template-v15_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- elif message.role == "assistant" %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- set content_lower = content | lower %} {%- if content | length < 500 and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %} {%- set ns_flags.last_tool_failed = true %} {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %} {%- else %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- endif %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.last_tool_failed %} {%- if ns_flags.consecutive_failures >= 2 %} {{- '<think>\n\n</think>\n\n⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }} {%- else %} {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }} {%- endif %} {%- elif ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v16.jinja ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <think>
78
+ Brief explanation of tool call
79
+ </think>
80
+
81
+ <tool_call>
82
+ <function=example_function_name>
83
+ <parameter=example_parameter_1>
84
+ value_1
85
+ </parameter>
86
+ <parameter=example_parameter_2>
87
+ This is the value for the second parameter
88
+ that can span
89
+ multiple lines
90
+ </parameter>
91
+ </function>
92
+ </tool_call>
93
+
94
+ <IMPORTANT>
95
+ Reminder:
96
+ - Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags
97
+ - Required parameters MUST be specified
98
+ - Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response
99
+ - 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
100
+ </IMPORTANT>
101
+ {%- endset %}
102
+ {{- '\n\n' ~ tool_instructions | trim }}
103
+ {%- if has_system and system_content %}
104
+ {{- '\n\n' + system_content }}
105
+ {%- endif %}
106
+ {{- '<|im_end|>\n' }}
107
+ {%- elif has_system and system_content %}
108
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
109
+ {%- endif %}
110
+ {%- for message in messages %}
111
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
112
+ {%- set content = render_content(message.content, true, is_system)|trim %}
113
+ {%- if '<|think_off|>' in content %}
114
+ {%- set ns_flags.enable_thinking = false %}
115
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
116
+ {%- elif '<|think_on|>' in content %}
117
+ {%- set ns_flags.enable_thinking = true %}
118
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
119
+ {%- endif %}
120
+ {%- if is_system %}
121
+ {%- if not loop.first and content %}
122
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
123
+ {%- endif %}
124
+ {%- elif message.role == "user" %}
125
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
126
+ {%- set ns_flags.last_tool_failed = false %}
127
+ {%- set ns_flags.consecutive_failures = 0 %}
128
+ {%- elif message.role == "assistant" %}
129
+ {%- set ns_flags.last_tool_failed = false %}
130
+ {%- set reasoning_content = '' %}
131
+ {%- if message.reasoning_content is string %}
132
+ {%- set reasoning_content = message.reasoning_content %}
133
+ {%- else %}
134
+ {%- set think_end_token = '' %}
135
+ {%- if '</think>' in content %}
136
+ {%- set think_end_token = '</think>' %}
137
+ {%- elif '</thinking>' in content %}
138
+ {%- set think_end_token = '</thinking>' %}
139
+ {%- elif '</ think>' in content %}
140
+ {%- set think_end_token = '</ think>' %}
141
+ {%- elif '</think >' in content %}
142
+ {%- set think_end_token = '</think >' %}
143
+ {%- endif %}
144
+ {%- if think_end_token %}
145
+ {%- set reasoning_parts = content.split(think_end_token) %}
146
+ {%- set reasoning_content = reasoning_parts[0] %}
147
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
148
+ {%- if '<think>' in reasoning_content %}
149
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
150
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
151
+ {%- set content = r_prefix ~ '\n' ~ content %}
152
+ {%- endif %}
153
+ {%- elif '<think>' in content %}
154
+ {%- set prefix = content.split('<think>')[0] %}
155
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
156
+ {%- if '<tool_call>' in think_part %}
157
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
158
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
159
+ {%- else %}
160
+ {%- set reasoning_content = think_part %}
161
+ {%- set content = prefix %}
162
+ {%- endif %}
163
+ {%- endif %}
164
+ {%- endif %}
165
+ {%- set reasoning_content = reasoning_content | trim %}
166
+ {%- set content = content | trim %}
167
+ {%- set show_think = false %}
168
+ {%- if reasoning_content %}
169
+ {%- if preserve_thinking is defined and preserve_thinking %}
170
+ {%- set show_think = true %}
171
+ {%- elif loop.last %}
172
+ {%- set show_think = true %}
173
+ {%- endif %}
174
+ {%- endif %}
175
+ {%- if show_think %}
176
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }}
177
+ {%- else %}
178
+ {{- '<|im_start|>' + message.role + '\n' + content }}
179
+ {%- endif %}
180
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
181
+ {%- for tool_call in message.tool_calls %}
182
+ {%- if tool_call.function is defined %}
183
+ {%- set tool_call = tool_call.function %}
184
+ {%- endif %}
185
+ {%- if loop.first and content %}
186
+ {{- '\n\n<tool_call>\n' }}
187
+ {%- else %}
188
+ {{- '\n<tool_call>\n' }}
189
+ {%- endif %}
190
+ {{- '<function=' ~ tool_call.name ~ '>\n' }}
191
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
192
+ {%- if tool_call.arguments | length > 0 %}
193
+ {%- for args_name in tool_call.arguments %}
194
+ {%- set args_value = tool_call.arguments[args_name] %}
195
+ {{- '<parameter=' ~ args_name ~ '>\n' }}
196
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
197
+ {{- args_value }}
198
+ {{- '\n</parameter>\n' }}
199
+ {%- endfor %}
200
+ {%- endif %}
201
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
202
+ {%- if tool_call.arguments | trim | length > 0 %}
203
+ {{- tool_call.arguments }}
204
+ {{- '\n' }}
205
+ {%- endif %}
206
+ {%- endif %}
207
+ {{- '</function>\n</tool_call>' }}
208
+ {%- endfor %}
209
+ {%- endif %}
210
+ {{- '<|im_end|>\n' }}
211
+ {%- elif message.role == "tool" %}
212
+ {%- set content_lower = content | lower %}
213
+ {%- if content | length < 500
214
+ and '$ ' not in content
215
+ and 'took ' not in content_lower
216
+ and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %}
217
+ {%- set ns_flags.last_tool_failed = true %}
218
+ {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}
219
+ {%- else %}
220
+ {%- set ns_flags.last_tool_failed = false %}
221
+ {%- set ns_flags.consecutive_failures = 0 %}
222
+ {%- endif %}
223
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
224
+ {{- '<|im_start|>user' }}
225
+ {%- endif %}
226
+ {{- '\n<tool_response>\n' }}
227
+ {{- content }}
228
+ {{- '\n</tool_response>' }}
229
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
230
+ {{- '<|im_end|>\n' }}
231
+ {%- elif loop.last %}
232
+ {{- '<|im_end|>\n' }}
233
+ {%- endif %}
234
+ {%- else %}
235
+ {{- raise_exception('Unexpected message role.') }}
236
+ {%- endif %}
237
+ {%- endfor %}
238
+ {%- if add_generation_prompt %}
239
+ {{- '<|im_start|>assistant\n' }}
240
+ {%- if ns_flags.last_tool_failed %}
241
+ {%- if ns_flags.consecutive_failures >= 2 %}
242
+ {%- if ns_flags.enable_thinking is not false %}
243
+ {{- '<think>\n\n</think>\n\n' }}
244
+ {%- endif %}
245
+ {{- '⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }}
246
+ {%- else %}
247
+ {%- if ns_flags.enable_thinking is not false %}
248
+ {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }}
249
+ {%- else %}
250
+ {{- 'The previous tool call returned an error. I must retry with completely corrected arguments:\n\n' }}
251
+ {%- endif %}
252
+ {%- endif %}
253
+ {%- elif ns_flags.enable_thinking is false %}
254
+ {{- '<think>\n\n</think>\n\n' }}
255
+ {%- else %}
256
+ {{- '<think>\n' }}
257
+ {%- endif %}
258
+ {%- endif %}
archive/qwen3.6/chat_template-v16_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<tool_call>{"name": "tool_name", "arguments": {"arg_name": "value"}}</tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner JSON object must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- Use the <think></think> block to reason about your actions, plan function calls, and synthesize results before your final response- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- elif message.role == "assistant" %} {%- set ns_flags.last_tool_failed = false %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '{"name": "' ~ tool_call.name ~ '", "arguments": ' ~ (tool_call.arguments | tojson if tool_call.arguments is mapping else tool_call.arguments) ~ '}\n' }} {{- '</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- set content_lower = content | lower %} {%- if content | length < 500 and '$ ' not in content and 'took ' not in content_lower and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %} {%- set ns_flags.last_tool_failed = true %} {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %} {%- else %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- endif %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.last_tool_failed %} {%- if ns_flags.consecutive_failures >= 2 %} {%- if ns_flags.enable_thinking is not false %} {{- '<think>\n\n</think>\n\n' }} {%- endif %} {{- '⚠️ ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors. My previous approach is wrong. I will now call the tool with a fundamentally different, corrected approach:\n\n' }} {%- else %} {%- if ns_flags.enable_thinking is not false %} {{- '<think>\nThe previous tool call returned an error. I must diagnose the failure and retry with completely corrected arguments:\n' }} {%- else %} {{- 'The previous tool call returned an error. I must retry with completely corrected arguments:\n\n' }} {%- endif %} {%- endif %} {%- elif ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v17.jinja ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <think>
78
+ Brief explanation of tool call
79
+ </think>
80
+ <tool_call>
81
+ <function=example_function_name>
82
+ <parameter=example_parameter_1>
83
+ value_1
84
+ </parameter>
85
+ <parameter=example_parameter_2>
86
+ This is the value for the second parameter
87
+ that can span
88
+ multiple lines
89
+ </parameter>
90
+ </function>
91
+ </tool_call>
92
+
93
+ <IMPORTANT>
94
+ Reminder:
95
+ - Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags
96
+ - Required parameters MUST be specified
97
+ - ALL explanation and reasoning MUST be placed strictly inside the <think></think> block.
98
+ - IMMEDIATELY after closing </think>, you must output the <tool_call> block. Do NOT output any conversational text in between.
99
+ - The <tool_call> and <function> tags MUST be at the very beginning of a new line, with NO spaces or indentation before them.
100
+ - To call multiple functions, output a separate, completely closed <tool_call></tool_call> block for EACH function. Do NOT nest <tool_call> blocks.
101
+ - 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
102
+ </IMPORTANT>
103
+ {%- endset %}
104
+ {{- '\n\n' ~ tool_instructions | trim }}
105
+ {%- if has_system and system_content %}
106
+ {{- '\n\n' + system_content }}
107
+ {%- endif %}
108
+ {{- '<|im_end|>\n' }}
109
+ {%- elif has_system and system_content %}
110
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
111
+ {%- endif %}
112
+ {%- for message in messages %}
113
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
114
+ {%- set content = render_content(message.content, true, is_system)|trim %}
115
+ {%- if '<|think_off|>' in content %}
116
+ {%- set ns_flags.enable_thinking = false %}
117
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
118
+ {%- elif '<|think_on|>' in content %}
119
+ {%- set ns_flags.enable_thinking = true %}
120
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
121
+ {%- endif %}
122
+ {%- if is_system %}
123
+ {%- if not loop.first and content %}
124
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
125
+ {%- endif %}
126
+ {%- elif message.role == "user" %}
127
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
128
+ {%- set ns_flags.last_tool_failed = false %}
129
+ {%- set ns_flags.consecutive_failures = 0 %}
130
+ {%- elif message.role == "assistant" %}
131
+ {%- set ns_flags.last_tool_failed = false %}
132
+ {%- set reasoning_content = '' %}
133
+ {%- if message.reasoning_content is string %}
134
+ {%- set reasoning_content = message.reasoning_content %}
135
+ {%- else %}
136
+ {%- set think_end_token = '' %}
137
+ {%- if '</think>' in content %}
138
+ {%- set think_end_token = '</think>' %}
139
+ {%- elif '</thinking>' in content %}
140
+ {%- set think_end_token = '</thinking>' %}
141
+ {%- elif '</ think>' in content %}
142
+ {%- set think_end_token = '</ think>' %}
143
+ {%- elif '</think >' in content %}
144
+ {%- set think_end_token = '</think >' %}
145
+ {%- endif %}
146
+ {%- if think_end_token %}
147
+ {%- set reasoning_parts = content.split(think_end_token) %}
148
+ {%- set reasoning_content = reasoning_parts[0] %}
149
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
150
+ {%- if '<think>' in reasoning_content %}
151
+ {%- set r_prefix = reasoning_content.split('<think>')[0] %}
152
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %}
153
+ {%- set content = r_prefix ~ '\n' ~ content %}
154
+ {%- endif %}
155
+ {%- elif '<think>' in content %}
156
+ {%- set prefix = content.split('<think>')[0] %}
157
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
158
+ {%- if '<tool_call>' in think_part %}
159
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
160
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
161
+ {%- else %}
162
+ {%- set reasoning_content = think_part %}
163
+ {%- set content = prefix %}
164
+ {%- endif %}
165
+ {%- endif %}
166
+ {%- endif %}
167
+ {%- set reasoning_content = reasoning_content | trim %}
168
+ {%- set content = content | trim %}
169
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
170
+ {%- if '<tool_call>' in content %}
171
+ {%- set content = content.split('<tool_call>')[0] | trim %}
172
+ {%- endif %}
173
+ {%- endif %}
174
+ {%- set show_think = false %}
175
+ {%- if reasoning_content %}
176
+ {%- if preserve_thinking is defined and preserve_thinking %}
177
+ {%- set show_think = true %}
178
+ {%- elif loop.last %}
179
+ {%- set show_think = true %}
180
+ {%- endif %}
181
+ {%- endif %}
182
+ {%- if show_think %}
183
+ {%- if content %}
184
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n' + content }}
185
+ {%- else %}
186
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>' }}
187
+ {%- endif %}
188
+ {%- else %}
189
+ {%- if message.role == 'assistant' and ns_flags.enable_thinking is not false %}
190
+ {%- if content %}
191
+ {{- '<|im_start|>' + message.role + '\n<think>\n</think>\n' + content }}
192
+ {%- else %}
193
+ {{- '<|im_start|>' + message.role + '\n<think>\n</think>' }}
194
+ {%- endif %}
195
+ {%- else %}
196
+ {%- if content %}
197
+ {{- '<|im_start|>' + message.role + '\n' + content }}
198
+ {%- else %}
199
+ {{- '<|im_start|>' + message.role }}
200
+ {%- endif %}
201
+ {%- endif %}
202
+ {%- endif %}
203
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
204
+ {%- for tool_call in message.tool_calls %}
205
+ {%- if tool_call.function is defined %}
206
+ {%- set tool_call = tool_call.function %}
207
+ {%- endif %}
208
+ {%- if loop.first and content %}
209
+ {{- '\n<tool_call>\n' }}
210
+ {%- else %}
211
+ {{- '\n<tool_call>\n' }}
212
+ {%- endif %}
213
+ {{- '<function=' ~ tool_call.name ~ '>\n' }}
214
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
215
+ {%- if tool_call.arguments | length > 0 %}
216
+ {%- for args_name in tool_call.arguments %}
217
+ {%- set args_value = tool_call.arguments[args_name] %}
218
+ {{- '<parameter=' ~ args_name ~ '>\n' }}
219
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
220
+ {{- args_value }}
221
+ {{- '\n</parameter>\n' }}
222
+ {%- endfor %}
223
+ {%- endif %}
224
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
225
+ {%- if tool_call.arguments | trim | length > 0 %}
226
+ {{- tool_call.arguments }}
227
+ {{- '\n' }}
228
+ {%- endif %}
229
+ {%- endif %}
230
+ {{- '</function>\n</tool_call>' }}
231
+ {%- endfor %}
232
+ {%- endif %}
233
+ {{- '<|im_end|>\n' }}
234
+ {%- elif message.role == "tool" %}
235
+ {%- set content_lower = content | lower %}
236
+ {%- if content | length < 500
237
+ and '$ ' not in content
238
+ and 'took ' not in content_lower
239
+ and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %}
240
+ {%- set ns_flags.last_tool_failed = true %}
241
+ {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}
242
+ {%- else %}
243
+ {%- set ns_flags.last_tool_failed = false %}
244
+ {%- set ns_flags.consecutive_failures = 0 %}
245
+ {%- endif %}
246
+ {%- if loop.previtem and loop.previtem.role != "tool" %}
247
+ {{- '<|im_start|>user' }}
248
+ {%- endif %}
249
+ {{- '\n<tool_response>\n' }}
250
+ {{- content }}
251
+ {%- if ns_flags.last_tool_failed %}
252
+ {%- if ns_flags.consecutive_failures >= 2 %}
253
+ {{- '\n\n⚠️ SYSTEM WARNING: ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors detected. Your previous approach is incorrect. You MUST use a fundamentally different approach or corrected arguments.' }}
254
+ {%- else %}
255
+ {{- '\n\n⚠️ SYSTEM WARNING: The previous tool call returned an error. Diagnose the failure and retry with completely corrected arguments.' }}
256
+ {%- endif %}
257
+ {%- endif %}
258
+ {{- '\n</tool_response>' }}
259
+ {%- if not loop.last and loop.nextitem.role != "tool" %}
260
+ {{- '<|im_end|>\n' }}
261
+ {%- elif loop.last %}
262
+ {{- '<|im_end|>\n' }}
263
+ {%- endif %}
264
+ {%- else %}
265
+ {{- raise_exception('Unexpected message role.') }}
266
+ {%- endif %}
267
+ {%- endfor %}
268
+ {%- if add_generation_prompt %}
269
+ {{- '<|im_start|>assistant\n' }}
270
+ {%- if ns_flags.enable_thinking is false %}
271
+ {{- '<think>\n\n</think>\n\n' }}
272
+ {%- elif ns_flags.last_tool_failed and ns_flags.consecutive_failures >= 2 %}
273
+ {{- '<think>\n\n</think>\n\n' }}
274
+ {%- else %}
275
+ {{- '<think>\n' }}
276
+ {%- endif %}
277
+ {%- endif %}
archive/qwen3.6/chat_template-v17_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %} {%- if content is string %} {{- content }} {%- elif content is iterable and content is not mapping %} {%- for item in content %} {%- if 'image' in item or 'image_url' in item or item.type == 'image' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain images.') }} {%- endif %} {%- if do_vision_count %} {%- set image_count.value = image_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Picture ' ~ image_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|image_pad|><|vision_end|>' }} {%- elif 'video' in item or item.type == 'video' %} {%- if is_system_content %} {{- raise_exception('System message cannot contain videos.') }} {%- endif %} {%- if do_vision_count %} {%- set video_count.value = video_count.value + 1 %} {%- endif %} {%- if add_vision_id is defined and add_vision_id %} {{- 'Video ' ~ video_count.value ~ ': ' }} {%- endif %} {{- '<|vision_start|><|video_pad|><|vision_end|>' }} {%- elif 'text' in item %} {{- item.text }} {%- else %} {{- raise_exception('Unexpected item type in content.') }} {%- endif %} {%- endfor %} {%- elif content is none or content is undefined %} {{- '' }} {%- else %} {{- raise_exception('Unexpected content type.') }} {%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}{%- if enable_thinking is defined %} {%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %} {{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %} {%- set has_system = true %} {%- set system_content = render_content(messages[0].content, false, true)|trim %} {%- if '<|think_off|>' in system_content %} {%- set ns_flags.enable_thinking = false %} {%- set system_content = system_content | replace('<|think_off|>', '') %} {%- endif %} {%- if '<|think_on|>' in system_content %} {%- set ns_flags.enable_thinking = true %} {%- set system_content = system_content | replace('<|think_on|>', '') %} {%- endif %} {%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %} {%- set ns_flags.has_tools = true %} {{- '<|im_start|>system\n' }} {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }} {%- for tool in tools %} {{- '\n' }} {%- set fn = tool.function if tool.function is defined else tool %} {{- fn | tojson }} {%- endfor %} {{- "\n</tools>" }} {%- set tool_instructions %}If you choose to call a function ONLY reply in the following format with NO suffix:<think>Brief explanation of tool call</think><tool_call><function=example_function_name><parameter=example_parameter_1>value_1</parameter><parameter=example_parameter_2>This is the value for the second parameterthat can spanmultiple lines</parameter></function></tool_call><IMPORTANT>Reminder:- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags- Required parameters MUST be specified- ALL explanation and reasoning MUST be placed strictly inside the <think></think> block.- IMMEDIATELY after closing </think>, you must output the <tool_call> block. Do NOT output any conversational text in between.- The <tool_call> and <function> tags MUST be at the very beginning of a new line, with NO spaces or indentation before them.- To call multiple functions, output a separate, completely closed <tool_call></tool_call> block for EACH function. Do NOT nest <tool_call> blocks.- 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</IMPORTANT> {%- endset %} {{- '\n\n' ~ tool_instructions | trim }} {%- if has_system and system_content %} {{- '\n\n' + system_content }} {%- endif %} {{- '<|im_end|>\n' }}{%- elif has_system and system_content %} {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %} {%- set is_system = (message.role == "system" or message.role == "developer") %} {%- set content = render_content(message.content, true, is_system)|trim %} {%- if '<|think_off|>' in content %} {%- set ns_flags.enable_thinking = false %} {%- set content = content | replace('<|think_off|>', '') | trim %} {%- elif '<|think_on|>' in content %} {%- set ns_flags.enable_thinking = true %} {%- set content = content | replace('<|think_on|>', '') | trim %} {%- endif %} {%- if is_system %} {%- if not loop.first and content %} {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }} {%- endif %} {%- elif message.role == "user" %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- elif message.role == "assistant" %} {%- set ns_flags.last_tool_failed = false %} {%- set reasoning_content = '' %} {%- if message.reasoning_content is string %} {%- set reasoning_content = message.reasoning_content %} {%- else %} {%- set think_end_token = '' %} {%- if '</think>' in content %} {%- set think_end_token = '</think>' %} {%- elif '</thinking>' in content %} {%- set think_end_token = '</thinking>' %} {%- elif '</ think>' in content %} {%- set think_end_token = '</ think>' %} {%- elif '</think >' in content %} {%- set think_end_token = '</think >' %} {%- endif %} {%- if think_end_token %} {%- set reasoning_parts = content.split(think_end_token) %} {%- set reasoning_content = reasoning_parts[0] %} {%- set content = reasoning_parts[1:] | join(think_end_token) %} {%- if '<think>' in reasoning_content %} {%- set r_prefix = reasoning_content.split('<think>')[0] %} {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') %} {%- set content = r_prefix ~ '\n' ~ content %} {%- endif %} {%- elif '<think>' in content %} {%- set prefix = content.split('<think>')[0] %} {%- set think_part = content.split('<think>')[1:] | join('<think>') %} {%- if '<tool_call>' in think_part %} {%- set reasoning_content = think_part.split('<tool_call>')[0] %} {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %} {%- else %} {%- set reasoning_content = think_part %} {%- set content = prefix %} {%- endif %} {%- endif %} {%- endif %} {%- set reasoning_content = reasoning_content | trim %} {%- set content = content | trim %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- if '<tool_call>' in content %} {%- set content = content.split('<tool_call>')[0] | trim %} {%- endif %} {%- endif %} {%- set show_think = false %} {%- if reasoning_content %} {%- if preserve_thinking is defined and preserve_thinking %} {%- set show_think = true %} {%- elif loop.last %} {%- set show_think = true %} {%- endif %} {%- endif %} {%- if show_think %} {%- if content %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>' }} {%- endif %} {%- else %} {%- if message.role == 'assistant' and ns_flags.enable_thinking is not false %} {%- if content %} {{- '<|im_start|>' + message.role + '\n<think>\n</think>\n' + content }} {%- else %} {{- '<|im_start|>' + message.role + '\n<think>\n</think>' }} {%- endif %} {%- else %} {%- if content %} {{- '<|im_start|>' + message.role + '\n' + content }} {%- else %} {{- '<|im_start|>' + message.role }} {%- endif %} {%- endif %} {%- endif %} {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {%- if loop.first and content %} {{- '\n<tool_call>\n' }} {%- else %} {{- '\n<tool_call>\n' }} {%- endif %} {{- '<function=' ~ tool_call.name ~ '>\n' }} {%- if tool_call.arguments is defined and tool_call.arguments is mapping %} {%- if tool_call.arguments | length > 0 %} {%- for args_name in tool_call.arguments %} {%- set args_value = tool_call.arguments[args_name] %} {{- '<parameter=' ~ args_name ~ '>\n' }} {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %} {{- args_value }} {{- '\n</parameter>\n' }} {%- endfor %} {%- endif %} {%- elif tool_call.arguments is defined and tool_call.arguments is string %} {%- if tool_call.arguments | trim | length > 0 %} {{- tool_call.arguments }} {{- '\n' }} {%- endif %} {%- endif %} {{- '</function>\n</tool_call>' }} {%- endfor %} {%- endif %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- set content_lower = content | lower %} {%- if content | length < 500 and '$ ' not in content and 'took ' not in content_lower and ('error' in content_lower or 'fail' in content_lower or 'invalid' in content_lower or 'exceeds' in content_lower or 'retry' in content_lower or 'exception' in content_lower) %} {%- set ns_flags.last_tool_failed = true %} {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %} {%- else %} {%- set ns_flags.last_tool_failed = false %} {%- set ns_flags.consecutive_failures = 0 %} {%- endif %} {%- if loop.previtem and loop.previtem.role != "tool" %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- content }} {%- if ns_flags.last_tool_failed %} {%- if ns_flags.consecutive_failures >= 2 %} {{- '\n\n⚠️ SYSTEM WARNING: ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors detected. Your previous approach is incorrect. You MUST use a fundamentally different approach or corrected arguments.' }} {%- else %} {{- '\n\n⚠️ SYSTEM WARNING: The previous tool call returned an error. Diagnose the failure and retry with completely corrected arguments.' }} {%- endif %} {%- endif %} {{- '\n</tool_response>' }} {%- if not loop.last and loop.nextitem.role != "tool" %} {{- '<|im_end|>\n' }} {%- elif loop.last %} {{- '<|im_end|>\n' }} {%- endif %} {%- else %} {{- raise_exception('Unexpected message role.') }} {%- endif %}{%- endfor %}{%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- if ns_flags.enable_thinking is false %} {{- '<think>\n\n</think>\n\n' }} {%- elif ns_flags.last_tool_failed and ns_flags.consecutive_failures >= 2 %} {{- '<think>\n\n</think>\n\n' }} {%- else %} {{- '<think>\n' }} {%- endif %}{%- endif %}
archive/qwen3.6/chat_template-v18.jinja ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- set image_count = namespace(value=0) %}
2
+ {%- set video_count = namespace(value=0) %}
3
+ {%- macro render_content(content, do_vision_count, is_system_content=false) %}
4
+ {%- if content is string %}
5
+ {{- content }}
6
+ {%- elif content is iterable and content is not mapping %}
7
+ {%- for item in content %}
8
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}
9
+ {%- if is_system_content %}
10
+ {{- raise_exception('System message cannot contain images.') }}
11
+ {%- endif %}
12
+ {%- if do_vision_count %}
13
+ {%- set image_count.value = image_count.value + 1 %}
14
+ {%- endif %}
15
+ {%- if add_vision_id is defined and add_vision_id %}
16
+ {{- 'Picture ' ~ image_count.value ~ ': ' }}
17
+ {%- endif %}
18
+ {{- '<|vision_start|><|image_pad|><|vision_end|>' }}
19
+ {%- elif 'video' in item or item.type == 'video' %}
20
+ {%- if is_system_content %}
21
+ {{- raise_exception('System message cannot contain videos.') }}
22
+ {%- endif %}
23
+ {%- if do_vision_count %}
24
+ {%- set video_count.value = video_count.value + 1 %}
25
+ {%- endif %}
26
+ {%- if add_vision_id is defined and add_vision_id %}
27
+ {{- 'Video ' ~ video_count.value ~ ': ' }}
28
+ {%- endif %}
29
+ {{- '<|vision_start|><|video_pad|><|vision_end|>' }}
30
+ {%- elif 'text' in item %}
31
+ {{- item.text }}
32
+ {%- else %}
33
+ {{- raise_exception('Unexpected item type in content.') }}
34
+ {%- endif %}
35
+ {%- endfor %}
36
+ {%- elif content is none or content is undefined %}
37
+ {{- '' }}
38
+ {%- else %}
39
+ {{- raise_exception('Unexpected content type.') }}
40
+ {%- endif %}
41
+ {%- endmacro %}
42
+ {%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}
43
+ {%- if enable_thinking is defined %}
44
+ {%- set ns_flags.enable_thinking = enable_thinking %}
45
+ {%- endif %}
46
+ {%- if not messages %}
47
+ {{- raise_exception('No messages provided.') }}
48
+ {%- endif %}
49
+ {%- set system_content = '' %}
50
+ {%- set has_system = false %}
51
+ {%- if messages[0].role == 'system' or messages[0].role == 'developer' %}
52
+ {%- set has_system = true %}
53
+ {%- set system_content = render_content(messages[0].content, false, true)|trim %}
54
+ {%- if '<|think_off|>' in system_content %}
55
+ {%- set ns_flags.enable_thinking = false %}
56
+ {%- set system_content = system_content | replace('<|think_off|>', '') %}
57
+ {%- endif %}
58
+ {%- if '<|think_on|>' in system_content %}
59
+ {%- set ns_flags.enable_thinking = true %}
60
+ {%- set system_content = system_content | replace('<|think_on|>', '') %}
61
+ {%- endif %}
62
+ {%- set system_content = system_content | trim %}
63
+ {%- endif %}
64
+ {%- if tools and tools is iterable and tools is not mapping %}
65
+ {%- set ns_flags.has_tools = true %}
66
+ {{- '<|im_start|>system\n' }}
67
+ {{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}
68
+ {%- for tool in tools %}
69
+ {{- '\n' }}
70
+ {%- set fn = tool.function if tool.function is defined else tool %}
71
+ {{- fn | tojson }}
72
+ {%- endfor %}
73
+ {{- "\n</tools>" }}
74
+ {%- set tool_instructions %}
75
+ If you choose to call a function ONLY reply in the following format with NO suffix:
76
+
77
+ <think>
78
+ Brief explanation of tool call
79
+ </think>
80
+ <tool_call>
81
+ <function=example_function_name>
82
+ <parameter=example_parameter_1>
83
+ value_1
84
+ </parameter>
85
+ <parameter=example_parameter_2>
86
+ This is the value for the second parameter
87
+ that can span
88
+ multiple lines
89
+ </parameter>
90
+ </function>
91
+ </tool_call>
92
+
93
+ <IMPORTANT>
94
+ Reminder:
95
+ - Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags
96
+ - Required parameters MUST be specified
97
+ - ALL explanation and reasoning MUST be placed strictly inside the <think></think> block.
98
+ - IMMEDIATELY after closing </think>, you must output the <tool_call> block. Do NOT output any conversational text in between.
99
+ - The <tool_call> and <function> tags MUST be at the very beginning of a new line, with NO spaces or indentation before them.
100
+ - To call multiple functions, output a separate, completely closed <tool_call></tool_call> block for EACH function. Do NOT nest <tool_call> blocks.
101
+ - 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
102
+ </IMPORTANT>
103
+ {%- endset %}
104
+ {{- '\n\n' ~ tool_instructions | trim }}
105
+ {%- if has_system and system_content %}
106
+ {{- '\n\n' + system_content }}
107
+ {%- endif %}
108
+ {{- '<|im_end|>\n' }}
109
+ {%- elif has_system and system_content %}
110
+ {{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}
111
+ {%- endif %}
112
+ {%- for message in messages %}
113
+ {%- set is_system = (message.role == "system" or message.role == "developer") %}
114
+ {%- set content = render_content(message.content, true, is_system)|trim %}
115
+ {%- if '<|think_off|>' in content %}
116
+ {%- set ns_flags.enable_thinking = false %}
117
+ {%- set content = content | replace('<|think_off|>', '') | trim %}
118
+ {%- elif '<|think_on|>' in content %}
119
+ {%- set ns_flags.enable_thinking = true %}
120
+ {%- set content = content | replace('<|think_on|>', '') | trim %}
121
+ {%- endif %}
122
+ {%- if is_system %}
123
+ {%- if not loop.first and content %}
124
+ {{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}
125
+ {%- endif %}
126
+ {%- elif message.role == "user" %}
127
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}
128
+ {%- set ns_flags.last_tool_failed = false %}
129
+ {%- set ns_flags.consecutive_failures = 0 %}
130
+ {%- elif message.role == "assistant" %}
131
+ {%- set ns_flags.last_tool_failed = false %}
132
+ {%- set reasoning_content = '' %}
133
+ {%- if message.reasoning_content is string %}
134
+ {%- set reasoning_content = message.reasoning_content %}
135
+ {%- else %}
136
+ {%- set think_end_token = '' %}
137
+ {%- if '</think>' in content %}
138
+ {%- set think_end_token = '</think>' %}
139
+ {%- elif '</thinking>' in content %}
140
+ {%- set think_end_token = '</thinking>' %}
141
+ {%- elif '</ think>' in content %}
142
+ {%- set think_end_token = '</ think>' %}
143
+ {%- elif '</think >' in content %}
144
+ {%- set think_end_token = '</think >' %}
145
+ {%- endif %}
146
+ {%- if think_end_token %}
147
+ {%- set reasoning_parts = content.split(think_end_token) %}
148
+ {%- set reasoning_content = reasoning_parts[0] %}
149
+ {%- set content = reasoning_parts[1:] | join(think_end_token) %}
150
+ {%- if '<think>' in reasoning_content %}
151
+ {%- set r_prefix = reasoning_content.split('<think>')[0] | trim %}
152
+ {%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') | trim %}
153
+ {%- set content = (r_prefix ~ '\n' ~ content) | trim %}
154
+ {%- endif %}
155
+ {%- elif '<think>' in content %}
156
+ {%- set prefix = content.split('<think>')[0] %}
157
+ {%- set think_part = content.split('<think>')[1:] | join('<think>') %}
158
+ {%- if '<tool_call>' in think_part %}
159
+ {%- set reasoning_content = think_part.split('<tool_call>')[0] %}
160
+ {%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}
161
+ {%- else %}
162
+ {%- set reasoning_content = think_part %}
163
+ {%- set content = prefix %}
164
+ {%- endif %}
165
+ {%- endif %}
166
+ {%- endif %}
167
+ {%- set reasoning_content = reasoning_content | trim %}
168
+ {%- set content = content | trim %}
169
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
170
+ {%- if '<tool_call>' in content %}
171
+ {%- set content = content.split('<tool_call>')[0] | trim %}
172
+ {%- endif %}
173
+ {%- endif %}
174
+ {%- set show_think = false %}
175
+ {%- if reasoning_content %}
176
+ {%- if preserve_thinking is defined and preserve_thinking %}
177
+ {%- set show_think = true %}
178
+ {%- elif loop.last %}
179
+ {%- set show_think = true %}
180
+ {%- endif %}
181
+ {%- endif %}
182
+ {%- if show_think %}
183
+ {%- if content %}
184
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n' + content }}
185
+ {%- else %}
186
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>' }}
187
+ {%- endif %}
188
+ {%- else %}
189
+ {%- if message.role == 'assistant' and ns_flags.enable_thinking is not false %}
190
+ {%- if content %}
191
+ {{- '<|im_start|>' + message.role + '\n<think>\n</think>\n' + content }}
192
+ {%- else %}
193
+ {{- '<|im_start|>' + message.role + '\n<think>\n</think>' }}
194
+ {%- endif %}
195
+ {%- else %}
196
+ {%- if content %}
197
+ {{- '<|im_start|>' + message.role + '\n' + content }}
198
+ {%- else %}
199
+ {{- '<|im_start|>' + message.role }}
200
+ {%- endif %}
201
+ {%- endif %}
202
+ {%- endif %}
203
+ {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}
204
+ {%- for tool_call in message.tool_calls %}
205
+ {%- if tool_call.function is defined %}
206
+ {%- set tool_call = tool_call.function %}
207
+ {%- endif %}
208
+ {{- '\n<tool_call>\n' }}
209
+ {{- '<function=' ~ tool_call.name ~ '>\n' }}
210
+ {%- if tool_call.arguments is defined and tool_call.arguments is mapping %}
211
+ {%- if tool_call.arguments | length > 0 %}
212
+ {%- for args_name in tool_call.arguments %}
213
+ {%- set args_value = tool_call.arguments[args_name] %}
214
+ {{- '<parameter=' ~ args_name ~ '>\n' }}
215
+ {%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}
216
+ {{- args_value }}
217
+ {{- '\n</parameter>\n' }}
218
+ {%- endfor %}
219
+ {%- endif %}
220
+ {%- elif tool_call.arguments is defined and tool_call.arguments is string %}
221
+ {%- if tool_call.arguments | trim | length > 0 %}
222
+ {{- tool_call.arguments }}
223
+ {{- '\n' }}
224
+ {%- endif %}
225
+ {%- endif %}
226
+ {{- '</function>\n</tool_call>' }}
227
+ {%- endfor %}
228
+ {%- endif %}
229
+ {{- '<|im_end|>\n' }}
230
+ {%- elif message.role == "tool" %}
231
+ {%- set content_lower = content | lower %}
232
+ {%- if content | length < 500
233
+ and '$ ' not in content
234
+ and 'took ' not in content_lower
235
+ and ('"error":' in content_lower or 'error:' in content_lower or 'exception:' in content_lower or 'traceback' in content_lower or 'command not found' in content_lower or 'invalid syntax' in content_lower or 'failed to' in content_lower) %}
236
+ {%- set ns_flags.last_tool_failed = true %}
237
+ {%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}
238
+ {%- else %}
239
+ {%- set ns_flags.last_tool_failed = false %}
240
+ {%- set ns_flags.consecutive_failures = 0 %}
241
+ {%- endif %}
242
+ {%- if loop.index0 > 0 and messages[loop.index0 - 1].role != "tool" %}
243
+ {{- '<|im_start|>user' }}
244
+ {%- endif %}
245
+ {{- '\n<tool_response>\n' }}
246
+ {{- content }}
247
+ {%- if ns_flags.last_tool_failed %}
248
+ {%- if ns_flags.consecutive_failures >= 2 %}
249
+ {{- '\n\n⚠️ SYSTEM WARNING: ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors detected. Your previous approach is incorrect. You MUST use a fundamentally different approach or corrected arguments.' }}
250
+ {%- else %}
251
+ {{- '\n\n⚠️ SYSTEM WARNING: The previous tool call returned an error. Diagnose the failure and retry with completely corrected arguments.' }}
252
+ {%- endif %}
253
+ {%- endif %}
254
+ {{- '\n</tool_response>' }}
255
+ {%- if not loop.last and messages[loop.index0 + 1].role != "tool" %}
256
+ {{- '<|im_end|>\n' }}
257
+ {%- elif loop.last %}
258
+ {{- '<|im_end|>\n' }}
259
+ {%- endif %}
260
+ {%- else %}
261
+ {{- raise_exception('Unexpected message role.') }}
262
+ {%- endif %}
263
+ {%- endfor %}
264
+ {%- if add_generation_prompt %}
265
+ {{- '<|im_start|>assistant\n' }}
266
+ {%- if ns_flags.enable_thinking is false %}
267
+ {{- '<think>\n</think>\n' }}
268
+ {%- elif ns_flags.last_tool_failed and ns_flags.consecutive_failures >= 2 %}
269
+ {{- '<think>\n</think>\n' }}
270
+ {%- else %}
271
+ {{- '<think>\n' }}
272
+ {%- endif %}
273
+ {%- endif %}
archive/qwen3.6/chat_template-v18_oneline.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ {%- set image_count = namespace(value=0) %}{%- set video_count = namespace(value=0) %}{%- macro render_content(content, do_vision_count, is_system_content=false) %}{%- if content is string %}{{- content }}{%- elif content is iterable and content is not mapping %}{%- for item in content %}{%- if 'image' in item or 'image_url' in item or item.type == 'image' %}{%- if is_system_content %}{{- raise_exception('System message cannot contain images.') }}{%- endif %}{%- if do_vision_count %}{%- set image_count.value = image_count.value + 1 %}{%- endif %}{%- if add_vision_id is defined and add_vision_id %}{{- 'Picture ' ~ image_count.value ~ ': ' }}{%- endif %}{{- '<|vision_start|><|image_pad|><|vision_end|>' }}{%- elif 'video' in item or item.type == 'video' %}{%- if is_system_content %}{{- raise_exception('System message cannot contain videos.') }}{%- endif %}{%- if do_vision_count %}{%- set video_count.value = video_count.value + 1 %}{%- endif %}{%- if add_vision_id is defined and add_vision_id %}{{- 'Video ' ~ video_count.value ~ ': ' }}{%- endif %}{{- '<|vision_start|><|video_pad|><|vision_end|>' }}{%- elif 'text' in item %}{{- item.text }}{%- else %}{{- raise_exception('Unexpected item type in content.') }}{%- endif %}{%- endfor %}{%- elif content is none or content is undefined %}{{- '' }}{%- else %}{{- raise_exception('Unexpected content type.') }}{%- endif %}{%- endmacro %}{%- set ns_flags = namespace(enable_thinking=true, has_tools=false, last_tool_failed=false, consecutive_failures=0) %}{%- if enable_thinking is defined %}{%- set ns_flags.enable_thinking = enable_thinking %}{%- endif %}{%- if not messages %}{{- raise_exception('No messages provided.') }}{%- endif %}{%- set system_content = '' %}{%- set has_system = false %}{%- if messages[0].role == 'system' or messages[0].role == 'developer' %}{%- set has_system = true %}{%- set system_content = render_content(messages[0].content, false, true)|trim %}{%- if '<|think_off|>' in system_content %}{%- set ns_flags.enable_thinking = false %}{%- set system_content = system_content | replace('<|think_off|>', '') %}{%- endif %}{%- if '<|think_on|>' in system_content %}{%- set ns_flags.enable_thinking = true %}{%- set system_content = system_content | replace('<|think_on|>', '') %}{%- endif %}{%- set system_content = system_content | trim %}{%- endif %}{%- if tools and tools is iterable and tools is not mapping %}{%- set ns_flags.has_tools = true %}{{- '<|im_start|>system\n' }}{{- "# Tools\n\nYou have access to the following functions:\n\n<tools>" }}{%- for tool in tools %}{{- '\n' }}{%- set fn = tool.function if tool.function is defined else tool %}{{- fn | tojson }}{%- endfor %}{{- "\n</tools>" }}{%- set tool_instructions %} If you choose to call a function ONLY reply in the following format with NO suffix: <think> Brief explanation of tool call </think> <tool_call> <function=example_function_name> <parameter=example_parameter_1> value_1 </parameter> <parameter=example_parameter_2> This is the value for the second parameter that can span multiple lines </parameter> </function> </tool_call> <IMPORTANT> Reminder: - Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags - Required parameters MUST be specified - ALL explanation and reasoning MUST be placed strictly inside the <think></think> block. - IMMEDIATELY after closing </think>, you must output the <tool_call> block. Do NOT output any conversational text in between. - The <tool_call> and <function> tags MUST be at the very beginning of a new line, with NO spaces or indentation before them. - To call multiple functions, output a separate, completely closed <tool_call></tool_call> block for EACH function. Do NOT nest <tool_call> blocks. - 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 </IMPORTANT> {%- endset %}{{- '\n\n' ~ tool_instructions | trim }}{%- if has_system and system_content %}{{- '\n\n' + system_content }}{%- endif %}{{- '<|im_end|>\n' }}{%- elif has_system and system_content %}{{- '<|im_start|>system\n' + system_content + '<|im_end|>\n' }}{%- endif %}{%- for message in messages %}{%- set is_system = (message.role == "system" or message.role == "developer") %}{%- set content = render_content(message.content, true, is_system)|trim %}{%- if '<|think_off|>' in content %}{%- set ns_flags.enable_thinking = false %}{%- set content = content | replace('<|think_off|>', '') | trim %}{%- elif '<|think_on|>' in content %}{%- set ns_flags.enable_thinking = true %}{%- set content = content | replace('<|think_on|>', '') | trim %}{%- endif %}{%- if is_system %}{%- if not loop.first and content %}{{- '<|im_start|>system\n' + content + '<|im_end|>\n' }}{%- endif %}{%- elif message.role == "user" %}{{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>\n' }}{%- set ns_flags.last_tool_failed = false %}{%- set ns_flags.consecutive_failures = 0 %}{%- elif message.role == "assistant" %}{%- set ns_flags.last_tool_failed = false %}{%- set reasoning_content = '' %}{%- if message.reasoning_content is string %}{%- set reasoning_content = message.reasoning_content %}{%- else %}{%- set think_end_token = '' %}{%- if '</think>' in content %}{%- set think_end_token = '</think>' %}{%- elif '</thinking>' in content %}{%- set think_end_token = '</thinking>' %}{%- elif '</ think>' in content %}{%- set think_end_token = '</ think>' %}{%- elif '</think >' in content %}{%- set think_end_token = '</think >' %}{%- endif %}{%- if think_end_token %}{%- set reasoning_parts = content.split(think_end_token) %}{%- set reasoning_content = reasoning_parts[0] %}{%- set content = reasoning_parts[1:] | join(think_end_token) %}{%- if '<think>' in reasoning_content %}{%- set r_prefix = reasoning_content.split('<think>')[0] | trim %}{%- set reasoning_content = reasoning_content.split('<think>')[1:] | join('<think>') | trim %}{%- set content = (r_prefix ~ '\n' ~ content) | trim %}{%- endif %}{%- elif '<think>' in content %}{%- set prefix = content.split('<think>')[0] %}{%- set think_part = content.split('<think>')[1:] | join('<think>') %}{%- if '<tool_call>' in think_part %}{%- set reasoning_content = think_part.split('<tool_call>')[0] %}{%- set content = prefix ~ '\n<tool_call>' ~ think_part.split('<tool_call>')[1:] | join('<tool_call>') %}{%- else %}{%- set reasoning_content = think_part %}{%- set content = prefix %}{%- endif %}{%- endif %}{%- endif %}{%- set reasoning_content = reasoning_content | trim %}{%- set content = content | trim %}{%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}{%- if '<tool_call>' in content %}{%- set content = content.split('<tool_call>')[0] | trim %}{%- endif %}{%- endif %}{%- set show_think = false %}{%- if reasoning_content %}{%- if preserve_thinking is defined and preserve_thinking %}{%- set show_think = true %}{%- elif loop.last %}{%- set show_think = true %}{%- endif %}{%- endif %}{%- if show_think %}{%- if content %}{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>\n' + content }}{%- else %}{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content + '\n</think>' }}{%- endif %}{%- else %}{%- if message.role == 'assistant' and ns_flags.enable_thinking is not false %}{%- if content %}{{- '<|im_start|>' + message.role + '\n<think>\n</think>\n' + content }}{%- else %}{{- '<|im_start|>' + message.role + '\n<think>\n</think>' }}{%- endif %}{%- else %}{%- if content %}{{- '<|im_start|>' + message.role + '\n' + content }}{%- else %}{{- '<|im_start|>' + message.role }}{%- endif %}{%- endif %}{%- endif %}{%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}{%- for tool_call in message.tool_calls %}{%- if tool_call.function is defined %}{%- set tool_call = tool_call.function %}{%- endif %}{{- '\n<tool_call>\n' }}{{- '<function=' ~ tool_call.name ~ '>\n' }}{%- if tool_call.arguments is defined and tool_call.arguments is mapping %}{%- if tool_call.arguments | length > 0 %}{%- for args_name in tool_call.arguments %}{%- set args_value = tool_call.arguments[args_name] %}{{- '<parameter=' ~ args_name ~ '>\n' }}{%- set args_value = args_value | tojson if args_value is mapping or (args_value is iterable and args_value is not string) else args_value | string %}{{- args_value }}{{- '\n</parameter>\n' }}{%- endfor %}{%- endif %}{%- elif tool_call.arguments is defined and tool_call.arguments is string %}{%- if tool_call.arguments | trim | length > 0 %}{{- tool_call.arguments }}{{- '\n' }}{%- endif %}{%- endif %}{{- '</function>\n</tool_call>' }}{%- endfor %}{%- endif %}{{- '<|im_end|>\n' }}{%- elif message.role == "tool" %}{%- set content_lower = content | lower %}{%- if content | length < 500 and '$ ' not in content and 'took ' not in content_lower and ('"error":' in content_lower or 'error:' in content_lower or 'exception:' in content_lower or 'traceback' in content_lower or 'command not found' in content_lower or 'invalid syntax' in content_lower or 'failed to' in content_lower) %}{%- set ns_flags.last_tool_failed = true %}{%- set ns_flags.consecutive_failures = ns_flags.consecutive_failures + 1 %}{%- else %}{%- set ns_flags.last_tool_failed = false %}{%- set ns_flags.consecutive_failures = 0 %}{%- endif %}{%- if loop.index0 > 0 and messages[loop.index0 - 1].role != "tool" %}{{- '<|im_start|>user' }}{%- endif %}{{- '\n<tool_response>\n' }}{{- content }}{%- if ns_flags.last_tool_failed %}{%- if ns_flags.consecutive_failures >= 2 %}{{- '\n\n⚠️ SYSTEM WARNING: ' ~ ns_flags.consecutive_failures ~ ' consecutive tool errors detected. Your previous approach is incorrect. You MUST use a fundamentally different approach or corrected arguments.' }}{%- else %}{{- '\n\n⚠️ SYSTEM WARNING: The previous tool call returned an error. Diagnose the failure and retry with completely corrected arguments.' }}{%- endif %}{%- endif %}{{- '\n</tool_response>' }}{%- if not loop.last and messages[loop.index0 + 1].role != "tool" %}{{- '<|im_end|>\n' }}{%- elif loop.last %}{{- '<|im_end|>\n' }}{%- endif %}{%- else %}{{- raise_exception('Unexpected message role.') }}{%- endif %}{%- endfor %}{%- if add_generation_prompt %}{{- '<|im_start|>assistant\n' }}{%- if ns_flags.enable_thinking is false %}{{- '<think>\n</think>\n' }}{%- elif ns_flags.last_tool_failed and ns_flags.consecutive_failures >= 2 %}{{- '<think>\n</think>\n' }}{%- else %}{{- '<think>\n' }}{%- endif %}{%- endif %}