# 子代理完成卡双轨「已消化」降级 · 设计(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)。