Skip to content
中文

Answering ​

KIT · constant · Runtime value

Import ​

ts
import { Answering } from '@jangts/agent-core/kits/answering';
js
import { Answering } from '@jangts/agent-core/kits/answering';

Other public entry points:@jangts/agent-core/types, @jangts/agent-core/kits/answering, @jangts/agent-core/kits.

Definition ​

Member index ​

MemberPurpose
defineAnswerTaskCatalogSee the overload below for full inputs and outputs.
defineAnswerReaderCatalogSee the overload below for full inputs and outputs.
defineAnswerCheckCatalogSee the overload below for full inputs and outputs.
defineAnswerFlowSee the overload below for full inputs and outputs.
validateAnswerBatchSee the overload below for full inputs and outputs.

Member details ​

defineAnswerTaskCatalog ​

ts
Answering.defineAnswerTaskCatalog<Input, Evidence, App, Data = unknown>(definitions: readonly AnswerTaskDefinition<Input, Data>[], ports: AnswerTaskPorts<Input, Evidence, App, Data>): Readonly<{ describe: () => { inputJsonSchema: Readonly<Record<string, unknown>>; id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; metadata: Data; }[]; read(request: { taskId: string; input: unknown; }, context: OperationContext<App>): Evidence; readAsync(request: { taskId: string; input: unknown; }, context: OperationContext<App>): Promise<Evidence>; definitions: readonly Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>[]; ids(): readonly string[]; values(): IterableIterator<Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>>; entries(): IterableIterator<readonly [string, Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>]>; has(id: string): boolean; get(id: string): Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }> | undefined; require(id: string): Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>; }>

Compile the answer task catalog from its declarations and shared ports.

Task ids, schemas, readers, outputs and checks have one compiled authority: a task can only reference a reader or check that the ports actually registered, and metadata is cloned and frozen so later mutation by the caller cannot change a registered task.

Type parameterConstraintDefault type
Input——
Evidence——
App——
Data—unknown
ParameterTypePassingDescription
definitionsreadonly AnswerTaskDefinition<Input, Data>[]Required—
portsAnswerTaskPorts<Input, Evidence, App, Data>Required—
Fields of ports
FieldTypeRequiredDescription
readersReadonlyCatalog<AnswerReader<Input, Evidence, App, Data>>RequiredRead-only. See the type definition and usage context.
outputsReadonlyCatalog<{ readonly id: string; }>RequiredRead-only. See the type definition and usage context.
checksReadonlyCatalog<{ readonly id: string; }>RequiredRead-only. See the type definition and usage context.
assertDefinition((task: Readonly<AnswerTaskDefinition<Input, Data>>) => void) | undefinedOptionalExtra App assertion over a raw definition, before it is compiled.

Returns: Readonly<{ describe: () => { inputJsonSchema: Readonly<Record<string, unknown>>; id: string; description: string; readerId: string; outputId: string; scopeId: string \| undefined; goalIds: readonly any[]; checkIds: readonly any[]; metadata: Data; }[]; read(request: { taskId: string; input: unknown; }, context: OperationContext<App>): Evidence; readAsync(request: { taskId: string; input: unknown; }, context: OperationContext<App>): Promise<Evidence>; definitions: readonly Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string \| undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>[]; ids(): readonly string[]; values(): IterableIterator<Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string \| undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>>; entries(): IterableIterator<readonly [string, Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string \| undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>]>; has(id: string): boolean; get(id: string): Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string \| undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }> \| undefined; require(id: string): Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string \| undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>; }>.

Return value structure
FieldTypeRequiredDescription
describe() => { inputJsonSchema: Readonly<Record<string, unknown>>; id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; metadata: Data; }[]RequiredTask metadata with the JSON schema flattened for model or admin presentation.
read(request: { taskId: string; input: unknown; }, context: OperationContext<App>) => EvidenceRequiredRead evidence through a task's registered reader, synchronously.
readAsync(request: { taskId: string; input: unknown; }, context: OperationContext<App>) => Promise<Evidence>RequiredRead evidence through a task's registered reader, awaiting an async reader.
definitionsreadonly Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>[]RequiredRead-only. Definitions in registration order; each entry is frozen by the implementation.
ids() => readonly string[]RequiredIds in the same order as definitions.
values() => IterableIterator<Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>>RequiredSee the type definition and usage context.
entries() => IterableIterator<readonly [string, Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>]>RequiredSee the type definition and usage context.
has(id: string) => booleanRequiredSee the type definition and usage context.
get(id: string) => Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }> | undefinedRequiredReturns the definition or undefined; the caller decides whether absence is an error.
require(id: string) => Readonly<{ id: string; description: string; readerId: string; outputId: string; scopeId: string | undefined; goalIds: readonly any[]; checkIds: readonly any[]; inputSchema: SchemaAdapter<Input>; metadata: Data; }>RequiredReturns the definition or throws; use when the id is a required reference.

