Renderer
The AIPCRenderer produces deterministic content blocks from validated output. Compliance-critical elements are rendered by code, not by the LLM.
Why deterministic rendering?
At L1 enforcement, the LLM is responsible for including disclosures, formatting data, and adding attribution. This works, but it is probabilistic — the LLM might rephrase a verbatim disclosure, round a number differently, or forget an attribution. The Renderer eliminates this risk by generating these elements with deterministic code. The LLM only writes the narrative.
The render() API
The render() method takes a ValidatedOutput (from the runtime's validate() step) and a RenderConfig, and returns a RenderedOutput:
import { AIPCRenderer } from '@aipc/runtime';
const renderer = new AIPCRenderer();
const rendered = renderer.render(validatedOutput, { modality: 'visual', visualFormat: 'html' });
// rendered.blocks — deterministic content blocks
// rendered.narrativeContext — context for LLM narrative generation
Block types
The renderer produces the following block types, each rendered deterministically from the contract and validated output:
| Block type | Description |
|---|---|
disclosure | Required disclosure text, rendered verbatim or with approved paraphrasing. Includes placement metadata. |
data_point | A single formatted field value with its label (e.g., "Temperature: 62.3°F"). |
data_table | A group of related data points rendered as a table structure. |
attribution | Source attribution text and optional link. Can appear as header, footer, or both. |
freshness_warning | Warning text when data is stale. Only present when freshness status is not "valid". |
suppression_notice | Notice that a field was suppressed, with optional reason text. |
conditional_notice | Notice triggered by a conditional rule (e.g., high-risk warnings). |
NarrativeContext
In addition to deterministic blocks, the renderer produces a NarrativeContext object. This is what the LLM receives to generate its narrative text. It contains enough information for the LLM to write a coherent response without needing access to raw contract data:
| Field | Purpose |
|---|---|
dataSummary | Human-readable summary of the data for the LLM to reference in its narrative. |
referenceableFields | List of fields the LLM may mention by name. Each includes the formatted value so the LLM does not need to reformat. |
toneRestrictions | The tone directives from the contract: framing, prohibited phrases, editorial restrictions. |
prohibitions | Explicit list of things the LLM must not do (e.g., "Do not reformat data values", "Do not reproduce disclosures"). |
suggestedScope | Guidance on what the narrative should cover, based on the fields and disclosures present. |
Modality support
The renderer supports three modalities, each with format variants:
- visual — Output as
html,markdown, orplaintext. HTML includes semantic class names for styling. - voice — Output optimized for text-to-speech. Disclosures are shortened where allowed, data is spelled out, and attribution uses a spoken format.
- document — Output structured for PDF or document generation. Includes section markers and page-break hints.
Usage example
import { AIPCRenderer } from '@aipc/runtime';
const renderer = new AIPCRenderer();
const rendered = renderer.render(validatedOutput, {
modality: 'visual',
visualFormat: 'html'
});
// Deterministic blocks — display these directly
for (const block of rendered.blocks) {
console.log(block.type, block.content);
}
// Narrative context — pass this to the LLM
const llmPrompt = `
Write a brief summary of the following data.
${rendered.narrativeContext.dataSummary}
You may reference these fields: ${rendered.narrativeContext.referenceableFields.map(f => f.label).join(', ')}
Restrictions: ${rendered.narrativeContext.prohibitions.join('; ')}
`;