Public TML chat types, native tokenizer, and TMLv0 render/parse
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.7 MB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f5ff0b08ba5ffe92071cb32215d65cda88d92205850f9f4dd1823f5d0dc2aeb
|
|
| MD5 |
f1fdd1e0f89ca761e96ab72f97b0b65a
|
|
| BLAKE2b-256 |
26e1e4f8e7acfafaff35b59031b9af308aa059a845a4b094a43bd49dbb729508
|
File details
Details for the file tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: tml_renderers-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.5 MB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52cf4c1b4d1ab2664903f0438e661544546b4d7f0378fe245f53bafc01368014
|
|
| MD5 |
2993c6773e187868022f6e14c30a1051
|
|
| BLAKE2b-256 |
d6ddc31bb2e874cb11a175f8f14967cee128b2d159507a602b3740152be6a8d6
|
File details
Details for the file tml_renderers-0.1.0-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: tml_renderers-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.4 MB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f484e983fe42df95c5c69108c7ec4046340f416566f726bd76e211736db29391
|
|
| MD5 |
c6aaa38cfee3f5fe53eb817c8d32ed89
|
|
| BLAKE2b-256 |
0db312b182a39effd1021263451e6eff0ff47c310f2957706a903ce838935dd5
|