defineAnswerReaderCatalog ​

ts
Answering.defineAnswerReaderCatalog<Input, Evidence, App, Data = unknown>(definitions: readonly AnswerReader<Input, Evidence, App, Data>[]): ReadonlyCatalog<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }>

Compile a reader catalog.

Type parameterConstraintDefault type
Input——
Evidence——
App——
Data—unknown
ParameterTypePassingDescription
definitionsreadonly AnswerReader<Input, Evidence, App, Data>[]Required—

Returns: ReadonlyCatalog<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }>.

Return value structure
FieldTypeRequiredDescription
definitionsreadonly Readonly<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }>[]RequiredRead-only. Definitions in registration order; each entry is frozen by the implementation.
ids() => readonly string[]RequiredIds in the same order as definitions.
values() => IterableIterator<Readonly<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }>>RequiredSee the type definition and usage context.
entries() => IterableIterator<readonly [string, Readonly<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }>]>RequiredSee the type definition and usage context.
has(id: string) => booleanRequiredSee the type definition and usage context.
get(id: string) => Readonly<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }> | undefinedRequiredReturns the definition or undefined; the caller decides whether absence is an error.
require(id: string) => Readonly<{ id: string; read: (input: Input, context: OperationContext<App> & { readonly task: Readonly<AnswerTaskDefinition<Input, Data>>; }) => MaybePromise<Evidence>; }>RequiredReturns the definition or throws; use when the id is a required reference.

defineAnswerCheckCatalog ​

ts
Answering.defineAnswerCheckCatalog<Value, App>(definitions: readonly AnswerChecker<Value, App>[]): Readonly<{ check(request: { checkIds: readonly string[]; value: Value; }, context: OperationContext<App>): AnswerCheck<Value>; definitions: readonly Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>[]; ids(): readonly string[]; values(): IterableIterator<Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>>; entries(): IterableIterator<readonly [string, Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>]>; has(id: string): boolean; get(id: string): Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }> | undefined; require(id: string): Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>; }>

Compile a checker catalog.

A checker may return a replacement value; it is threaded into the next checker, so the selected ids behave like an ordered chain rather than independent assertions.

Type parameterConstraintDefault type
Value——
App——
ParameterTypePassingDescription
definitionsreadonly AnswerChecker<Value, App>[]Required—

Returns: Readonly<{ check(request: { checkIds: readonly string[]; value: Value; }, context: OperationContext<App>): AnswerCheck<Value>; definitions: readonly Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>[]; ids(): readonly string[]; values(): IterableIterator<Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>>; entries(): IterableIterator<readonly [string, Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>]>; has(id: string): boolean; get(id: string): Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }> \| undefined; require(id: string): Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>; }>.

Return value structure
FieldTypeRequiredDescription
check(request: { checkIds: readonly string[]; value: Value; }, context: OperationContext<App>) => AnswerCheck<Value>RequiredSee the type definition and usage context.
definitionsreadonly Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>[]RequiredRead-only. Definitions in registration order; each entry is frozen by the implementation.
ids() => readonly string[]RequiredIds in the same order as definitions.
values() => IterableIterator<Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>>RequiredSee the type definition and usage context.
entries() => IterableIterator<readonly [string, Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>]>RequiredSee the type definition and usage context.
has(id: string) => booleanRequiredSee the type definition and usage context.
get(id: string) => Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }> | undefinedRequiredReturns the definition or undefined; the caller decides whether absence is an error.
require(id: string) => Readonly<{ id: string; check: (value: Value, context: OperationContext<App>) => CheckResult<Value>; }>RequiredReturns the definition or throws; use when the id is a required reference.

defineAnswerFlow ​

