createContextSelectionNode
SUPPORT · function · Runtime value
Create an ordinary node that selects reduction steps without executing them.
The node reports the registered step IDs so the graph can route to reduction nodes itself.
Import
ts
import { createContextSelectionNode } from '@jangts/agent-core/support';js
import { createContextSelectionNode } from '@jangts/agent-core/support';Other public entry points:@jangts/agent-core/support, @jangts/agent-core/support/context.
Definition
Type parameters
| Type parameter | Constraint | Default type |
|---|---|---|
State | — | — |
Result | — | — |
App | — | undefined |
Call
ts
createContextSelectionNode<State, Result, App = undefined>(definition: ContextSelectionNodeDefinition<State, Result, App>): WorkflowNode<State, Result, App>Create an ordinary node that selects reduction steps without executing them.
The node reports the registered step IDs so the graph can route to reduction nodes itself.
| Type parameter | Constraint | Default type |
|---|---|---|
State | — | — |
Result | — | — |
App | — | undefined |
| Parameter | Type | Passing | Description |
|---|---|---|---|
definition | ContextSelectionNodeDefinition<State, Result, App> | Required | — |
Fields of definition
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Required | Read-only. Stable node id referenced by routes and error handling. |
description | string | Required | Read-only. Required explanation of what the node does; also used in diagnostics. |
name | string | undefined | Optional | Read-only. Display name; defaults to id when omitted. |
requires | readonly (keyof State & string)[] | undefined | Optional | Read-only. State keys that must be present before this node runs; enforced by the engine. |
provides | readonly (keyof State & string)[] | undefined | Optional | Read-only. State keys this node is expected to produce; validated after run. |
routes | readonly WorkflowRoute<State, Result, App>[] | Required | Read-only. Candidate successors, evaluated in order. A getter must be pure; registration reads it once. |
startsRound | boolean | undefined | Optional | Read-only. Reserves a fresh round on entry. Use it for steps that may legitimately repeat; entering such a node when the round budget is exhausted fails with the configured exhausted error. |
onErrorNodeId | string | undefined | Optional | Read-only. Node entered when run/provides/route fails; contract errors always propagate instead. |
onErrorRouteId | string | undefined | Optional | Read-only. Route id reported with the recovery transition. |
prepared | ((state: Readonly<State>, context: WorkflowContext<App>) => PreparedModelCall) | undefined | Optional | Read-only. Optional prebuilt model call, used instead of preparing request. |
plan | (state: Readonly<State>, context: WorkflowContext<App>) => ContextPlan | Required | Read-only. Builds the context plan; must be synchronous so budget failures surface before any I/O. |
request | (ModelPrepareRequest<string | ModelTransportDefinition<unknown>> & { modelId?: string; }) | ((state: Readonly<State>, context: WorkflowContext<App>) => ModelPrepareRequest<string | ModelTransportDefinition> & { modelId?: string; }) | undefined | Optional | Read-only. Model preparation request, either static or derived from the current node state. |
policy | ContextPolicy | undefined | Optional | Read-only. Processing policy; omitted means validate (no reduction, audit checks only). |
timeoutMs | number | undefined | Optional | Read-only. Per-node timeout in milliseconds; defaults to the Core call timeout. |
compressors | readonly ContextCompressor[] | undefined | Optional | Read-only. Compressors referenced by compression steps; validated against the policy at creation. |
selectors | readonly ContextSelector[] | undefined | Optional | Read-only. Selectors referenced by model-driven selection; validated against the policy at creation. |
update | (result: ContextSelectionResult, state: Readonly<State>) => Partial<State> | Required | Read-only. Receives the chosen step IDs so the graph can route to reduction nodes. |
Returns: WorkflowNode<State, Result, App>.
Return value structure
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Required | Read-only. Stable node id referenced by routes and error handling. |
description | string | Required | Read-only. Required explanation of what the node does; also used in diagnostics. |
name | string | undefined | Optional | Read-only. Display name; defaults to id when omitted. |
report | ((update: void | Readonly<Partial<State>>, context: NodeReportingContext) => WorkflowNodeReport) | undefined | Optional | Read-only. Optional application-reported detail, collected only when content logging is enabled. |
startsRound | boolean | undefined | Optional | Read-only. Reserves a fresh round on entry. Use it for steps that may legitimately repeat; entering such a node when the round budget is exhausted fails with the configured exhausted error. |
onErrorNodeId | string | undefined | Optional | Read-only. Node entered when run/provides/route fails; contract errors always propagate instead. |
onErrorRouteId | string | undefined | Optional | Read-only. Route id reported with the recovery transition. |
requires | readonly (keyof State & string)[] | undefined | Optional | Read-only. State keys that must be present before this node runs; enforced by the engine. |
provides | readonly (keyof State & string)[] | undefined | Optional | Read-only. State keys this node is expected to produce; validated after run. |
routes | readonly WorkflowRoute<State, Result, App>[] | Required | Read-only. Candidate successors, evaluated in order. A getter must be pure; registration reads it once. |
run | ((state: Readonly<State>, context: WorkflowContext<App>) => void | Partial<State> | Promise<void | Partial<State>>) | undefined | Optional | Read-only. Return only changed fields. Core commits them after cancellation and output checks. |
Examples
- Context processing is an ordinary Workflow node: Integrate selection, trimming, and compression through normal nodes and routes; Core records and schedules them uniformly.
Validate and assemble only, without compression yet
Beginner · Node.js
ts
import { AgentCoreEngine, defineWorkflow, route } from '@jangts/agent-core/engine';
import { Support } from '@jangts/agent-core';
import type { BuiltContext, PreparedModelCall } from '@jangts/agent-core/types';
type State = { question: string; input?: BuiltContext; prepared?: PreparedModelCall; answer?: string };
const builder = Support.defineContextFragments<State>([
{ id: 'question', sourceId: 'request', trust: 'user', lifetime: 'turn', role: 'user', maxChars: 1000, format: state => state.question },
], { maxInputChars: 2000 });
const prepare = Support.createContextProcessingNode<State, string>({
id: 'prepare', description: '装配并校验输入', startsRound: true,
plan: state => builder.plan({ input: state }),
update: result => ({ input: result.input, prepared: result.prepared }),
routes: [route.to('reply')],
});
const workflow = defineWorkflow<State, string>({ id: 'chat', nodes: [prepare, {
id: 'reply', description: '使用同次准备回答', requires: ['input', 'prepared'],
async run(state, { model }) { const { value } = await model.invoke({ input: state.input!, prepared: state.prepared! }); return { answer: String(value) }; },
routes: [route.deliver('answer')],
}] });
const agent = new AgentCoreEngine({ workflow, model: { provider: { async *stream() { yield '服务正常'; } } } });
console.log(await agent.run({ question: '状态?' }));js
import { AgentCoreEngine, defineWorkflow, route } from '@jangts/agent-core/engine';
import { Support } from '@jangts/agent-core';
const builder = Support.defineContextFragments([
{ id: 'question', sourceId: 'request', trust: 'user', lifetime: 'turn', role: 'user', maxChars: 1000, format: state => state.question },
], { maxInputChars: 2000 });
const prepare = Support.createContextProcessingNode({
id: 'prepare', description: '装配并校验输入', startsRound: true,
plan: state => builder.plan({ input: state }),
update: result => ({ input: result.input, prepared: result.prepared }),
routes: [route.to('reply')],
});
const workflow = defineWorkflow({ id: 'chat', nodes: [prepare, {
id: 'reply', description: '使用同次准备回答', requires: ['input', 'prepared'],
async run(state, { model }) { const { value } = await model.invoke({ input: state.input, prepared: state.prepared }); return { answer: String(value) }; },
routes: [route.deliver('answer')],
}] });
const agent = new AgentCoreEngine({ workflow, model: { provider: { async *stream() { yield '服务正常'; } } } });
console.log(await agent.run({ question: '状态?' }));Add a history trimming policy to the same node contract
Configuration · Node.js
Put this node back into the same Workflow as the previous example; each run just adds history to State, and the model reply node does not change its interface. In a complete flow the reply target must exist.
ts
import { Support } from '@jangts/agent-core';
import { route } from '@jangts/agent-core/engine';
import type { BuiltContext, PreparedModelCall } from '@jangts/agent-core/types';
type State = { question: string; history: { role: string; content: string }[]; input?: BuiltContext; prepared?: PreparedModelCall };
const builder = Support.defineContextFragments<State>([
{ id: 'question', sourceId: 'request', trust: 'user', lifetime: 'turn', role: 'user', maxChars: 1000, format: state => state.question },
{ id: 'history', sourceId: 'conversation', trust: 'user', lifetime: 'turn', role: 'user', maxChars: 10000, format: state => ({ messages: state.history }) },
], { maxInputChars: 1200 });
const prepare = Support.createContextProcessingNode<State, string>({
id: 'prepare', description: '按需要裁切旧历史', startsRound: true,
plan: state => builder.plan({ input: state }),
policy: { mode: 'reduce', steps: [{ id: 'recent', kind: 'trim', fragmentId: 'history', field: 'messages',
targetChars: 700, grouping: { kind: 'user-turn' }, keepGroups: 1 }] },
update: result => ({ input: result.input, prepared: result.prepared }),
routes: [route.to('reply')],
});
console.log(prepare.id);js
import { Support } from '@jangts/agent-core';
import { route } from '@jangts/agent-core/engine';
const builder = Support.defineContextFragments([
{ id: 'question', sourceId: 'request', trust: 'user', lifetime: 'turn', role: 'user', maxChars: 1000, format: state => state.question },
{ id: 'history', sourceId: 'conversation', trust: 'user', lifetime: 'turn', role: 'user', maxChars: 10000, format: state => ({ messages: state.history }) },
], { maxInputChars: 1200 });
const prepare = Support.createContextProcessingNode({
id: 'prepare', description: '按需要裁切旧历史', startsRound: true,
plan: state => builder.plan({ input: state }),
policy: { mode: 'reduce', steps: [{ id: 'recent', kind: 'trim', fragmentId: 'history', field: 'messages',
targetChars: 700, grouping: { kind: 'user-turn' }, keepGroups: 1 }] },
update: result => ({ input: result.input, prepared: result.prepared }),
routes: [route.to('reply')],
});
console.log(prepare.id);