ACP 适配架构决策记录¶
状态:持续维护。
实时实施状态见 progress.md。
ADR-001:使用官方 Python SDK¶
- 状态:Accepted
- 决策:依赖
agent-client-protocol,通过acp.run_agent提供 stdio 服务。 - 不采用:
deepagents-acp、自研 JSON-RPC/schema。 - 原因:协议 schema 和 transport 应由官方 SDK 维护;Synapse 只负责自身 runtime 的语义适配。
- 约束:SDK 必须精确锁版本,升级先做 schema/API diff。
ADR-002:目标是完整 ACP v1 Agent 语义¶
- 状态:Accepted
- 决策:P0 从锁定 schema 建立完整矩阵,P8 逐项关闭。
- 原因:允许阶段性交付,但不能把“最小可互通”误当最终范围。
- 约束:稳定方法、capability、ContentBlock、SessionUpdate 和错误语义都必须进入矩阵。
ADR-003:ACP 是 runtime 的外部适配器¶
- 状态:Accepted
- 决策:
synapse.acp依赖synapse.runtime,runtime 不依赖 ACP SDK。 - 原因:TUI、CLI、Web 和 ACP 应共享同一 headless runtime,不形成多套 Agent loop。
- 约束:ACP handler 不直接调用 Agent 原始
astream()。
ADR-004:独立 stdio 入口¶
- 状态:Accepted
- 决策:新增
synapse-acpconsole script,不复用现有交互式 CLI 启动路径。 - 原因:ACP stdout 必须只包含有效 JSON-RPC 消息。
- 约束:日志、trace 和诊断只能写 stderr 或文件。
ADR-005:capability 单一真源¶
- 状态:Accepted
- 决策:由
CapabilityRegistry同时驱动 initialize 声明、handler guard 和测试参数化。 - 原因:避免声明支持但没有实现,或实现存在但永远不声明。
- 约束:capability 只能在对应阶段门禁通过后启用。
ADR-006:一个 ACP session 对应一个隔离的 SessionRuntime¶
- 状态:Accepted
- 决策:session descriptor 固定 cwd、additional directories、MCP、Client capability 和 config。
- 原因:会话是执行、取消、权限和资源隔离域。
- 约束:同 session prompt 排他,不同 session 在全局上限内并发。
ADR-007:Permission 在同一 ACP prompt 内闭环¶
- 状态:Accepted
- 决策:一个 ACP prompt 可以驱动普通 turn 和多个 LangGraph resume turn。
- 原因:Synapse 当前 HITL 以 turn 为边界,而 ACP permission 属于一个未结束的 prompt 生命周期。
- 约束:cancel 必须同时结束活跃 turn 和 pending permission requests。
ADR-008:语义事件优先增强 runtime¶
- 状态:Accepted
- 决策:缺失的 tool args、diff、plan、usage 等先加入 UI-independent
TurnEvent,再投影 ACP。 - 原因:禁止 ACP 层重复解析 provider/LangGraph 原始 chunk;TUI 也可复用增强语义。
- 约束:事件版本变化必须保持兼容或显式升级。
ADR-009:线程边界使用有界事件桥¶
- 状态:Accepted
- 决策:broker callback 通过
loop.call_soon_threadsafe投递到 ACP loop 的有界队列。 - 原因:Agent runtime 和 ACP server 可能运行在不同 asyncio loop/线程。
- 约束:终态和工具事件不得丢;文本可合并但不得乱序。
ADR-010:Client-provided MCP 按 session 隔离¶
- 状态:Accepted
- 决策:ACP 请求携带的 MCP servers 使用 session scope pool,关闭 session 即释放。
- 原因:Client MCP 是会话资源,不是 Synapse 全局配置。
- 约束:不得持久化 Client MCP 凭据,不得泄漏到其他 session。
ADR-011:Client 服务有能力时优先、无能力时回退¶
- 状态:Proposed,P6 确认
- 决策:filesystem/terminal capability 存在时优先 Client-backed backend,否则使用本地 backend。
- 原因:Client 能提供未保存 editor buffer 和 IDE terminal;本地 backend 保持无 Client 能力时可用。
- 待确认:同一 Agent graph 内 backend 动态路由的具体接口。
ADR-012:协议版本基线由 P0 决定¶
- 状态:Accepted
- 决策:总体方案只固定 ACP v1 stable,不在调查阶段猜测具体 SDK/schema patch 版本。
- 原因:官方 SDK 变化较快,必须以实际可安装包、源码和生成 schema 为证据。
- 约束:P0 完成前不得提交依赖或实现代码。
ADR-013:P1 先使用可注入 SessionFactory¶
- 状态:Accepted
- 决策:
SynapseACPAgent通过ACPSessionRegistry和可注入SessionFactory连接现有RuntimeManager,默认 factory 只在实际session/new时构建 Agent。 - 原因:P1 协议测试不能依赖真实模型、API 凭据或 MCP;同时为 P4/P5 的 session descriptor 和资源隔离保留边界。
- 约束:生产默认路径复用
build_coding_agent,测试路径必须注入 fake factory;不得在 ACP handler 中直接调用astream()。
ADR-014:P1 不静默接受未实现的 MCP¶
- 状态:Accepted
- 决策:P1 handler 收到非空
mcp_servers时返回明确的 invalid params;P5 实现 session-scoped MCP 后再启用。 - 原因:P1 尚未连接 Client-provided MCP,静默忽略会违反 capability/行为一致性。
- 约束:P1 可以接受空列表或省略字段;不得把配置写入全局 MCP 配置。
ADR-015:notification 处理、batch 不适用¶
- 状态:Accepted
- 决策:notification(无
id)由官方 SDK router/dispatcher 处理,未知 notification 静默忽略、不产生响应;JSON-RPC batch 数组不纳入 ACP 适配范围。 - 原因:ACP wire 使用 newline-delimited JSON(每行一个 message),batch 数组不是该 framing 的合法输入;官方 SDK 亦按单条 message 处理。
- 约束:
session/cancel等 notification 必须保持幂等且不依赖响应;适配层不自行解析 batch,也不伪造 batch 支持声明。
决策更新规则¶
- 新决策追加 ADR,不覆盖历史结论。
- 被替代决策标记 Superseded,并链接替代 ADR。
- SDK/schema 升级、能力范围变化、状态机变化必须记录 ADR。
- 实时任务状态不写在本文件,统一维护于
progress.md。