ts
Answering.defineAnswerFlow<Data, Value, App = undefined>(definition: AnswerFlowDefinition<Data, Value, App>): Readonly<{ run(request: { inputIds: readonly string[]; items: readonly AnswerItem<Data>[]; }, context: OperationContext<App>): Promise<AnswerResult<Data, Value>[]>; }>

Compile a reusable answer workflow.

Reusable answer workflow. Requests own cells and repair budgets; models remain caller-owned. The flow runs at most maxRepairs + 1 rounds: one generation pass, then one repair round per failing item set, and finally an explicit accepted/fallback/blocked result per item.

Type parameterConstraintDefault type
Data——
Value——
App—undefined
ParameterTypePassingDescription
definitionAnswerFlowDefinition<Data, Value, App>Required—
Fields of definition
FieldTypeRequiredDescription
maxItemsnumberRequiredRead-only. Maximum items in one batch; must be a positive integer.
maxRepairsnumberRequiredRead-only. Repair rounds; the flow runs at most maxRepairs + 1 rounds in total.
reviewPolicy"required" | "off" | "optional" | undefinedOptionalRead-only. Review policy; defaults to optional, required blocks on an unresolved review.
canInvoke(context: OperationContext<App>) => booleanRequiredRequest-level budget guard; must return boolean synchronously.
generate(input: { readonly items: readonly AnswerItem<Data>[]; readonly repairs?: ReadonlyMap<string, readonly AnswerIssue[]>; readonly previous?: ReadonlyMap<string, Value> | undefined; }, context: OperationContext<App>) => Promise<ReadonlyMap<string, Value>>RequiredProduces values for the items that still need one. repairs carries the issues of a failed attempt and previous its rejected values.
check(input: { readonly item: AnswerItem<Data>; readonly value: Value; }, context: OperationContext<App>) => AnswerCheck<Value>RequiredLocal check for one generated value; must return synchronously.
review((input: { readonly items: readonly { item: AnswerItem<Data>; value: Value; }[]; }, context: OperationContext<App>) => Promise<ReadonlyMap<string, AnswerCheck<Value>>>) | undefinedOptionalBatch review; returns one check per reviewed item and must cover the submitted items.
fallback(input: { readonly item: AnswerItem<Data>; readonly issues: readonly AnswerIssue[]; }, context: OperationContext<App>) => RecoveryResult<Value>RequiredLast resort for a failed item; handled supplies a replacement value.
observe((input: { readonly stageId: string; readonly results: readonly AnswerResult<Data, Value>[]; }, context: OperationContext<App>) => MaybePromise<void>) | undefinedOptionalObserves a stage outcome; failures must not affect the flow result.

Returns: Readonly<{ run(request: { inputIds: readonly string[]; items: readonly AnswerItem<Data>[]; }, context: OperationContext<App>): Promise<AnswerResult<Data, Value>[]>; }>.

Return value structure
FieldTypeRequiredDescription
run(request: { inputIds: readonly string[]; items: readonly AnswerItem<Data>[]; }, context: OperationContext<App>) => Promise<AnswerResult<Data, Value>[]>RequiredRun one answer batch.

validateAnswerBatch ​

ts
Answering.validateAnswerBatch<Data>(inputIds: readonly string[], items: readonly AnswerItem<Data>[], maxItems: number): void

Validate that one batch is well formed and fully covered.

Type parameterConstraintDefault type
Data——
ParameterTypePassingDescription
inputIdsreadonly string[]Required—
itemsreadonly AnswerItem<Data>[]Required—
maxItemsnumberRequired—

Returns: void.

Examples ​

First handle one question that has a source ​

Beginner · Node.js

The offline example uses already-read body text directly to show the flow contract; when switching to model generation, the same generate port still applies.

