MLX
jinja
chat-template
qwen
qwen3.5
qwen3.6
qwen3.8
llama.cpp
lm-studio
vllm
tool-calling
thinking
token-efficient
Instructions to use peculiar-ragdoll/Qwen-Sharp-Chat-Templates with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use peculiar-ragdoll/Qwen-Sharp-Chat-Templates with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir Qwen-Sharp-Chat-Templates peculiar-ragdoll/Qwen-Sharp-Chat-Templates
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
File size: 5,510 Bytes
a2784ae 435b6b8 a2784ae 435b6b8 a2784ae 435b6b8 a2784ae 435b6b8 e18e763 435b6b8 e18e763 435b6b8 e18e763 a2784ae 435b6b8 e18e763 a2784ae | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #!/usr/bin/env python3
"""Verify the Sharp template: minimal diff from upstream, correct rendering, minify round-trip.
python3 scripts/verify_template.py
Run this before publishing, and after any edit to chat_template.jinja. It fetches current
upstream (v22.1) fresh, so it also catches the case where froggeric ships a new version and our
splice silently sits on top of a template we haven't looked at.
The checks exist because each of them has a real failure mode:
* diff-vs-upstream -- guards against accidentally shipping edits we didn't intend to make
* terseness-once -- a double-splice would send the instruction twice and waste context
* system-preserved -- the else-branch is the whole reason a user's own prompt survives
* think-retained -- froggeric's retention fix is the thing we must NOT have broken
* minify round-trip -- the minifier collapses newlines; our {% set %} body must survive it
"""
from __future__ import annotations
import difflib
import pathlib
import sys
import urllib.request
from jinja2 import Environment
HERE = pathlib.Path(__file__).resolve().parent.parent
UPSTREAM = ("https://huggingface.co/froggeric/Qwen-Fixed-Chat-Templates/"
"resolve/main/chat_template.jinja")
MARKER = "Never: open with preamble"
fails: list[str] = []
def check(ok: bool, label: str) -> None:
print(f" {'PASS' if ok else 'FAIL'} {label}")
if not ok:
fails.append(label)
def render(src: str, msgs: list[dict], **kw) -> str:
return Environment().from_string(src).render(
messages=msgs, add_generation_prompt=True, **kw)
def main() -> int:
full = (HERE / "chat_template.jinja").read_text()
mini = (HERE / "chat_template_oneline.txt").read_text()
print("=== diff vs upstream v22.1")
with urllib.request.urlopen(UPSTREAM, timeout=60) as r:
up = r.read().decode()
diff = [l for l in difflib.unified_diff(up.splitlines(), full.splitlines(), lineterm="")
if l.startswith(("+", "-")) and not l.startswith(("+++", "---"))]
check(all(l.startswith("+") for l in diff), "only insertions, no upstream lines changed")
check(len(diff) == 11, f"exactly 11 inserted lines (got {len(diff)})")
check('template_version = "qwen3.8-froggeric-v22.1"' in full, "upstream version is v22.1")
check("Nail" not in full and "Dagger" not in full, "no model-specific identity in template")
print("\n=== rendering")
cases = {
"no system prompt": [{"role": "user", "content": "hi"}],
"with system prompt": [{"role": "system", "content": "Be a pirate."},
{"role": "user", "content": "hi"}],
"multi-turn w/ think": [{"role": "user", "content": "Q1"},
{"role": "assistant", "content": "<think>t</think>A1"},
{"role": "user", "content": "Q2"}],
}
for name, msgs in cases.items():
out = render(full, msgs)
check(out.count(MARKER) == 1, f"{name}: terseness appears exactly once")
check("Be a pirate." in render(full, cases["with system prompt"]),
"user's own system prompt is preserved")
check("<think>t</think>" in render(full, cases["multi-turn w/ think"]),
"prior thinking is retained across turns")
# v22.1 defaults reasoning_effort to MEDIUM, which injects no steering line -- so out-of-the-box
# behavior is terseness-only with no forced effort, matching tuned v1, WITHOUT us suppressing
# anything (upstream fixed the old forced-xhigh default). An EXPLICIT effort still injects steering,
# so froggeric's feature is honored as opt-in.
STEER = "Reasoning effort is set to"
check(STEER not in render(full, cases["no system prompt"]),
"default (no reasoning_effort): no steering line (upstream medium default)")
check(STEER not in render(full, cases["with system prompt"]),
"default with system prompt: still no steering line")
check("Reasoning effort is set to low" in render(full, cases["no system prompt"],
reasoning_effort="low"), "explicit reasoning_effort=low is still honored (opt-in)")
check(MARKER in render(full, cases["no system prompt"], reasoning_effort="low"),
"terseness still present when an explicit effort is requested")
tools = [{"type": "function", "function": {"name": "get_weather", "description": "w",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}}}}]
out = render(full, [{"role": "user", "content": "weather?"}], tools=tools)
check("get_weather" in out and out.count(MARKER) == 1, "tool definitions still render")
print("\n=== minified round-trip")
for name, msgs in cases.items():
check(render(full, msgs) == render(mini, msgs), f"{name}: oneline == full")
sysblk = render(mini, cases["no system prompt"]).split("<|im_start|>system")[1] \
.split("<|im_end|>")[0].strip()
# the terseness tail starts with "Answer directly," (at medium default no steering precedes it);
# isolate it and confirm ITS newlines survived minification as 4 lines.
terse = "Answer directly," + sysblk.split("Answer directly,", 1)[1]
check(len(terse.splitlines()) == 4, "terseness survives minification as 4 lines")
print(f"\n{'ALL CHECKS PASSED' if not fails else str(len(fails)) + ' FAILED: ' + '; '.join(fails)}")
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())
|