Skip to main content

Overview

Renderers transform context fragments into different output formats. All renderers extend the abstract ContextRenderer base class and implement the same interface.

Base Class

ContextRenderer

Abstract base class implementing the Template Method pattern.
abstract class ContextRenderer {
  protected options: RendererOptions;
  
  constructor(options?: RendererOptions);
  
  abstract render(fragments: ContextFragment[]): string;
  
  protected abstract renderFragment(
    fragment: ContextFragment,
    ctx: RenderContext
  ): string;
  
  protected abstract renderPrimitive(
    key: string,
    value: string,
    ctx: RenderContext
  ): string;
  
  protected abstract renderArray(
    key: string,
    items: FragmentData[],
    ctx: RenderContext
  ): string;
  
  protected abstract renderObject(
    key: string,
    obj: FragmentObject,
    ctx: RenderContext
  ): string;
}

RendererOptions

interface RendererOptions {
  /**
   * When true, fragments with the same name are grouped under
   * a pluralized parent tag.
   */
  groupFragments?: boolean;
}
Example:
const renderer = new XmlRenderer({ groupFragments: true });

const fragments = [
  term('API', 'Application Programming Interface'),
  term('SDK', 'Software Development Kit'),
];

// With groupFragments: true
// <terms>
//   <term>...</term>
//   <term>...</term>
// </terms>

// With groupFragments: false (default)
// <term>...</term>
// <term>...</term>

RenderContext

interface RenderContext {
  depth: number;   // Current nesting depth
  path: string[];  // Path through the fragment tree
}

XmlRenderer

Renders fragments as XML with proper nesting, escaping, and indentation.

Constructor

class XmlRenderer extends ContextRenderer {
  constructor(options?: RendererOptions)
}

render()

render(fragments: ContextFragment[]): string
Parameters:
  • fragments - Array of context fragments to render
Returns:
  • XML string with 2-space indentation
Example:
import { XmlRenderer, term, hint } from '@deepagents/context';

const renderer = new XmlRenderer();
const output = renderer.render([
  term('API', 'Application Programming Interface'),
  hint('Always validate input'),
]);

console.log(output);
// <term>
//   <name>API</name>
//   <definition>Application Programming Interface</definition>
// </term>
// <hint>Always validate input</hint>

Features

Automatically escapes special characters:
CharacterEscaped
&&amp;
<&lt;
>&gt;
"&quot;
'&apos;
const frag = term('Example', 'Use <tags> & "quotes"');
const renderer = new XmlRenderer();
console.log(renderer.render([frag]));
// <term>
//   <name>Example</name>
//   <definition>Use &lt;tags&gt; &amp; &quot;quotes&quot;</definition>
// </term>
Arrays are singularized and wrapped:
const frag = workflow({
  task: 'Analysis',
  steps: ['Load', 'Process', 'Report'],
});

// Output:
// <workflow>
//   <task>Analysis</task>
//   <steps>
//     <step>Load</step>
//     <step>Process</step>
//     <step>Report</step>
//   </steps>
// </workflow>
Objects are recursively rendered:
const frag = {
  name: 'config',
  data: {
    database: {
      host: 'localhost',
      port: 5432,
    },
  },
};

// Output:
// <config>
//   <database>
//     <host>localhost</host>
//     <port>5432</port>
//   </database>
// </config>
Multiline values are indented:
const frag = hint(`Rules:
1. Validate
2. Process
3. Log`);

// Output:
// <hint>
//   Rules:
//   1. Validate
//   2. Process
//   3. Log
// </hint>

MarkdownRenderer

Renders fragments as human-readable Markdown with bullet points and headers.

Constructor

class MarkdownRenderer extends ContextRenderer {
  constructor(options?: RendererOptions)
}

render()

render(fragments: ContextFragment[]): string
Parameters:
  • fragments - Array of context fragments to render
Returns:
  • Markdown string with headers and bullet points
Example:
import { MarkdownRenderer, styleGuide } from '@deepagents/context';

const renderer = new MarkdownRenderer();
const output = renderer.render([
  styleGuide({
    prefer: 'CTEs for readability',
    never: 'Deep subquery nesting',
    always: 'Use meaningful aliases',
  }),
]);

console.log(output);
// ## Style Guide
//
// - **prefer**: CTEs for readability
// - **never**: Deep subquery nesting
// - **always**: Use meaningful aliases

Features

Top-level fragments use ## headers:
## Term

- **name**: API
- **definition**: Application Programming Interface
Nested structures use indented bullet points:
## Workflow

- **task**: Customer Analysis
- **steps**:
  - Segment customers
  - Calculate metrics
  - Identify trends
Fragment names are automatically title-cased:
{ name: 'styleGuide', data: { ... } }
// Renders as:
// ## Style Guide

TomlRenderer

Renders fragments as TOML-like configuration format.

Constructor

class TomlRenderer extends ContextRenderer {
  constructor(options?: RendererOptions)
}

render()

render(fragments: ContextFragment[]): string
Parameters:
  • fragments - Array of context fragments to render
Returns:
  • TOML-formatted string
Example:
import { TomlRenderer, styleGuide } from '@deepagents/context';

const renderer = new TomlRenderer();
const output = renderer.render([
  styleGuide({
    prefer: 'CTEs',
    never: 'subqueries',
  }),
]);

console.log(output);
// [styleGuide]
// prefer = "CTEs"
// never = "subqueries"

Features

