Skip to content
English

Presentation ​

KIT · constant · 运行时值

导入 ​

ts
import { Presentation } from '@jangts/agent-core/kits/presentation';
js
import { Presentation } from '@jangts/agent-core/kits/presentation';

其他公开入口:@jangts/agent-core/types、@jangts/agent-core/kits/presentation、@jangts/agent-core/kits。

定义 ​

字段结构 ​

字段类型必需说明
replyFormatChecksReadonly<{ bubbles(totalLimit: number): ReplyFormatCheck; textBudget(maxChars: number): ReplyFormatCheck; }>必需见类型定义及调用场景。
REPLY_BUBBLE_BOUNDARY"\u001E"必需见类型定义及调用场景。

成员目录 ​

成员用途
defineOutputCatalog完整输入输出见下方重载。
defineReplyFormats完整输入输出见下方重载。
mergeReplyBubbles完整输入输出见下方重载。
defineTextTemplate完整输入输出见下方重载。
defineSemanticSlots完整输入输出见下方重载。
selectVariant完整输入输出见下方重载。
resolvePreference完整输入输出见下方重载。
replyBubbleTexts完整输入输出见下方重载。
publishReplyEvents完整输入输出见下方重载。
serializeOutputEvents完整输入输出见下方重载。
textOutputEvents完整输入输出见下方重载。

成员详情 ​

defineOutputCatalog ​

ts
Presentation.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.

类型参数约束默认类型
App—unknown
参数类型传递说明
definitionsreadonly OutputDefinition[]必需—
optionsOutputCatalogOptions<App>可省略—
options 的字段
字段类型必需说明
providersreadonly OutputProvider<App>[] | undefined可省略只读。Providers referenced by bound and semantic fields.
observe((result: OutputResult) => void | Promise<void>) | undefined可省略只读。Observer invoked with every composed result.

返回: 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; }>; }>。

返回值结构
字段类型必需说明
toModelSchema(id: string) => { type: string; properties: { [k: string]: Readonly<Record<string, unknown>>; }; required: string[]; additionalProperties: boolean; }必需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[]; }必需Validate a generated value without composing it.
compose(request: { outputId: string; input: OutputComposeInput; }, context: OperationContext<App>) => OutputResult必需Compose the final output value from generated fields, providers and constants.
definitionsreadonly Readonly<{ id: string; kind: "text" | "master" | "record" | "group"; fields?: readonly OutputField[] | undefined; master?: string | undefined; allowedOutputIds?: readonly string[] | undefined; maxItems?: number | undefined; }>[]必需只读。Definitions in registration order; each entry is frozen by the implementation.
ids() => readonly string[]必需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; }>>必需见类型定义及调用场景。
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必需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; }>必需Returns the definition or throws; use when the id is a required reference.

defineReplyFormats ​

ts
Presentation.defineReplyFormats<Context = unknown>(options: ReplyFormatOptions<Context>): Readonly<{ resolve(context: Context): CompiledReplyFormat | undefined; }>

Compile reply formats so that checks run only for templates the current turn uses.

类型参数约束默认类型
Context—unknown
参数类型传递说明
optionsReplyFormatOptions<Context>必需—
options 的字段
字段类型必需说明
formatsreadonly ReplyFormatDefinition<Context>[]必需只读。见类型定义及调用场景。
checksreadonly ReplyFormatCheck[]必需只读。见类型定义及调用场景。

返回: Readonly<{ resolve(context: Context): CompiledReplyFormat \| undefined; }>。

返回值结构
字段类型必需说明
resolve(context: Context) => CompiledReplyFormat | undefined必需The template this turn uses, or undefined when it has no output-format requirement.

mergeReplyBubbles ​

ts
Presentation.mergeReplyBubbles(bubbles: readonly string[], limit: number): string[]

Normalize a reply that has no declared format: drop blank bubbles and merge overflow into the last allowed one. Text content is preserved.

参数类型传递说明
bubblesreadonly string[]必需—
limitnumber必需—

返回: string[]。

defineTextTemplate ​

ts
Presentation.defineTextTemplate(master: string, options?: TextTemplateOptions): Readonly<{ slots: readonly string[]; render(values: Readonly<Record<string, string>>): string; }>

The program owns the master; inserted model text is a value and is substituted once only.

Substitution is single-pass String.replace: a value that itself contains {{slot}} is left as literal text, so a slot value cannot inject further substitutions.

参数类型传递说明
masterstring必需—
optionsTextTemplateOptions可省略—
options 的字段
字段类型必需说明
observe((result: string) => void | Promise<void>) | undefined可省略只读。Observer invoked with every rendered text.
errors{ readonly missingField?: (key: string) => Error | string; } | undefined可省略只读。Builds the error for a slot the caller did not supply; receives the slot name.

返回: Readonly<{ slots: readonly string[]; render(values: Readonly<Record<string, string>>): string; }>。

返回值结构
字段类型必需说明
slotsreadonly string[]必需见类型定义及调用场景。
render(values: Readonly<Record<string, string>>) => string必需见类型定义及调用场景。

