跳到主要内容

ACP 内部机制

ACP 适配器将 Hermes 的同步 AIAgent 包装为一个异步 JSON-RPC 标准输入/输出(stdio)服务器。

关键实现文件:

  • acp_adapter/entry.py
  • acp_adapter/server.py
  • acp_adapter/session.py
  • acp_adapter/events.py
  • acp_adapter/permissions.py
  • acp_adapter/tools.py
  • acp_adapter/auth.py
  • acp_registry/agent.json

启动流程

hermes acp / hermes-acp / python -m acp_adapter
-> acp_adapter.entry.main()
-> load ~/.hermes/.env
-> configure stderr logging
-> construct HermesACPAgent
-> acp.run_agent(agent)

标准输出(stdout)保留用于 ACP JSON-RPC 传输。人类可读的日志输出到标准错误(stderr)。

主要组件

HermesACPAgent

acp_adapter/server.py 实现了 ACP 代理协议。

职责包括:

  • 初始化 / 认证
  • 新建 / 加载 / 恢复 / 分叉 / 列出 / 取消会话方法
  • 提示执行
  • 会话模型切换
  • 将同步的 AIAgent 回调连接到 ACP 的异步通知机制

SessionManager

acp_adapter/session.py 跟踪当前活跃的 ACP 会话。

每个会话存储以下信息:

  • session_id
  • agent
  • cwd
  • model
  • history
  • cancel_event

该管理器是线程安全的,支持:

  • 创建
  • 获取
  • 移除
  • 分叉
  • 列出
  • 清理
  • 工作目录(cwd)更新

事件桥接

acp_adapter/events.pyAIAgent 的回调转换为 ACP 的 session_update 事件。

桥接的回调包括:

  • tool_progress_callback
  • thinking_callback
  • step_callback
  • message_callback

由于 AIAgent 在工作线程中运行,而 ACP I/O 在主线程事件循环中运行,因此桥接使用:

asyncio.run_coroutine_threadsafe(...)

权限桥接

acp_adapter/permissions.py 将危险的终端确认提示转换为 ACP 的权限请求。

映射关系如下:

  • allow_once → Hermes once
  • allow_always → Hermes always
  • 拒绝选项 → Hermes deny

超时或桥接失败时,默认拒绝。

工具渲染辅助函数

acp_adapter/tools.py 将 Hermes 工具映射到 ACP 工具类型,并构建面向编辑器的显示内容。

示例:

  • patch / write_file → 文件差异(diff)
  • terminal → Shell 命令文本
  • read_file / search_files → 文本预览
  • 大型结果 → 截断的文本块,确保 UI 安全

会话生命周期

new_session(cwd)
-> create SessionState
-> create AIAgent(platform="acp", enabled_toolsets=["hermes-acp"])
-> bind task_id/session_id to cwd override

prompt(..., session_id)
-> extract text from ACP content blocks
-> reset cancel event
-> install callbacks + approval bridge
-> run AIAgent in ThreadPoolExecutor
-> update session history
-> emit final agent message chunk

取消操作

cancel(session_id)

  • 设置会话取消事件
  • 若可用则调用 agent.interrupt()
  • 导致提示响应返回 stop_reason="cancelled"

分叉操作

fork_session() 将消息历史深度复制到一个新的活跃会话中,保留对话状态,同时为分叉会话分配独立的 session_idcwd

提供者/认证行为

ACP 未实现自己的认证存储。

而是复用 Hermes 的运行时解析器:

  • acp_adapter/auth.py
  • hermes_cli/runtime_provider.py

因此,ACP 宣告并使用当前配置的 Hermes 提供者/凭证。

工作目录绑定

ACP 会话携带编辑器的工作目录(cwd)。

会话管理器通过任务作用域的终端/文件覆盖机制,将该 cwd 绑定到 ACP 会话 ID,使得文件和终端工具的操作均相对于编辑器工作区进行。

同名工具调用重复问题

事件桥接按工具名称维护 FIFO 队列(先进先出),而非仅每个名称一个 ID。这一点对于以下情况至关重要:

  • 并行的同名调用
  • 单步中重复的同名调用

若无 FIFO 队列,完成事件将错误地关联到错误的工具调用。

批准回调恢复

ACP 在提示执行期间临时安装一个终端工具的批准回调,执行完成后恢复之前的回调。这避免了将 ACP 会话特定的批准处理器永久全局安装。

当前限制

  • 从 ACP 服务器的角度看,ACP 会话是进程本地的
  • 非文本提示块目前在请求文本提取时被忽略
  • 编辑器特定的用户体验因 ACP 客户端实现而异
  • tests/acp/ — ACP 测试套件
  • toolsets.pyhermes-acp 工具集定义
  • hermes_cli/main.pyhermes acp CLI 子命令
  • pyproject.toml[acp] 可选依赖项 + hermes-acp 脚本