内核
内核是 @lite-agent/core 的心脏——轮次循环:编码 → 调模型 → 解码 → 执行 → 回灌,循环往复直到模型停止。理解它的回报无处不在:它精确告诉你策略插在哪一步、中间件包在哪一层、事件在何时发出。内核本身不懂权限和压缩——它们都是中间件。循环本体只剩「编码 → 调模型 → 解码 → 执行 → 回灌」。
用法
createAgent(config) 把配置装配成 KernelConfig,返回一个带两个入口的 Agent:
run(input, opts?)—— 异步生成器,产出每一个AgentEvent,并最终返回RunResult。send(input, opts?)—— 排空同一个生成器,只 resolveRunResult。
两者都通过 RunOptions 接受 { signal, sessionId, steer }。
一次运行,逐步解析
- 加载会话。 配置了
checkpointer时,回放事件日志并用foldEvents重建消息列表;crashRecovery: "safe"时,已开始但未完成的工具会补一条合成的错误tool_result。 - 运行
beforeAgent钩子(每次运行一次),随后排空事件队列。 - 开启一轮 —— 产出
turn_start,应用待处理的 steer 和后台任务完成通知,然后运行beforeModel钩子(compaction 中间件就挂在这里)。 - 调用模型。 请求由
ToolCallCodec编码,流经wrapModelCall中间件链,文本以text_delta事件透出。在产出任何 chunk 之前发生上下文溢出错误时,若 ContextEngine 处于激活状态,会触发一次紧急 compaction 并重试。 - 解码响应。 codec 把 assistant 消息归一化为文本 +
ToolCall[]。prompt codec 输出格式错误会抛CodecError;内核追加 codec 的repairPrompt并重试(默认 2 次,由maxDecodeRetries控制)。 - 停止或执行工具。 没有工具调用 →
turn_end(stop)并退出循环(除非 steer/后台任务让它复活)。否则先按输入顺序产出全部tool_use事件,然后每个调用走wrapToolCall链——schema 校验、执行、转成ToolResult。最多maxParallelTools(默认 10)个并发执行;工具阶段事件按完成顺序实时流出,而面向模型的消息仍按输入顺序组装。 - 回灌结果:把所有结果块组装成一条 user 消息,产出
turn_end(tool_use),继续循环——直到stop、aborted或达到maxTurns。 - 收尾。 运行
afterAgent钩子,产出携带RunResult(messages、text、usage、stopReason)的done事件。
Tip
abort 只在轮次边界被观察:通过 run(input, { signal }) 传入 AbortSignal,生成器会以 done(reason: "aborted") 收尾。
drain 语义
消费或发送事件时有两条关键性质:
- 事件是观察性的,不是控制流。 中间件和工具调用
ctx.emit(ev);内核把这些事件缓冲进队列,在循环边界(钩子之后、模型调用之后、下一轮之前)统一 drain。emit 永远不会暂停循环,消费端再慢也不会阻塞内核。 - 交互 handler 自行阻塞自己的 I/O。 当有
ApprovalHandler或InputHandler参与时,内核先发出approval_request/input_request事件,然后await handler.request(...)。循环确实停在这个 Promise 上——你的 CLI 读 stdin、web handler 等按钮点击——resolve 之后循环恢复。事件流和中断发生在同一进程内,提问过程中没有任何东西被持久化。
工具执行阶段,队列会被替换为实时 channel,使并发工具(以及转发的子代理事件)按完成顺序实时透出。