defineOutputCatalog
KIT · function · Runtime value
Compile output definitions into one catalog.
Compilation is where most mistakes surface: group membership is checked for cycles, master templates must have exactly one slot per field, and every bound/semantic field must name a registered provider. Composition then trusts the compiled catalog.
Import
import { defineOutputCatalog } from '@jangts/agent-core/kits/presentation';import { defineOutputCatalog } from '@jangts/agent-core/kits/presentation';Other public entry points:@jangts/agent-core/types, @jangts/agent-core/kits/presentation, @jangts/agent-core/kits.
Definition
Type parameters
| Type parameter | Constraint | Default type |
|---|---|---|
App | — | unknown |
Call
defineOutputCatalog<App = unknown>(definitions: readonly OutputDefinition[], options?: OutputCatalogOptions<App>): Readonly<{ toModelSchema: (id: string) => { type: string; properties: { [k: string]: Readonly<Record<string, unknown>>; }; required: string[]; additionalProperties: boolean; }; check(request: { outputId: string; value: unknown; }): { status: "passed" | "failed"; value: Record<string, unknown>; issues: OutputIssue[]; }; compose(request: { outputId: string; input: OutputComposeInput; }, context: OperationContext<App>): OutputResult; definitions: readonly Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>[]; ids(): readonly string[]; values(): IterableIterator<Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>>; entries(): IterableIterator<readonly [string, Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>]>; has(id: string): boolean; get(id: string): Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }> | undefined; require(id: string): Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>; }>Compile output definitions into one catalog.
Compilation is where most mistakes surface: group membership is checked for cycles, master templates must have exactly one slot per field, and every bound/semantic field must name a registered provider. Composition then trusts the compiled catalog.
| Type parameter | Constraint | Default type |
|---|---|---|
App | — | unknown |
| Parameter | Type | Passing | Description |
|---|---|---|---|
definitions | readonly OutputDefinition[] | Required | — |
options | OutputCatalogOptions<App> | Optional | — |
Fields of options
| Field | Type | Required | Description |
|---|---|---|---|
providers | readonly OutputProvider<App>[] | undefined | Optional | Read-only. Providers referenced by bound and semantic fields. |
observe | ((result: OutputResult) => void | Promise<void>) | undefined | Optional | Read-only. Observer invoked with every composed result. |
Returns: Readonly<{ toModelSchema: (id: string) => { type: string; properties: { [k: string]: Readonly<Record<string, unknown>>; }; required: string[]; additionalProperties: boolean; }; check(request: { outputId: string; value: unknown; }): { status: "passed" \| "failed"; value: Record<string, unknown>; issues: OutputIssue[]; }; compose(request: { outputId: string; input: OutputComposeInput; }, context: OperationContext<App>): OutputResult; definitions: readonly Readonly<{ id: string; kind: "text" \| "master" \| "record" \| "group"; fields?: readonly OutputField[] \| undefined; master?: string \| undefined; allowedOutputIds?: readonly string[] \| undefined; maxItems?: number \| undefined; }>[]; ids(): readonly string[]; values(): IterableIterator<Readonly<{ id: string; kind: "text" \| "master" \| "record" \| "group"; fields?: readonly OutputField[] \| undefined; master?: string \| undefined; allowedOutputIds?: readonly string[] \| undefined; maxItems?: number \| undefined; }>>; entries(): IterableIterator<readonly [string, Readonly<{ id: string; kind: "text" \| "master" \| "record" \| "group"; fields?: readonly OutputField[] \| undefined; master?: string \| undefined; allowedOutputIds?: readonly string[] \| undefined; maxItems?: number \| undefined; }>]>; has(id: string): boolean; get(id: string): Readonly<{ id: string; kind: "text" \| "master" \| "record" \| "group"; fields?: readonly OutputField[] \| undefined; master?: string \| undefined; allowedOutputIds?: readonly string[] \| undefined; maxItems?: number \| undefined; }> \| undefined; require(id: string): Readonly<{ id: string; kind: "text" \| "master" \| "record" \| "group"; fields?: readonly OutputField[] \| undefined; master?: string \| undefined; allowedOutputIds?: readonly string[] \| undefined; maxItems?: number \| undefined; }>; }>.
Return value structure
| Field | Type | Required | Description |
|---|---|---|---|
toModelSchema | (id: string) => { type: string; properties: { [k: string]: Readonly<Record<string, unknown>>; }; required: string[]; additionalProperties: boolean; } | Required | JSON schema of the fields a model must generate for this output. |
check | (request: { outputId: string; value: unknown; }) => { status: "passed" | "failed"; value: Record<string, unknown>; issues: OutputIssue[]; } | Required | Validate a generated value without composing it. |
compose | (request: { outputId: string; input: OutputComposeInput; }, context: OperationContext<App>) => OutputResult | Required | Compose the final output value from generated fields, providers and constants. |
definitions | readonly Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>[] | Required | Read-only. Definitions in registration order; each entry is frozen by the implementation. |
ids | () => readonly string[] | Required | Ids in the same order as definitions. |
values | () => IterableIterator<Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>> | Required | See the type definition and usage context. |
entries | () => IterableIterator<readonly [string, Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>]> | Required | See the type definition and usage context. |
has | (id: string) => boolean | Required | See the type definition and usage context. |
get | (id: string) => Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }> | undefined | Required | Returns the definition or undefined; the caller decides whether absence is an error. |
require | (id: string) => Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }> | Required | Returns the definition or throws; use when the id is a required reference. |
Examples
- Presentation: field ownership and final output: The model fills only the fields it is assigned; fixed text, bound values, and semantic keys are owned by the program.
First compose one piece of generated text
Beginner · Node.js
import { Presentation } from '@jangts/agent-core/kits/presentation';
const outputs = Presentation.defineOutputCatalog([
{ id: 'reply', kind: 'text', fields: [{ id: 'text', owner: 'generated' }] },
]);
console.log(outputs.toModelSchema('reply'));
const output = outputs.compose({ outputId: 'reply', input: { generated: { text: '普通对象即可定义节点。' } } }, { app: {}, signal: new AbortController().signal });
console.log(output.value);import { Presentation } from '@jangts/agent-core/kits/presentation';
const outputs = Presentation.defineOutputCatalog([
{ id: 'reply', kind: 'text', fields: [{ id: 'text', owner: 'generated' }] },
]);
console.log(outputs.toModelSchema('reply'));
const output = outputs.compose({ outputId: 'reply', input: { generated: { text: '普通对象即可定义节点。' } } }, { app: {}, signal: new AbortController().signal });
console.log(output.value);Let the program own the explanatory prefix in the same compose
Configuration · Node.js
import { Presentation } from '@jangts/agent-core/kits/presentation';
const outputs = Presentation.defineOutputCatalog([
{ id: 'reply', kind: 'master', master: '{{prefix}}{{text}}', fields: [
{ id: 'prefix', owner: 'constant', constantValue: '接口说明:' },
{ id: 'text', owner: 'generated' },
] },
]);
console.log(outputs.toModelSchema('reply')); // 只有 text 由模型填写
console.log(outputs.compose({ outputId: 'reply', input: { generated: { text: '普通对象即可定义节点。' } } }, { app: {}, signal: new AbortController().signal }).value);import { Presentation } from '@jangts/agent-core/kits/presentation';
const outputs = Presentation.defineOutputCatalog([
{ id: 'reply', kind: 'master', master: '{{prefix}}{{text}}', fields: [
{ id: 'prefix', owner: 'constant', constantValue: '接口说明:' },
{ id: 'text', owner: 'generated' },
] },
]);
console.log(outputs.toModelSchema('reply')); // 只有 text 由模型填写
console.log(outputs.compose({ outputId: 'reply', input: { generated: { text: '普通对象即可定义节点。' } } }, { app: {}, signal: new AbortController().signal }).value);Add bound fields and semantic keys while keeping the compose entry
Extension · Node.js
import { Presentation } from '@jangts/agent-core/kits/presentation';
const outputs = Presentation.defineOutputCatalog<{ displayName: string }>([
{ id: 'reply', kind: 'record', fields: [
{ id: 'text', owner: 'generated' },
{ id: 'author', owner: 'bound', providerId: 'author' },
{ id: 'tone', owner: 'semantic', providerId: 'tone', semanticKeys: ['brief', 'detailed'] },
] },
], { providers: [
{ id: 'author', resolve: (_input, { app }) => app.displayName },
{ id: 'tone', resolve: ({ key }) => key === 'brief' ? '简洁说明' : '详细说明' },
] });
const result = outputs.compose({ outputId: 'reply', input: { generated: { text: '普通对象即可。', tone: 'brief' } } }, { app: { displayName: '示例助手' }, signal: new AbortController().signal });
console.log(result.value);import { Presentation } from '@jangts/agent-core/kits/presentation';
const outputs = Presentation.defineOutputCatalog([
{ id: 'reply', kind: 'record', fields: [
{ id: 'text', owner: 'generated' },
{ id: 'author', owner: 'bound', providerId: 'author' },
{ id: 'tone', owner: 'semantic', providerId: 'tone', semanticKeys: ['brief', 'detailed'] },
] },
], { providers: [
{ id: 'author', resolve: (_input, { app }) => app.displayName },
{ id: 'tone', resolve: ({ key }) => key === 'brief' ? '简洁说明' : '详细说明' },
] });
const result = outputs.compose({ outputId: 'reply', input: { generated: { text: '普通对象即可。', tone: 'brief' } } }, { app: { displayName: '示例助手' }, signal: new AbortController().signal });
console.log(result.value);Related policy source
- Field ownership, model Schema, and composition
- Reply format declarations, shared checks, and bubble normalization