一个引擎,一个门面
上一章的 agentLoop() 是底层引擎:给它 context、config、一个 stream 函数,它就吐事件、转圈圈,纯粹、无状态、不关心你是谁。但真实产品里还需要有人管「这是哪个会话、历史存哪、用户中途插话怎么办、权限谁来批」——这就是AgentSession,业务门面。
┌───────────────────────────────────────────────┐ │ AgentSession (packages/coding-agent) │ │ • 持有会话状态 / 历史 / cwd 服务 │ │ • submitMessage() 入队、起一轮 turn │ │ • 提供 hooks:beforeToolCall / shouldStop … │ │ • 把 AgentEvent 转译给 UI │ │ │ 调用 │ │ ▼ │ │ agentLoop() (packages/agent) ← 无状态引擎 │ │ • 思考 → 行动 → 观察 → 重复 │ └───────────────────────────────────────────────┘
为什么要分两层?
- 可测试:引擎纯函数式,喂假 stream 就能测循环逻辑,不碰文件系统。
- 可复用:同一个引擎,CLI、Web、SDK 三种门面都能接。
- 可治理:权限、压缩、停止策略都通过 config 上的 hook 注入,引擎本身保持干净。
记忆口诀:agentLoop 负责「怎么转」,AgentSession 负责「为谁转、转的过程谁说了算」。