压缩器与选择器:推荐实现和自定义算法
将提示词、输出解析和算法绑定为 handler;模型 I/O 通过同一请求的 callModel。
createContextCompressor 需要业务 instruction、已登记 transport ID、输出预留与结果 parse;Core 不决定怎样概括业务资料。createContextSelector 有内置选择指令和 {stepIds} 默认输出协议,默认 maxExcerptChars=0,只传候选元数据;自定义 parser 必须同时提供相应 instruction。
handler 也可以直接由 App 对象或类实现,声明 maxCalls=0 表示纯本地处理。模型 handler 应使用调用参数的 callModel,而不是新建 Runner 绕过祖先预算、取消和日志。算法可替换,但保护范围、输出结构和最终预算不因自定义实现而取消。
创建 handler 只形成配置,不会自动登记传输或进入 Workflow;节点的 compressors/selectors 显式接入,policy 中用 handlerId 引用。
由简到繁的同业务示例
绑定一个文本压缩 handler
入门 · Node.js
ts
import { Support } from '@jangts/agent-core';
const compressor = Support.createContextCompressor({
id: 'history-summary', instruction: '保留事实、时间和未完成事项,精简重复表达。',
transport: 'core:plain-text', maxOutputTokens: 500,
parse(value: unknown) { if (typeof value !== 'string' || !value.trim()) throw new TypeError('需要非空摘要'); return value; },
});
console.log(compressor.id);js
import { Support } from '@jangts/agent-core';
const compressor = Support.createContextCompressor({
id: 'history-summary', instruction: '保留事实、时间和未完成事项,精简重复表达。',
transport: 'core:plain-text', maxOutputTokens: 500,
parse(value) { if (typeof value !== 'string' || !value.trim())
throw new TypeError('需要非空摘要'); return value; },
});
console.log(compressor.id);选择器明确控制可见摘录范围
配置 · Node.js
selector-json 必须由 App 注册,返回 value={stepIds:string[]};不能把普通文本传输当成已解析 JSON。此例只展示 handler 装配,不发请求。
ts
import { Support } from '@jangts/agent-core';
const selector = Support.createContextSelector({ id: 'select-reduction',
transport: 'selector-json', maxOutputTokens: 200, maxExcerptChars: 1000,
});
console.log(selector.id);js
import { Support } from '@jangts/agent-core';
const selector = Support.createContextSelector({ id: 'select-reduction',
transport: 'selector-json', maxOutputTokens: 200, maxExcerptChars: 1000,
});
console.log(selector.id);用本地类实现同一选择合同
扩展 · Node.js
这段策略不调用模型。它只建议已登记候选,仍由节点执行与检查。
ts
import type { ContextSelector, ContextSelectionCall } from '@jangts/agent-core/support/context';
class TrimFirst implements ContextSelector {
readonly id = 'trim-first';
readonly maxCalls = 0;
async select(call: ContextSelectionCall) {
const candidate = call.candidates.find(item => item.kind === 'trim');
return candidate ? [candidate.id] : [];
}
}
const selector = new TrimFirst();
console.log(selector.id, selector.maxCalls);js
class TrimFirst {
id = 'trim-first';
maxCalls = 0;
async select(call) {
const candidate = call.candidates.find(item => item.kind === 'trim');
return candidate ? [candidate.id] : [];
}
}
const selector = new TrimFirst();
console.log(selector.id, selector.maxCalls);
export {};