ts
import { Answering } from '@jangts/agent-core/kits/answering';
const flow = Answering.defineAnswerFlow<{ source: string }, string, {}>({
  maxItems: 4, maxRepairs: 0, reviewPolicy: 'off', canInvoke: () => true,
  async generate({ items }) { return new Map(items.map(item => [item.id, item.data.source])); },
  check: ({ value }) => ({ status: value.trim() ? 'passed' : 'failed', issues: [] }),
  fallback: () => ({ handled: false }),
});
const result = await flow.run({ inputIds: ['question-1'], items: [{ id: 'explain', inputIds: ['question-1'], sourceStatus: 'ready', data: { source: '普通对象可以实现节点合同。' } }] }, { app: {}, signal: new AbortController().signal });
console.log(result[0].status, result[0].value);
js
import { Answering } from '@jangts/agent-core/kits/answering';
const flow = Answering.defineAnswerFlow({
    maxItems: 4, maxRepairs: 0, reviewPolicy: 'off', canInvoke: () => true,
    async generate({ items }) { return new Map(items.map(item => [item.id, item.data.source])); },
    check: ({ value }) => ({ status: value.trim() ? 'passed' : 'failed', issues: [] }),
    fallback: () => ({ handled: false }),
});
const result = await flow.run({ inputIds: ['question-1'], items: [{ id: 'explain', inputIds: ['question-1'], sourceStatus: 'ready', data: { source: '普通对象可以实现节点合同。' } }] }, { app: {}, signal: new AbortController().signal });
console.log(result[0].status, result[0].value);

Keep run unchanged and add review plus one local repair ​

Configuration · Node.js

The example triggers one real local repair with an empty draft; production review should rely on real evidence instead of substituting string equality for semantic review.

ts
import { Answering } from '@jangts/agent-core/kits/answering';
const flow = Answering.defineAnswerFlow<{ source: string }, string, {}>({
  maxItems: 4, maxRepairs: 1, reviewPolicy: 'required', canInvoke: () => true,
  async generate({ items, repairs }) { return new Map(items.map(item => [item.id, repairs?.has(item.id) ? item.data.source : ''])); },
  check: ({ value }) => ({ status: value.trim() ? 'passed' : 'failed', issues: value.trim() ? [] : [{ code: 'EMPTY', message: '需要非空回答' }] }),
  async review({ items }) { return new Map(items.map(({ item, value }) => [item.id, { status: value === item.data.source ? 'passed' as const : 'failed' as const, issues: [] }])); },
  fallback: () => ({ handled: true, value: '当前资料不足,暂时无法回答。' }),
});
const result = await flow.run({ inputIds: ['question-1'], items: [{ id: 'explain', inputIds: ['question-1'], sourceStatus: 'ready', data: { source: '普通对象可以实现节点合同。' } }] }, { app: {}, signal: new AbortController().signal });
console.log(result[0].status, result[0].checks);
js
import { Answering } from '@jangts/agent-core/kits/answering';
const flow = Answering.defineAnswerFlow({
    maxItems: 4, maxRepairs: 1, reviewPolicy: 'required', canInvoke: () => true,
    async generate({ items, repairs }) { return new Map(items.map(item => [item.id, repairs?.has(item.id) ? item.data.source : ''])); },
    check: ({ value }) => ({ status: value.trim() ? 'passed' : 'failed', issues: value.trim() ? [] : [{ code: 'EMPTY', message: '需要非空回答' }] }),
    async review({ items }) { return new Map(items.map(({ item, value }) => [item.id, { status: value === item.data.source ? 'passed' : 'failed', issues: [] }])); },
    fallback: () => ({ handled: true, value: '当前资料不足,暂时无法回答。' }),
});
const result = await flow.run({ inputIds: ['question-1'], items: [{ id: 'explain', inputIds: ['question-1'], sourceStatus: 'ready', data: { source: '普通对象可以实现节点合同。' } }] }, { app: {}, signal: new AbortController().signal });
console.log(result[0].status, result[0].checks);

First validate multi-question coverage to avoid missing inputs ​

Extension · Node.js

ts
import { Answering } from '@jangts/agent-core/kits/answering';
const items = [
  { id: 'define', inputIds: ['q1'], sourceStatus: 'ready' as const, data: { source: '定义节点' } },
  { id: 'run', inputIds: ['q2'], sourceStatus: 'unavailable' as const, data: { source: '' } },
];
Answering.validateAnswerBatch(['q1', 'q2'], items, 4);
console.log('两个问题均有明确处理项,包括资料不可用的项。');
js
import { Answering } from '@jangts/agent-core/kits/answering';
const items = [
    { id: 'define', inputIds: ['q1'], sourceStatus: 'ready', data: { source: '定义节点' } },
    { id: 'run', inputIds: ['q2'], sourceStatus: 'unavailable', data: { source: '' } },
];
Answering.validateAnswerBatch(['q1', 'q2'], items, 4);
console.log('两个问题均有明确处理项,包括资料不可用的项。');

API reference, usage examples and developer guides.