Skip to content

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 ParameterDescription
TThe validated output type (inferred from the Zod schema)

Methods

agentLimit()

ts
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

ParameterTypeDescription
maxnumberMaximum items to keep in the data array
onTruncate(omittedCount) => UiBlockCallback that generates a warning UI block. Receives the count of omitted items.

Returns

this

this for chaining

Example

typescript
.agentLimit(50, (omitted) =>
    ui.summary(`⚠️ Truncated. 50 shown, ${omitted} hidden. Use filters.`)
)

collectionUiBlocks()

ts
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

ParameterTypeDescription
fnCollectionUiBlocksFn<T>`(items[], ctx?) => (UiBlock

Returns

this

this for chaining

Example

typescript
.collectionUiBlocks((invoices) => [
    ui.echarts({ xAxis: { data: invoices.map(i => i.id) } }),
    ui.summary(`${invoices.length} invoices found.`),
])

embed()

ts
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

ParameterTypeDescription
keystringThe property key containing the nested data
childPresenterPresenter<unknown>The Presenter to apply to data[key]

Returns

this

this for chaining

Example

typescript
import { ClientPresenter } from './ClientPresenter';

export const InvoicePresenter = createPresenter('Invoice')
    .schema(invoiceSchema)
    .embed('client', ClientPresenter);

getSchemaKeys()

ts
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()

ts
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()

ts
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()

ts
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()

ts
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

ParameterTypeDescription
maxnumberMaximum items to keep in the data array

Returns

this

this for chaining

Example

typescript
// 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()

ts
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

ParameterTypeDescription
dataT | T[]Raw data from the handler (object or array)
ctx?unknownOptional 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

ResponseBuilder

A ResponseBuilder ready for chaining or .build()

Throws

If Zod validation fails

Example

typescript
// Full data (default)
return InvoicePresenter.make(rawInvoice).build();

// With _select filtering — only 'status' reaches the AI
return InvoicePresenter.make(rawInvoice, ctx, ['status']).build();

redact()

ts
redact(paths, censor?): this;

Defined in: packages/core/src/presenter/Presenter.ts:571

Alias for .redactPII() — fluent shorthand.

Parameters

ParameterTypeDescription
pathsstring[]Object paths to redact
censor?string | (value) => stringReplacement value or function

Returns

this

this for chaining

Example

typescript
createPresenter('User')
    .schema({ name: t.string, ssn: t.string })
    .redact(['ssn'])

redactPII()

ts
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

ParameterTypeDescription
pathsstring[]Object paths to redact. Supports dot notation, bracket notation, wildcards ('*'), and array indices.
censor?string | (value) => stringReplacement value. Default: '[REDACTED]'. Can be a function (originalValue) => maskedValue.

Returns

this

this for chaining

Example

typescript
// 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

fast-redact


rules()

ts
rules(rules): this;

Defined in: packages/core/src/presenter/Presenter.ts:423

Alias for .systemRules() — fluent shorthand.

Parameters

ParameterTypeDescription
rulesreadonly string[] | (data, ctx?) => (string | null)[]Static rules array or dynamic `(data, ctx?) => (string

Returns

this

this for chaining

Example

typescript
.rules(['CRITICAL: amounts in CENTS.'])
.rules((inv) => [
    inv.status === 'overdue' ? '⚠️ OVERDUE' : null,
])

schema()

Call Signature

ts
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 ParameterDescription
TSchema extends ZodType<any, any, any>Zod type with output type inference
Parameters
ParameterTypeDescription
zodSchemaTSchemaA Zod schema (z.object, z.array, etc.)
Returns

Presenter<TSchema["_output"]>

A narrowed Presenter with the schema's output type

Example
typescript
createPresenter('Invoice')
    .schema(z.object({
        id: z.string(),
        amount_cents: z.number(),
    }))
// Presenter<{ id: string; amount_cents: number }>

Call Signature

ts
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
ParameterTypeDescription
shapeTShapeObject 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
typescript
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()

ts
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

ParameterTypeDescription
fnSuggestActionsFn<T>`(data, ctx?) => (ActionSuggestion

Returns

this

this for chaining

Example

typescript
import { suggest } from '@vinkius-core/mcp-fusion';

.suggest((inv) => [
    suggest('invoices.get', 'View details'),
    inv.status === 'overdue'
        ? suggest('billing.remind', 'Send reminder')
        : null,
])

suggestActions()

ts
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

ParameterTypeDescription
fnSuggestActionsFn<T>(data, ctx?) => ActionSuggestion[]

Returns

this

this for chaining

Example

typescript
.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()

ts
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

ParameterTypeDescription
rulesreadonly string[] | (data, ctx?) => (string | null)[]Array of rule strings, or a function `(data, ctx?) => (string

Returns

this

this for chaining

Example

typescript
// 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()

ts
ui(fn): this;

Defined in: packages/core/src/presenter/Presenter.ts:440

Alias for .uiBlocks() — fluent shorthand.

Parameters

ParameterTypeDescription
fnItemUiBlocksFn<T>`(item, ctx?) => (UiBlock

Returns

this

this for chaining

Example

typescript
.ui((inv) => [
    ui.echarts({ series: [{ type: 'gauge', data: [{ value: inv.amount / 100 }] }] }),
])

uiBlocks()

ts
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

ParameterTypeDescription
fnItemUiBlocksFn<T>`(item, ctx?) => (UiBlock

Returns

this

this for chaining

Example

typescript
.uiBlocks((invoice, ctx) => [
    ui.echarts({ series: [...] }),
    ctx?.user?.department === 'finance' ? ui.echarts(advancedChart) : null,
])