Skip to content

ACP 协议

源码版本v2026.7.20

职责

ACP(Agent Client Protocol)是编辑器/IDE 与 agent 通信的标准协议。acp_adapter/ 把 Hermes 暴露为 ACP server,让支持 ACP 的客户端(Zed、VS Code 扩展等)能直接驱动 Hermes:管理会话、读写资源(文件/图片)、审批编辑、追溯来源(provenance)、按权限隔离工具。这让 Hermes 不止于消息平台,也能嵌入开发工作流。

设计动机

Hermes 原本为消息平台设计——网关层接 Telegram/Discord 这类长会话。但 IDE 是另一回事:工作目录是编辑器开的,cwd 要跟着编辑器走;改文件不能 agent 说改就改,得弹到用户面前过一遍;会话之间还要能追溯「这条压缩自哪条」。ACP 这层就是把这些 IDE 特有约束翻译成 Hermes 已有的原语。代码里没有重写一套 agent 循环,而是把 ACP 消息流接到 run_conversation,把 ACP 资源转成 OpenAI content parts,把工具调用里的写文件操作改造成 EditProposal 走人审。核心是「适配,不是重写」。

关键文件

数据流

  1. 客户端按 acp_registry/agent.json 发现并启动 Hermes ACP server(acp_adapter/__main__.py)。
  2. 发起会话 → SessionManager:175 创建 SessionState,对齐 cwd(acp_adapter/session.py:29)、展开 toolsets(acp_adapter/session.py:129)。
  3. 发消息/资源 → 资源转换:201 把 ACP resource(文件/图片,受 acp_adapter/server.py:96 大小限制)转成 OpenAI content parts,喂给 run_conversation:588
  4. agent 改文件时,工具调用经 build_edit_proposal:178EditProposal,经审批请求器(acp_adapter/edit_approval.py:51)弹给用户确认。
  5. 工具执行受 acp_adapter/permissions.py 权限管控,每步经 acp_adapter/provenance.py:22 记 provenance,流式事件(acp_adapter/events.py)回传客户端。

acp_registry/agent.json 是客户端第一次见 Hermes 时的名片:版本、分布方式(uvx)、启动命令。这层契约必须和实际二进制对齐,否则客户端装错版本就跑不起来。

cwd 翻译是 ACP 场景最容易踩坑的地方:Windows 客户端把 Hermes 跑在 WSL 里,工作区却是 E:\Projects\\wsl.localhost\... UNC 路径。_translate_acp_cwd 把它统一翻成 POSIX,否则 agent 里所有 Path 操作对不齐。

编辑提案是 frozen dataclass,关键在 old_text——_proposal_for_write_file 先读已存在的文件内容,这样 diff 展示能看到「之前/之后」,而不是盲改:

python
@dataclass(frozen=True)
class EditProposal:
    tool_name: str
    path: str
    old_text: str | None
    new_text: str
    arguments: dict[str, Any]

审批请求器走 ContextVar 绑定,不是全局变量,多个并发 ACP 会话各自有自己的 requester,不会串扰。.env / id_rsa 默认走 ask 而非 workspace_session,避免被「整个工作区都信任」的策略误放行。

provenance 是 IDE 场景特有:消息平台里会话是线性线,IDE 里会话会被压缩、分叉、resume。build_session_provenance 沿 parent_session_id 往上走,数 end_reason == 'compression' 的层数,标出 sessionKindcompressionDepth,把内部 Hermes session id 和对外 ACP session id 一起放在 _meta.hermes.sessionProvenance

边界与失败

  • 握手版本不匹配:agent.json 钉死 hermes-agent[acp]==0.19.0。Hermes 升到 0.20 后客户端缓存旧清单,启动的 server 和客户端 schema 对不上,InitializeResponse 缺字段就会握手失败。
  • WSL cwd 翻译漏网:translate_cwd_for_wsl_backend 没覆盖到某个新的 Windows 路径形式时,agent 拿到对不齐的 cwd,所有 Path 操作跑偏,但不会立刻报错,只在第一次写文件时以「找不到目录」炸出来。
  • 审批请求器死锁:审批走 ContextVar + 用户回调,客户端事件循环卡住没回 ACK 时,build_edit_proposal 之后的等待一直挂着。ACP 协议层的 cancel 是否能传播到这个等待点,要看 events.py 的中断路径有没有覆盖。
  • provenance 链断:压缩分叉时 parent_session_id 写错,build_session_provenance 走到断点就返回 root,客户端把 continuation 误当新会话展示,历史看起来就「丢了」。

小结

ACP 让 Hermes 嵌入编辑器工作流:会话管理、资源读写、编辑审批、权限隔离、来源追溯。核心是 server.py(协议适配)+ session.py(会话)+ edit_approval.py(人审编辑)。和网关层互补——网关接消息平台,ACP 接 IDE。

非官方社区学习站,内容以 MIT 许可的 NousResearch/hermes-agent 源码为依据。