实验
ACP 线程绑定代理
概述
本计划定义了 OpenClaw 应如何在支持线程的通道(首先是 Discord)中支持 ACP 编码代理,并提供生产级的生命周期管理和恢复能力。相关文档:
目标用户体验:
- 用户在某个线程中生成或聚焦一个 ACP 会话
- 用户在该线程中的消息被路由到绑定的 ACP 会话
- 代理输出流式传输回同一线程身份
- 会话可以是持久性的,也可以是单次性的,并具有显式的清理控制
决策摘要
长期建议采用混合架构:
- OpenClaw 核心负责 ACP 控制平面相关事宜
- 会话身份和元数据
- 线程绑定和路由决策
- 交付不变性和重复抑制
- 生命周期清理和恢复语义
- ACP 运行时后端是可插拔的
- 第一个后端是基于 acpx 的插件服务
- 运行时处理 ACP 传输、队列、取消、重连
OpenClaw 不应在核心中重新实现 ACP 传输内部逻辑。OpenClaw 不应依赖纯插件拦截路径进行路由。
终极架构(理想目标)
将 ACP 视为 OpenClaw 中的一等控制平面,并配备可插拔的运行时适配器。不可协商的不变性:
- 每个 ACP 线程绑定都引用一个有效的 ACP 会话记录
- 每个 ACP 会话都有明确的生命周期状态(
creating、idle、running、cancelling、closed、error) - 每个 ACP 运行都有明确的运行状态(
queued、running、completed、failed、cancelled) - 生成、绑定和初始入队是原子操作
- 命令重试是幂等的(无重复运行或无重复 Discord 输出)
- 绑定线程的通道输出是 ACP 运行事件的投影,绝不是临时的副作用
长期所有权模型:
AcpSessionManager是唯一的 ACP 写入器和编排器- 管理器首先驻留在网关进程中;稍后可以移动到专用 sidecar 后面,但保持相同的接口
- 对于每个 ACP 会话键,管理器拥有一个内存中的参与者(序列化命令执行)
- 适配器(
acpx、未来的后端)仅是传输/运行时实现
长期持久化模型:
- 将 ACP 控制平面状态移动到 OpenClaw 状态目录下的专用 SQLite 存储(WAL 模式)
- 在迁移期间,将
SessionEntry.acp作为兼容性投影保留,而非真相源 - 以仅追加方式存储 ACP 事件,以支持重放、崩溃恢复和确定性交付
交付策略(通往理想目标的桥梁)
- 短期桥梁
- 保留当前的线程绑定机制和现有的 ACP 配置表面
- 修复元数据间隙错误,并通过单一核心 ACP 分支路由 ACP 轮次
- 立即添加幂等键和故障关闭路由检查
- 长期切换
- 将 ACP 真相源移至控制平面数据库 + 参与者
- 使绑定线程的交付完全基于事件投影
- 移除依赖于机会性会话条目元数据的遗留回退行为
为何不采用纯插件方案
当前的插件钩子不足以在不修改核心的情况下实现端到端的 ACP 会话路由。
- 来自线程绑定的入站路由首先在核心分发中解析为会话键
- 消息钩子是即发即弃的,无法短路主回复路径
- 插件命令适用于控制操作,但不适用于替换核心的每轮次分发流程
结果:
- ACP 运行时可以被插件化
- ACP 路由分支必须存在于核心中