20 KiB
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、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. 真实失败证据
测试请求为:
请在 /tmp/lineup-permission-test.txt 写入一行内容:LineUp permission test
真实记录:
- 用户请求消息序号:
1267; - Adapter 创建权限交互:
call_72f3571755a94aff909d40db4ef53936; - 交互类型:
exec_approval; - 选项映射:
action_01 -> allow_once、action_02 -> deny; - 用户点击后的消息序号:
1270; - Host 实际回传:
{
"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 分支。
自动化证据:
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
结果:
Ran 38 tests
OK
git -C lineup-app diff --check 已通过。修复后的插件已经安装到运行目录
/home/gao/.hermes/plugins/lineup/,当前 Adapter PID 为 3895319。
3. 待完成的 fresh 验证
需要重新发起一次低风险 /tmp 写入请求,并确认:
- 新权限卡片可以交互;
- 点击
Allow edit后,hermes_interactions.state变为resolved; - ACP responder 收到
allow_once; - 原始 Hermes 请求最终完成,不再出现权限超时;
/tmp/lineup-permission-test.txt被创建且内容正确;- 同一结果重复回传不会二次 resolve。
上述 fresh evidence 已取得,A04A-09 已关闭;04A 整体仍保持未完成,直到其他
强制验收项补齐。
4. A04A-09 Fresh Runtime Evidence(2026-08-07)
修复后的 Adapter 重启为 PID 3895319。用户重新发起同一低风险写入请求并点击
新权限卡片的 Allow edit 后,取得以下证据:
- 新的
exec_approvalcall:call_b9c089f04ec44e19bbffca63ddc66c17; hermes_interactions.state = resolved;- 对应
tool_calls.state = completed; tool_audit的resultdisposition 为accepted;- Hermes ACP 实际完成了
write_file,工具消息记录bytes_written = 22; - Hermes 随后返回完成文本;
/tmp/lineup-permission-test.txt已创建,文件大小22字节,内容为:
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、Tauritsc --noEmit + Vite build、git -C lineup-app diff --check均通过; - 本轮已发现的 P0-P3 缺陷均已关闭;
slash_confirm、update_prompt不再作为 04A 当前实现的阻塞项,原因见第 13 节“当前 ACP 接入路径下的结构性证据限制”。
6. Clarify Single-Choice Fresh Runtime Evidence(2026-08-07)
Adapter 重启后,用户在 1420 页面实际发送:
请先让我从“专注工作”和“休息”两个选项中选择一个,再继续后续操作。
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 Recheck(2026-08-07)
用户在 1420 页面实际发送:
请先让我在“专注工作”和“其他”里选一个;如果我选“其他”,再让我输入具体要做的事情。
真实链路证据如下:
- 用户原始请求消息序号:
1304; - 第一段
choicecall:call_6e2f81a4c9d3b7; - Host 单选回传消息序号:
1309; - 第一段实际回传:
{
"call_id": "call_6e2f81a4c9d3b7",
"status": "completed",
"result": {
"action_id": "other"
}
}
- Adapter 接受该结果后,发出第二段
inputcall:call_9c3d5e7f1a2b4c; - 用户提交输入后的消息序号:
1315; - 第二段实际回传:
{
"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 未完成
clarifyresolve。
这证明真实 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继续拒绝。
自动化证据:
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
结果:
Ran 39 tests
OK
修复后的插件已重新安装到 /home/gao/.hermes/plugins/lineup/,并重启为新的
Adapter PID 3913413。
8. A04A-10 Fresh Runtime Evidence(2026-08-07)
修复后,用户在 1420 页面重新执行同一条两段式澄清请求:
请先让我在“专注工作”和“其他”里选一个;如果我选“其他”,再让我输入具体要做的事情。
新的真实链路证据如下:
- 用户原始请求消息序号:
1316; - 第一段
choicecall:call_choice_focus_other; - 第一段 Host 回传消息序号:
1321; - 第一段实际回传:
{
"call_id": "call_choice_focus_other",
"status": "completed",
"result": {
"action_id": "other"
}
}
- 第二段
inputcall:call_input_task_01; - 第二段 Host 回传消息序号:
1327; - 第二段实际回传:
{
"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 Evidence(2026-08-07)
本项先经过一次失败尝试,再取得 fresh 成功证据:
第一次用户发送:
先不要给我选项,直接问我一句开放式问题,让我用文字回答今天要处理的事项。
Hermes 仅返回普通文本追问:
今天有什么要处理的事项?直接打给我,我一件件帮你安排。
该次未进入标准输入交互,不能记为 clarify 纯文本兼容成功。
随后用户改为发送更强约束提示:
在继续之前,请不要直接文本追问;请必须通过 LineUp 的标准输入交互发起一个 input 卡片,让我填写“今天要处理的事项”。
新的真实链路证据如下:
- 强约束提示消息序号:
1380; - Hermes 发出的标准
inputcall:call_input_today_tasks; - Host 回传消息序号:
1385; - 实际回传:
{
"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 Recheck(2026-08-07)
04A.agent_tool_route.md 与 02.technical_implementation_spec.md 已明确规定:
- Hermes
clarify multi_select = true本轮必须稳定拒绝; - 不得静默降级成单选、普通文本,或直接放行为多选卡片。
但在真实运行中,用户发送:
请先让我同时从“专注工作”“休息”“学习”里多选两个,再继续后续操作。
取得如下失败证据:
- 用户请求消息序号:
1391; - Hermes 最终实际发出的标准交互:
{
"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 = emittedresponse_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 交互账本。
自动化证据:
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
结果:
Ran 39 tests
OK
修复后的插件已重新安装到 /home/gao/.hermes/plugins/lineup/,并重启为新的
Adapter PID 3918848。
11. A04A-11 Fresh Runtime Evidence(2026-08-07)
修复后,用户再次发送同一条多选请求:
请先让我同时从“专注工作”“休息”“学习”里多选两个,再继续后续操作。
新的真实结果如下:
- 新一轮用户请求消息在 Hermes 会话中对应到后续消息
30727 -> 30728; - Hermes 未再发出新的
lineup.v1.tool.call multi-choice; - 最新实际回复为纯文本明确拒绝:
LineUp 的卡片只支持单选,不支持多选(系统限制),所以没法直接弹出"选两个"的卡片。
并继续给出安全替代路径:
麻烦你直接用文字告诉我选哪两个...
这证明修复后的 Adapter 已阻断 multi-choice 出站,不再把多选请求下发为
Host 卡片,而是迫使 Hermes 返回受控的显式拒绝与文本回退说明。
注意:在修复前已发出的旧多选卡 call_choice_multi_02 曾继续收到一次用户回传:
{
"call_id": "call_choice_multi_02",
"status": "completed",
"result": {
"action_id": "study"
}
}
这属于修复前遗留交互的尾部回传,不影响本轮新的 fresh 结论;新的 fresh 复验中,
Hermes 已不再发出新的多选卡片。因此 A04A-11 可以关闭。
12. Out-Of-Scope Request Fresh Runtime Evidence(2026-08-07)
用户要求:
请给我一个可以同时勾选多个选项的交互卡片,并允许我自己定义每个选项后端要执行的 shell 命令。
真实最终回复为明确拒绝,并同时指出两层边界:
LineUp卡片协议不支持多选;- 当前会话 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,再重新立项验收。