初始化 agent_ops 文档治理体系

This commit is contained in:
2026-08-07 16:56:51 +08:00
commit 10840909ab
75 changed files with 15750 additions and 0 deletions
@@ -0,0 +1,498 @@
# 04A.agent_tool_route 验收评审(五)
**状态:** 已完成本轮联合验收,A04A-09 / A04A-10 / A04A-11 已通过 fresh runtime 验证;`slash_confirm` / `update_prompt` 已转为当前 ACP 接入路径下的结构性证据限制记录
**日期:** 2026-08-07
**评审对象:** `lineup-adapter/hermes/lineup/` 当前实现、[04A.agent_tool_route.md](04A.agent_tool_route.md)、[02.technical_implementation_spec.md](02.technical_implementation_spec.md)、实际 LineUp Host / Hermes Adapter 运行状态
**评审方法:** 将自动化测试与真实消息链路证据交叉核对;本轮重点复核 Hermes `session/request_permission` 投影后的单选结果是否与 Host 实际发送的 `lineup.v1.tool.result` 形状一致。
**总体结论:** 已发现并修复三个会破坏 04A 交互边界的 P2 缺陷。权限卡片闭环、`clarify other -> input`、纯文本 `clarify``multi_select` 稳定拒绝,以及至少一种范围外稳定拒绝的 fresh evidence 均已通过。结合 `02.正式方案``04.runtime_workspace` 与当前实际接入实现复核后,可以确认 `slash_confirm``update_prompt` 在本轮 1420 + `hermes acp` 接入路径下缺少安全、稳定、可重复的运行期触发源;它们当前不应继续按“未修复缺陷”处理,而应作为后续 bridge / trigger 能力的小迭代承接项记录。
## 问题清单(Outline
状态标记:🔴 未解决,必须处理;🟡 已修复但等待运行期确认;✅ 已解决;⚪ 可延期但必须保留记录。
| 状态 | 优先级 | 编号 | 问题 | 当前结论 / 下一步 |
|---|---:|---|---|---|
| ✅ | P2 | A04A-09 | Host 单选卡片实际回传 `result.action_id`Adapter 只接受 `result.action_ids[]`,导致用户点击允许后结果被拒绝,Hermes 交互保持 pending 并最终超时。 | 已在 `protocol.py` 增加严格单选规范化;真实 Host 验证通过,交互 `call_b9c089f04ec44e19bbffca63ddc66c17``resolved`Hermes 已收到 `allow_once`,目标文件已创建。 |
| ✅ | P2 | A04A-10 | `clarify other -> input` 的第二段输入卡片真实回传 `result.text`Adapter 只接受 `result.values.{field_id}`,导致用户提交后卡片失效但 Hermes 未被解除阻塞。 | 已在 `protocol.py` 增加单字段输入 `text -> values.{field_id}` 严格规范化;新的 1420 页面 fresh 复验已通过,`call_input_task_01``completed`Hermes 已确认收到 `验收 04A other-input`。 |
| ✅ | P2 | A04A-11 | 04A 要求 `clarify multi_select = true` 稳定拒绝,但 Hermes 主回复提示词和 `tool.call` 校验仍允许模型直接发出 `multi-choice` 卡片,导致多选请求被错误放行。 | 已移除 Adapter 出站层对 `multi-choice` 的接受并更新回归测试;新的 1420 页面 fresh 复验已确认“不再出现多选卡片”,Hermes 改为明确提示“LineUp 卡片只支持单选,不支持多选”。 |
## 1. 真实失败证据
测试请求为:
```text
请在 /tmp/lineup-permission-test.txt 写入一行内容:LineUp permission test
```
真实记录:
- 用户请求消息序号:`1267`
- Adapter 创建权限交互:`call_72f3571755a94aff909d40db4ef53936`
- 交互类型:`exec_approval`
- 选项映射:`action_01 -> allow_once``action_02 -> deny`
- 用户点击后的消息序号:`1270`
- Host 实际回传:
```json
{
"call_id": "call_72f3571755a94aff909d40db4ef53936",
"status": "completed",
"result": {
"action_id": "action_01"
}
}
```
修复前该消息被记录为 `invalid hermes interaction response``tool_audit`
`result / rejected`,交互仍为 `pending`,目标文件不存在,原始 Hermes 请求最终为
`Hermes ACP response timeout`。旧交互在 Adapter 重启恢复时已被正确标记为
`aborted`,不能继续重复操作。
## 2. 修复与自动化证据
修复内容:
- `validate_tool_response()``mode = single-choice` 且不存在 `action_ids` 时接受唯一字符串 `action_id`
- 统一规范化为内部 `action_ids = [action_id]`
- 保留 inventory/schema 边界,未知、缺失、非字符串、多选及重复选项继续拒绝;
- Hermes resolve 继续只消费规范化后的内部形状,因此不新增第二套 resolve 分支。
自动化证据:
```bash
PYTHONPATH=lineup-adapter/hermes python3 -m unittest \
lineup-adapter/hermes/lineup/tests/test_protocol.py \
lineup-adapter/hermes/lineup/tests/test_core.py \
lineup-adapter/hermes/lineup/tests/test_acp_client.py \
lineup-adapter/hermes/lineup/tests/test_state.py
```
结果:
```text
Ran 38 tests
OK
```
`git -C lineup-app diff --check` 已通过。修复后的插件已经安装到运行目录
`/home/gao/.hermes/plugins/lineup/`,当前 Adapter PID 为 `3895319`
## 3. 待完成的 fresh 验证
需要重新发起一次低风险 `/tmp` 写入请求,并确认:
1. 新权限卡片可以交互;
2. 点击 `Allow edit` 后,`hermes_interactions.state` 变为 `resolved`
3. ACP responder 收到 `allow_once`
4. 原始 Hermes 请求最终完成,不再出现权限超时;
5. `/tmp/lineup-permission-test.txt` 被创建且内容正确;
6. 同一结果重复回传不会二次 resolve。
上述 fresh evidence 已取得,`A04A-09` 已关闭;04A 整体仍保持未完成,直到其他
强制验收项补齐。
## 4. A04A-09 Fresh Runtime Evidence2026-08-07
修复后的 Adapter 重启为 PID `3895319`。用户重新发起同一低风险写入请求并点击
新权限卡片的 `Allow edit` 后,取得以下证据:
- 新的 `exec_approval` call`call_b9c089f04ec44e19bbffca63ddc66c17`
- `hermes_interactions.state = resolved`
- 对应 `tool_calls.state = completed`
- `tool_audit``result` disposition 为 `accepted`
- Hermes ACP 实际完成了 `write_file`,工具消息记录 `bytes_written = 22`
- Hermes 随后返回完成文本;
- `/tmp/lineup-permission-test.txt` 已创建,文件大小 `22` 字节,内容为:
```text
LineUp permission test
```
这证明真实 Host 的单选 `action_id` 回传已经被 Adapter 规范化并 resolve 回
Hermes,且没有再次出现 `Hermes ACP response timeout`
## 5. 当前验收结论
- `clarify` 单选、`other -> input`、纯文本输入、`multi_select` 稳定拒绝与至少一种范围外稳定拒绝均已具备 fresh evidence
- 当前自动化门禁:Adapter `39 tests`、Runtime 定向测试 `71 tests`、Tauri `tsc --noEmit + Vite build``git -C lineup-app diff --check` 均通过;
- 本轮已发现的 P0-P3 缺陷均已关闭;
- `slash_confirm``update_prompt` 不再作为 04A 当前实现的阻塞项,原因见第 13 节“当前 ACP 接入路径下的结构性证据限制”。
## 6. Clarify Single-Choice Fresh Runtime Evidence2026-08-07
Adapter 重启后,用户在 1420 页面实际发送:
```text
请先让我从“专注工作”和“休息”两个选项中选择一个,再继续后续操作。
```
Hermes 生成了真实标准交互:
- `call_id = call_8f3a2c91d4e6b7a0`
- `tool = choice`
- `mode = single-choice`
- `action_ids = ["focus", "rest"]`
- Host 回传消息序号:`1287`
- 实际回传 `result.action_id = "focus"`
- Adapter `tool_audit``call / accepted``result / accepted`
- 对应 `tool_calls.state = completed`
- Hermes 最终回复已明确收到“专注工作”选择。
这证明真实 Hermes -> LineUp `tool.call`、用户选择 -> `tool.result`
Adapter ledger -> Hermes resolve 的单选路径已闭环,并再次验证 Host 的
`action_id` 形状兼容。
同一次会话的 Hermes 回复指出当前 inventory 为 `revision:none`。这是因为 Adapter
重启后 Host 尚未重新下发新的 `client.inventory`,不属于 clarify 交互失败;但在
继续验证 `pomodoro.start` 之前,必须先刷新 1420 Host 或让 Host 重新发布 inventory。
## 7. A04A-10 Real Runtime Failure And Fix Pending Fresh Recheck2026-08-07
用户在 1420 页面实际发送:
```text
请先让我在“专注工作”和“其他”里选一个;如果我选“其他”,再让我输入具体要做的事情。
```
真实链路证据如下:
- 用户原始请求消息序号:`1304`
- 第一段 `choice` call`call_6e2f81a4c9d3b7`
- Host 单选回传消息序号:`1309`
- 第一段实际回传:
```json
{
"call_id": "call_6e2f81a4c9d3b7",
"status": "completed",
"result": {
"action_id": "other"
}
}
```
- Adapter 接受该结果后,发出第二段 `input` call`call_9c3d5e7f1a2b4c`
- 用户提交输入后的消息序号:`1315`
- 第二段实际回传:
```json
{
"call_id": "call_9c3d5e7f1a2b4c",
"status": "completed",
"result": {
"text": "验收 04A other-input"
}
}
```
失败时的 Adapter 账本状态:
- `tool_audit(call_6e2f81a4c9d3b7)``call / accepted``result / accepted`
- `tool_audit(call_9c3d5e7f1a2b4c)``call / accepted``result / rejected`
- `tool_calls(call_9c3d5e7f1a2b4c).state = emitted`
- 用户侧实际观察为第二张输入卡片提交后变为不可交互,但 Hermes 未完成 `clarify` resolve。
这证明真实 Host 对单字段 `input` 的结果回传 shape 为 `result.text`,而 Adapter 先前只接受 `result.values.{field_id}`,因此属于会阻断 `clarify other -> input` 闭环的 P2 兼容缺陷。
修复内容:
- `validate_tool_response()``tool = input` 且 schema 只有一个字段时,接受唯一字符串 `result.text`
- 规范化为内部 `values.{field_id}` 后再走原有 schema 校验;
- 保持严格边界:多字段表单仍必须使用 `values`,非字符串 `text` 继续拒绝。
自动化证据:
```bash
PYTHONPATH=lineup-adapter/hermes python3 -m unittest \
lineup-adapter/hermes/lineup/tests/test_protocol.py \
lineup-adapter/hermes/lineup/tests/test_core.py \
lineup-adapter/hermes/lineup/tests/test_acp_client.py \
lineup-adapter/hermes/lineup/tests/test_state.py
```
结果:
```text
Ran 39 tests
OK
```
修复后的插件已重新安装到 `/home/gao/.hermes/plugins/lineup/`,并重启为新的
Adapter PID `3913413`
## 8. A04A-10 Fresh Runtime Evidence2026-08-07
修复后,用户在 1420 页面重新执行同一条两段式澄清请求:
```text
请先让我在“专注工作”和“其他”里选一个;如果我选“其他”,再让我输入具体要做的事情。
```
新的真实链路证据如下:
- 用户原始请求消息序号:`1316`
- 第一段 `choice` call`call_choice_focus_other`
- 第一段 Host 回传消息序号:`1321`
- 第一段实际回传:
```json
{
"call_id": "call_choice_focus_other",
"status": "completed",
"result": {
"action_id": "other"
}
}
```
- 第二段 `input` call`call_input_task_01`
- 第二段 Host 回传消息序号:`1327`
- 第二段实际回传:
```json
{
"call_id": "call_input_task_01",
"status": "completed",
"result": {
"text": "验收 04A other-input"
}
}
```
修复后的账本状态:
- `tool_calls(call_choice_focus_other).state = completed`
- `tool_calls(call_input_task_01).state = completed`
- Hermes 最终回复消息已明确确认:
- 选择:`其他`
- 输入:`验收 04A other-input`
- 结论:两段式交互已跑通。
用户侧同步观察为:提交后输入卡片变为不可交互,且 Hermes 立即返回确认文本。
这证明单字段 `input``result.text` 已被 Adapter 严格规范化并成功 resolve 回 Hermes`A04A-10` 可以关闭。
## 9. Clarify Pure-Text Fresh Runtime Evidence2026-08-07
本项先经过一次失败尝试,再取得 fresh 成功证据:
第一次用户发送:
```text
先不要给我选项,直接问我一句开放式问题,让我用文字回答今天要处理的事项。
```
Hermes 仅返回普通文本追问:
```text
今天有什么要处理的事项?直接打给我,我一件件帮你安排。
```
该次未进入标准输入交互,不能记为 `clarify` 纯文本兼容成功。
随后用户改为发送更强约束提示:
```text
在继续之前,请不要直接文本追问;请必须通过 LineUp 的标准输入交互发起一个 input 卡片,让我填写“今天要处理的事项”。
```
新的真实链路证据如下:
- 强约束提示消息序号:`1380`
- Hermes 发出的标准 `input` call`call_input_today_tasks`
- Host 回传消息序号:`1385`
- 实际回传:
```json
{
"call_id": "call_input_today_tasks",
"status": "completed",
"result": {
"text": "验收 04A pure-text clarify"
}
}
```
账本状态:
- `tool_calls(call_input_today_tasks).state = completed`
- `tool_audit(call_input_today_tasks)``call / accepted``result / accepted`
- Hermes 最终确认文本明确回显:
- 交互方式:`input` 卡片(标准输入交互)
- 填写内容:`验收 04A pure-text clarify`
- 结论:卡片流程跑通。
这证明在明确要求下,Hermes 纯文本 `clarify` 已可通过 Adapter 投影为
LineUp 标准 `input` 交互,并通过现有消息链路闭环 resolve。
## 10. A04A-11 Real Runtime Failure And Fix Pending Fresh Recheck2026-08-07
`04A.agent_tool_route.md``02.technical_implementation_spec.md` 已明确规定:
- Hermes `clarify multi_select = true` 本轮必须稳定拒绝;
- 不得静默降级成单选、普通文本,或直接放行为多选卡片。
但在真实运行中,用户发送:
```text
请先让我同时从“专注工作”“休息”“学习”里多选两个,再继续后续操作。
```
取得如下失败证据:
- 用户请求消息序号:`1391`
- Hermes 最终实际发出的标准交互:
```json
{
"v": 1,
"type": "lineup.v1.tool.call",
"payload": {
"call_id": "call_choice_multi_02",
"tool": "choice",
"title": "选择两项",
"prompt": "请从以下选项中选择两项",
"expires_at": "2026-08-07T05:15:00Z",
"data": {
"action_group": {
"mode": "multi-choice",
"actions": [
{"id": "focus", "label": "专注工作"},
{"id": "rest", "label": "休息"},
{"id": "study", "label": "学习"}
]
}
}
}
}
```
- Adapter 账本记录:
- `tool_calls(call_choice_multi_02).state = emitted`
- `response_schema.mode = multi-choice`
- 用户侧实际观察为:1420 页面出现了多选提示卡。
这证明问题并不在 ACP clarify 投影层,而在 Hermes 主回复通路本身:
Adapter 的主提示词仍显式允许 `multi-choice``validate_tool_call_payload()` 也仍接受
`mode = multi-choice`,因此模型可以绕过“Hermes clarify 多选必须拒绝”的设计结论,
直接生成一张多选卡片。
修复内容:
- 从 Adapter `tool.call` 出站校验中移除 `multi-choice` 允许集;
- 更新 Hermes 主提示词,明确 `multi-choice` 在当前 LineUp Hermes 通路中不受支持;
- 新增回归测试,确保模型直接输出 `multi-choice` 会被拒绝,不能再进入 Host 交互账本。
自动化证据:
```bash
PYTHONPATH=lineup-adapter/hermes python3 -m unittest \
lineup-adapter/hermes/lineup/tests/test_protocol.py \
lineup-adapter/hermes/lineup/tests/test_core.py \
lineup-adapter/hermes/lineup/tests/test_acp_client.py \
lineup-adapter/hermes/lineup/tests/test_state.py
```
结果:
```text
Ran 39 tests
OK
```
修复后的插件已重新安装到 `/home/gao/.hermes/plugins/lineup/`,并重启为新的
Adapter PID `3918848`
## 11. A04A-11 Fresh Runtime Evidence2026-08-07
修复后,用户再次发送同一条多选请求:
```text
请先让我同时从“专注工作”“休息”“学习”里多选两个,再继续后续操作。
```
新的真实结果如下:
- 新一轮用户请求消息在 Hermes 会话中对应到后续消息 `30727 -> 30728`
- Hermes 未再发出新的 `lineup.v1.tool.call multi-choice`
- 最新实际回复为纯文本明确拒绝:
```text
LineUp 的卡片只支持单选,不支持多选(系统限制),所以没法直接弹出"选两个"的卡片。
```
并继续给出安全替代路径:
```text
麻烦你直接用文字告诉我选哪两个...
```
这证明修复后的 Adapter 已阻断 `multi-choice` 出站,不再把多选请求下发为
Host 卡片,而是迫使 Hermes 返回受控的显式拒绝与文本回退说明。
注意:在修复前已发出的旧多选卡 `call_choice_multi_02` 曾继续收到一次用户回传:
```json
{
"call_id": "call_choice_multi_02",
"status": "completed",
"result": {
"action_id": "study"
}
}
```
这属于修复前遗留交互的尾部回传,不影响本轮新的 fresh 结论;新的 fresh 复验中,
Hermes 已不再发出新的多选卡片。因此 `A04A-11` 可以关闭。
## 12. Out-Of-Scope Request Fresh Runtime Evidence2026-08-07
用户要求:
```text
请给我一个可以同时勾选多个选项的交互卡片,并允许我自己定义每个选项后端要执行的 shell 命令。
```
真实最终回复为明确拒绝,并同时指出两层边界:
1. `LineUp` 卡片协议不支持多选;
2. 当前会话 inventory 为空,没有任何 shell 执行能力暴露给 Hermes。
Hermes 没有下发任何新的危险交互卡片,也没有伪造 shell / app capability /
runtime tool 权限,而是改为提供受控的文本替代方案。
这可作为“范围外 Hermes 请求被稳定拒绝,且未形成隐式授权”的 fresh runtime 证据。
## 13. `slash_confirm` / `update_prompt`:当前 ACP 接入路径下的结构性证据限制(2026-08-07)
本轮在真实 1420 页面上已多次尝试补充 `slash_confirm` / `update_prompt` 的 fresh runtime evidence,但结合源码与运行事实复核后,可以确认这两项当前缺的不是“Adapter 尚未修好”,而是**当前 ACP 接入路径本身没有稳定触发源投影**。
### 13.1 源码对照
- 当前 LineUp Hermes 插件通过 `hermes acp` 挂接,插件侧入口位于 `/home/gao/.hermes/plugins/lineup/acp_client.py`
- 该 ACP client 当前唯一显式处理的 server request method 是 `session/request_permission`
- 在同一文件中,未知 server request method 会直接返回 `Unsupported ACP client method`,没有看到与 `slash_confirm``update_prompt` 对应的 ACP request 分发入口;
- Hermes 原生 `slash_confirm` 触发源位于 gateway/native platform 路径:
- `/home/gao/.hermes/hermes-agent/gateway/run.py` 中的 `_request_slash_confirm(...)`
- `/home/gao/.hermes/hermes-agent/gateway/slash_commands.py` 中对 `_request_slash_confirm(...)` 的调用
- 其交互依赖平台 adapter 的 `send_slash_confirm(...)`,失败时退回 gateway 文本确认;
- Hermes 原生 `update_prompt` 触发源同样位于 gateway watcher / native platform 路径:
- `/home/gao/.hermes/hermes-agent/gateway/run.py` 中对 `.update_prompt.json` 的轮询
- 再调用平台 adapter 的 `send_update_prompt(...)`,或退回 gateway 文本提示。
这说明:当前 LineUp 1420 页面走的是 **ACP stdio 接入链路**,而不是 Hermes gateway 的原生平台 adapter 按钮链路。两者属于不同事件源。
### 13.2 运行期事实
- `/reload-mcp` 在当前会话里因 `~/.hermes/config.yaml``mcp_servers: {}` 被短路为普通文本说明,没有进入可复用的确认交互;
- `/model custom/deepseek-v4-pro` 在当前会话里也没有稳定进入 `slash_confirm`,而是走成了“编辑 `config.yaml`”的写入审批路径,用户看到的是 `edit config.yaml` 审批卡;
- 已通过的 fresh evidence 全部来自当前 ACP 路径可稳定发出的两类来源:
- `session/request_permission` -> `exec_approval`
- Adapter 主回复 / `tool.call` -> `clarify` / `input`
因此,继续在 1420 页面上重复盲测,并不能合理提高 `slash_confirm` / `update_prompt` 的证据覆盖率。
### 13.3 评审结论
- `04A` 当前实现已经证明:Adapter 层可以把可达的 Hermes 内置交互收敛到 LineUp 协议,并通过现有消息链路完成用户选择回传;
- `slash_confirm` / `update_prompt` 仍应保留在 04A 的目标模型与映射表中,作为 Adapter 兼容层未来要承接的 contract;
- 但在当前 `1420 + hermes acp` 接入方式下,它们缺少安全、稳定、可重复的运行期触发源,不再作为本轮关闭验收的阻塞条件;
- 若后续需要 fresh runtime evidence,必须新增单独的 bridge / trigger 路径,或在后续小迭代中引入可控的 gateway-native event source,再重新立项验收。