defineSemanticSlots ​

ts
Presentation.defineSemanticSlots(definition: SemanticSlotDefinition): Readonly<{ namespace: string; isValid(text: string): boolean; }>

Models select public semantic keys; hosts retain private values and selection policy.

A text is valid when it uses at most maxOccurrences namespaced slots, every name is a declared key, and no malformed {{namespace remnant is left behind — the last check stops partial or misspelled placeholders from reaching the template engine.

参数类型传递说明
definitionSemanticSlotDefinition必需—
definition 的字段
字段类型必需说明
namespacestring必需只读。Slot namespace; must match ^[a-z][a-z0-9-]*$.
keysreadonly string[]必需只读。Allowed keys after the namespace; any other key makes the text invalid.
maxOccurrencesnumber必需只读。Maximum total occurrences across the text; must be a non-negative integer.

返回: Readonly<{ namespace: string; isValid(text: string): boolean; }>。

返回值结构
字段类型必需说明
namespacestring必需见类型定义及调用场景。
isValid(text: string) => boolean必需见类型定义及调用场景。

selectVariant ​

ts
Presentation.selectVariant<Value>(values: readonly Value[], options: { previous?: Value; randomIndex(limit: number): number; }): Value | undefined

Pick one variant, avoiding an immediate repeat when alternatives exist.

When every candidate equals previous, the full list is used again, so a single-value set still yields a result instead of failing.

类型参数约束默认类型
Value——
参数类型传递说明
valuesreadonly Value[]必需—
options{ previous?: Value; randomIndex(limit: number): number; }必需—
options 的字段
字段类型必需说明
previousValue | undefined可省略见类型定义及调用场景。
randomIndex(limit: number) => number必需见类型定义及调用场景。

返回: Value \| undefined。

等待后的值: Awaited<Value> \| undefined。

resolvePreference ​

ts
Presentation.resolvePreference<Value>(candidates: readonly { value: Value; priority: number; order: number; }[]): Value | undefined

Resolve the preferred candidate.

Highest priority wins; order breaks ties with the later entry first, so recency can be encoded without touching priority. The input array is copied before sorting.

类型参数约束默认类型
Value——
参数类型传递说明
candidatesreadonly { value: Value; priority: number; order: number; }[]必需—

返回: Value \| undefined。

等待后的值: Awaited<Value> \| undefined。

replyBubbleTexts ​

ts
Presentation.replyBubbleTexts(reply: ReplyBubbleInput): string[]

Collect the non-empty-text parts of a reply.

参数类型传递说明
replyReplyBubbleInput必需—
reply 的字段
字段类型必需说明
textunknown可省略Primary reply text.
bubblesunknown可省略Additional bubbles appended after text, when the value is an array.

返回: string[]。

publishReplyEvents ​

ts
Presentation.publishReplyEvents(request: { text: string; delivery?: ReplyDeliveryOptions; }, context: ExecutionContext): AsyncIterable<AgentOutputEvent>

Stream one reply as paced text chunks and bubble separators.

Publish a validated reply without exposing its internal boundary to consumers. The pacing options are upper bounds, not exact timings: the pause and interval are clamped against maxDurationMs, so added delay never exceeds the budget while every chunk is still emitted.

参数类型传递说明
request{ text: string; delivery?: ReplyDeliveryOptions; }必需—
contextExecutionContext必需—
request 的字段
字段类型必需说明
textstring必需见类型定义及调用场景。
deliveryReplyDeliveryOptions | undefined可省略见类型定义及调用场景。
context 的字段
字段类型必需说明
loggerSubFlowLog | undefined可省略只读。Explicit optional recorder for this operation; never inferred from diagnostics.
signalAbortSignal必需只读。Non-optional cancellation signal; never undefined once execution has started.
diagnosticsDiagnosticContext | undefined可省略只读。Diagnostic scope of the enclosing call, when recording is enabled.

返回: AsyncIterable<AgentOutputEvent>。

serializeOutputEvents ​

ts
Presentation.serializeOutputEvents(events: AsyncIterable<AgentOutputEvent>): AsyncIterable<string>

Serialize the event protocol for callers using a text stream.

preview events are dropped because they are not final text; bubbles become the boundary character again, so a consumer can re-split the stream.

参数类型传递说明
eventsAsyncIterable<AgentOutputEvent>必需—

返回: AsyncIterable<string>。

textOutputEvents ​

ts
Presentation.textOutputEvents(chunks: AsyncIterable<string>): AsyncIterable<AgentOutputEvent>

Wrap already-chunked text as text events.

参数类型传递说明
chunksAsyncIterable<string>必需—

返回: AsyncIterable<AgentOutputEvent>。

使用示例 ​

先组合一段生成文本 ​

入门 · Node.js

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

相同 compose 让程序持有说明前缀 ​

配置 · Node.js

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

增加绑定字段和语义键,保持 compose 入口 ​

扩展 · Node.js

ts
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);
js
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);

相关策略源码 ​

相关定义 ​

接口参考、使用示例与开发指南。