Files
DevFlow/temp/S2-子代理审批勘察-2026-10-03.md
T
lxy 36bc485112 优化: 界面交互完善与设置体验
- 审批卡尊重滚动意图,等长切换回底,排队超时按钮修活
- 带图编辑提示不静默丢,删除目标回写,切换文案消歧
- 会话键盘可达+搜索态重命名,筛选计数口径对齐
- 子任务提示正名,看板加载态
- 主题跟随系统,表单脏态拦截,密钥显隐留空提示
2026-10-03 16:27:48 +08:00

82 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# S2 子代理审批语义勘察(只读,2026-10-03)
> 结论先行:任务前提不成立。sub_agent.rs grep approval 零命中≠语义空白——审批以
> 「无通道→一律拒绝(fail-closed)」实现,命名是 deny 非 approval。**非安全债**。
## 1. ToolExecPolicy::SubAgent 分流实况
`policy` 入参 → `is_sub_agent = matches!(policy, ToolExecPolicy::SubAgent)`
(src-tauri/src/commands/ai/audit/mod.rs:474-477;策略文档 mod.rs:100-112)
| 路径 | SubAgent 行为 | 证据 |
|---|---|---|
| spawn 入口白名单 | 非 Low 工具根本不进子 tool_defs,恒剔 spawn_agent | sub_agent.rs:210-251 |
| 路径授权 NeedsAuth | 就地拒绝(sub_agent_path_denied) | mod.rs:618-622 |
| 路径黑名单 Denied | 就地拒绝(同上收集) | mod.rs:633-636, 676-682 |
| Medium/High 风险 | 就地拒绝,**在 auto_exec_mode 判定之前,all 档也不放行** | mod.rs:795-803 |
| Low + 已授权 | 正常并行执行(与主会话同路径,含缓存/去重/信任) | mod.rs:774, 972+ |
拒绝形态 = `deny_sub_agent_tool` 单点(mod.rs:117-148):结构化 envelope
`{status:rejected, reason:sub_agent_denied}` + push tool_result + emit
AiToolCallCompleted + 审计 decided_by=sub_agent_denied。
**挂起对子会话实际不能工作**:SubAgent 策略下 pending 恒 0(不 insert);
子循环断言 pending>0 即 Failed 终止(sub_agent.rs:577-587)。即便 insert 也无
人消费——try_continue_agent_loop 是主 loop 恢复器(agentic/mod.rs:1888),
子 loop 是 spawn_agent handler 内同步 for-round 循环,且子会话跑完即从
per_conv 移除(sub_agent.rs:348),无任何恢复入口。
## 2. 若复用主会话审批链路到子会话:缺口清单
- 事件路由:AiApprovalRequired 带 conversation_id,前端 per-conv 幂等收集
(useAiToolEvents.ts:60-87)本可收;但子会话不在侧栏(mod.rs:235 注释
「挂父不挂子」),审批卡挂 child conv 下无处展示。
- 批准续跑:ai_approve 批准后调 try_continue_agent_loop(conv_id)
(commands/ai/commands/chat.rs:1051)恢复主 loop;子 loop 无对应机制——
deadline/tokens/fail_window/stall 计数全在 run_sub_agent_loop_inner 栈上,
挂起即栈销毁,resume 需整套状态快照/重建。
- 拒绝终止:主会话拒绝=replace tool_result+emit AiApprovalResult
(chat.rs:1004-1034);子会话侧缺 ① 不 emit AiAgentFinished 终态卡
(sub_agent.rs:320 仅单一出口处发)② 不落库子轨迹(:342)③ 不清
per_conv 条目(:348)④ payload 固定 user_denied 无子代理语义。
- 超时:arm_approval_timeout_timers 扫 pending 表可覆盖子条目
(mod.rs:826),但超时收尾不含子循环 truncated 终态,会留孤儿。
## 3. 现状语义定性
**默认拒绝(fail-closed)**:入口钳制 + 运行期就地处决双层,零挂起零放行,
Med/High 连 all 档都拒。风险评级:**非安全债**;真正可议是产品语义债——
子代理遇需审批操作只能拒绝并提示转交主会话(envelope 文案 mod.rs:130),
无「上报父会话审批」通道。
## 4. S2 最小方案骨架
**方案A(推荐,颗粒=单代理一轮)**:维持默认拒绝,增强转交闭环。
- audit/mod.rs:deny envelope 增结构化字段 tool/args/reason(现仅 message 文案)。
- sub_agent.rs:报告协议(system_prompt 段)要求列「被拒操作清单」→ 父会话
收报告后由主 loop 决定是否发起审批。
- 前端无需改。
**方案B(真审批通道,超单轮,拆 3 批)**:
1. 挂起路径:SubAgent 下 Med/High 不 deny 改 insert pending(kind 新增
SubAgentRisk{parent_conv_id})+ emit AiApprovalRequired(conversation_id
填父 conv 复用现有弹窗);子循环 pending>0 改返新状态 AwaitingApproval,
栈上状态快照存 per_conv 新字段(conv_state.rs),不删条目。
2. resume 通道:ai_approve 识别 kind==SubAgentRisk → 批准则调新函数
resume_sub_agent_loop(从快照重建上下文续 for-round);拒绝则替换
tool_result+emit AiAgentFinished(truncated)+落库+清条目。
3. 收尾:approval_timeout 超时终态补子循环 truncated 收尾;前端 agent 卡
消费 AiApprovalResult。
- 涉及文件:audit/mod.rs、agentic/sub_agent.rs、commands/ai/commands/chat.rs、
agentic/conv_state.rs、src/composables/ai/useAiToolEvents.ts、src/api/types.ts。
- 拆批理由:子循环暂停/恢复状态快照(deadline/tokens/fail_window/stall 等
7+ 项)是硬骨头,与事件路由、前端消费耦合度低,可独立验收。
## 关键文件索引
- E:\wk-lab\devflow\src-tauri\src\commands\ai\audit\mod.rs(策略分流+deny 单点)
- E:\wk-lab\devflow\src-tauri\src\commands\ai\agentic\sub_agent.rs(白名单钳制+子循环+单一出口)
- E:\wk-lab\devflow\src-tauri\src\commands\ai\commands\chat.rs(ai_approve/ai_authorize_dir)
- E:\wk-lab\devflow\src-tauri\src\commands\ai\agentic\helpers.rs(try_continue_agent_loop)
- E:\wk-lab\devflow\src\composables\ai\useAiToolEvents.ts(前端审批事件消费)