tml-renderers
tml-renderers is the default TML renderer for text and multimodal chat. It packages
public message types, a native tokenizer, TMLv0 rendering and parsing, and media
codecs for inference and training.
Installation
pip install tml-renderers
tml-renderers is a compiled extension that requires PyTorch 2.10 or newer.
Quickstart
from tml_renderers.chat import Message, MessageList, Text, Author, AuthorKind
message = Message(
content=Text("Hello, world!"),
author=Author(AuthorKind.User),
)
messages = MessageList([message])
OpenAI message compatibility
Partners can use OpenAI-shaped message dictionaries at the package boundary without rewriting their chat data into native classes:
from tml_renderers import chat, tokenizers, v0
openai_message_dicts = [
{"role": "system", "content": "Answer concisely."},
{"role": "user", "content": "What is 2 + 2?"},
]
openai_messages = chat.OpenAIMessage.from_oss_messages(openai_message_dicts)
round_tripped = chat.OpenAIMessage.to_oss_messages(openai_messages)
renderer = v0.Renderer(tokenizers.o200k_base_chat())
spans, parser = renderer.render_for_completion(openai_messages)
The compatibility surface covers role/content messages, multipart text and
image_url content, assistant tool calls, and tool results.
render_for_completion and render_for_sft also accept list[OpenAIMessage]
directly. This is a message-format bridge; it does not implement the OpenAI
network client or server API. Use MessageList.from_oss_messages(...) and
MessageList.to_oss_messages() when you want the same conversion through a
native MessageList.
Rendering and parsing (TMLv0)
Rendering converts structured chat messages into the exact token and media-span
sequence consumed by the model. v0 uses the same TMLv0 grammar for
both inference and training:
render_for_completion(...)renders an inference prompt and returns a parser for turning generated model tokens back into messages.render_for_sft(...)renders supervised-training examples with aligned, per-token loss weights.
The parser performs the reverse operation, reconstructing structured messages from generated token spans:
from tml_renderers import chat, tokenizers, v0
tokenizer = tokenizers.o200k_base_chat()
renderer = v0.Renderer(tokenizer)
messages = [
chat.Message(
content=chat.Text("Hello"),
author=chat.Author(chat.AuthorKind.User),
)
]
spans, parser = renderer.render_for_completion(messages)
parsed = parser.parse(spans)
training_examples = renderer.render_for_sft(messages)
The tokenizer is a native o200k BPE tokenizer plus the fixed TMLv0 special
tokens. No Hugging Face chat template or remote code is involved.
tokenizer.encode_ordinary("hello")
tokenizer.decode([24912])
tokenizer.encode_special("message_user") # -> 200000
tokenizer.decode_special(200000) # -> "message_user"
Full method surface:
| method | maps | on invalid / partial UTF-8 |
|---|---|---|
encode_ordinary(text) |
text → ids | — (special-token markup is encoded as literal text) |
encode_special(name) |
name → id | raises if name isn't a special token |
decode(ids) |
ids → text | lossy — invalid/partial bytes become U+FFFD, never raises (tiktoken parity) |
decode_strict(ids) |
ids → text | raises ValueError on invalid/partial UTF-8 |
decode_bytes(ids) |
ids → bytes | raw bytes, no UTF-8 handling |
decode_special(id) |
id → name | None if id isn't a special token |
Plus is_special_token(id), special_tokens(), and the eos_token / bos_token /
all_special_tokens properties. decode is lossy so a truncated multi-byte tail (common
when streaming) renders as � rather than raising — reach for decode_strict only when you
want that raise.
render_for_completion accepts a MessageList, a list[Message], or a
list[OpenAIMessage]. render_for_completion_with_effort(messages, effort) (with
effort a float in [0, 1]) inserts a system message containing
Thinking effort level: 0.9 before the first non-system message; the messages
must not already contain a ThinkingEffort content. For SFT,
render_for_sft returns TrainingExamples carrying per-token loss weights.
Media
tml-renderers includes the multimodal codec logic used by the default TMLv0
renderer:
- An
ImagePointeris mapped to the model's black-padded image patch layout and rendered as anImageAssetPointerTokenSpanwith the expected image-token count. - An
AudioPointeris decoded, resampled to 16 kHz, DMel-encoded, and rendered as aDmelTokenSpan.
Image and audio messages use the same completion and training APIs as text:
from tml_renderers import chat, tokenizers, v0
renderer = v0.Renderer(tokenizers.o200k_base_chat())
image_msg = chat.Message(
content=chat.ImagePointer(
location="image.png",
format=chat.ImageFormat.Png,
width=512,
height=512,
),
author=chat.Author(chat.AuthorKind.User),
)
audio_msg = chat.Message(
content=chat.AudioPointer(
location="clip.wav",
format=chat.AudioFormat.Wav,
num_frames=48_000,
sample_rate=16_000,
),
author=chat.Author(chat.AuthorKind.User),
)
spans, _ = renderer.render_for_completion([image_msg, audio_msg])
dmel = next(s.span for s in spans if type(s.span).__name__ == "DmelTokenSpan")
print(dmel.dmel.shape) # [num_audio_tokens, num_dmel_bins], uint8
Media locations are represented as pointers. Audio is read from local files;
tml-renderers never fetches remote media.
Streaming
Parser.parse_token / parse_updates / flush_updates return incremental
ParseUpdates, so you can render a completion as tokens arrive rather than only
returning completed Messages. Each update is a StreamingMessageHeader, a
StreamingContent delta, or a completed Message. See
tests/test_v0_streaming.py for a worked example.
Token spans
Renderers work with token-span types you can construct directly:
from tml_renderers.chat import (
EncodedTextTokenSpan,
ImageAssetPointerTokenSpan,
ImageFormat,
PaddingTokenSpan,
TokenSpan,
)
text = EncodedTextTokenSpan([101, 102])
image = ImageAssetPointerTokenSpan(
location="image.png", format=ImageFormat.Png, width=512, height=512, num_tokens=256
)
padding = PaddingTokenSpan(4)
# Wrap in the oneof only where a call boundary asks for a TokenSpan.
wrapped = TokenSpan(text)
DmelTokenSpan is the encoded-audio span produced by the renderer's audio
handler; dmel is a uint8 tensor of shape [num_audio_tokens, num_dmel_bins].
Using with Tinker
Install the latest Tinker SDK and Tinker Cookbook, then select the
tml_v0 renderer in your Cookbook recipe. Cookbook handles model-specific
configuration and converts rendered text, image, and audio inputs for sampling
and SFT.
The lower-level tml_renderers.tinker helpers are also available when integrating
directly with the Tinker SDK. Remote media is never fetched; provide local files
or base64 image data.
Types
- Core:
Message,MessageList,Author,AuthorKind,MessageChannel,MessageMetadata - Content:
Text,Thinking,ThinkingEffort,ImagePointer,AudioPointer,InvokeTool,StructuredToolCall,ToolError,ToolDeclareJson,ModelEndSampling - Token spans:
TokenSpan,EncodedTextTokenSpan,ImageAssetPointerTokenSpan,DmelTokenSpan,PaddingTokenSpan - Formats:
ImageFormat,AudioFormat - Tool args:
ToolArg,ToolMetadata.ToolArg.valueis a JSON-encoded value string, matching the OpenAIfunction.argumentsconvention. - Tool declarations:
ToolSpecJson(one declared tool:name/description/type_name, plusparametersas a JSON-schema string; the constructor acceptsparametersas a dict and serializes it), grouped into aToolDeclareJson.
Examples
examples/run_tml_v0.py— low-level render/parse of text, tools, and audio.examples/cookbook_tinker_demo.py— OpenAI-style dicts alongside native types.
License
Apache-2.0. See LICENSE.
Metadata
Release files for tml-renderers 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| tml_renderers-0.1.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 13.6 MB
Release files / tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6f5ff0b08ba5ffe92071cb32215d65cda88d92205850f9f4dd1823f5d0dc2aeb
|
|
BLAKE2b-256 checksum How to use checksums |
26e1e4f8e7acfafaff35b59031b9af308aa059a845a4b094a43bd49dbb729508
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Release files / tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 4.5 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
52cf4c1b4d1ab2664903f0438e661544546b4d7f0378fe245f53bafc01368014
|
|
BLAKE2b-256 checksum How to use checksums |
d6ddc31bb2e874cb11a175f8f14967cee128b2d159507a602b3740152be6a8d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Release files / tml_renderers-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | tml_renderers-0.1.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 4.4 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f484e983fe42df95c5c69108c7ec4046340f416566f726bd76e211736db29391
|
|
BLAKE2b-256 checksum How to use checksums |
0db312b182a39effd1021263451e6eff0ff47c310f2957706a903ce838935dd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|