forked from Zakaria/hermes-agent
Hermes-agent
This commit is contained in:
+184
@@ -0,0 +1,184 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
title: "ACP 内部机制"
|
||||
description: "ACP 适配器的工作原理:生命周期、会话、事件桥接、审批流程与工具渲染"
|
||||
---
|
||||
|
||||
# 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`
|
||||
|
||||
## 启动流程
|
||||
|
||||
```text
|
||||
hermes acp / hermes-acp / python -m acp_adapter
|
||||
-> acp_adapter.entry.main()
|
||||
-> parse --version / --check / --setup before server startup
|
||||
-> load ~/.hermes/.env
|
||||
-> configure stderr logging
|
||||
-> construct HermesACPAgent
|
||||
-> acp.run_agent(agent, use_unstable_protocol=True)
|
||||
```
|
||||
|
||||
Zed ACP Registry 路径通过 `uvx --from 'hermes-agent[acp]==<version>' hermes-acp` 启动同一适配器,指向 `hermes-agent` PyPI 发布包。
|
||||
|
||||
stdout 保留用于 ACP JSON-RPC 传输。人类可读的日志输出至 stderr。
|
||||
|
||||
## 主要组件
|
||||
|
||||
### `HermesACPAgent`
|
||||
|
||||
`acp_adapter/server.py` 实现 ACP agent 协议。
|
||||
|
||||
职责:
|
||||
|
||||
- 初始化 / 认证
|
||||
- 新建/加载/恢复/fork/列出/取消会话方法
|
||||
- prompt(提示词)执行
|
||||
- 会话模型切换
|
||||
- 将同步 AIAgent 回调接入 ACP 异步通知
|
||||
|
||||
### `SessionManager`
|
||||
|
||||
`acp_adapter/session.py` 跟踪活跃的 ACP 会话。
|
||||
|
||||
每个会话存储:
|
||||
|
||||
- `session_id`
|
||||
- `agent`
|
||||
- `cwd`
|
||||
- `model`
|
||||
- `history`
|
||||
- `cancel_event`
|
||||
|
||||
管理器线程安全,支持:
|
||||
|
||||
- create
|
||||
- get
|
||||
- remove
|
||||
- fork
|
||||
- list
|
||||
- cleanup
|
||||
- cwd 更新
|
||||
|
||||
### 事件桥接
|
||||
|
||||
`acp_adapter/events.py` 将 AIAgent 回调转换为 ACP `session_update` 事件。
|
||||
|
||||
已桥接的回调:
|
||||
|
||||
- `tool_progress_callback`
|
||||
- `thinking_callback`(当前在 ACP 桥接中设置为 `None`——推理内容通过 `step_callback` 转发)
|
||||
- `step_callback`
|
||||
|
||||
由于 `AIAgent` 在工作线程中运行,而 ACP I/O 位于主事件循环,桥接使用:
|
||||
|
||||
```python
|
||||
asyncio.run_coroutine_threadsafe(...)
|
||||
```
|
||||
|
||||
### 权限桥接
|
||||
|
||||
`acp_adapter/permissions.py` 将危险终端审批 prompt 适配为 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 安全)
|
||||
|
||||
## 会话生命周期
|
||||
|
||||
```text
|
||||
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()`
|
||||
- 使 prompt 响应返回 `stop_reason="cancelled"`
|
||||
|
||||
### Fork
|
||||
|
||||
`fork_session()` 将消息历史深拷贝至新的活跃会话,在保留对话状态的同时为 fork 分配独立的 session ID 和 cwd。
|
||||
|
||||
## Provider/认证行为
|
||||
|
||||
ACP 不实现自己的认证存储。
|
||||
|
||||
而是复用 Hermes 的运行时解析器:
|
||||
|
||||
- `acp_adapter/auth.py`
|
||||
- `hermes_cli/runtime_provider.py`
|
||||
|
||||
因此 ACP 通告并使用当前配置的 Hermes provider/凭据。它还始终通告一个终端 setup 认证方法(`hermes-setup`,参数 `--setup`),以便首次运行的 registry 客户端在启动正常 ACP 会话前可以打开 Hermes 的交互式模型/provider 配置。
|
||||
|
||||
## 工作目录绑定
|
||||
|
||||
ACP 会话携带编辑器 cwd。
|
||||
|
||||
会话管理器通过任务作用域的终端/文件覆盖将该 cwd 绑定到 ACP session ID,使文件和终端工具相对于编辑器工作区运行。
|
||||
|
||||
## 重复同名工具调用
|
||||
|
||||
事件桥接按工具名称以 FIFO 队列跟踪工具 ID,而非每个名称仅保留一个 ID。这对以下场景至关重要:
|
||||
|
||||
- 并行同名调用
|
||||
- 单步内重复同名调用
|
||||
|
||||
若不使用 FIFO 队列,完成事件将附加到错误的工具调用上。
|
||||
|
||||
## 审批回调恢复
|
||||
|
||||
ACP 在 prompt 执行期间临时在终端工具上安装审批回调,执行完成后恢复之前的回调。这避免了将 ACP 会话特定的审批处理器永久全局安装。
|
||||
|
||||
## 当前限制
|
||||
|
||||
- ACP 会话持久化至共享的 `~/.hermes/state.db`(SessionDB),在进程重启后透明恢复;它们会出现在 `session_search` 中
|
||||
- 非文本 prompt 块在请求文本提取时当前被忽略
|
||||
- 编辑器特定的 UX 因 ACP 客户端实现而异
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `tests/acp/` — ACP 测试套件
|
||||
- `toolsets.py` — `hermes-acp` toolset 定义
|
||||
- `hermes_cli/main.py` — `hermes acp` CLI 子命令
|
||||
- `pyproject.toml` — `[acp]` 可选依赖 + `hermes-acp` 脚本
|
||||
Reference in New Issue
Block a user