Chat Template Renderer
Render a message list into the single string a model is actually given, with every space and newline made visible — and parse a rendered string back into messages.
≈ 54 estimated tokens, of which the markers are a fixed overhead you pay on every turn.
- Messages rendered
- 4
- Role markers emitted
- 5
- Characters spent on markers
- 141
- Ends with the generation prompt
- yes
- A assistant message was opened but its closing marker never appeared — the string is truncated, or the suffix is wrong.
- The string ends with the generation prompt, so the last message is the model's turn to speak rather than a completed one.
<|im_start|> is usually a single token rather than twelve characters' worth. Everything on this page runs in your browser. Nothing you paste is uploaded, logged or sent anywhere.A chat model does not receive a list of messages. It receives one string, assembled from your messages by a template, and everything the model knows about who said what comes from the special tokens that template inserted. When a good model suddenly behaves like a bad one, the string is the first place to look: a doubled newline, a missing end-of-turn marker, or a system message rendered into a slot the model was never trained to read.
Why the whitespace toggle exists
The difference between a template that works and one that does not is frequently a single trailing space, and a trailing space is invisible. Turning on the reveal shows every one of them, along with the double newlines that appear when a suffix ends with \n and the next prefix begins with one. This also matters for caching: a prefix that differs by one character is a different prefix, and the cache hit you were counting on silently becomes a miss.
The round trip is the test
Rendering messages into a string is easy. Parsing that string back into messages is what proves the markers are unambiguous — if the parser cannot tell where a user turn ended, neither can anything else that reads your logs. Paste a real prompt string from your own stack into the other direction and see whether it decomposes cleanly; if leftover text shows up in the unattributed list, your template and your assumed template are not the same template.