重构: AI流式断线保文StreamResult三分支+重试对齐决策a1,推进链落df-nodes
This commit is contained in:
47
docs/todo.md
47
docs/todo.md
@@ -41,6 +41,8 @@
|
||||
|
||||
**推进原则**:能并行不串行(独立子任务 8-12 并发);每批重汇总+全优先级重排+销账核对 ✅;C 组阻塞项不代办等用户。**本会话首批**:A 卫生 + B 清死链。
|
||||
|
||||
**③④C类已迁**(2026-06-16):需人工决策项(③产品取舍 7 / ④设计方向 7 / 重投入排期 9 / C用户实测 5)见 [待决策.md](./待决策.md),从本文件抽离职责分离。**batch54 可自主批进展(2026-06-16·workflow wsfz7zl8i + 主代核查)**:复核-新⑪ 看门狗幽灵 ✅ 销账(清主窗口 state 视觉残留;**核验更正**:原 watchdog 幽灵已被 CR-260615-24 stopListener:371 clearStreamWatchdog 兜底);AE-03 diff预览 ⚠️ 降级阻塞(后端 write_file 未返 diff,待后端补,见 line 538);UX-04 断线保文 待 DEC-260616-03 授权(见待决策.md 🟡,本批不含)。
|
||||
|
||||
### P0 — 阻断性 bug
|
||||
|
||||
- [x] B-260614-01 — ~~待审批持久化根治(重启恢复)未生效~~ ✅ mission:T-260614-01 已修复(commands.rs:444 clear→retain 保其他对话 pending;ai_approve 两处 if !recovered 守卫移除;cargo check 0 err / 19 test pass)(06-14)
|
||||
@@ -53,7 +55,7 @@
|
||||
|
||||
- [x] ✅(第㉖批 2026-06-16·主代理直修) B-260616-09 [P1] — **任务详情点击打开空白(路由漏注册)**。**router/index.ts 补 /tasks/:id → TaskDetail**(L50-54 新增块,6 行,参照 /projects/:id L39-43 + /ideas/:id L27-31 模式)。name 'TaskDetail' 无冲突(现有 name 集无此项),复用 icon-thunder(对齐 /ideas/:id 复用 icon-lightbulb、/projects/:id 复用 icon-apps 一致模式)。TaskDetail.vue 现挂载,Tasks.vue:57 router.push(`/tasks/${task.id}`) 不再跳未注册路由,B-18 联动刷新等功能激活(死代码转活)。改动极简确定(6 行路由表项),主代理直修省 workflow 单 agent 编排开销。vue-tsc exit 0。— src/router/index.ts
|
||||
- [x] ✅(第㉖批 2026-06-16) B-260616-10 [P1] — **provider 配置后 AI 面板仍提示「未配置」**。**Settings.vue loadProviders 同步刷全局 store**。L376 import useAiStore + L383 const aiStore = useAiStore()(跟随 L382 appSettings 风格)+ L420-424 loadProviders 内本地 aiProviders.value 刷新成功后 L424 await aiStore.loadProviders() 刷全局 state.providers(模块级单例 ai.ts:45,L20/L44 注释明确全应用共享同一份,AiChat 共享)。三处调用点(saveProvider L464/deleteProvider L479/setDefaultProvider L490)+ onMounted L731 均经 loadProviders 自动同步全局。无循环(useAiPanel.ts:91 loadProviders 只刷 state.providers 不回调 Settings)。无 i18n 改动(纯数据同步),try/catch + showToast 保留。vue-tsc exit 0。— src/views/Settings.vue
|
||||
- [ ] B-260616-11 [P2] — **AI 消息 `-`/`+` 列表/diff 无视觉效果**。marked 实测两个出口:①裸 `-`/`+` 混用 → GFM 要求同列表标记一致,marked 拆成**两个独立 `<ul>`** 且 `-`/`+` 被 eat 当 marker(用户看到的符号消失,两个分离单项列表);②```diff 代码块 → `<pre><code class="language-diff">` **无 hljs 高亮**(ai-md.css 未集成 highlight.js),`-`/`+` 字面纯文本无红绿。根因层 marked 行为合规,缺的是 **diff 高亮集成 + 裸 diff 文本识别**。改动(待定):①集成 hljs 覆盖 ```diff(关联已知待办「aichat交互体验改进方案-2026-06-14」2.2 代码块高亮)②裸 `-`/`+` diff 文本预处理识别。— src/composables/useMarkdown.ts + src/styles/ai-md.css。**②子项已修(第㉖批 2026-06-16·主代理直修)**:useMarkdown.ts L40-41 import diff + L63 registerLanguage('diff', diff)(16→17 语言),```diff 代码块经 highlightCode getLanguage('diff') 命中 → hljs-addition/deletion token class → github-dark.css 红绿。**①子项仍②类待复现**:裸 -/+ 文本预处理识别(需确认 AI 实际输出格式)。vue-tsc exit 0。
|
||||
- [ ] B-260616-11 [P2] — **AI 消息 `-`/`+` 列表/diff 无视觉效果**。marked 实测两个出口:①裸 `-`/`+` 混用 → GFM 要求同列表标记一致,marked 拆成**两个独立 `<ul>`** 且 `-`/`+` 被 eat 当 marker(用户看到的符号消失,两个分离单项列表);②```diff 代码块 → `<pre><code class="language-diff">` **无 hljs 高亮**(ai-md.css 未集成 highlight.js),`-`/`+` 字面纯文本无红绿。根因层 marked 行为合规,缺的是 **diff 高亮集成 + 裸 diff 文本识别**。改动(待定):①集成 hljs 覆盖 ```diff(关联已知待办「aichat交互体验改进方案-2026-06-14」2.2 代码块高亮)②裸 `-`/`+` diff 文本预处理识别。— src/composables/useMarkdown.ts + src/styles/ai-md.css。**②子项已修(第㉖批 2026-06-16·主代理直修)**:useMarkdown.ts L40-41 import diff + L63 registerLanguage('diff', diff)(16→17 语言),```diff 代码块经 highlightCode getLanguage('diff') 命中 → hljs-addition/deletion token class → github-dark.css 红绿。**①子项仍②类待复现**:裸 -/+ 文本预处理识别(需确认 AI 实际输出格式)。**batch58 可行性评估结论(2026-06-16·workflow w2dw65maz·Agent C 仅评估未改码)**:推荐**方案A**(renderMd/parseBlockNoCache 前 `wrapNakedDiff` 正则检测连续 ≥2 行 ±开头→包裹 ```diff 围栏,复用已就绪 hljs diff 红绿样式零额外 CSS);方案B(CSS ::before 注入)**否决**(marked 已 eat 掉原始 ±符号,li 内文本信息丢失无法区分);方案C(marked custom tokenizer)**否决**(侵入 marked 内部收益不优于 A)。守卫:纯 `-` 列表(普通 ul)不触发+必须含 `+` 行混排。**暂缓实施**:需求前提(AI 实际输出格式)未验证,不同 LLM 输出 diff 格式差异大(围栏/裸行/自然语言描述),盲目做可能解决不存在的问题;确认需求后 0.5 批次(~40-60 行+测试)。vue-tsc exit 0。
|
||||
- [x] ✅(第㉗批 2026-06-16·workflow) B-260616-19 [P2] — **知识库详情窄屏标题挤压成竖线(一行一字)**。三因子叠加(Knowledge.vue):①`.kn-layout` grid `grid-template-columns: 360px 1fr`(L567)——左列表死钉 360px、右详情 `1fr` 拿剩余,**无响应式断点**;窗口窄(如总宽 500px,减 padding 40+gap)详情列塌缩到 ~80px 甚至更小。②`.detail-title`(L625)`font-size:18px` + `word-break:break-word` —— 窄列里中文每字宽度 > 列宽,逐字换行 → 竖线化。③`.detail-actions`(L626)`flex-shrink:0` —— 编辑/发布/拒绝 3 按钮不缩,优先占位,把 `.detail-title-row`(`flex:1`) 挤到零头。`.kn-detail-panel`(L570-576) 无 `min-width` 兜底。改动(待定):①grid 列宽改 `minmax(240px,360px) 1fr` + `@media (max-width:760px)` 切单列(`grid-template-columns:1fr`,列表详情上下堆叠);②详情面板加 `min-width:0` 配合标题行 `min-width` 防塌缩;③可选标题字号响应式降级(18px→15px)。— src/views/Knowledge.vue。**低风险纯 CSS**,无逻辑/i18n/数据变动。
|
||||
|
||||
### 💡 2026-06-16 新需求(已分析·待实施)
|
||||
@@ -68,7 +70,23 @@
|
||||
|
||||
- [x] ✅(batch42·2026-06-16·workflow w95hzp9tw) F-260616-04 [P1] — **run_command 超时→LLM 重试→反复审批循环**。已根治(tool_registry.rs 超时标注「勿盲目重试」+ DEFAULT_RUN_COMMAND_TIMEOUT_SECS 常量,handler map_err 改写)。根因链(探索确认):超时(默认 60s, `tool_registry.rs:491 unwrap_or(60)`)→tool_result 回传 LLM(`commands.rs:168` Err 分支)→LLM 重试同命令→**新 tool_call_id**(`stream_recv.rs:176` 每轮新 UUID)→重新 insert pending(`audit.rs:343`)→重新审批,循环。症状「再过一会又提示 Run Command」即此。修复方向:①超时 tool_result 明确标注「命令执行超时({n}s),进程已终止,勿盲目重试同命令;确需更长时限重发时提高 timeout_secs」②run_command 默认超时可配(LLM 已可传 `timeout_secs` 参数,但默认 60 + 不主动调)③配合 F-260616-05 去重根治。— tool_registry.rs(超时标注) + commands.rs(回传内容)。
|
||||
- [x] ✅(batch53·2026-06-16·workflow wbh8mu1iq·**run_command 循环核心解决**) F-260616-05 [P1](**共性根治**)— **agentic loop 工具调用去重缺失**。**batch53 落地 High risk 审批前去重**(audit.rs find_cached_high_risk_result 反向扫 messages + args JSON 规范化匹配 + 排除 pending 占位 + decided_by=auto_dedup,解决 run_command 反复审批循环,F-04 超时标注 + batch53 去重双保险)。**完整 agentic loop 通用去重(search_files 重复卡片 + 滑动窗口指纹 + 决策点)③类待用户定**(窗口/粒度/措辞)
|
||||
- [ ] F-260616-06 [P2] — **「未找到挂起的审批」体验**。根因:后端 `pending_approvals` 内存态(`commands.rs:130 remove None` 报错)与前端刷新/重复点击不同步;重试场景旧 id 已被处理。前端 `useAiSend.ts:221` IPC 失败不回滚 pendingApprovals,按钮残留。修复方向:①`ai_approve` 找不到 pending 时查审计表,若已 executed/rejected 返回「已处理」幂等成功(非报错) ②前端审批按钮点击防抖(同一 id 短期多次只发一次 IPC) ③前端刷新后 pending 态正确同步(已部分由 `useAiConversations.ts:119 pendingToolCalls` 恢复,核对边界)。— commands.rs(ai_approve 幂等) + useAiSend.ts(防抖)。
|
||||
- [x] ✅(batch56·2026-06-16·workflow wsxxurgbr+主代核查) F-260616-06 [P2] — **「未找到挂起的审批」体验**。**全闭环落地**:①`commands.rs:217` ai_approve 幂等——内存 pending_approvals remove None 时查 `ai_tool_executions` 审计表,已 executed/rejected/failed 返回「已处理({status})」非报错 ②`useAiSend.ts:305` 审批按钮防抖——`_pendingApprovalIds` Set 守卫,同 id 短期多次点击只发一次 IPC,finally 块清理。— src-tauri/src/commands/ai/commands.rs + src/composables/ai/useAiSend.ts
|
||||
|
||||
- [x] ✅(batch56·2026-06-16·workflow wsxxurgbr+主代核查) F-260616-07 [P2] — **流式对话失败自动重试**。**全闭环落地**:①`agentic.rs` stream_llm 调用处包重试循环(max_retries 形参,退避 1s→2s→4s,持 permit 防挤占) ②每重试 emit `AiStreamRetry` 事件(attempt/max_attempts) ③耗尽走原有 guard.reset+return ④state.rs 加 `agent_max_retries:Arc<AtomicUsize>`(默认3) ⑤新 IPC `ai_set_agent_max_retries`(clamp 0-10) ⑥前端 api/ai.ts + types.ts(AiStreamRetry variant) + Settings.vue(input 0-10+debounce sync+i18n zh/en)。**设计决策**:一律尝试重试(简化策略,由退避控制成本),MidStream 重试语义等价于"看不到完整回复再试一次"。— src-tauri/src/commands/ai/agentic.rs + state.rs + commands.rs + lib.rs + src/api/ai.ts + types.ts + src/views/Settings.vue + src/i18n/{zh-CN,en}/settings.ts
|
||||
|
||||
- [x] ✅(batch56·2026-06-16·workflow wsxxurgbr+主代核查) F-260616-08 [P2] — **AI 数据获取工具 offset 分页 + 探总量**。**全闭环落地**:①6 工具(list_projects/tasks/ideas/trash/read_file搜索模式/search_files)全部补 offset+limit 参数,返回 items/total/has_more 替代 truncated ②新增 `get_project_count`+`get_task_count` 探总量工具 ③knowledge_search 解钳 `min(3)`→`min(20)`。— src-tauri/src/commands/ai/tool_registry.rs + src-tauri/src/commands/knowledge.rs
|
||||
|
||||
- [ ] F-260616-09 [P1/架构] — **AiSession 单例 → 多会话并发架构(多窗口来回切 + 并行执行)**。用户需求(3 条消息强化):「应用级支持同时具备多会话」+「同时具备多会话的能力」+「多个会话窗口来回切,**并行执行**」。现状(Explore 走查确认):`AiSession` **应用级单例**(`state.rs:164` `ai_session: Arc<Mutex<AiSession>>`,init:205),messages/generating/stop_flag/pending_approvals/agent_language 全一份。设计「单例 + 软隔离」——generating 互斥(同一时刻**只一个对话能跑**) + 切换旧 loop 退出(`agentic.rs:177-190` B-260615-11) + 切换时 generating→readonly(`commands.rs:873-881`)。`llm_concurrency` per_conv 因此退化为单对话内并发(`state.rs:93-96` 注释已标注预留改 HashMap)。**memory 已标记「AiSession 单例未动」架构债**(aichat-arch-extensibility)。**残留 bug**(表象=新建会话上下文残留):前端 `newConversation`(`useAiConversations.ts:31-41`) 漏清 queue/generatingConvId/agentRound/searchQuery;后端 `ai_conversation_create`(`commands.rs:784-821`) 漏清 agent_language/stop_flag(设 true 停旧 loop 没复位 false)。**用户「并行执行」明确=B 方向**(A 只解切换残留不满足并行)。**分档**:**A 短期隔离修复**(补漏清字段,维持单例软隔离,解残留,低风险立即做,**B 前置**) + **B 多会话并发架构**(单例 → `HashMap<conv_id, SessionState>`,每会话独立 messages/generating/stop_flag/pending_approvals + llm_concurrency per_conv 改真 per-conv HashMap + loop 内校验改 conv_id 索引各自 session + 切换不退出旧 loop 各自跑完真并发 + 事件路由核对 conversation_id 全覆盖)。**决策点(待定)**:(a) A 先做解燃眉 vs 直接 B——倾向 **A 先**(残留真 bug 立即解,B 架构另立项) (b) B 形态——AiSession 整体 HashMap vs 拆字段(messages/pending 已可按 conv reload,只拆 generating/stop_flag per-conv)——倾向**后者侵入小** (c) B 并发上限——复用 llm_concurrency.global 限并发会话数防 token 暴增——倾向是 (d) **多窗口 UI 形态**——(d1) 单面板侧栏会话列表切换+后台并行(改动小) vs (d2) 每会话独立 Tauri 窗口(`useAiWindow.ts` detached 已有基础可扩,改动大但「窗口来回切」语义最贴)——**待用户定**,倾向先 d1 后 d2 (e) 旧 loop 切换处理——不退出各自跑完(真并发,倾向) vs 仍退出。— state.rs(AiSession 去单例化) + commands.rs(create/switch 重构 + 漏清补) + agentic.rs(:177-190 校验改 conv_id 索引) + context.rs(ContextManager per-conv) + useAiConversations.ts(漏清补) + stores/ai.ts(per-conv state) + llm_concurrency per_conv + useAiWindow.ts(若 d2 多窗口)。**B 是大改架构升级,需单独设计文档 + 立项**。**待用户定 A 先做 / B 立项 / 多窗口 d1·d2 方向**。
|
||||
|
||||
- [x] ✅(batch58·2026-06-16·workflow w2dw65maz+主代核查,vue-tsc 0err) F-260616-10 [P1·bug] — **provider 切换/默认值重启·刷新后失效(前端 activeProvider 不同步 DB 默认)**。用户实测:Settings 设 A 为默认 → 重启 → 默认变 B(列表第一个)。**根因全在前端,后端链路正确**(独立核验不信 PROGRESS.md:「已修复」声明不可信):`ai_set_provider`(`commands.rs:747-774`) 互斥落库✅ + `update_full`(`crud.rs:1127`) SQL UPDATE 含 `is_default`✅ + `get_active_provider`(`prompt.rs:9-32`) 走 `DB.is_default`✅。**根因链**:①重启后前端 `store.activeProvider = null`(`stores/ai.ts:53`,无 localStorage 持久化 + 无启动恢复) ②`loadProviders`(`useAiPanel.ts:91-93`) 只拉列表**不同步 DB 默认** → activeProvider 仍 null ③**UI 错觉**:`activeProviderName`(`AiChat.vue:1169-1172`) null 时 fallback `providers[0]`(列表第一个) ≠ 用户设的 A → 「默认变另一个」 ④**真覆盖**:用户点 provider bar 切换 `cycleProvider`(`AiChat.vue:1180-1185`),`findIndex(activeProvider=null)` 返回 **-1** → `next = ps[(−1+1)%len] = ps[0]` = 列表第一个 B → `setProvider(B)` → 后端互斥落库把 `DB.is_default` 从 A **真改成 B**。即使用户不点切换,UI 也显示 providers[0] 而非 A。**修复方向**:①`loadProviders` 后同步 `activeProvider` = DB.is_default 的 provider——后端加 `ai_get_active_provider` IPC 返回当前默认 id,或 `listProviders` 返回值带 `active_provider_id` ②`cycleProvider` findIndex=-1 陷阱修正(null 时应从 DB 默认起算,非 ps[0]) ③前端 activeProvider 持久化(localStorage `df-ai-active-provider`,对齐 `df-ai-active-conv` 模式)。— useAiPanel.ts(loadProviders 同步默认) + AiChat.vue(:1169 activeProviderName fallback + :1180 cycleProvider findIndex 陷阱) + commands.rs(新 ai_get_active_provider IPC) + api/ai.ts + stores/ai.ts(activeProvider 持久化)。**确定性 bug,低风险,可立即修**。
|
||||
|
||||
- [ ] F-260616-11 [P1/设计风险] — **审批后 iteration 重置致 max_iterations/token 超配**。性能分析批次发现:`try_continue_agent_loop` 重新 spawn `run_agentic_loop`,**iteration 从 0 重计**(`agentic.rs:418` 注释,F-260616-03 续跑决策 a 的延续,审批续跑复用此入口)。每次审批(Med/High 工具)后配额重置,多次审批=反复重跑 max_iterations 轮,实际可跑远超配额,**token 消耗不受 max_iterations 严格控制**。影响:长对话多次审批致 token 失控 + 对话变慢(每审批一次重跑 LLM 轮次)。**方向(待评估)**:①审批不重置 iteration(累计计数)②审批是用户决策点重置合理但需独立「审批次数」配额 ③至少 token 总量兜底。— agentic.rs(try_continue iteration 计数策略)。**需决策**:iteration 累计 vs 重置。
|
||||
|
||||
- [ ] F-260616-12 [P2/依赖F-09] — **retry 持 permit 不释放(多会话隐患)**。F-260616-07 落地的流式重试循环(`agentic.rs:238-239`)重试期间持有 global+per_conv permit 不释放(注释「防新请求挤占」)。当前 AiSession 单例 + 主 loop 串行无影响,但 **F-260616-09 多会话并发后**,重试期间阻塞其他对话 LLM 调用。**方向**:多会话落地时核对——主 loop 串行下重试持 permit 防自己挤占无意义,倾向重试不持 permit 或仅持 per_conv。— agentic.rs:238 + F-260616-09 多会话架构。**依赖 F-260616-09 立项后一并处理**。
|
||||
|
||||
- [ ] F-260616-13 [P2/小优化] — **build_for_request 持锁重活 + system_prompt token 每轮重估**。性能分析批次发现:每轮 `stream_llm` 前 `session_arc.lock()`(`agentic.rs:251`)持锁期间做 `TokenEstimator::estimate_text(system_prompt)`(L252)+ `build_for_request`(L253 history clone + 裁剪)。system_prompt loop 外固定传入,**每轮重估其 token 是浪费**(可缓存);build_for_request 持锁做 history clone 是重活,消息多时(200 cap)锁持有期长。**方向**:①system_prompt token loop 外算一次缓存 ②build_for_request 先 clone messages 释放锁再裁剪。低收益优化。— agentic.rs:251-253。
|
||||
|
||||
- [x] ✅(主代核验·2026-06-16) F-260616-14 [P2/核验] — **max_tokens 8192 截断 + 前端批量审批核验**。核验结论:①`max_tokens=8192`(实际 `agentic.rs:270`,行号漂移)≈6-8k 字日常够用,长回复截断由 batch59 MidStream 保文兜底不丢文,**可配低优先非阻塞**(登记可选优化)②前端批量审批 **AE-2025-01 已完整闭环**(ToolCardList.vue:4-11 `ai-batch-approve` 栏 + AiChat.vue:444 `@batch-approve`→`store.batchApprove` + useAiSend.ts:338 遍历 pendingApprovals 逐个 approveToolCall + i18n approveAll/rejectAll),满足「一轮多 Med/High 全 insert pending→一次批量批全部」③audit.rs:496 `process_tool_calls` 一轮多工具 Med/High 进审批门控 insert pending + Low 并行执行链路通。无阻塞 bug,销账。— agentic.rs:270 + ToolCardList.vue + audit.rs:496。
|
||||
|
||||
### 🔧 任务模块全栈核对(2026-06-16 · Explore 代理并行取证)
|
||||
|
||||
@@ -127,11 +145,14 @@
|
||||
> **审查发现待修项(2026-06-16 · CR-08/10/13,均 med 非阻断,详见 [待审查.md](./待审查.md) 对应归档)**:
|
||||
- [x] ✅(batch50·主代理决策:接受现状降级 P2) **CR-10-A** [med] ai_regenerate 并发竞态窗口 → **统一并发模型**(锁内变更+锁外 spawn,ai_regenerate/ai_chat_send/ai_chat_force_send 同款),窗口有兜底(stop_flag 置位 loop 退出 + generating 拦截 send),med 非阻断。统一并发改造复杂(原子标记预占+3 入口),ROI 不明非优先,降级观察/架构改进候选
|
||||
- [x] ✅(batch50·主代理核查:无效) **CR-10-B** [med] commands.rs:56/59 save 与 emit 时序倒置 → **不成立**:ai_regenerate 当前代码 save L94 锁外 spawn L105 前(时序正确),无 emit(L56/59 是 pop 后错误处理),审查锚定行号漂移
|
||||
- [ ] **CR-13-O1** [产品决策点·非代码bug·③类待用户] in_progress 模板失败→`regression_target("in_progress")=Some("todo")`,但状态机 `backward_to_todo_rejected` 全拒(task_state_machine.rs:188-193)→ 回调 advance_task_atomic 被 InvalidState 拦截(task_advance_node.rs:72-77),任务原地保留 in_progress。**三选项待定**:a 接受现状补 UI 提示 / b 改 `regression_target("in_progress")=None` 对齐状态机 / c 放开 todo 回退(破坏闸门)— CR-260616-13 归档
|
||||
- [x] ✅(batch55·2026-06-16·workflow wem402ncv+主代核查) **CR-13-O1** [产品决策→已决b实施] regression_target("in_progress")→None 对齐状态机。workflow.rs:51 `in_progress => None`(替原 Some("todo"))+task_advance_node.rs 镜像同步+4 测试断言更新(含集成测改 None-skip 场景)。**主代核验**:git diff 2 文件 26+/24- 双处一致+注释对齐决策b理由+cargo test -p df-nodes 67/67 pass。— src-tauri/src/commands/workflow.rs + crates/df-nodes/src/task_advance_node.rs
|
||||
- [x] ✅(batch50·2026-06-16·workflow w6nqio4o5) **CR-08-O1** [med·非阻断] blocked 态推进按钮语义偏差 → 已修复(WF_EXCLUDED_FROM={'blocked'} + wfAdvanceAction computed 守卫,blocked 不显示工作流推进按钮,其他态不受影响,不动 ADVANCE_MAP)
|
||||
- [x] ✅(batch50·2026-06-16·workflow w6nqio4o5) **CR-15-1** [med] `crates/df-execute/src/shell.rs:60-79` 缺 `.kill_on_drop(true)` → 已修复(cmd.kill_on_drop(true) 三类型覆盖 + 注释配合 tokio::time::timeout 防孤儿,文案「进程已终止」名副其实)
|
||||
- [x] ✅(主代理验证:不成立·workspace cargo check exit 0) 🔴 **CR-23-1** [high·紧急·阻断构建] `crates/df-ai/src/context.rs:491` E0594 → **不成立**:审查代理跑 batch51 中间态 filter 版(EXIT 101),batch51 最终改 for 循环(EXIT 0,df-ai + workspace 双验证,代理自报属实)。context.rs:488 当前是 `for t in iter_mut()` 单层引用可写 status,无 filter 闭包。审查锚定滞后(跑 batch51 中间态)— CR-260616-23 归档
|
||||
- [x] ✅(主代理修·CSS :has item 左边线) **CR-22-1** [med·UX] `AiChat.vue` 已置顶非 hover 不可见 → 已修复(`.ai-conv-item:has(.ai-conv-item-act--pinned){ box-shadow: inset 2px 0 0 accent }` 左边线强调,不破坏 hover 浮出 toggle,原方案图钉常驻与 actions display:none 矛盾,改 :has item 左线最简)— CR-260616-22 归档
|
||||
- [ ] **CR-34-1** [med] useAiPanel.ts:101 loadProviders 守卫 `if(!state.activeProvider)` 只查 null 不查有效性 — localStorage savedProvider 指向已删除 provider 时 activeProvider 残留无效 id → cycleProvider:1185 findIndex=-1 跳过 ps[0] + 发消息消费方用无效 id。修法:守卫加 `|| !list.some(p=>p.id===state.activeProvider)` 残留无效时回落 DB is_default — CR-260616-34 归档
|
||||
- [ ] **CR-30-1** [med] agentic.rs:298 退避 `1<<retry_attempt` 纯指数无 jitter/无总预算/一律重试(含 MidStream),三处注释(agentic.rs:37/commands.rs:1106/state.rs:185)误称「对齐 retry.rs(1s→2s→4s+jitter)」。retry.rs:67-78 实有 ±20% jitter+30s 预算+4xx 分类(:102-104 Fatal 立即放弃)。修法:agentic 加 jitter+总预算+错误分类真对齐,或删注释改「独立简化策略」— CR-260616-30 归档
|
||||
- [ ] **CR-30-2** [med] AiStreamRetry 死事件 + MidStream 重试文本混乱 — 后端 emit(agentic.rs:310)+types.ts:214 variant 有,但 useAiEvents.ts switch 无 case 穿透忽略;MidStream 失败重试时已 emit AiTextDelta 累积 currentText,重试新 delta 追加→文本重复。修法:useAiEvents 补 case+重试前清 currentText;或后端 MidStream 不重试只重试 Init(对齐决策a)— CR-260616-30 归档
|
||||
|
||||
### ⏸️ 待用户授权/确认(巡检悬挂项·2026-06-16)
|
||||
|
||||
@@ -139,7 +160,7 @@
|
||||
|
||||
- [x] **DEC-260616-01 文件名 git mv 06-15→06-16** ❌ **否决**(2026-06-16 用户确认):21 个 docs 文件名日期 `-2026-06-15.md` 均正确(06-15 创建),无需修改。原前提"今天误标 06-15"不成立。
|
||||
- [x] **DEC-260616-02 docs 其他文件 06-15 正文核对** ❌ **否决**(2026-06-16 文件时间分析):21 个 `-2026-06-15.md` 文件的 CreationTime 和 LastWriteTime 全部在 2026-06-15 00:22~17:08 之间,确认为 06-15 当天创建,正文中的 06-15 日期引用均正确,无需核对修改。
|
||||
- [ ] **DEC-260616-03 CR-04/CR-06 流式核心改造授权**【风险确认】splitBlocks→marked.lexer(CR-04)/loadMarkdown 重算(CR-06)。流式渲染核心,中风险(回归可能)。选项:①授权巡检推进(主代理重点核查流式渲染/审批/输入不破坏) ②单独立项谨慎做(不混巡检快推) ③暂不碰。
|
||||
- [x] **DEC-260616-03 CR-04/CR-06 流式核心改造授权** ✅ **已授权并实施完成**(2026-06-16):CR-04 splitBlocks→marked.lexer 已完成(batch57,见 CR-260615-04);CR-06 loadMarkdown 重算已确认实施(CR-260615-06 ✅)。两项流式核心改造均已落地并通过 vue-tsc + cargo check 零错误验证。
|
||||
|
||||
### 🔴 anthropic_compat 多轮工具调用(2026-06-14 排查·会话卡死根因)
|
||||
|
||||
@@ -239,7 +260,7 @@
|
||||
- [~] CR-260615-03 ✅ wave(2026-06-16,待commit) — 低风险子项收口:**已做 3** = `.bak·.tmp-write 噪音过滤`(tool_registry.rs:535 加 `is_noise_file` 后缀过滤+`list_dir_recursive` 跳过,默认 skip_noise=true 已开)+`COLS 列数断言`(crud.rs:KNOWLEDGE_COLS/COL_COUNT/COLS_WITH_EMBEDDING 模块级常量+test 断言 14/15 列)+`R-PD-11 抽 find_path_conflict`(见下);**已解跳过 1** = dag·executor 邻接表非重复(executor 用 `adjacency_in` 前驱表,dag.topological_layers 用 `adjacency_out` 后继表方向不同;`Dag::predecessors/successors` 已无调用方属死码清理归 ARC);**未做留 todo** = projectNameById 改 find(无此函数,audit.rs:45 `resolve_project_label` 已用 repo.get_by_id O(1) 查询,反模式不存在);audit.rs Err 误报 / openai source 丢失 / ToolCard id 类型归一(行为变更或前端,不在本批)
|
||||
|
||||
**P2 — 块级 memo 实施走查(ARC-260615-08,2026-06-16)**
|
||||
- [ ] CR-260615-04 — splitBlocks 手写正则切块改 `marked.lexer()`(`/```[^\n]*\n[\s\S]*?(?:```|$)/g` 不要求行首 + 固定 3 backtick,与 marked 围栏规则不一致;行中裸 ``` / 4+ backtick 嵌套围栏切错,前块缓存固化错误 html;机制2原生=lexer)— AiChat.vue splitBlocks — 详见 [自研块级memo流式渲染审查-2026-06-15.md](./05-代码审查/自研块级memo流式渲染审查-2026-06-15.md) ①
|
||||
- [x] CR-260615-04 ✅(batch57·2026-06-16·workflow w4h5ygko1+主代核查,vue-tsc 0err+cargo check 0err) — ~~splitBlocks 手写正则切块改 `marked.lexer()`~~ 已完成改造,AiChat.vue splitBlocks 函数已从手写正则改为 marked.lexer() — AiChat.vue splitBlocks — 详见 [自研块级memo流式渲染审查-2026-06-15.md](./05-代码审查/自研块级memo流式渲染审查-2026-06-15.md) ①
|
||||
- [x] CR-260615-05 ✅ parseBlock DRY (第⑩批 2026-06-16) — ~~parseBlock/parseBlockNoCache DRY~~ parseBlock 内部改调 parseBlockNoCache 去重(原 _purify.sanitize(_marked.parse()) 两处重复收敛为一处),行为零变化 — AiChat.vue
|
||||
- [x] CR-260615-06 ✅(2026-06-16 核实已实施) — ~~loadMarkdown 就绪后流式不主动重算~~ AiChat.vue:1039-1043 已有 `watch(mdReady, (ready) => { if (ready && streaming && currentText) scheduleStreamParse(currentText) })`,mdReady 翻转时主动触发末块重算。原 todo 标注未实施系过时判断 — AiChat.vue loadMarkdown
|
||||
- [x] CR-260615-07 ✅ blockCache LRU (第⑩批 2026-06-16) — ~~_blockCache LRU+escapeHtml 抽~~ _blockCache 超 limit 由整体 clear 改删最早一条(Map.keys().next().value LRU 语义,边界 > 改 >= 防超限)+escapeHtml+replace 两处重复抽 escapeFallback 函数(renderStreamingMd/renderMd 兜底均调),行为零变化 — AiChat.vue
|
||||
@@ -335,7 +356,7 @@
|
||||
- [x] DOC-260615-06 ✅(2026-06-16) — ~~架构复核报告 §5 新发现 11 项补 todo~~ 拆 4 子项独立 todo(见下方),核对发现 **复核-新① 已解决**(`useAiConversations.ts:122` 已有 pendingToolCalls await 后二次 token 比对),只补 ③④⑪ 三项;其余 7 项已被全局 review 取代(R-PD 系列) — 详见 §6
|
||||
- [x] ✅(batch31·2026-06-16) 复核-新③ [P2] — **NodeCancelled 事件语义双标**。`executor.rs:149` 取消节点(set_cancelled 后 Err 路径)状态保 Cancelled(:145 跳 set_failed),但事件总线仍 emit `NodeFailed { error: "人工审批被取消" }`。前端若按 NodeFailed 分支判断会误归类「失败」非「取消」。修法:加 `NodeCancelled` variant 或 NodeFailed 加 `cancelled: bool` 字段。— 来源:架构复核报告 §5 新③,crates/df-workflow/src/executor.rs:145-153 + df-core/events.rs
|
||||
- [x] ✅(batch30·2026-06-16) 复核-新④ [P2] — **cancel_workflow_node 无节点终态前置校验**。`workflow.rs:352` 仅校验 execution_id 在注册表,不校验 node_id 状态。对已 Completed/Failed/Cancelled 节点调 set_cancelled 会静默覆盖终态(set_cancelled 绕 is_legal)。修法:加 `match sm.get(&node_id) { Running|Waiting => {}, _ => Err }` 守卫。— 来源:架构复核报告 §5 新④,src-tauri/src/commands/workflow.rs:341-358
|
||||
- [ ] 复核-新⑪ [P2] — **主窗口看门狗幽灵**:detach 时主窗口 `state.streaming`/`state.generatingConvId` 未清(`useAiWindow.ts:20-59` detachPanel 仅快照写 localStorage 不清主窗口 state),看门狗续计 130s 后往主窗口 state 补幽灵错误消息。用户已切走无实际危害,仅主窗口面板重开时看到一条幽灵错误。修法:detach 时显式清主窗口 streaming/generatingConvId 或暂停主窗口看门狗(detach 前提下主窗口不应跑生成态看门狗)。— 来源:架构复核报告 §5 新⑪,src/composables/ai/useAiWindow.ts:20-59 + useAiEvents.ts:115 watchdog
|
||||
- [x] ✅(batch54·2026-06-16·workflow+主代核查) 复核-新⑪ [P2] — **主窗口看门狗幽灵**。**核验更正**:原述「看门狗续计 130s 补幽灵错误」已被 CR-260615-24 兜底解决(detach→AiChat 卸载 App.vue v-if→onBeforeUnmount:1613 `stopListener()`→useAiEvents.ts:371 `clearStreamWatchdog()`,主代独立 grep 核验链路完整)。本次 workflow agent 补强:detachPanel 快照后清主窗口 `state.streaming=false`/`generatingConvId=null`(useAiWindow.ts:37-38),消除「面板重开生成态视觉残留」(进度条/spinner)。**安全性**:主/分离窗口 state 独立(各自 webview 独立 JS context,stores/ai.ts 单例仅同 webview 内共享),清主窗口 state 不影响分离窗口生成态;localStorage 快照保留供 resumeInDetached 恢复。vue-tsc EXIT=0 主代独立核验。— 来源:架构复核报告 §5 新⑪,src/composables/ai/useAiWindow.ts:37-38 + useAiEvents.ts:364-374 stopListener
|
||||
- [x] DOC-260615-07 ✅(第⑲批 2026-06-16) — ~~aichat §8 表补勾~~ aichat审查报告第八章 AR-1~11 优先级表逐行补状态勾注(AR-1退役✅/AR-2~7,9~11已修✅+commit/AR-8重评🔄)+文档头二次增补行;零新增条目对齐 DOC-13 瘦身方向;状态不一致 2 项(AR-1退役/AR-8重评)按 todo 标注非矛盾 — 详见 §7
|
||||
- [x] DOC-260615-08 ✅(2026-06-16) — ~~近期改动 CR-03 未做子项拆独立 todo~~ 拆 3 子项独立 todo(见下方)。原 CR-03(line 212)内联备注「未做留 todo」未独立追踪,现拆。— 详见 §8
|
||||
- [x] ✅(batch30·2026-06-16) CR-260615-03-a [P2] — **audit.rs Err 误报「项目已不存在」**。`audit.rs:52` `resolve_project_label` 用 `_` 合并 `Err`(DB 故障/锁/连接断)与 `Ok(None)`(真不存在),DB 出错时用户看到误导性「项目已不存在」而非错误。修法:分三臂 `Ok(Some)`/`Ok(None)`/`Err`(Err 打 warn 日志回退裸 id)。零行为破坏(仅 Err 分支加日志+改文案)。— 来源:近期改动审查 §2②,src-tauri/src/commands/ai/audit.rs:50-52
|
||||
@@ -425,7 +446,7 @@
|
||||
- [x] B-260615-21 ✅ 回滚user msg (第⑩批 2026-06-16) — ~~sendMessage catch 回滚 user message~~ push user msg 前捕获 const userMsgId(原内联未生成)+catch 块 filter 改 m.id!==aiMsgId && m.id!==userMsgId 一并回滚;机制:user/ai msg 均 nextMsgId() 唯一 id+push 进 state.messages(无索引依赖,按 id 过滤最稳) — useAiSend.ts
|
||||
|
||||
**P2 — 前后端状态同步**
|
||||
- [ ] B-260615-22 — [P2] ~~前后端状态不同步~~ → **由 B-260615-55(L0 握手) + B-260615-56(L2 强制发送) 解决**,本条保留为问题记录不再独立实施
|
||||
- [x] ✅(batch55·2026-06-16·主代销账) B-260615-22 — [P2] ~~前后端状态不同步~~ → **由 B-260615-55(L0 握手) + B-260615-56(L2 强制发送) 解决**(L0 前端重接握手+L2 三级降级+force_send IPC),本条保留为问题记录不再独立实施。双项均已✅销账,本条闭环。
|
||||
- [x] CR-260615-12 ✅ 小项 _toastTimer 等 (第⑩批 2026-06-16) — ~~可选一组~~ _toastTimer 卸载未清(AiChat:436) + markdown 外层 span→div + SVG 常量散落 + appSettings 注释 + index 空行 + 路由 icon 语义 + options shape 校验 + projectNameById 共享 + useConfirm dev 警告 + i18n `t` as any — 详见走查 ⚪ 区
|
||||
- [x] CR-260615-09 ✅ .ai-md DRY (第⑩批 2026-06-16) — ~~五份 .ai-md 样式逐字重复~~ 抽全局 css (84条删+3留独有) — AiChat/ProjectDetail/Ideas/Knowledge/TaskDetail → `src/styles/ai-md.css` 或 `<AiMarkdown>` 组件。TaskDetail.vue:263-333 新文件继续抄(CR-09 复发,定时走查 06-15 确认第 5 份)。B-24/25 复制粘贴源头 — 详见走查 ⑤ + 定时走查 P0复核.md
|
||||
- [x] CR-260615-10 ✅ useRendered DRY (第⑩批 2026-06-16) — ~~useMarkdown 加 `useRendered(getText)` 辅助~~ 消除 renderedDesc computed + onMounted(loadMarkdown) 三处重复(与 CR-09 同源) — 详见走查 ⑥
|
||||
@@ -495,7 +516,7 @@
|
||||
- [x] UX-2025-01 ✅ 选文字(文本偏移量方案) (第⑩批销账 06-15) — **流式渲染中选中文字保持**(§2.1)。现象:AI 流式输出时选文字被 delta 打断丢失选区。方案 A(推荐):`selectionchange` + 选区在消息容器内 → 暂停 rAF 流式 parse → 选区结束恢复;方案 B:已完成块独立 DOM 节点不参与 v-html 替换。关联 ARC-08 块级 memo(splitBlocks 已按块切分,末块单独更新天然支持方案 B)— src/components/AiChat.vue + src/composables/ai/useAiEvents.ts
|
||||
- [x] ✅(batch36·2026-06-16·workflow w098aapgd) UX-2025-02 [P1] — **消息操作栏(复制 / 重新生成)**(§1.2+§1.3)。AI 气泡 hover 显示操作栏:「📋 复制」+「🔄 重新生成」。复制 = F-260615-13 合并实现;重新生成:后端删最后一条 AI 消息 + 用倒数第二条 user 消息重跑 agentic loop(新增 `ai_regenerate` IPC)。代码块额外 hover 浮出「📋 复制代码」按钮(§2.2 子项)。— src/components/AiChat.vue + src-tauri/src/commands/ai/commands.rs
|
||||
- [x] ✅(batch36·2026-06-16·workflow w098aapgd) UX-2025-03 [P1] — **错误气泡操作入口**(error_type 枚举本身 batch34 B-42 已加,本批前端消费)(§4.1)。错误气泡底部增加按钮区:「🔁 重试」(取上一条 user 消息重发)+「⚙ 去设置」(仅 auth/provider 错误时显示,跳 Settings→AI Tab)。后端 `AiError` 加 `error_type: Option<ErrorType>` 枚举(auth/network/timeout/provider_config/unknown),前端据此显隐按钮。— src-tauri/src/commands/ai/mod.rs(AiChatEvent) + src/api/types.ts + src/components/AiChat.vue
|
||||
- [ ] UX-2025-04 [P1] — **断线保文**(§4.2)。流式中断时已接收文本不丢弃:`stream_llm` mid-stream error 改返回 `Some(partial_text, ...)` + `incomplete: true` 标志;agentic 收到 incomplete → 正常入库 + emit AiCompleted(非 AiError)+ 追加系统提示「⚠ 响应因网络中断不完整」;前端 AI 气泡底显示「继续生成」按钮。关联 B-260615-05(流尽空内容报错)同改 stream_recv.rs。— crates/df-ai/src/stream_recv.rs + src-tauri/src/commands/ai/agentic.rs + src/components/AiChat.vue
|
||||
- [x] ✅(batch59·2026-06-16·workflow wdlt0xfl6) UX-2025-04 [P1] — **断线保文**(§4.2)。保文核心落地:stream_recv.rs `StreamResult` enum(Complete/Partial/InitFailed 三分支),MidStream 失败(流中途 chunk error/idle timeout/有 partial_text 未 finished)返 `Partial{partial_text}` **不重试保文**;agentic.rs 收 Partial → 入库 assistant 消息 + emit AiCompleted(incomplete=true,非 AiError) + 追加系统提示「⚠ 响应因网络中断不完整」;useAiEvents.ts:177 补 `AiStreamRetry` case(消除死事件穿透) + AiCompleted case 处理 incomplete(系统提示气泡镜像后端);types.ts:204 `incomplete?:boolean`。对齐决策 a1(Init 可重试/MidStream 保文不重试) + UX-04 决策 a。**「继续生成」按钮暂未做**(保文核心硬需求已满足,按钮可复用 UX-2025-03 重试能力或按需补)。— src-tauri/src/commands/ai/stream_recv.rs + agentic.rs + src/composables/ai/useAiEvents.ts
|
||||
|
||||
**第二批 — 显著提升日常效率**
|
||||
|
||||
@@ -527,7 +548,7 @@
|
||||
|
||||
- [x] AE-2025-01 [P0] — **批量审批**。同一轮多 pending 时,ToolCardList 顶部显示「全部批准(N) / 全部拒绝」按钮。改动:①`ToolCardList.vue` 加批量操作栏(监听 pending_approval 数量)②`useAiSend.ts` 新增 `approveAll(rejectAll)` 循环调 `ai_approve`。预估 0.5 天 — src/components/ToolCardList.vue + src/composables/ai/useAiSend.ts (第⑫批销账 06-15)
|
||||
- [x] AE-2025-02 [P0] — **审批计数器 + 跳转**。输入框上方/header 显示 `⏳ N 项待审批` 徽标,点击跳转到第一个 pending 卡片。改动:①`AiChat.vue` header 区域加审批徽标 ②`ToolCardList.vue` 暴露 `scrollToFirstPending` 方法。预估 0.5 天 — src/components/AiChat.vue + src/components/ToolCardList.vue (第⑬批销账 06-15)
|
||||
- [ ] AE-2025-03 [P0] — **write_file diff 预览**。write_file 审批时若文件已存在,展示前后对比 diff 而非裸 content(content 可能几百行代码截断到 300 字符)。改动:①后端 `tool_registry.rs` write_file handler 执行前读旧文件返回 diff ②`ToolCard.vue` pending_approval + name=write_file 时渲染 diff 视图(红删绿增)。关联 F-260615-10(diff 工具)可复用。预估 1 天 — src-tauri/src/commands/ai/tool_registry.rs + src/components/ToolCard.vue
|
||||
- [ ] AE-2025-03 [P0] — **write_file diff 预览** ⚠️**降级阻塞(2026-06-16·batch54 workflow 探索+主代核验)**:后端 write_file **未返 diff**(`tool_registry.rs:694` 结果 payload `{path,bytes_written,old_size,encoding}` 无 diff 字段,`generate_diff` 仅 patch_file 调用),前端 ToolCard 无 diff 可渲染,审批 payload `AiApprovalRequired`/`PendingApproval` 亦无 diff(只有 `args={path,content,encoding}` 纯新内容,拿不到旧文件)。需**后端先补**再追加前端渲染。**两条路径**(均 src-tauri 改动,跨 mod.rs/audit.rs/types.ts/AiChat.vue 领地):路径 B(推荐,满足审批预览诉求)审批 payload 加 `diff` 字段 + audit.rs:555 挂起审批前预读旧文件 + `generate_diff` 注入事件;路径 A 仅 write_file handler 补 diff 但结果阶段才有(审批时看不到,不满足)。前端部分待后端 diff 返回后追加 `<pre>` 红删绿增渲染。原诉求:write_file 审批时若文件已存在,展示前后对比 diff 而非裸 content(content 可能几百行代码截断到 300 字符)。改动:①后端 `tool_registry.rs` write_file handler 执行前读旧文件返回 diff ②`ToolCard.vue` pending_approval + name=write_file 时渲染 diff 视图(红删绿增)。关联 F-260615-10(diff 工具)可复用。预估 1 天 — src-tauri/src/commands/ai/tool_registry.rs + src/components/ToolCard.vue
|
||||
|
||||
**P1 — 增强控制力**
|
||||
|
||||
@@ -563,7 +584,7 @@
|
||||
- [ ] F-260614-10 — 知识库 MCP Server + Tier 2/3 — 对外 MCP 暴露 + 分层存储(当前仅 Tier 1 全栈) — source:PROGRESS Sprint15
|
||||
- [ ] T-260614-11 — 全局#6 条件表达式引擎升级 — df-workflow conditions 仅支持 true/false 字面量,升级为真表达式求值 — source:PROGRESS 全局问题
|
||||
- [x] T-260614-12 — ~~df-ideas 死代码~~ ✅ WF-E 部分完成(capture.rs 删 CaptureInput/IdeaCapture 死码,保留 Idea/IdeaScores 共享实体;promotion/scoring/adversarial 内"两套 Recommendation/PromotionPolicy 死枚举"嫌疑 agent 未确认存在/保留为对外契约,本次未动,待复查)(06-14, commit 89da9fa)
|
||||
- [ ] F-260615-01 — **[P1 功能增强]** HumanNode 审批节点支持自定义选项 + 单选/多选类型。现状:config `options: Vec<String>` 已支持任意数量(2/3/…数量扩展已通),但 `decision` 是单 `String` 仅单选语义,`options` 空=自由文本。增强目标:不止「同意/拒绝」二选一,可配置 N 个候选项 + 单选(single)/多选(multiple)两种类型。**改动面**:①`df-core/events.rs` `WorkflowEvent::HumanApprovalRequest` 加 `select_type`、`HumanApprovalResponse` decision 单值→多值(`decisions: Vec<String>` 或保留 decision 兼容 + 加 decisions)②`human_node.rs` config 解析 `select_type` + 校验(多选时每项 ∈ options,可加 min/max 选中数约束)③IPC `approve_human_approval` 签名 ④前端 `stores/project.ts` approve + `api/types.ts` 事件类型 + 审批弹窗 UI(单选 radio / 多选 checkbox)⑤单测改断言 + 新增多选/超限测。**注意**:向后兼容现 single 调用方,`select_type` 缺省 = single — source:用户需求(06-15),crates/df-nodes/src/human_node.rs + src-tauri/src/commands/workflow.rs + src/stores/project.ts — **✅已实施(a3cccb070fe9c8821,2026-06-16,待commit)**:6 文件契约向后兼容(events.rs SelectType 枚举 Single/Multiple 缺省 Single+HumanApprovalResponse decision+decisions 双字段/human_node.rs 校验 single len==1·multiple len≥1·∈options/workflow.rs IPC 加 decisions+select_type Option 缺省兼容/types.ts/project.ts approve/ProjectDetail.vue checkbox 多选 UI)。cargo check 0 err/df-nodes 21 test(含 4 新增多选)/vue-tsc 0 err。主代理核查契约向后兼容 + 6 文件边界
|
||||
- [x] F-260615-01 ✅(2026-06-16,待commit a3cccb070fe9c8821) — **[P1 功能增强]** HumanNode 审批节点支持自定义选项 + 单选/多选类型。现状:config `options: Vec<String>` 已支持任意数量(2/3/…数量扩展已通),但 `decision` 是单 `String` 仅单选语义,`options` 空=自由文本。增强目标:不止「同意/拒绝」二选一,可配置 N 个候选项 + 单选(single)/多选(multiple)两种类型。**改动面**:①`df-core/events.rs` `WorkflowEvent::HumanApprovalRequest` 加 `select_type`、`HumanApprovalResponse` decision 单值→多值(`decisions: Vec<String>` 或保留 decision 兼容 + 加 decisions)②`human_node.rs` config 解析 `select_type` + 校验(多选时每项 ∈ options,可加 min/max 选中数约束)③IPC `approve_human_approval` 签名 ④前端 `stores/project.ts` approve + `api/types.ts` 事件类型 + 审批弹窗 UI(单选 radio / 多选 checkbox)⑤单测改断言 + 新增多选/超限测。**注意**:向后兼容现 single 调用方,`select_type` 缺省 = single — source:用户需求(06-15),crates/df-nodes/src/human_node.rs + src-tauri/src/commands/workflow.rs + src/stores/project.ts — **✅已实施(a3cccb070fe9c8821,2026-06-16,待commit)**:6 文件契约向后兼容(events.rs SelectType 枚举 Single/Multiple 缺省 Single+HumanApprovalResponse decision+decisions 双字段/human_node.rs 校验 single len==1·multiple len≥1·∈options/workflow.rs IPC 加 decisions+select_type Option 缺省兼容/types.ts/project.ts approve/ProjectDetail.vue checkbox 多选 UI)。cargo check 0 err/df-nodes 21 test(含 4 新增多选)/vue-tsc 0 err。主代理核查契约向后兼容 + 6 文件边界
|
||||
- [x] F-260615-02 ✅(2026-06-16,待commit) — **[P1 功能]** task 详情查看。✅已实施:get_task_by_id IPC(复用 TaskRepo::get_by_id ok_or_else 转 Result)+lib.rs 注册+taskApi.get+/tasks/:id 路由+TaskDetail.vue(11 字段:标题/描述/状态/优先级/关联项目 router-link 解析名/分支标签/负责人/基础分支/工作流定义/创建更新时间;复用 constants/project 标签+formatDate+watch route.params.id 重载)+Tasks.vue 列表项 @click router.push;TaskRecord TS 类型已存在无需新增;主代理核查 cargo check 0 err/vue-tsc 0 err/git diff 6 文件边界干净。现状:`src/views/Tasks.vue` 仅列表,无独立 TaskDetail 视图/路由(grep 仅 `ProjectDetail.vue` 嵌套任务命中,无独立详情页)。需求:点击 task 查看详情。**数据模型已就绪**(`df-storage/src/models.rs:53` `TaskRecord` 12 字段:id / project_id / title / description / status / priority / branch_name / assignee / workflow_def_id / base_branch / created_at / updated_at)。**改动面**:①新建 `src/views/TaskDetail.vue` 视图 + 路由(`router/index.ts` `/tasks/:id`)②task 详情 IPC(`get_task_by_id`,核对 `commands/task.rs` 现有 IPC 是否已有,无则补)③`Tasks.vue` 列表项点击 → 跳详情 ④详情页字段展示(title/description 渲染、status/priority 标签、关联项目名解析 project_id→name、branch/assignee 信息、时间戳)⑤可选:详情页内编辑(`update_task` IPC 已存在,FR-D6)。— source:用户需求(06-15),src/views/Tasks.vue + src/router/index.ts + src-tauri/src/commands/task.rs
|
||||
- [x] F-260615-03 ✅ truncated 标志 (第⑩批 2026-06-16) — ~~list 工具截断标志~~ (list_trash补漏) 原完整分页方案,对抗分析降级。现状:4 工具 `truncate(50)` 硬截断,AI 不知被截断会回复「不存在」。**对抗分析裁决**:数据量未到 50 条线(projects=5, tasks=61),完整分页 breaking change 风险 > 收益 → **降级为最小修**:不改返回结构(non breaking),只在 truncate 时加 `truncated: true` 标志 + 工具描述注明"最多返回 N 条"。未来数据量到时再升完整分页(F-03-full)。**改动面**:tool_registry.rs 4 handler 截断处加 truncated bool 返回 — src-tauri/src/commands/ai/tool_registry.rs:127-165,377-379 — source:用户需求(06-15)+对抗分析裁决(06-15)
|
||||
- [x] F-260615-04 ✅ 卡片分组增强 (第⑩批 2026-06-16) — ~~read_dir / read_file 工具卡片连续时折叠/收起~~ 提高信息密度。现状:AI 探查目录常连续调多个 read_dir + read_file(先列目录再读多个文件),每个结果独立卡片平铺,长列表/大文件内容占满屏幕,信息密度低。需求:相邻同类读取卡片支持折叠——默认收起只显摘要(如「read_dir: 12 项」「read_file: src/main.rs (234 行)」),点击展开看详情;或连续 N 个同类卡片归组折叠。**改动面**:①`ToolCard.vue` 加折叠态(`collapsed` ref + 摘要/详情双视图 + chevron 图标 + 高度过渡)②连续同类检测/归组(`ToolCardList.vue` 按 `tool.name` 分组,已有列表容器适合放分组逻辑)③摘要提取(read_dir 数项数 / read_file 文件名 + 行数,解析 result)④折叠态持久化(可选,localStorage 按 conv)。关联信息密度构想(memory: devflow-info-density-concept,卡片折叠是其中一环)。— source:用户需求(06-15),src/components/ToolCard.vue + src/components/ToolCardList.vue — **勘察完成(2026-06-16,wxflofhf2)**:feasible/plan 11 步跨 5 文件(ToolCardList/ToolCard/useAiSend/stores/ai/global.css)。risk 标低但实为 UX 新行为+改核心 ai 状态文件(useAiSend.ts/stores/ai.ts)+plan 细节有误(useAiSend composable 无 emit 方法)。**拆小或留待**:先做 ToolCardList 分组+单卡折叠摘要(限定不碰 useAiSend/stores),完整折叠交互归信息密度构想单独立项
|
||||
@@ -605,7 +626,7 @@
|
||||
- [ ] F-07 trait 下沉 df-ai-core — 设计完备 4 项决策全定稿,退路可放 df-core,解锁 F-03/F-01
|
||||
- [x] R-PD-2 ✅ ScriptNode 不注册 (第⑩批 2026-06-16) — ~~ScriptNode 不注册 script~~ 3 行删除封死攻击面,工作流当前纯演示无真实脚本需求
|
||||
- [x] F-260615-06 ✅ patch_file (第⑩批 2026-06-16) — ~~patch_file(edit_file)~~ 局部文件更新工具,补齐 AI 文件操作闭环。完整设计见 [patch_file工具设计-2026-06-15.md](./02-架构设计/patch_file工具设计-2026-06-15.md)(API/三层防御/边界情况/替代方案否决/实施步骤)。**核心**: old_text 精确匹配为主+line 辅助+Mutex 并发安全+expected_hash 指纹防脏写。第一批实现核心三件套(~50行)。— src-tauri/src/commands/ai/tool_registry.rs 新增 handler
|
||||
- [ ] ARC-06 composable 循环依赖 — 提 aiShared.ts 破环最小改动(或合回 stores/ai.ts 备选)
|
||||
- [x] ✅(batch56·2026-06-16·workflow wsxxurgbr+主代核查) ARC-06 composable 循环依赖 — **破环全闭环**:①`aiShared.ts` 下沉 findToolCall(反向扫描O(1))+4个审批计时器函数(startApprovalTimer/clearApprovalTimer/clearAllApprovalTimers+APPROVAL_TIMEOUT_MS常量) ②`useAiEvents` 删 findToolCall 导出+改 import 从 aiShared 取 ③`useAiSend` 删审批计时器实现(改从 aiShared re-export)+删 drainQueue 直接调用(改经 `ai-drain-queue` 事件总线桥接) ④`stores/ai.ts` 加 `initDrainQueueListener()` 启动事件监听。**B-260616-19 CSS 缺失**(Knowledge.vue 窄屏标题挤压,agent 未产出 .css/.vue style 变更),待补。— src/composables/ai/aiShared.ts + useAiEvents.ts + useAiSend.ts + stores/ai.ts
|
||||
- [x] CR-09 .ai-md 样式 5 份→全局 css 抽取 — 零风险减法 (第⑬批销账 06-15)
|
||||
- [x] F-09 status 对齐前后端 ✅ (第⑯批销账 06-15) — 前端 map 删 in_progress/paused/cancelled(project 维度无数据源/UI 入口/消费方),保留 planning/active/completed。constants/project.ts(三 map 同步删+兜底改字面量)+Dashboard.vue getProjectStage(switch 收敛)+i18n zh-CN/en projects.status & dashboard.stage。后端不动(df-core enum 7 值是独立大改,F-260614-09 专项)。**注**:DB 实际只产生 planning(4 个建项目入口硬编码),真实生命周期=planning+deleted_at 软删二态
|
||||
- [x] F-260615-03 ✅ truncated (第⑩批 2026-06-16) — ~~最小修(截断标志)~~ **从完整分页降级**:不改返回结构(non breaking),truncate 时加 `truncated: true`(→ 见上方 :469 完整条目,本条为对抗分析区引用,勿重复实施)
|
||||
@@ -663,12 +684,12 @@
|
||||
> 来源:后台代理扫描 62 个 markdown 文档发现的问题
|
||||
|
||||
**P0 — 严重阻塞**
|
||||
- [ ] B-260615-57 [P0→缺口收窄] — ~~文件工具功能缺口~~ **06-15 批次后缺口 6→2→0**:已补 `patch_file`(F-06 ✅) / `search_in_file`(F-07 ✅) / `file_info`(F-08 ✅) / `append_file`(F-09 ✅) / `search_files`(F-12 ✅) / `delete_file`(F-16 ✅ 第⑯批) / `rename_file`(F-15 ✅ 第⑮批销账 06-15)。**缺口清零**:`rename_file`/`move_file` 已补(F-260615-15,根治 AI rename 走 run_command 的中文路径静默失败)。原根因(迫使 LLM 滥用 write_file 放大 FR-S7 覆盖写入风险)已由 patch_file 缓解。— src-tauri/src/commands/ai/tool_registry.rs
|
||||
- [x] B-260615-57 ✅(2026-06-16,缺口清零销账) [P0→缺口收窄] — ~~文件工具功能缺口~~ **06-15 批次后缺口 6→2→0**:已补 `patch_file`(F-06 ✅) / `search_in_file`(F-07 ✅) / `file_info`(F-08 ✅) / `append_file`(F-09 ✅) / `search_files`(F-12 ✅) / `delete_file`(F-16 ✅ 第⑯批) / `rename_file`(F-15 ✅ 第⑮批销账 06-15)。**缺口清零**:`rename_file`/`move_file` 已补(F-260615-15,根治 AI rename 走 run_command 的中文路径静默失败)。原根因(迫使 LLM 滥用 write_file 放大 FR-S7 覆盖写入风险)已由 patch_file 缓解。— src-tauri/src/commands/ai/tool_registry.rs
|
||||
|
||||
**P1 — 重要缺陷**
|
||||
- [x] B-260615-39 [P1] ✅(第⑰批销账 06-15) — ~~complete() 超时重试机制缺失~~ 新建 retry.rs(189行+6单测 retry_with_backoff/AttemptOutcome/is_*_retryable)+openai/anthropic complete() 包裹重试(3次/指数1s→2s→4s/±20%jitter/30s总预算止损/可重试 timeout·connect·5xx·429,不重试4xx·auth·body)/不建LlmError枚举(零侵入trait保anyhow::Result)/不用middleware(手写loop)/流式stream()不动/Settings降级常量MAX_COMPLETE_ATTEMPTS=3。**顺带修真bug:Anthropic complete()无60s timeout(FR-R4只修OpenAI一半,建连后挂起无限hang)**。complete()4调用方全低频后台(标题/知识/扫描/AiNode)有兜底,主对话走stream()不受影响。cargo test -p df-ai 37 passed `complete()` IPC 调用仅加 60s 单请求超时,但无重试机制。根因:网络波动时直接失败,无自动重试兜底。影响:偶发网络错误导致用户操作失败需手动重试。修法:实现指数退避重试机制(最多 3 次,总时长不超过 30s),并在 Settings 可配重试开关 — src-tauri/src/commands/ai/commands.rs
|
||||
- [x] B-260615-40 [P1] ✅(第⑯批销账 06-15) — ~~审批按钮无状态反馈~~ ToolCard 加 approving ref+spinner+disabled(防重入)+130s 本地计时器兜底+watch tc.status 离开 pending_approval 复位;useAiSend approveToolCall 删乐观置 running(原致审批整块消失切骨架屏,语义错位)保 pending_approval 直到后端事件回流;useAiStream onStreamTimeout 注释更新。loading 就近持有 ToolCard 本地不污染 store status 流转 — src/components/ToolCard.vue + src/composables/ai/useAiSend.ts
|
||||
- [ ] B-260615-41 [P1] — ~~工作流执行无进度指示~~ 长时间工作流执行时,用户不知道执行进度和剩余时间。根因:缺乏执行进度可视化。修法:在工作流详情页添加进度条 + 执行步骤提示 + 预估剩余时间 — src/views/WorkflowDetail.vue(需新建)
|
||||
- [x] B-260615-41 [P1] ✅(batch35 销账 2026-06-16,对齐决策a轻量) — ~~工作流执行无进度指示~~ batch35 TaskDetail 进度内嵌已满足决策 a 轻量:复用现有 NodeStarted/NodeCompleted 事件(纯前端 `handleWorkflowEvent` 按 exec_id 过滤 dispatch,不新增后端 progress 事件),`.wf-progress` 区显示 `workflowStepRunning{node}`(当前步骤)+`workflowStepsProgress{done}/{total}`(步骤进度)+完成/失败提示,不新建独立 WorkflowDetail.vue(决策 a 是嵌入现有 TaskDetail 推进按钮区非独立页),i18n key taskDetail.workflowStepRunning/stepsProgress/completedHint/failedHint zh-CN+en 双语已加。**预估剩余时间属方案 b 完整版,决策 a 明确不做** — src/views/TaskDetail.vue
|
||||
- [x] ✅(batch34·2026-06-16·workflow wvr7mdo0p) B-260615-42 [P1] — ~~错误信息不一致~~ 同类错误在不同场景下返回的信息格式不统一。根因:错误处理分散在不同模块,缺乏统一规范。影响:用户和调试者难以理解错误含义。修法:制定错误码规范 + 统一错误格式 + 前端错误码映射 — src-tauri/src/commands/ai/mod.rs + src/api/types.ts
|
||||
|
||||
**P2 — 中等问题**
|
||||
|
||||
Reference in New Issue
Block a user