Chat models never see JSON messages. They see one string with special tokens marking each turn. The ChatML format looks like this:
<|im_start|>system
You are helpful.<|im_end|>
<|im_start|>user
Hi<|im_end|>
Each message renders as <|im_start|>{role}\n{content}<|im_end|>\n.
Implement:
render(messages, add_generation_prompt=False) for a list of {"role", "content"} dicts. Validate first, raising ValueError if:
system, user or assistant<|im_start|> or <|im_end|> (users must not be able to inject fake turns)If add_generation_prompt is set, append <|im_start|>assistant\n so the model knows to reply.
parse(text): the inverse, returning the list of messages (ignore a trailing generation prompt)