Class: Presenter<T>
Defined in: packages/core/src/presenter/Presenter.ts:136
Domain-level Presenter — the "View" in MVA (Model-View-Agent).
Encapsulates:
- Schema (Zod): Validates and filters data before it reaches the LLM
- System Rules: JIT context directives that travel with the data
- UI Blocks: SSR-rendered visual blocks (charts, diagrams, tables)
- Agent Limit: Smart truncation for large collections
- Action Suggestions: HATEOAS-style next-action hints
- Embeds: Relational Presenter composition (DRY)
See
createPresenter for the factory function
Type Parameters
| Type Parameter | Description |
|---|---|
T | The validated output type (inferred from the Zod schema) |
Methods
agentLimit()
agentLimit(max, onTruncate): this;Defined in: packages/core/src/presenter/Presenter.ts:347
Set a cognitive guardrail that truncates large collections.
Protects against context DDoS: if a tool returns thousands of records, the Presenter automatically truncates the data array and injects a summary block teaching the AI to use filters.
Parameters
| Parameter | Type | Description |
|---|---|---|
max | number | Maximum items to keep in the data array |
onTruncate | (omittedCount) => UiBlock | Callback that generates a warning UI block. Receives the count of omitted items. |
Returns
this
this for chaining
Example
.agentLimit(50, (omitted) =>
ui.summary(`⚠️ Truncated. 50 shown, ${omitted} hidden. Use filters.`)
)collectionUiBlocks()
collectionUiBlocks(fn): this;Defined in: packages/core/src/presenter/Presenter.ts:322
Define aggregated UI blocks for a collection (array) of items.
When the handler returns an array, this callback is called once with the entire validated array. Prevents N individual charts from flooding the LLM's context.
Parameters
| Parameter | Type | Description |
|---|---|---|
fn | CollectionUiBlocksFn<T> | `(items[], ctx?) => (UiBlock |
Returns
this
this for chaining
Example
.collectionUiBlocks((invoices) => [
ui.echarts({ xAxis: { data: invoices.map(i => i.id) } }),
ui.summary(`${invoices.length} invoices found.`),
])embed()
embed(key, childPresenter): this;Defined in: packages/core/src/presenter/Presenter.ts:490
Compose a child Presenter for a nested relation.
When data[key] exists, the child Presenter's rules and UI blocks are merged into the parent response. This is the DRY solution for relational data: define ClientPresenter once, embed it everywhere.
Parameters
| Parameter | Type | Description |
|---|---|---|
key | string | The property key containing the nested data |
childPresenter | Presenter<unknown> | The Presenter to apply to data[key] |
Returns
this
this for chaining
Example
import { ClientPresenter } from './ClientPresenter';
export const InvoicePresenter = createPresenter('Invoice')
.schema(invoiceSchema)
.embed('client', ClientPresenter);getSchemaKeys()
getSchemaKeys(): string[];Defined in: packages/core/src/presenter/Presenter.ts:588
Get the Zod schema's top-level keys.
Returns the field names declared in the Presenter's schema. Safe to call at any time — does NOT seal the Presenter.
Returns
string[]
Array of key names, or empty array if no schema is set
getStaticRuleStrings()
getStaticRuleStrings(): readonly string[];Defined in: packages/core/src/presenter/Presenter.ts:652
Return static rule strings for introspection hashing.
If rules are dynamic (function), returns an empty array because the actual rule content depends on runtime data/context.
Returns
readonly string[]
Static rule strings, or empty array if rules are contextual
getUiBlockTypes()
getUiBlockTypes(): string[];Defined in: packages/core/src/presenter/Presenter.ts:623
Get which UI block factory methods were configured.
Inspects the configuration callbacks to determine supported UI block types. Does NOT execute any callbacks.
Returns
string[]
Array of UI block type labels
hasContextualRules()
hasContextualRules(): boolean;Defined in: packages/core/src/presenter/Presenter.ts:640
Whether the Presenter uses dynamic (context-aware) system rules.
Static rules (string arrays) are NOT contextual. Functions (data, ctx?) => ... ARE contextual.
Returns
boolean
true if rules are a function
limit()
limit(max): this;Defined in: packages/core/src/presenter/Presenter.ts:463
Cognitive guardrail shorthand with auto-generated message.
Truncates large collections and injects a smart summary block. For custom truncation messages, use .agentLimit(max, onTruncate) instead.
Parameters
| Parameter | Type | Description |
|---|---|---|
max | number | Maximum items to keep in the data array |
Returns
this
this for chaining
Example
// Auto-generated message:
.limit(50)
// → "⚠️ Dataset truncated. 50 shown, {omitted} hidden. Use filters to narrow results."
// For custom message, use agentLimit():
.agentLimit(50, (omitted) => ui.summary(`Custom: ${omitted} hidden`))make()
make(
data,
ctx?,
selectFields?): ResponseBuilder;Defined in: packages/core/src/presenter/Presenter.ts:695
Compose a ResponseBuilder from raw data.
Orchestrates: truncate → validate → embed → render UI → attach rules → suggest actions → Late Guillotine (_select filter).
Late Guillotine pattern: UI blocks, system rules, and action suggestions are computed using the full validated data, ensuring charts and rules never see undefined for pruned fields. Only the wire-facing data block in the ResponseBuilder is filtered by _select — the UI consumes full data in RAM, the AI consumes pruned data on the wire.
After the first call, the Presenter is sealed (immutable).
Auto-detection: If data is an array, items are validated individually and collectionUiBlocks is called (if defined). Otherwise, uiBlocks is called for the single item.
Parameters
| Parameter | Type | Description |
|---|---|---|
data | T | T[] | Raw data from the handler (object or array) |
ctx? | unknown | Optional request context (for RBAC, locale, etc.) |
selectFields? | string[] | Optional top-level field names to keep in the data block. When provided, only these keys survive in the JSON payload sent to the AI. Nested objects are kept whole (shallow). |
Returns
A ResponseBuilder ready for chaining or .build()
Throws
If Zod validation fails
Example
// Full data (default)
return InvoicePresenter.make(rawInvoice).build();
// With _select filtering — only 'status' reaches the AI
return InvoicePresenter.make(rawInvoice, ctx, ['status']).build();redact()
redact(paths, censor?): this;Defined in: packages/core/src/presenter/Presenter.ts:571
Alias for .redactPII() — fluent shorthand.
Parameters
| Parameter | Type | Description |
|---|---|---|
paths | string[] | Object paths to redact |
censor? | string | (value) => string | Replacement value or function |
Returns
this
this for chaining
Example
createPresenter('User')
.schema({ name: t.string, ssn: t.string })
.redact(['ssn'])redactPII()
redactPII(paths, censor?): this;Defined in: packages/core/src/presenter/Presenter.ts:541
Declare PII fields to redact before data leaves the framework.
Uses fast-redact (Pino's V8-optimized serialization engine) to compile object paths into hyper-fast masking functions at config time — zero overhead on the hot path.
The redaction is applied structurally on the wire-facing data (after _select filter, before ResponseBuilder). UI blocks and system rules still see the full unmasked data (Late Guillotine pattern preserved).
Requires fast-redact as an optional peer dependency. If not installed, passes data through unmodified (defensive fallback).
Parameters
| Parameter | Type | Description |
|---|---|---|
paths | string[] | Object paths to redact. Supports dot notation, bracket notation, wildcards ('*'), and array indices. |
censor? | string | (value) => string | Replacement value. Default: '[REDACTED]'. Can be a function (originalValue) => maskedValue. |
Returns
this
this for chaining
Example
// Basic PII masking
createPresenter('Patient')
.schema({ name: t.string, ssn: t.string, diagnosis: t.string })
.redactPII(['ssn', 'diagnosis'])
// Wildcard — redact all nested SSN fields
createPresenter('Users')
.redactPII(['*.ssn', '*.password', 'credit_card.number'])
// Array wildcard — redact diagnosis in all patients
createPresenter('Hospital')
.redactPII(['patients[*].diagnosis', 'patients[*].ssn'])
// Custom censor — last 4 digits visible
createPresenter('Payment')
.redactPII(['credit_card.number'], (v) => '****-****-****-' + String(v).slice(-4))See
rules()
rules(rules): this;Defined in: packages/core/src/presenter/Presenter.ts:423
Alias for .systemRules() — fluent shorthand.
Parameters
| Parameter | Type | Description |
|---|---|---|
rules | readonly string[] | (data, ctx?) => (string | null)[] | Static rules array or dynamic `(data, ctx?) => (string |
Returns
this
this for chaining
Example
.rules(['CRITICAL: amounts in CENTS.'])
.rules((inv) => [
inv.status === 'overdue' ? '⚠️ OVERDUE' : null,
])schema()
Call Signature
schema<TSchema>(zodSchema): Presenter<TSchema["_output"]>;Defined in: packages/core/src/presenter/Presenter.ts:199
Set the Zod schema for data validation and filtering.
The schema acts as a security contract: only fields declared in the schema will reach the LLM. Sensitive data (passwords, tenant IDs, internal flags) is automatically stripped.
Type Parameters
| Type Parameter | Description |
|---|---|
TSchema extends ZodType<any, any, any> | Zod type with output type inference |
Parameters
| Parameter | Type | Description |
|---|---|---|
zodSchema | TSchema | A Zod schema (z.object, z.array, etc.) |
Returns
Presenter<TSchema["_output"]>
A narrowed Presenter with the schema's output type
Example
createPresenter('Invoice')
.schema(z.object({
id: z.string(),
amount_cents: z.number(),
}))
// Presenter<{ id: string; amount_cents: number }>Call Signature
schema<TShape>(shape): Presenter<{ [k in string | number | symbol]: addQuestionMarks<baseObjectOutputType<TShape>, any>[k] }>;Defined in: packages/core/src/presenter/Presenter.ts:224
Set the schema from an object of ZodTypes (enables t.* shorthand).
Accepts a plain object where each value is a ZodType. Internally wraps it into z.object(shape) for full validation.
Type Parameters
| Type Parameter |
|---|
TShape extends ZodRawShape |
Parameters
| Parameter | Type | Description |
|---|---|---|
shape | TShape | Object shape with ZodType values (e.g. { id: t.string, name: t.string }) |
Returns
Presenter<{ [k in string | number | symbol]: addQuestionMarks<baseObjectOutputType<TShape>, any>[k] }>
A narrowed Presenter with the inferred output type
Example
import { createPresenter, t } from '@vinkius-core/mcp-fusion';
createPresenter('Invoice')
.schema({
id: t.string,
amount: t.number.describe('in cents'),
status: t.enum('draft', 'paid'),
})suggest()
suggest(fn): this;Defined in: packages/core/src/presenter/Presenter.ts:405
Alias for .suggestActions() — fluent shorthand.
Define HATEOAS-style action suggestions based on data state. Use with the suggest() helper for maximum fluency.
Parameters
| Parameter | Type | Description |
|---|---|---|
fn | SuggestActionsFn<T> | `(data, ctx?) => (ActionSuggestion |
Returns
this
this for chaining
Example
import { suggest } from '@vinkius-core/mcp-fusion';
.suggest((inv) => [
suggest('invoices.get', 'View details'),
inv.status === 'overdue'
? suggest('billing.remind', 'Send reminder')
: null,
])suggestActions()
suggestActions(fn): this;Defined in: packages/core/src/presenter/Presenter.ts:376
Define HATEOAS-style action suggestions based on data state.
The callback inspects the data and returns suggested next tools, guiding the AI through the business state machine. Eliminates routing hallucinations by providing explicit next-step hints.
Parameters
| Parameter | Type | Description |
|---|---|---|
fn | SuggestActionsFn<T> | (data, ctx?) => ActionSuggestion[] |
Returns
this
this for chaining
Example
.suggestActions((invoice, ctx) => {
if (invoice.status === 'pending') {
return [
{ tool: 'billing.pay', reason: 'Offer immediate payment' },
{ tool: 'billing.send_reminder', reason: 'Send reminder email' },
];
}
return [];
})systemRules()
systemRules(rules): this;Defined in: packages/core/src/presenter/Presenter.ts:274
Set JIT system rules that travel with the data.
Rules are Context Tree-Shaking: they only appear in the LLM's context when this specific domain's data is returned.
Accepts either a static array or a dynamic function that receives the data and request context for RBAC/DLP/locale rules. Return null from dynamic rules to conditionally exclude them.
Parameters
| Parameter | Type | Description |
|---|---|---|
rules | readonly string[] | (data, ctx?) => (string | null)[] | Array of rule strings, or a function `(data, ctx?) => (string |
Returns
this
this for chaining
Example
// Static rules
.systemRules(['CRITICAL: amounts in CENTS.'])
// Dynamic context-aware rules (RBAC)
.systemRules((user, ctx) => [
ctx?.user?.role !== 'admin' ? 'Mask email and phone.' : null,
`Format dates using ${ctx?.tenant?.locale ?? 'en-US'}`
])ui()
ui(fn): this;Defined in: packages/core/src/presenter/Presenter.ts:440
Alias for .uiBlocks() — fluent shorthand.
Parameters
| Parameter | Type | Description |
|---|---|---|
fn | ItemUiBlocksFn<T> | `(item, ctx?) => (UiBlock |
Returns
this
this for chaining
Example
.ui((inv) => [
ui.echarts({ series: [{ type: 'gauge', data: [{ value: inv.amount / 100 }] }] }),
])uiBlocks()
uiBlocks(fn): this;Defined in: packages/core/src/presenter/Presenter.ts:298
Define UI blocks generated for a single data item.
The callback receives the validated data item and optionally the request context. Return null for conditional blocks (filtered automatically).
Parameters
| Parameter | Type | Description |
|---|---|---|
fn | ItemUiBlocksFn<T> | `(item, ctx?) => (UiBlock |
Returns
this
this for chaining
Example
.uiBlocks((invoice, ctx) => [
ui.echarts({ series: [...] }),
ctx?.user?.department === 'finance' ? ui.echarts(advancedChart) : null,
])