25 -- TOON Context Format: Token-Efficient LLM Serialization¶
This document specifies how AgentEnsemble integrates the TOON (Token-Oriented Object Notation) serialization format as a configurable alternative to JSON for structured data sent to LLMs, reducing token usage by 30-60%.
TOON is an optional, user-activated feature. JSON remains the default for full backward compatibility.
1. Motivation¶
AgentEnsemble sends structured data to LLMs in several places:
- Prompt building: Context from prior tasks, memory entries, and tool descriptions are serialized into prompts.
- Tool output: Tool execution results are returned as strings that the LLM processes in subsequent reasoning steps.
- Task hand-offs: In sequential/hierarchical workflows, one agent's output becomes another agent's context.
- Trace export: Execution traces are serialized for analysis and debugging.
All of these currently use JSON. JSON is verbose -- curly braces, quotes around every key, commas, colons, and brackets consume tokens that carry no semantic value for the LLM. In long multi-agent pipelines with rich context, this overhead compounds quickly.
TOON (spec v3.0.3) is a compact, human-readable serialization format designed specifically for LLM contexts. It combines YAML-like indentation with CSV-like tabular arrays and achieves 30-60% token reduction versus JSON while remaining fully parseable.
JSON:
TOON:
JToon (dev.toonformat:jtoon) is
the Java implementation. It is MIT-licensed, available on Maven Central, requires
Java 17+, and supports Jackson annotations -- which AgentEnsemble already uses.
2. Design Goals¶
- Opt-in: JSON remains the default. Users who want TOON add one dependency and one builder call.
- Fail-fast: If
TOONis selected but JToon is not on the classpath,Ensemble.build()fails immediately with a clear error message. - Single configuration point: One
contextFormatfield onEnsemble.builder()controls all serialization points. No per-task or per-tool configuration is needed (or exposed) in v1. - Optional dependency: JToon is
compileOnlyinagentensemble-core. Users add the runtime dependency themselves when they choose TOON. - Extensible: The
ContextFormatenum andContextFormatterinterface allow future formats without changing the public API.
3. Concepts¶
| Term | Description |
|---|---|
| ContextFormat | Enum (JSON, TOON) selecting the serialization format for LLM-facing structured data. |
| ContextFormatter | Interface with format(Object) and formatJson(String) methods. |
| JsonContextFormatter | Built-in implementation wrapping Jackson ObjectMapper. Always available. |
| ToonContextFormatter | Implementation wrapping JToon.encode(). Loaded via reflection; requires JToon on classpath. |
| ContextFormatters | Factory class that resolves the correct ContextFormatter for a given ContextFormat. |
4. ContextFormat Enum¶
package net.agentensemble.format;
/**
* Serialization format for structured data included in LLM prompts.
*
* <p>JSON is the default and is always available. TOON provides 30-60%
* token reduction but requires the {@code dev.toonformat:jtoon} library
* on the classpath.
*/
public enum ContextFormat {
/** Standard JSON serialization (default). Always available. */
JSON,
/**
* TOON (Token-Oriented Object Notation) serialization.
* Requires {@code dev.toonformat:jtoon} on the runtime classpath.
*/
TOON
}
5. ContextFormatter Interface¶
package net.agentensemble.format;
/**
* Serializes structured data for inclusion in LLM prompts.
*
* <p>Implementations are obtained via {@link ContextFormatters#forFormat(ContextFormat)}.
*/
public interface ContextFormatter {
/**
* Serialize a Java object to the target format.
*
* @param value any Java object (Map, List, record, POJO, etc.)
* @return formatted string; never null
*/
String format(Object value);
/**
* Convert a JSON string to the target format.
*
* <p>For the JSON formatter this is a no-op (returns the input).
* For TOON this parses the JSON and re-encodes it as TOON.
*
* @param json a valid JSON string
* @return formatted string; never null
*/
String formatJson(String json);
}
6. Implementations¶
JsonContextFormatter¶
Always available. Uses the shared Jackson ObjectMapper for format(Object).
formatJson(String) returns the input unchanged.
ToonContextFormatter¶
Available only when JToon is present on the classpath. On first use,
ContextFormatters checks for dev.toonformat.jtoon.JToon and, if found,
instantiates ToonContextFormatter directly; otherwise it throws
IllegalStateException. JToon is declared as a compileOnly dependency so
applications that do not use TOON are not required to include it.
format(Object) delegates to JToon.encode(value).
formatJson(String) delegates to JToon.encodeJson(json).
7. Ensemble Wiring¶
Ensemble.builder() gains a contextFormat field:
Ensemble.builder()
.chatLanguageModel(model)
.contextFormat(ContextFormat.TOON) // opt-in to TOON
.task(task1)
.task(task2)
.build()
.run();
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
contextFormat |
ContextFormat |
No | JSON |
Serialization format for structured data in LLM prompts. TOON requires dev.toonformat:jtoon on classpath. |
At execution time (inside run() / runWithInputs()), if contextFormat is
TOON, the framework verifies that the JToon class is loadable via
ContextFormatters.forFormat(TOON). If not, it throws an IllegalStateException
with a clear message including the Maven/Gradle coordinates to add.
The resolved ContextFormatter is stored in ExecutionContext and passed to all
components that serialize data for the LLM.
8. Integration Points¶
8.1 AgentPromptBuilder¶
The prompt builder receives the ContextFormatter from ExecutionContext. When
building the user prompt:
- Context from previous tasks: Task output strings that contain structured
data are formatted via
contextFormatter.format(...)before inclusion. - Memory entries: Structured content from memory entries is formatted via the configured formatter.
- Structured output schema: JSON schema descriptions remain in JSON (the LLM needs to produce JSON for parsing), but context data around them uses the configured format.
8.2 AgentExecutor (Tool Output)¶
When a tool returns structured data (JSON), the executor can optionally reformat
it via contextFormatter.formatJson(toolResultText) before appending it to the
conversation as a ToolExecutionResultMessage.
This is the highest-impact integration point -- tool results often contain large JSON payloads that consume significant context window space over multiple iterations of the ReAct loop.
8.3 SequentialWorkflowExecutor (Task Hand-offs)¶
Task outputs passed as context to subsequent tasks flow through the prompt builder (8.1), so no additional changes are needed in the workflow executor itself.
8.4 ExecutionTrace¶
ExecutionTrace gains companion export methods:
/** Serialize this trace to TOON format. */
public String toToon() { ... }
/** Write this trace to a file in TOON format. */
public void toToon(Path outputPath) { ... }
These methods use JToon directly and are only available when JToon is on the
classpath. They throw IllegalStateException with dependency instructions if
JToon is missing.
9. Dependency Configuration¶
Version Catalog (gradle/libs.versions.toml)¶
[versions]
jtoon = "1.0.9"
[libraries]
jtoon = { group = "dev.toonformat", name = "jtoon", version.ref = "jtoon" }
Core Module (agentensemble-core/build.gradle.kts)¶
User's Build File¶
10. Testing Strategy¶
| Level | What |
|---|---|
| Unit | JsonContextFormatter serializes objects to JSON. |
| Unit | ToonContextFormatter serializes objects to TOON (with JToon on test classpath). |
| Unit | ContextFormatters.forFormat(TOON) fails with clear message when JToon absent. |
| Unit | ContextFormatters.forFormat(JSON) always succeeds. |
| Unit | AgentPromptBuilder uses configured formatter for context sections. |
| Unit | ExecutionTrace.toToon() produces valid TOON output. |
| Unit | ExecutionTrace.toToon() throws clear error when JToon absent. |
| Integration | Ensemble.builder().contextFormat(TOON) with JToon present: full run succeeds. |
| Integration | Ensemble.builder().contextFormat(TOON) without JToon: fails at build time. |
| Integration | Sequential workflow with TOON: context from task 1 formatted as TOON in task 2 prompt. |
11. Future Considerations¶
- Per-task format override: Allow individual tasks to use a different format than the ensemble default (e.g., JSON for a task that needs exact JSON in its output, TOON for everything else).
- TOON delimiter configuration: Expose
EncodeOptions(tab vs comma vs pipe delimiter) on the ensemble builder for users who want maximum token savings with tab delimiters. - Bidirectional support: If LLMs improve at producing TOON output, structured output parsing could accept TOON in addition to JSON.
- Token savings metrics: Track and report actual token savings from TOON vs
JSON in
ExecutionMetrics.