Instructions to use CCSSNE/froggeric-Qwen-Fixed-Chat-Templates with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use CCSSNE/froggeric-Qwen-Fixed-Chat-Templates with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir froggeric-Qwen-Fixed-Chat-Templates CCSSNE/froggeric-Qwen-Fixed-Chat-Templates
- Notebooks
- Google Colab
- Kaggle
- Local Apps
- LM Studio
Duplicate from froggeric/Qwen-Fixed-Chat-Templates
Browse filesCo-authored-by: froggeric <froggeric@users.noreply.huggingface.co>
This view is limited to 50 files because it contains too many changes. See raw diff
- .gitignore +4 -0
- README.md +230 -0
- archive/README-v10.md +208 -0
- archive/README-v11.md +224 -0
- archive/README-v12.md +226 -0
- archive/README-v13.md +230 -0
- archive/README-v14.md +218 -0
- archive/README-v15.md +237 -0
- archive/README-v16.md +279 -0
- archive/README-v17.md +248 -0
- archive/README-v18.md +252 -0
- archive/README-v19.md +230 -0
- archive/README-v8.md +192 -0
- archive/README-v9.md +200 -0
- archive/qwen3.5/chat_template-v10.jinja +223 -0
- archive/qwen3.5/chat_template-v10_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v11.jinja +230 -0
- archive/qwen3.5/chat_template-v11_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v12.jinja +246 -0
- archive/qwen3.5/chat_template-v12_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v13.jinja +204 -0
- archive/qwen3.5/chat_template-v13_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v14.jinja +214 -0
- archive/qwen3.5/chat_template-v14_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v15.jinja +220 -0
- archive/qwen3.5/chat_template-v15_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v16.jinja +258 -0
- archive/qwen3.5/chat_template-v16_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v8.jinja +211 -0
- archive/qwen3.5/chat_template-v8_oneline.txt +1 -0
- archive/qwen3.5/chat_template-v9.jinja +219 -0
- archive/qwen3.5/chat_template-v9_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v10.jinja +223 -0
- archive/qwen3.6/chat_template-v10_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v11.jinja +230 -0
- archive/qwen3.6/chat_template-v11_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v12.jinja +246 -0
- archive/qwen3.6/chat_template-v12_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v13.jinja +204 -0
- archive/qwen3.6/chat_template-v13_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v14.jinja +214 -0
- archive/qwen3.6/chat_template-v14_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v15.jinja +220 -0
- archive/qwen3.6/chat_template-v15_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v16.jinja +258 -0
- archive/qwen3.6/chat_template-v16_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v17.jinja +277 -0
- archive/qwen3.6/chat_template-v17_oneline.txt +1 -0
- archive/qwen3.6/chat_template-v18.jinja +273 -0
- 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 %}
|