1. 先记住状态机,不要先读函数
turn/start
↓ claim next input
agent/pre-step
↓
step/start
↓ derive messages + assemble prompt/tools
agent/request → llm/stream
↓
assistant chunks/message
↓ tool calls?
tools/pre-execute → execute → post-execute
↓ tool/result
step/end
↓ more work? ── yes ──↺ next step
agent/turn-stopping
↓
turn/end
2. Turn vs Step
Turn 可以包含 0~N 个 step。比如用户说“读 README 并总结”:step 1 模型先调用 read;工具结果回来后 step 2 模型给总结。两次 LLM 请求属于同一个 turn。
3. Inbox 是什么
运行中的 agent 可能同时接收新用户消息、steering、工具产生的 follow-up。Loop 不应该直接把所有输入马上塞进模型,而是先进入 inbox,再在合适边界 claim。这样才能支持取消、编辑、插入和持久化事件。
4. 为什么 agent/pre-step 可以拒绝
它是策略扩展点:权限、目标管理、上下文压缩、外部 steering 都可能在真正发模型请求前修改或拒绝本次输入。即便首个 claim 被拒绝,turn 仍应有闭合事件,保证日志结构完整。
5. 并行工具调用
Loop 会对标记可并行的调用维持有限池;需要独占的调用必须串行。关键不是 Promise.all,而是调度语义必须由工具定义/策略声明,而不是让模型自己猜。