文档: 设计定稿与评估纪律登记

- 无人值守长任务设计定稿,含效率与可观测补遗
- u-relay wire 协议规格与五项评估结论
- 新能力引入评估纪律五项清单
- todo 销账与狗粮短板分析登记
This commit is contained in:
lxy
2026-10-04 16:27:32 +08:00
parent 08e9d0292d
commit b994cf2c54
10 changed files with 1214 additions and 20 deletions
@@ -0,0 +1,97 @@
# 子代理完成卡双轨「已消化」降级 · 设计(2026-10-04)
> ✅ 拍板通过(2026-10-04,2/2 按建议:D1 自动折叠默认开/D2 trace 随 namespace 批;见 [拍板集](../滚动规范/拍板集-2026-10-04.md))
> 来源:todo.md 子代理深查「P2 完成卡(前端全文)与父上下文(压缩)双轨无『已消化』降级机制[需设计]」。
> 勘察结论(2026-10-04 现场核实,以源码为准,**修正深查一处过时结论**):
> - 完成卡前端已非「重启蒸发」:`aiShared.ts:677` 已有按父 conv 经 `ai_sub_agent_list` 反查重建完成卡(轨迹存在即视为 completed),重启回补链路已通。剩余缺口即「已消化」降级。
> - 双轨现状:前端卡持 summary 全文(`AgentFinishedCard.summary`,卡面 160 字截断展示);父上下文中报告经 namespace 引用+`context_helpers.rs` 视图压缩(`TOOL_RESULT_SUMMARIZE_BYTES=2048` / `TOOL_RESULT_JSON_STR_FIELD_MAX=512`),**父 LLM 后续轮次只能看到 ≤512 字符折叠摘要**。
> - 事件链:`sub_agent.rs:495` 统一出口 emit `AiAgentFinished{status,summary,rounds,tokens,rejected_tools,stop_kind}`(挂父会话)+ 整轨迹落库(V44 origin='sub_agent')。
## 1. 问题定义
「双轨无降级」的三层含义:
1. **信息层**:父 LLM 与前端卡各持一份(上下文折叠摘要 vs 前端全文),两者无互认,用户在卡上看到的细节 LLM 答不上;
2. **生命周期层**:卡永久挂在消息流(直到会话删除),无「已读/已消化」状态;多轮追问后卡仍以初始完整态占据视觉焦点;
3. **一致性层**:父 LLM 被追问报告细节时若折叠摘要不够,唯一出路是重新 `ai_sub_agent_list` 反查轨迹(LLM 未必想到/舍得花 token)。
## 2. 设计目标
1. 卡可标记「已消化」,视觉降级(折叠/淡化)但**可展开复原**,信息不丢;
2. 父 LLM 追问细节时有**结构化自助通道**(不用重跑子代理);
3. 「已消化」状态**持久化**(重启/切会话后保留);
4. 零后端 schema 变更(复用现有落库轨迹)。
非目标:不做卡全文注入上下文(会反向膨胀 prompt);不做自动消化判定(何时算「消化」留人工,v2 可议 LLM 显式 ack)。
## 3. 方案
### 3.1 「已消化」状态与持久化
前端 `AgentFinishedCard` 增字段:
```
+ digested?: boolean // 默认 false
```
持久化载体:**复用 KV 存储**(app 已有 settings/KV 表),key = `agentCardDigested:{parentConvId}` → `string[]`(agentId 列表,JSON)。切换/挂载回补时(aiShared.ts:677 重建路径)读 KV 合并标记。不落 SQLite 新列/新表——卡本身是派生态(由轨迹重建),消化标记是用户偏好,KV 语义足够。
### 3.2 视觉降级交互
```
未消化卡: 现状(标题行+status 徽章+160 字摘要+展开全文)
已消化卡: 标题行单行化(✓ 已消化 · summary 首 40 字 · status 徽章淡化),点击展开复原全文
手动标记: 卡右上角「标记已消化」动作(hover 显现),支持批量(同会话多卡)
自动辅助: 同会话出现新完成卡时,旧未消化卡自动折叠为单行(不标已消化,仅视觉收纳,复用 ToolCardList 分组折叠的 touched 语义——用户手动展开过则不自动收)
```
### 3.3 父 LLM 自助通道(关键补强)
现状 LLM 有 `ai_sub_agent_list`(列轨迹元数据)但**没有读单条轨迹全文的工具**(前端卡经 IPC `ai_sub_agent_list` 拉的是轨迹列表,LLM 侧工具面无对应读全文入口)。
新增 LLM 工具(注册进 tool_registry,risk=Low 只读):
```
ai_sub_agent_trace(conversation_id, agent_id) -> { summary, status, rounds, tokens, messages_tail? }
```
- 返回该子代理轨迹的关键内容(summary 全文 + 末 N 条消息摘要),**只读、走现有 V44 落库数据**,零新存储;
- system prompt 子代理指引段补一句:「追问子代理产出细节时,先调 ai_sub_agent_trace 而非重新 spawn」;
- 这同时是 namespace 淘汰治理( sister 设计文档)中「报告蒸发死路」的兜底——即使 namespace 条目被淘,轨迹在 DB,工具可读。
### 3.4 「已消化」与上下文压缩的联动(可选增强,默认关)
`AgentFinishedCard.digested=true` 时,前端在后续轮次注入的用户消息尾部不加任何内容(保持零侵入);该标记仅影响 UI 与用户心智。**不**把 digested 同步回后端压缩策略(避免跨端状态同步复杂度)。
## 4. 改动面清单
| 层 | 文件 | 改动 |
|---|---|---|
| 前端 | `src/composables/ai/aiShared.ts` | AgentFinishedCard+digested;重建路径读 KV 合并 |
| 前端 | 完成卡渲染组件(MessageList 内 SubAgentCard 或同域) | 降级态渲染+标记动作+批量 |
| 前端 | KV 读写封装(复用现有 settings composable) | get/set `agentCardDigested:{convId}` |
| 后端 | `src-tauri/src/commands/ai/agentic/sub_agent.rs` | 暴露 ai_sub_agent_trace IPC(读库组装) |
| 后端 | `tool_registry.rs` | 注册 ai_sub_agent_trace(Low/只读白名单) |
| 提示词 | system prompt 子代理指引段 | 追问先 trace 不重跑 |
## 5. 风险与对策
| 风险 | 对策 |
|---|---|
| KV 标记与轨迹删除不同步(轨迹删了 KV 残留) | 重建路径只对「轨迹存在的卡」应用标记,孤儿 key 自然失效,无需清理任务 |
| trace 工具被滥用(LLM 反复查大轨迹) | 返回体加尾部分页/上限(messages_tail ≤ 20 条),复用 T-05 工具结果截断口径 |
| 卡交互改动碰 MessageList 渲染热点 | 卡是独立组件,降级态纯展示层,vue-tsc+手测三态(未消化/已消化/展开) |
## 6. 验收
1. 标记已消化 → 卡单行化 → 重启应用后仍单行(KV 持久);
2. 展开已消化卡 → 全文复原;
3. LLM 调 ai_sub_agent_trace 能返回指定子代理 summary 全文;
4. 未做任何标记的会话,渲染与现状逐像素一致(回归门);
5. cargo test(新增 trace IPC 组装单测)+ vue-tsc 0 error。
## 7. 拍板点(2 项)
- **拍板1**:旧卡自动折叠(§3.2)默认开还是关?建议开( touched 语义保护手动展开)。
- **拍板2**:ai_sub_agent_trace 本期做还是随 namespace 治理批一起做?建议**随 namespace 批**(同域文件+互为兜底)。
## 8. 工作量估算
约 1-1.5 天:digested+KV(2h)+ 卡降级渲染(3h)+ trace IPC+注册(3h)+ 提示词(0.5h)+ 测试(2h)。