Overview
The transform system bridges rigid API specifications and LLM-friendly interfaces. You define schemas that match the API documentation exactly, and the LLM gets semantic, human-readable types.Core principle: LLMs should interact with data like humans, not like computers dealing with wire formats.Transforms compose with the mode system, which controls which fields the LLM sees; transforms control what type those fields have.
The pipeline
Stated plainly:- APIs speak in rigid formats — base64, RFC822, protobuf JSON.
- You annotate schema fields with
Formatmarkers matching the API docs. - Charter generates the LLM-facing view, where those fields carry semantic types.
- The LLM provides natural input (
to/subject/body, not raw MIME). - The transform engine converts semantic input to the exact wire format.
- The API receives the payload it expects. No glue code.
Components
1. Transform registry
One place where every transformation is declared, viaTransformRegistry:
rfc822_transform.py
- Declarative registration
- Semantic type recorded alongside the function, so schema generation knows what to show the LLM
- LLM-friendly description attached to the field
2. Format markers
Annotate the fields that need conversion withFormat:
format_marker.py
3. LLM schema generation
send_email_request.py
- detects
Formatmarkers, - replaces the wire type with the registered semantic type,
- swaps in the transform’s LLM-facing description,
- preserves the
Path/Query/Body/Case/Modemarkers.
Built-in transforms
bytes and base64url encode identically. The separate name exists for
fidelity with Google API specs that annotate a field as bytes.
Nesting
Transforms apply at any depth. The runtime walks nested models and lists, applying everyFormat marker it finds, then routes the transformed value to the
HTTP location its Path/Query/Body marker names.
Registering your own
Callregister_transform with the
semantic type, the conversion, and the description the LLM will see:
custom_transform.py
Annotated[str, Query(), Format("latlon_string")] shows the LLM a
Coordinates object and sends "48.8584,2.2945".
Failure
An unknown transform name, a payload that will not validate as the semantic type, or a transform function that raises all produce aTransformError naming the transform and the
field. Transform failures are never swallowed — a silently untransformed value
reaches the API as a confusing 400.
Related
TransformSpec,TransformRegistry,register_transform— the registry API in fullFormat— the marker that names a transform- Semantic types —
EmailContent,CalendarEvent,DocumentContent,FileContent TransformError— what a failed conversion raises