复盘、分支和资料发布
Core提供模型调用、执行、分支身份与取消合同。Kit在 App 提供的授权和存储端口上处理复盘、数据版本和持久任务。
这些 Kit 的 authorize、Family.validate 和 verifySources 都是断言式回调:成功返回 void,拒绝时抛错;同步或异步返回 false、true、null 等其他值均视为合同错误,不继续执行或保存。
Family 与资料发布在进入异步授权或读取前固定请求身份、目标和可序列化数据,后续修改原请求不改变本次操作。Family 的读取校验和授权取得隔离的数据,不能借检查回调改写存储原件或待提交记录。来源引用不得有缺失项,提交前仍检查有效期。
有界子任务组合
普通任务调用同一 createChild 入口。组合多个独立任务时,Support.runChildren 按根 runner 的容量启动子 runner,隔离 journal、signal 和输出;任务仍使用自己的普通 handler 或 Workflow。
import { ModelRunner, Support } from '@jangts/agent-core';
export async function analyze(provider, inputs, signal) {
const model = new ModelRunner({ provider, maxCalls: 8, execution: { signal },
children: { maxDepth: 2, maxConcurrentCalls: 2, maxChildren: 8 } });
return Support.runChildren(model, inputs.map((text, index) => ({
id: `part-${index}`, maxCalls: 2, reserveCalls: 1, timeoutMs: 30000,
transports: [],
async run(child) { return (await child.invoke(text)).value; },
})), {
concurrency: 2,
accept(value) { if (typeof value !== 'string' || !value.trim()) throw Error('Empty analysis'); },
});
}accept 与 commit 成功时均返回 void;拒绝通过抛错表达,不以布尔返回值表示。子任务的传输清单在启动该组时固定。accept 检查每项结果,等待期间仍受该子任务的取消和期限约束;全部接受后,才按声明顺序调用可选 commit(value, id)。任一任务或接受检查失败会取消同组任务,迟到结果不能进入提交。commit 是 App 的真实副作用端口,已发生的提交不能因取消假装回滚;需要全组原子性时,由 App 在真实事务中提交整个返回数组。角色和工具清单显式登记,不能靠子执行自动继承权限。
accept 同样遵守断言合同:成功返回 void,其他返回值均拒绝,不能把 false 当成一次成功检查。
元数据复盘
import { defineReflection } from '@jangts/agent-core/kits/reflection';
import type { ReflectionSource } from '@jangts/agent-core/kits/reflection';
import type { ModelRunner, OperationContext } from '@jangts/agent-core';
export function review<App>(model: ModelRunner, source: ReflectionSource<App>,
authorize: (question: string, context: OperationContext<App>) => Promise<void>) {
return defineReflection({ model, source, authorize,
maxCalls: 4, reserveCalls: 1, maxPages: 4, maxEvents: 64, maxEvidenceChars: 12000 });
}run(question, context) 通过已注册的 history.query 工具取得证据,模型可选择发现运行、读取事件或提交报告。Source 对每次查询校验真实账号及范围;输出固定元数据字段,不传日志正文。报告区分 observed、hypothesis、recommendation;observed 必须引用本次实际返回的证据 ID。读取不完整、过期、预算不足或协议失败均保留真实限制,报告默认 persisted: false。
defineReflectionLogSource({ reader, id, traceId, authorize }) 可适配 App 自有的结构化日志 reader:固定 trace 范围,只读取本次已发现的 run,并只投影 Core 元数据。实际时间、span/父 span、调用与分支身份通过固定清单保留,供报告引用真实关系。覆盖信息仅保留 consistency、complete 和 gaps,不转发来源附带的其他字段。App 拥有目录、账号校验、reader 的关闭和日志保留期。额外工具必须为 read,在构造时固定清单及规范方法,仍走普通工具输入、授权与输出合同。
日志按事件声明读取元数据:model.end 使用 payload.state,workflow.event 使用 payload.event,loop.event 使用自身载荷。工作流及循环的实际生命周期转换为 running/success/error/cancelled;错误码与耗时沿相同投影保留,不向模型发送原始错误正文。
读取许可、交给模型处理和披露结果是独立决定。日志缺失不能证明未执行,动态报告的子步骤不能证明真实内部调度。源数据在返回前到期时拒绝交付。
报告的 createdAtMs、证据与报告的 expiresAtMs 均为绝对毫秒时间,与事件的 occurredAtMs 使用同一单位。
持久分支与显式启用
import { defineAgentFamily } from '@jangts/agent-core/kits/family';
import type { FamilyStore } from '@jangts/agent-core/kits/family';
import type { OperationContext } from '@jangts/agent-core';
type State = { goal: string; sourceRevision: string };
export function family<App>(store: FamilyStore<State>,
authorize: (context: OperationContext<App>) => Promise<void>,
verify: (state: State) => Promise<void>) {
return defineAgentFamily<State, App>({
store, maxVersions: 16, retentionMs: 7 * 86400000,
isState: (value): value is State => !!value && typeof (value as State).goal === 'string'
&& typeof (value as State).sourceRevision === 'string',
authorize: (_operation, _record, context) => authorize(context),
validate: candidate => verify(candidate.state),
async merge({ base, target, source }) {
if (target.goal !== base.goal && source.goal !== base.goal && target.goal !== source.goal)
return { conflicts: ['goal'] };
return { value: target.goal === base.goal ? source : target, conflicts: [] };
},
});
}create 建立初始版本;fork 接收真实父分支身份和克隆状态;merge 需要共同 base,并由 App 的三方合并器报告冲突。新版本先作为候选保存。promote({ id, revision, candidateId, expectedActiveId }, context) 再次检查当前来源与批准责任,显式切换 activeId。只允许以当前 active 为 base 的候选启用。
FamilyStore.compareAndSwap 必须把完整版本集合和 activeId 在真实存储中原子提交;返回 true 才是成功回执。读取权限由绑定的 store 执行,变更另走 authorize。分支数据不恢复身份、预算授权、工具实例或正在运行的函数;App 在使用选定版本时重绑当前依赖。Engine 已绑定请求级模型或工具运行实例时,fork 的 resume 必须提供对应实例;缺少时在派生阶段拒绝。Engine 的 exportCheckpoint/restoreCheckpoint 处理可序列化检查点,Family 管理 App 的版本集合。
版本使用 createdAtMs,集合使用 expiresAtMs,均为绝对毫秒时间。App 自有数据库字段可在 store 边界映射到这些合同字段。
持久专业任务
import { defineDurableTask } from '@jangts/agent-core/kits/durable';
export function professionalTask(store, isState, authorize, analyze) {
return defineDurableTask({ id: 'app.review', revision: '1', isState, authorize,
steps: [{ id: 'analyze', replayPolicy: 'safe',
async run(state, context) {
// analyze binds its real model runner to context.maxModelCalls.
return analyze(state, context);
},
}],
}, { store });
}App 创建 version=2 检查点,设置 definitionId/revision、state、nextStepIndex=0、attemptCount=0、maxAttempts、固定 deadlineAtMs、status=ready。需要累计模型限制时同时保存 modelBudget。任务仅在 App 显式调用 run({ taskId }, context) 时执行。
恢复先取得排他锁并重新授权,检查来源版本和执行期限,再保存尝试次数与模型预留。App 将每次预留绑定到真实 runner;读取、复核及其子调用都在这个预算内。失败不退回预留,完成步骤不重跑。可能已经提交副作用的步骤使用 reconcile,并提供真实回执查询,不能凭聊天文本猜测提交状态。
读取检查点后,授权也受固定 deadlineAtMs 约束。取消或过期可以停止等待授权及工作 handler;已经开始的 checkpoint 保存仍须等待确认,再释放 store 排他锁。
候选资料与发布
import { Knowledge } from '@jangts/agent-core/kits/knowledge';
export function publication(store, authorize, verifySources) {
return Knowledge.defineKnowledgePublication({ store, authorize, verifySources,
maxCandidates: 32, candidateRetentionMs: 7 * 86400000,
requiredReads: [{ documentId: 'guide', selection: { mode: 'document' } }],
maxReadChars: 12000,
});
}propose({ revision, document, sources }, context) 使用同一 Knowledge 编译器检查完整替换后的文档集合及 requiredReads,只写候选。publish({ revision, candidateId }, context) 重新授权并核对来源版本、有效期与 publishedRevision,再用 CAS 一次替换正式集合并移除候选。reject 显式删除候选。修改正文或元信息必须给文档新 revision。
候选期限和来源期限在异步核验、文档编译及提交快照准备后再次检查,检查通过才启动 CAS;已经开始的存储提交继续等待真实回执,不因途中到期伪称回滚。
Store 的 revision 协调全部写入,publishedRevision 专门识别正式集合变化;候选基于过期的正式版本时需重新准备。普通知识读取从 record.documents 构造 catalog,不把 candidates 混成事实。人工资料、累计偏好和经验候选各有自己的来源、权限及生命周期;发布行为由 App 明确授权,不由模型自行取得权限。
同一实例缓存最近一次记录的编译校验结果,键包含 revision、publishedRevision 和完整文档内容;相同版本号下的内容变化仍会重检。缓存不替代 store 读取、操作授权、来源验证或有效期检查。
候选的 createdAtMs/expiresAtMs 和来源可选的 expiresAtMs 使用绝对毫秒时间;candidateRetentionMs 是时长。来源到期时不能借候选保留期延长其有效性。