Agentic Chat Templates (TITO)
Multi-turn agentic rollout in Miles runs on TITO (Token-In-Token-Out): each turn’s token sequence is a bit-perfect prefix of the next, so the trainer sees exactly the tokens the engine produced — no re-tokenization, no drift. The why is in the blog (No Token Left Behind); this page is how. Your harness only ever sends and receives OpenAI chat messages, never tokens. Miles keeps the per-trajectory append-only token buffer (ids + logprobs + routed experts) internally and ships it straight to training.Prerequisites
Your rollout loop must keep two invariants, or TITO is rejected at runtime:- Append-only messages. Each turn = previous messages + new ones on the tail; past turns are never edited. The only exception is retrying the latest turn — a single-step rollback to the last assistant checkpoint, or to an empty session when the retried turn is the first one. Diverging earlier, or rolling back more than one turn, is rejected.
- Appended roles follow the chat template. After the first assistant message, the selected model’s chat template determines which roles may be appended; users do not configure this separately.
Pick your --tito-model
No auto-detection — pick the family matching your model. For every family, Miles resolves one FIXED_TEMPLATE registration from --tito-model alone. The registration owns the bundled Jinja template (or HuggingFace-native template) and fixed kwargs. A non-default family rejects --chat-template-path overrides and conflicting fixed kwargs; use --tito-model default for a custom renderer.
More models and verification history live in issue #712.
Turn it on
Example
A full multi-turn agentic setup on the session-server TITO path lives inexamples/swe-agent: its launchers wire --use-session-server + --tito-model glm47 against a real SWE agent.
Add a new model
Models in the table are verified by Miles maintainers. To support a new model, register itsTITOTokenizer and FIXED_TEMPLATE in tito_tokenizer.py, then run both checks below; either failure blocks support.