Top-level fragments become sections:
[database]
host = "localhost"
port = 5432
Nested objects use dotted notation:
[database.settings]
timeout = 30
retry = true
Arrays use inline format:
[workflow]
task = "Analysis"
steps = ["Load", "Process", "Report"]
Preserves types in output:
string_value = "text"
number_value = 42
boolean_value = true

ToonRenderer

Renders fragments as Token-Oriented Object Notation (TOON), a compact format optimized for token efficiency.

Constructor

class ToonRenderer extends ContextRenderer {
  constructor(options?: RendererOptions)
}

render()

render(fragments: ContextFragment[]): string
Parameters:
  • fragments - Array of context fragments to render
Returns:
  • TOON-formatted string
Example:
import { ToonRenderer, styleGuide } from '@deepagents/context';

const renderer = new ToonRenderer();
const output = renderer.render([
  styleGuide({
    prefer: 'CTEs',
    never: 'subqueries',
  }),
]);

console.log(output);
// styleGuide:
//   prefer: CTEs
//   never: subqueries

Features

Uses indentation for structure:
workflow:
  task: Analysis
  steps[3]:
    - Load data
    - Process
    - Report
Compact comma-separated format:
tags[3]: typescript,nodejs,ai
Uniform object arrays as CSV tables:
products[3]{id,name,price}:
  1,Widget,19.99
  2,Gadget,29.99
  3,Doohickey,39.99
Format: name[length]{fields}:
Only quotes when necessary:
simple: text
quoted: "text with: special chars"
number: 42
boolean: true
Represents null explicitly:
value: null
missing: null

TOON Format Specification

# Strings
unquoted: simple text
quoted: "text with: colons"

# Numbers
integer: 42
decimal: 3.14

# Booleans
flag: true
disabled: false

# Null
empty: null

Utility Methods

sanitizeFragments()

Remove null/undefined values recursively.
protected sanitizeFragments(
  fragments: ContextFragment[]
): ContextFragment[]
Example:
const fragments = [
  term('API', 'Application Programming Interface'),
  { name: 'empty', data: null },  // Will be removed
  guardrail({ rule: 'No PII', reason: undefined }),  // reason will be omitted
];

const sanitized = renderer.sanitizeFragments(fragments);
// Only non-null fragments with non-null fields remain

groupByName()

Group fragments by name.
protected groupByName(
  fragments: ContextFragment[]
): Map<string, ContextFragment[]>
Example:
const fragments = [
  term('API', 'Application Programming Interface'),
  term('SDK', 'Software Development Kit'),
  hint('Validate input'),
];

const groups = renderer.groupByName(fragments);
// Map {
//   'term' => [term1, term2],
//   'hint' => [hint1]
// }

isPrimitive()

Check if data is a primitive value.
protected isPrimitive(
  data: FragmentData
): data is string | number | boolean
Example:
if (renderer.isPrimitive(fragment.data)) {
  // data is string, number, or boolean
}

Custom Renderers

Create custom renderers by extending ContextRenderer:
import {
  ContextRenderer,
  type ContextFragment,
  type RenderContext,
  type FragmentData,
  type FragmentObject,
} from '@deepagents/context';

class JsonRenderer extends ContextRenderer {
  render(fragments: ContextFragment[]): string {
    const sanitized = this.sanitizeFragments(fragments);
    return JSON.stringify(sanitized, null, 2);
  }
  
  protected renderFragment(
    fragment: ContextFragment,
    ctx: RenderContext
  ): string {
    return JSON.stringify(fragment);
  }
  
  protected renderPrimitive(
    key: string,
    value: string,
    ctx: RenderContext
  ): string {
    return JSON.stringify({ [key]: value });
  }
  
  protected renderArray(
    key: string,
    items: FragmentData[],
    ctx: RenderContext
  ): string {
    return JSON.stringify({ [key]: items });
  }
  
  protected renderObject(
    key: string,
    obj: FragmentObject,
    ctx: RenderContext
  ): string {
    return JSON.stringify({ [key]: obj });
  }
}

// Usage
const renderer = new JsonRenderer();
const output = renderer.render([term('API', 'Application Programming Interface')]);

Render Helper

Convenience function for quick XML rendering:
function render(tag: string, ...fragments: ContextFragment[]): string
Parameters:
  • tag - Parent tag name
  • fragments - Fragments to render
Returns:
  • XML string with fragments wrapped in parent tag
Example:
import { render, term, hint } from '@deepagents/context';

const xml = render(
  'instructions',
  term('API', 'Application Programming Interface'),
  hint('Always validate input'),
);

console.log(xml);
// <instructions>
//   <term>
//     <name>API</name>
//     <definition>Application Programming Interface</definition>
//   </term>
//   <hint>Always validate input</hint>
// </instructions>

Choosing a Renderer

1

XmlRenderer

Best for models that prefer structured XML (e.g., Claude)
  • Hierarchical structure
  • Proper escaping
  • 2-space indentation
2

MarkdownRenderer

Best for human-readable output
  • Headers and bullet points
  • Natural reading flow
  • Good for documentation
3

TomlRenderer

Best for configuration-style data
  • Section-based structure
  • Type preservation
  • Between XML and YAML complexity
4

ToonRenderer

Best for token efficiency
  • Minimal delimiters
  • Tabular arrays (CSV)
  • Compact representation

Next Steps

Fragment Builders

Complete fragment builder API reference

StreamStore API

Complete stream storage API reference

Renderers Guide

Learn about using renderers

Domain Knowledge

Learn about domain fragments

Build docs developers (and LLMs) love