Projection
KIT · constant · Runtime value
Import
import { Projection } from '@jangts/agent-core/kits/projection';import { Projection } from '@jangts/agent-core/kits/projection';Other public entry points:@jangts/agent-core/types, @jangts/agent-core/kits/projection, @jangts/agent-core/kits.
Definition
Member index
| Member | Purpose |
|---|---|
defineContentProjection | See the overload below for full inputs and outputs. |
projectContinuousExcerpt | See the overload below for full inputs and outputs. |
defineTreeProjection | See the overload below for full inputs and outputs. |
Member details
defineContentProjection
Projection.defineContentProjection(options: ContentProjectionOptions): Readonly<{ project: ({ value, maxChars: limit, }: { value: unknown; maxChars: number; }) => ContentProjection; }>Compile a JSON-preserving projector.
Keep valid JSON while reducing prose before dropping records; budgets are caller policy. The candidate list is tried in order (outer counts, inner lengths), so callers control whether trimming text or dropping items is preferred, and the configured fallback is used only when no candidate fits.
| Parameter | Type | Passing | Description |
|---|---|---|---|
options | ContentProjectionOptions | Required | — |
Fields of options
| Field | Type | Required | Description |
|---|---|---|---|
counts | readonly number[] | Required | Read-only. Maximum array items to keep, tried in order before moving to the next length. |
lengths | readonly number[] | Required | Read-only. Maximum characters per string, tried in order inside each count candidate. |
render | (excerpt: unknown) => string | Required | Read-only. Renders a shortened value; must be synchronous. |
fallback | (limit: number) => string | Required | Read-only. Builds fallback text for a limit, used when no candidate fits; must be synchronous. |
Returns: Readonly<{ project: ({ value, maxChars: limit, }: { value: unknown; maxChars: number; }) => ContentProjection; }>.
Return value structure
| Field | Type | Required | Description |
|---|---|---|---|
project | ({ value, maxChars: limit, }: { value: unknown; maxChars: number; }) => ContentProjection | Required | See the type definition and usage context. |
projectContinuousExcerpt
Projection.projectContinuousExcerpt(body: string, limit: number, render: (length: number) => string): ContentProjection | undefinedProject a continuous excerpt of a body by binary-searching the longest prefix that fits.
Binary-search a continuous prefix and keep an existing surrogate pair intact. render receives the prefix length, not the text, so the caller decides how the excerpt is framed.
| Parameter | Type | Passing | Description |
|---|---|---|---|
body | string | Required | — |
limit | number | Required | — |
render | (length: number) => string | Required | — |
Returns: ContentProjection \| undefined.
Optional shapes of Return value: choose one shape; required fields for each branch are listed separately.
Branch 1
undefined
Branch 2
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Required | Read-only. Rendered text that fits the requested budget. |
truncated | boolean | Required | Read-only. True when anything was shortened or replaced by the fallback. |
defineTreeProjection
Projection.defineTreeProjection<Context>(options: TreeProjectionOptions<Context>): Readonly<{ visit: (value: unknown, context: Context) => unknown; }>Compile a depth-limited tree transform.
Traverse synchronously in property/array order; only undefined omits a result. Because a visitor returns a new value instead of mutating, an omitted branch disappears from arrays and objects the same way, and maxDepth bounds both cycles and cost.
| Type parameter | Constraint | Default type |
|---|---|---|
Context | — | — |
| Parameter | Type | Passing | Description |
|---|---|---|---|
options | TreeProjectionOptions<Context> | Required | — |
Fields of options
| Field | Type | Required | Description |
|---|---|---|---|
maxDepth | number | Required | Read-only. Maximum included depth; deeper values are omitted. Must be a non-negative integer. |
omit | ((value: unknown, depth: number, context: Context) => boolean) | undefined | Optional | Read-only. Drops a value when it returns true; must be synchronous boolean. |
visitRecord | ((value: Record<string, unknown>, depth: number, context: Context) => void) | undefined | Optional | Read-only. Observes every retained record, for example to record which fields were kept. |
Returns: Readonly<{ visit: (value: unknown, context: Context) => unknown; }>.
Return value structure
| Field | Type | Required | Description |
|---|---|---|---|
visit | (value: unknown, context: Context) => unknown | Required | See the type definition and usage context. |
Examples
- Projection: project content under a budget: Shorten text first, then reduce entries; source data, projection result, and budget are explicitly separated by the App.
Prepare compact JSON for the same query result
Beginner · Node.js
import { Projection } from '@jangts/agent-core/kits/projection';
const projection = Projection.defineContentProjection({
counts: [10, 3, 1], lengths: [200, 80, 20],
render: value => JSON.stringify(value), fallback: () => '{}',
});
const result = projection.project({ value: { items: [{ title: '配置说明', body: '正文'.repeat(100) }] }, maxChars: 120 });
console.log(result.text, result.truncated);import { Projection } from '@jangts/agent-core/kits/projection';
const projection = Projection.defineContentProjection({
counts: [10, 3, 1], lengths: [200, 80, 20],
render: value => JSON.stringify(value), fallback: () => '{}',
});
const result = projection.project({ value: { items: [{ title: '配置说明', body: '正文'.repeat(100) }] }, maxChars: 120 });
console.log(result.text, result.truncated);Remove private fields from the same data, then project under budget
Configuration · Node.js
import { Projection } from '@jangts/agent-core/kits/projection';
const tree = Projection.defineTreeProjection({
maxDepth: 4,
visitRecord(record) { delete record.privateNote; },
});
const source = { items: [{ title: '配置说明', body: '正文'.repeat(100), privateNote: '不向模型提供' }] };
// 调用者明确选择副本所有权;visitor 不会碰原记录。
const publicData = tree.visit(structuredClone(source), undefined);
const compact = Projection.defineContentProjection({ counts: [10, 3, 1], lengths: [200, 80, 20], render: JSON.stringify, fallback: () => '{}' });
console.log(compact.project({ value: publicData, maxChars: 120 }));import { Projection } from '@jangts/agent-core/kits/projection';
const tree = Projection.defineTreeProjection({
maxDepth: 4,
visitRecord(record) { delete record.privateNote; },
});
const source = { items: [{ title: '配置说明', body: '正文'.repeat(100), privateNote: '不向模型提供' }] };
// 调用者明确选择副本所有权;visitor 不会碰原记录。
const publicData = tree.visit(structuredClone(source), undefined);
const compact = Projection.defineContentProjection({ counts: [10, 3, 1], lengths: [200, 80, 20], render: JSON.stringify, fallback: () => '{}' });
console.log(compact.project({ value: publicData, maxChars: 120 }));Keep continuous body text instead of splitting paragraphs
Extension · Node.js
The output length of render must grow monotonically with the prefix length for the binary search to be meaningful.
import { Projection } from '@jangts/agent-core/kits/projection';
const body = '一段连续的资料正文。'.repeat(100);
const excerpt = Projection.projectContinuousExcerpt(body, 120, length => JSON.stringify({ excerpt: body.slice(0, length) }));
if (excerpt) console.log(JSON.parse(excerpt.text));import { Projection } from '@jangts/agent-core/kits/projection';
const body = '一段连续的资料正文。'.repeat(100);
const excerpt = Projection.projectContinuousExcerpt(body, 120, length => JSON.stringify({ excerpt: body.slice(0, length) }));
if (excerpt)
console.log(JSON.parse(excerpt.text));