代理循环
每次运行——一次性的 query() 或 LiteAgent 上的一次 send()——都由同一个内核轮次循环驱动:编码对话、流式调用模型、执行请求的工具、把结果回灌、重复。理解这个循环,SDK 里的其他一切就都有了答案:权限、沙箱、压缩都不是写死在 agent 里的特例——它们是插进这五个步骤的策略与中间件。
循环本身不需要配置;你通过事件观察它,通过替换策略或添加中间件来定制它。
一轮如何工作
每一轮,内核(@lite-agent/core)执行同样的五个步骤:
- 编码(Encode) —— 对话历史加工具规格由
ToolCallCodec编码成 provider 形状的请求。 - 流式(Stream) ——
ModelProvider流式返回数据块;文本以text_delta事件实时透出。 - 解码(Decode) —— codec 把完成的 assistant 消息解码为文本和结构化的
ToolCall({ id, name, input })。弱模型的畸形输出会触发 codec 修复重试。 - 工具中间件链 —— 每个工具调用在产出结果前都要穿过
wrapToolCall洋葱(权限、日志、你自己的层)。 - 结果回灌 —— 工具结果追加进对话,循环进入下一轮,直到模型停止或达到
maxTurns。
内核本身不懂权限、沙箱、压缩 —— 它们都是插进这个循环的策略与中间件。
SDK 在哪里插入
权限就是一个中间件。 闸门位于 wrapToolCall 洋葱之中:deny 直接短路调用,ask 把调用挂起在你的 onApproval 处理器上。门控没有任何硬编码进内核的部分;你可以像对待其他任何层一样重排、替换或包裹它。
Tip
换部件,而不是改内核。 本地小模型 → jsonCodec() 或 reactCodec();托管权限 → composePolicies(...);持久会话 → @lite-agent/checkpoint-sqlite 的 Checkpointer。只有当内置实现和兄弟包都覆盖不了某个角色时,才自己去实现接口。