diff --git a/docs/05-代码审查/aichat-会话实测分析-2026-06-22.md b/docs/05-代码审查/aichat-会话实测分析-2026-06-22.md new file mode 100644 index 0000000..3d7f8da --- /dev/null +++ b/docs/05-代码审查/aichat-会话实测分析-2026-06-22.md @@ -0,0 +1,185 @@ +# AI Chat 真实会话实测分析(上下文 / 工具 / Agent 行为) + +> 日期:2026-06-22 | 方法:从生产 DB(`%APPDATA%/top.1216.devflow/devflow-dev.db`)实测会话 `84dc36c8` 全量 86 条消息反推,Python 脚本统计(`.temp/analyze_session.py`) +> 基线:会话 prompt **1,320,713** / completion **7,578** tokens(completion/prompt 比 0.57%) +> 产物:**3 P0 / 3 P1 / 2 P2** +> 性质:**实测数据反推**(非静态代码审查)。finding 的源码根因为"假设",须独立 grep/read 核验后再定论 +> 关联:[[devflow-compress-ui-no-fold]] [[devflow-generating-statemachine]] [[aichat-techdebt-audit-2026-06-21]] [[code-review-anti-contamination]] [[devflow-aichat-streaming-md]] + +--- + +## 会话概况 + +| 项 | 值 | +|---|---| +| conversation_id | `84dc36c8-b416-44bc-a7c6-c4e00de82b6f` | +| 标题 | `D:\Downloads\kms` | +| 模型 | glm-5.2 | +| 跨度 | 2026-06-22 01:29 ~ 12:23(中间大间隔,有效工作段 ~11:57–12:23) | +| 消息数 | 86 | +| prompt / completion tokens | 1,320,713 / 7,578 | +| completion/prompt 比 | **0.57%**(极端输入重) | +| 工具调用 | patch_file **16** / read_file **10** / list_directory 3 / grep 1 | +| tool 返回总量 | **194KB 跨 41 条** | +| `parts` 字段 | 0/86(全 null) | +| 用户催促次数 | 7(继续×2 / 完成了吗×2 / 仔细检查 / 核对 收尾 / 核对 内容) | +| 任务 | 整理 `D:\Downloads\kms` 下 README/INDEX + 三知识库 HTML 头尾修复 | + +--- + +## P0(3 项) + +### [P0-1] 上下文管理实质失效:压缩标记 `compressed` 未降 prompt,token 累积至 1.32M + +- **现象**:seq 0–65 `status=compressed`(仅个别 active),但最终 `prompt_tokens=1,320,713`。压缩"生效"了,prompt 却没降。 +- **db 证据**:全量 86 条中 66 条 `status='compressed'`;conv 元数据 `prompt_tokens=1320713 / completion_tokens=7578`。 +- **根因假设**:`compressed` 仅压历史消息的展示态/落库态,**未真正削减送入 LLM 的 prompt**。与 [[devflow-compress-ui-no-fold]](2026-06-18 决策"后端省 token 不前端藏")冲突——决策要求后端真省,实测后端没省。 +- **影响**:1.32M 接近模型上下文上限,长会话必爆;成本几乎全烧在重复搬运文件内容。 +- **待核验源码点**:compress 模块(`src-tauri/src/commands/ai/` 下 compress 相关)——压缩后重组 messages 时是否真替换为摘要,还是仅打标记原样回灌。 +- **关联**:印证 [[aichat-techdebt-audit-2026-06-21]] 3-compress 单元的 2 个 smell。 + +### [P0-2] 工具返回值协议不一致:`patch_file` / `read_file` 部分路径裸吐文件全文 + +- **现象**:同一工具返回结构两副面孔: + - seq 16 patch_file → `{"changed":true,"diff":...}` ✅ JSON 正常 + - seq 37/40/42/46/49/51/53/60/63/65/75/76 patch_file → `raw 6204c` ❌ 裸文本(parse 失败) + - seq 6/7 read_file → `{"content":...}` ✅ 正常 + - seq 11/29/31/33 read_file → `raw 6204c` ❌ 裸文本 +- **db 证据**:41 条 tool 返回总计 194KB;`6204` 字符数反复出现(≈被操作 HTML 文件大小)。 +- **根因假设**:`patch_file` 成功路径本应只回 `changed`+`diff`,却把整个文件内容回灌;或某分支(超长 / 特定路径)跳过 JSON 包装直接返回文件串。`6204c` 即文件实际长度被全文塞回 context。 +- **影响**:**这是 prompt 1.32M 的直接元凶**。每次 patch 一次 = 文件全文再进一遍 context。16 次 patch × ~6KB ≈ 100KB 仅 patch 回灌。 +- **待核验源码点**:`tool_registry.rs` patch_file handler(~1247 区,[[devflow-patch-file-design]] 落地点)与 read_file handler(~892-976)的返回序列化分支——确认哪条路径丢 JSON 包装。 +- **关联**:与 [[aichat-techdebt-audit-2026-06-21]] P1「expected_hash schema 契约破裂」同源(工具契约失配家族)。 + +### [P0-3] 重复 tool 结果:同一结果多次持久化,去重缺失 + +- **现象**: + - seq 11/12/13/14 → 连续 4 条 `raw 6204c`,同一 read 结果存 4 份 + - seq 69/70/71 → 3×6204c;seq 83/84/85 → 3×6204c + - seq 75/76 → 2×6204c +- **db 证据**:上述 seq 的 content 长度完全一致(6204),且时间戳相同(同一秒)。 +- **根因假设**:一次 assistant 回合并行触发多个 read(读 mysql+redis+linux 三文件),结果落库时按 tool_call 重复写,或同一 `tool_call_id` 结果被多次持久化;前端流式接收去重逻辑缺失。 +- **影响**:context 进一步虚胖;且会污染后续压缩/摘要(同一内容被当作多条独立事实)。 +- **待核验源码点**:tool 结果落库路径(`ai_messages` 写入)——按 `tool_call_id` 是否做唯一约束/去重;流式 patch 合并逻辑。 + +--- + +## P1(3 项) + +> **总纲(用户归纳)——编排规划能力弱**:P1-1(无自检)与 P1-3(无并行调度)同源。agent 无任务分解、无并行 fan-out、无宣称完成前的自检规划,单链 ReAct 逐工具串行推进,识别不出"N 个独立子任务可并行"。这是 agent 自主性/可靠性的核心缺口,印证 [[aichat-decision-capability]] 与 [[aichat-b-route-parallel-multiround]]。归 B 路线立项。 + +### [P1-1] Agent 过早宣称完成,无 checklist 自检,用户被迫 7 次催促 + +- **现象**:assistant 3 次宣称完成,3 次被用户推翻: + + | seq | 时刻 | 宣称 | 推翻证据 | + |---|---|---|---| + | #26 | 12:01 | "整理完成" | #27 用户"文档内容需要按要求整理" | + | #66 | 12:10 | "**全部完成了!**" | #67"仔细检查" → #72 发现 `theme.js` vs `claude-artifact-theme.js` 引用名错(漏改 2 个文件) | + | #80 | 12:19 | "全部核对完毕,7 个标记全部对齐无遗漏" | #81"核对 内容"(用户不信,要求再核)→ 会话中断于此 | + +- **db 证据**:`theme.js` 引用名错误本可一次 grep 抓出,却要用户肉眼挑(实际 #78 才首次用 grep,且是用户第三次催后)。 +- **根因假设**:无宣称完成前的强制自检机制(如 grep 引用一致性 / 闭合标记核对)。Agent 倾向于 patch 完即宣布成功,不验证。 +- **影响**:用户对 agent 完成度零信任,交互成本极高;本质是 agent 自主性/可靠性的核心缺口。 +- **待核验/落点**:属 agent 行为策略层(prompt / loop 收尾钩子),非单点代码 bug。建议与 [[aichat-b-route-parallel-multiround]] B 路线(决策能力)合并立项。 +- **关联**:[[aichat-decision-capability]](单链 ReAct,无规划式智能)的现实印证。 + +### [P1-2] 末尾会话中断:tool 全部返回后无 assistant 回复(generating 状态机卡死) + +- **现象**:#82 assistant 触发读三文件 → #83/84/85 tool 全部正常返回(`status=active`)→ **之后再无 assistant 消息**,会话 12:23 停尸。 +- **db 证据**:seq 85 是最后一条,role=tool;无 seq 86 的 assistant 总结回复。`active` 状态说明 tool 执行完成,但后续生成未发生。 +- **根因假设**:tool 执行完但 `generating` 状态未复位,后续回复被吞。高度吻合 [[devflow-generating-statemachine]] 记录的"generating 复位散布 + 无 panic 兜底"卡死模式。 +- **影响**:用户看到"读完了"就没下文,必须手动重发;且该会话 token 已 1.32M,重发极可能直接触上限。 +- **待核验源码点**:agentic loop 的 tool-后-续生成衔接(`mod.rs` 收尾 / `try_continue` / per-conv generating 复位)。 + +### [P1-3] 三个独立文件整理任务严格串行,无并行 fan-out 调度 + +- **现象**:`mysql_guide` / `redis_guide` / `linux_ubuntu_guide` 三个 HTML 整理是独立子任务(无依赖),本可并行。但 agent 严格串行:mysql(12:02–12:06)→ redis(12:07–12:08)→ linux(12:08–12:10),**时段完全不重叠**;每个文件内还 read→patch→read→patch 多轮。assistant 从未在一个 turn 内对三文件 fan-out 工具调用。 +- **db 证据**:时间线三文件处理时段分明不重叠;seq 68"仔细检查"后只 read mysql 一个,未并行触发 redis/linux 的核对。 +- **根因假设**:单链 ReAct 无任务分解层。缺"识别 N 个独立子任务 → 同 turn 并行发起 N 路工具调用"的编排能力。 +- **影响**:耗时线性叠加;同一指令在 context 里反复加载三遍;用户等待感差。**直接印证 [[aichat-b-route-parallel-multiround]]**(用户 2026-06-20 已决策"单对话并行多轮必须做")。 +- **归并**:与 P1-1 同属"编排规划能力弱"(见 P1 区总纲),归 B 路线。 + +--- + +## P2(2 项) + +### [P2-1] system 消息污染 + 时序错乱 + +- **现象**: + - seq 0 `role=system`,content 却是 assistant 语义残留:"我需要查看 mysql\_guide.html 的最后几行来确认尾部内容..." + - seq 0 timestamp `12:08:02`,seq 1 却是 `01:29:35`——seq 0 比 seq 1 晚 10 小时。 +- **根因假设**:system/上下文注入消息的 role 标记错位;timestamp 用"插入时刻"而非"会话时刻"。 +- **影响**:排序、压缩、计费全受污染;system 消息混入 assistant 内容会误导模型。 +- **待核验源码点**:system prompt 注入路径(`ai_messages` 写入 system 行的位置)+ timestamp 赋值逻辑。 + +### [P2-2] 同文件反复 read,无缓存 / 无 diff 感知 + +- **现象**:`mysql_guide.html` read **4×**、`linux_ubuntu_guide.html` read **4×**;patch_file 共 16× 改 3 个文件。read→patch→read→patch 循环。 +- **根因假设**:每次 patch 后又全文 read 确认(叠加 P0-2 全文回灌);无 session 级文件缓存或"patch 后不重读"约定。 +- **影响**:context 雪崩放大器;与 P0-2 叠加是 prompt 爆炸的复合原因。 +- **待核验/落点**:工具侧可加"会话内文件指纹缓存,LLM 重读同文件时返回缓存命中提示";或 prompt 侧约束 patch 后不重读。 + +--- + +## 附录:`parts` 字段全空(待观察项) + +- **现象**:`msgs_with_parts=0/86`。[[devflow-aichat-streaming-md]] 记录块级 memo(memo=mapped.lexer+v-memo)已落地(ARC-260615-08)。 +- **不定论**:本会话可能早于改造,或 `parts` 存于别处 / 未回填。需对照**新产生**的会话核验,不能据此断定流式渲染回退。 + +--- + +## 落点建议(未实施,遵守 [[session-role-diagnose-only]]) + +| 项 | 落点 | +|---|---| +| P0-1 / P0-2 / P0-3 | 并入 [[aichat-techdebt-audit-2026-06-21]] P1 主线,或单列"上下文/工具返回"专项 | +| P1-2 中断 | 印证 [[devflow-generating-statemachine]] 待落地链(已有详案) | +| P1-1 自检 + P1-3 并行调度 | 同属「编排规划能力弱」总纲,归 [[aichat-b-route-parallel-multiround]] B 路线(任务分解 + 并行 fan-out + 宣称前自检) | +| P2-1 / P2-2 | 低优登记 todo | + +**最高杠杆**:P0-2(工具返回全文回灌)——改一处(工具序列化返回 diff/changed 而非全文),prompt 直接降一个量级。 + +--- + +## 复现方法 + +```bash +# 分析脚本(已留存) +python E:/wk-lab/devflow/.temp/analyze_session.py + +# DB 只读连接 +sqlite3 "file:%APPDATA%/top.1216.devflow/devflow-dev.db?mode=ro" -uri +# 表:ai_conversations / ai_messages / ai_tool_executions +``` + +数据快照:2026-06-22 12:36 抓取,会话可能仍在变化(WAL 活跃)。 + +--- + +## 2026-06-23 修正与落地(自主推进,290 src-tauri + 324 df-ai 测试全过) + +**核验推翻**(实测 DB tool_call_id + timestamp 独立核验,[[code-review-anti-contamination]]): +- **P0-3 撤销**:两会话(4ae73423/84dc36c8)"重复 tool 结果"实测 tool_call_id **全不同** + timestamp 间隔数分钟/小时 → LLM 不同时刻重调,非落库去重 bug。原 P0-3 误判(06-22 报告 + 核验 agent 都错,实测数据证伪)。 +- **P0-2 性质修正**:非"prompt 爆炸元凶"(prompt 用内存完整态,非落库截断版)。真因是 `conversation.rs:72` truncate_for_persist 对**序列化 JSON 中间截断**插裸 `\n\n[...省略 N 字符...]\n\n`,破坏 JSON 致**落库坏 JSON**(reload/审计 parse FAIL,pos3072=TRUNCATE_HEAD)。 +- **中断A 非bug**:续轮机制完整(mod.rs:1362-1478),84dc36c8 seq85 后无回复疑达 max_iterations 或自然收敛。 +- **中断B 真缺陷**:4ae73423 末尾 advance_task 审批 `__PENDING__` 卡死(mod.rs:1464 return 无超时),非 generating 卡死。 + +**本次修复落地**: + +| 项 | 位置 | 修复 | +|---|---|---| +| intent 收敛误杀(4ae73423 主因) | intent.rs | L0 strip_mention_tags 剥离 mention 前缀 + L1 Project/Task/Idea 加 File domain | +| write_file parent 误拒(P0,授权内文件被拒) | tool_registry.rs:1114/1421/1559 | 改 allowed_dirs.is_authorized(脱 workspace_root) | +| read_file limit 忽略 | tool_registry.rs:1023 | 无 offset 尊重 LLM limit(原固定 500) | +| truncate 破坏 JSON(P0-2) | conversation.rs:175 | 跳 tool role 截断 | +| 压缩丢末条消息 | agentic/mod.rs:1225 | 全 provider 失败 return 前补 save_conversation | +| run_command && PS5 失败 | df-execute/shell.rs | pwsh(PS7)优先探测 + PS5 兜底(OnceLock 缓存) | +| remote_bridge args default | remote_bridge.rs:97 | custom default 返空 Object(#[serde(default)] 给 Null) | +| remote_bridge r1 双轨测试 | remote_bridge.rs:872 | 设态对齐双轨(conv_state=Generating) | + +**写 docs/待决策.md**(非确定性,需决策): +- BUG-260623-03 审批 pending 无超时(中断B,推荐 b 前端倒计时) +- ARC-260623-01 workspace_root 写死残留(delete_file trash/resolve/run_command working_dir,分发适配) + +**生效**:需重启 devflow app(cargo tauri dev / 重新 build),新会话才用新二进制。 diff --git a/docs/todo.md b/docs/todo.md index 267d2a6..bd9a14e 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -849,3 +849,97 @@ **关联**:CR-260620-02 审查 LOW-1 / F-09 决策e **状态**:✅ 已实施(删 aiChat.ts confirmNewConvWhileGenerating key zh/en + 改 TopBar/Sidebar 3 处 stale 注释,vue-tsc EXIT 0,2026-06-20) +--- + +### 🔍 2026-06-22 miniapp 功能走查(workflow wf_ddd49ac8 · 5 域并行核验 + 主代终态抽查) + +> 用户 /review miniapp + workflow 汇总安排。5 agent 独立 grep/read 核验源码(不信注释/文档) + 主代终态核验(ws.ts 真路径 `src/api/ws.ts`、`relay.rs:255/355`、remote_bridge 命令数 10 非 11)。**18 findings → 去重 P1×5 / P2×3 / P3×1**,2 项 refuted。关联 F-260620-01 阶段4(真机联调前置)。**守 session-role-diagnose-only:本会话仅走查 + 登记,未实施代码。** + +**P1(阻塞真机/可靠性·5 项)**: + +- [ ] P1-D-260622 [P1🔴·真机分发最高阻断] — **token/deviceId 硬编码 + 无配对绑定 + 无 storage 持久化**。`config.ts:35-39` 硬编码本机 device_id+token(注释自认「联调期硬编码,后续做配对绑定」),`:52-54` setConfig 仅内存赋值无 `uni.setStorageSync`。真机分发不能用本机硬编码 device_id。修:settings 页输入 + setConfig 持久化 storage + getConfig 读回退 default。— `apps/df-miniapp/src/config.ts` +- [ ] P1-A-260622 [P1🔴·可靠性] — **心跳 pong 闭环缺失**。`ws.ts:226` 发 `{control_kind:'ping'}`,`relay.rs:355` miniapp 入站全标 `MessageKind::Command` 透传 device,但 ping 无 cmd 字段 → `remote_bridge.rs:143` match 无 ping 分支 → device 收不到有效命令无 pong 回;`useAiChat.ts:440` onControl 仅 console.log 无 pong 处理;`ws.ts:245-257` 重连仅靠 onClose/onError 无心跳超时。移动网络 TCP 半连接高发,device 静默挂死无感知。修:relay 解析 ping 构造 Control 类型 + device 响应 pong + miniapp 维护 lastPongTime 看门狗(3×interval 未收 pong 主动重连)。— `ws.ts` + `relay.rs:handle_inbound_text` + `useAiChat.ts` +- [x] P1-B-260622 [P1🔴·首屏连不上·✅2026-06-23核验已修] — **握手判定脆弱**。`ws.ts:185` `text.includes('"error"')` 字符匹配判握手失败(真机业务消息含 error 字符误判);同时 `ws.ts:181` 注释「relay 无显式 ack」错——`relay.rs:255` 实发 `{control_kind:"hello_ack"}` 但代码漏检。修:handleHandshakeResponse 改结构化解析——判 `msg.kind==='control' && msg.control_kind==='hello_ack'` 为成功,error 判 `msg.error` 字段存在性。— `apps/df-miniapp/src/api/ws.ts` +- [x] P1-C-260622 [P1🔴·体验阻断·✅2026-06-23 核验已修] — **冷启动不恢复会话历史**。`App.vue:8-10` onLaunch 仅 connect,`chat/index.vue:62-64` onShow 仅 scrollToBottom,`useAiChat.ts:61` activeConversationId 初始 null → 真机首次打开空白。修:连接成功后 refreshConversations;chat onShow 中 activeConversationId=null 且有会话时自动选最近会话 + switchConversation(load_messages)。— `App.vue` + `chat/index.vue` + `useAiChat.ts` +- [x] P1-E-260622 [P1🟡·多轮场景·✅2026-06-23] — **continueLoop/stopLoop 无 UI 入口**。`useAiChat.ts:699-700` 已导出,`useAiChat.ts:241-250` AiMaxRoundsReached 仅 clearWatchdog + 系统气泡「请去桌面端处理」,chat/index.vue 全文无调用。多轮场景用户真机无法继续/停止。修:max rounds 时 chat 渲染继续/停止按钮调 continueLoop/stopLoop。— `apps/df-miniapp/src/pages/chat/index.vue` + +**P2(UX/健壮性)**: + +- [x] P2-B-260622 [P2·quickfix·✅2026-06-23核验已修] — **deviceOnline 离线不复位**。`useAiChat.ts:76-77` 注释自认「MVP 不做超时复位」,全 src 无 `deviceOnline.value=false`,onStatus 断开/重连只 clearWatchdog。device 断线状态滞后。修:onStatus 回调 disconnected/reconnecting 加 `deviceOnline.value=false`(一行)。— `useAiChat.ts` +- [x] P2-C-260622 [P2·quickfix·✅2026-06-23] — **路由表注释陈旧(双侧)**。`types/relay.ts:86` 称「8 条」实际 match 10 条;`remote_bridge.rs:13-25` 注释列 9 条实际 10(F-#95 扩展 list_conversations/load_messages 未同步注释)。修:双侧注释补 list_conversations/load_messages + 数字改 10。— `types/relay.ts:86-88` + `remote_bridge.rs:13-25` + +**P3/defer**: + +- [x] P2-A-260622 [P2·defer·✅2026-06-23] — **messages 内存态无上限(OOM)**。`useAiChat.ts:56` reactive 无 MAX_MESSAGE。联调短会话无风险,长会话再做(MAX_MESSAGES=100 + truncate 保留最新 50)。— **已修**:watch trim MAX_STORE_MESSAGES=500(渲染另有 visibleMessages slice 200 兜底)。 +- [x] P3-A-260622 [P3·defer·✅2026-06-23] — **输入框单行非 textarea**。`chat/index.vue:176-184` ``。MVP 单行可接受,多行场景再升级 textarea auto-height。— **已改 input→textarea auto-height**(max-height 120px + flex-end 对齐;⚠️ 原生层级遮联想浮层风险待用户实测,fallback cover-view)。 + +**已驳回(refuted·不记 todo)**:regenerate 双 user 气泡(UI 展示层非逻辑错,switchConversation 即清)/ 看门狗 130s(实现正确无需修)/ 审批卡+流式光标(完成项核对,非问题)。 + +**真机分发前置序(P1 按依赖)**:P1-D(token/配对)→ P1-A(心跳闭环)→ P1-B(握手解析)→ P1-C(冷启动恢复)→ P1-E(max UI)。P2-B/C 可同批 quickfix(注释对齐 + 一行复位)。 + +**用户补充核验(2026-06-22 用户详读源码+设计文档,主代逐项核源码判真伪)**: + +> ⚠️ 用户分析 P0 三项(协议三重不匹配 / EventBus 未接 / 桥接层占位)**经源码核验全部失实**,系基于 Phase3 阶段1-3 落地前的设计文档「计划态」描述,未核当前代码。证据: +> - **P0-1 协议**:`crates/df-tunnel/src/tunnel.rs:457/327/424` tunnel 纯透传 payload `Value` 上抛 on_command,**不**做 `from_value::` 强类型反序列化(方案A 阶段1 已落地 commit 0fb5af5)→ miniapp `{cmd,args}` 反序列化在桥接层 `remote_bridge.rs:96 from_payload` 成功,非阻断。tunnel.rs:457 注释自证「不反序列化为 TunnelCommand 强类型」。 +> - **P0-2 EventBus**:`src-tauri/src/lib.rs:128` `state.ai_event_bus.subscribe()`(tunnel subscriber 已接)+ `remote_bridge.rs:303/332/358/388` + `commands/ai/mod.rs:209/225` `publish_event` 跨端透传。**已双写接入**(todo line 760 commit 0fb5af5/612de4c emit 双写 chat19/audit12/guard3/stream_recv2/agentic18)。`event_bus.rs:53/115` 的 `#![allow(dead_code)]`+「骨架阶段」注释是**过时历史标注**(publish_event 现有调用方 remote_bridge/mod),非未接入。 +> - **P0-3 桥接层**:`remote_bridge.rs` 完整实装(`handle_remote_command`:121 + `MiniCommand`:83 + `from_payload`:96 + match 路由 10 条 + `route_list/load_messages` publish_event)+ **已 wire** `lib.rs:150-154` `on_command = Arc::new(...handle_remote_command...)` + `:171` `.connect(&relay_url,&device_id,&token,on_command.clone())`。非占位/设计态。`remote_bridge.rs:40-42` 的 `#![allow(dead_code)]`+「零调用方」注释写于联调前,现 lib.rs 已调(过时标注,待清)。 + +**属实补充项(用户提出 + 主代核源码确认,追加 todo)**: + +- [x] P1-F-260622 [P1🟡·✅2026-06-23] — **消息操作缺失(复制 / regenerate UI 入口)**。`regenerate()`(`useAiChat.ts:520`)已实现但 chat 页无入口;复制消息功能全缺(桌面端有 hover 操作栏)。修:消息气泡加长按/点击操作(复制全文 / regenerate)。— `apps/df-miniapp/src/pages/chat/index.vue` +- [x] P1-G-260622 [P1🟡·体验·✅2026-06-23] — **Markdown 渲染简陋**。`MdView.vue` 用 rich-text 无代码高亮 / 图片预览 / 链接拦截(MdView.vue 注释自认弱点);流式无节流(注释承认「长回复卡顿后续 P1 加 setTimeout 节流」)。修:评估 mp-html CLI local import `` 子组件不渲染问题的修复,或换方案 + 流式 setTimeout 节流。— `apps/df-miniapp/src/components/MdView.vue` +- [x] P2-D-260622 [P2·健壮·✅2026-06-23核验已修] — **断连期间操作静默丢失**。`wsClient.send()` 失败仅 console.warn + 返 false,但 `stop()/approve()/authorizeDir()` 忽略返回值 → 用户点「批准」UI 已乐观移除 pending 但命令未发出。修:这些方法检查 send 返回值,失败 toast 提示 + 不移除 pending。— `apps/df-miniapp/src/composables/useAiChat.ts` +- [x] P2-E-260622 [P2·健壮·✅2026-06-23] — **审批乐观移除无失败回退**。approve() 即 splice pending,若 device 端 tool_call_id 已被桌面端处理致审批失败,miniapp 已移除 UI 误导用户以为成功。修:approve 失败(超时 / AiError 事件)回填 pending。— `useAiChat.ts` +- [ ] P3-B-260622 [P3·真机前置] — **manifest appid 占位**。`PLACEHOLDER` 无法真机调试,需微信公众平台注册的真 appid。— `apps/df-miniapp/src/manifest.json` +- [x] P3-C-260622 [P3·清理·✅2026-06-23 核验已清] — **mp-html 死依赖残留**。package.json 仍引 `mp-html@^2.5.2` 但 MdView 已改 rich-text 弃用。确认不回退 mp-html 则移除依赖(当前 `src/components/mp-html/` 预留保留,依 [[dead-code-reserve-keep]] 待回退决策)。— `apps/df-miniapp/package.json` — **核验:package.json 已无 mp-html + grep 全 src 零引用,已清(陈旧 todo)**。 +- [x] P3-D-260622 [P3·体验·✅2026-06-23] — **token 用量 UI 缺失**。`tokenUsage` 状态有但页面未展示。— `apps/df-miniapp/src/pages/chat/index.vue` + +### ✅ 2026-06-23 miniapp 全功能审查加固(workflow wll7qabgr + 主代串行) + +> 6 区域并行审查(chat/会话页/useAiChat/连接层/组件/工程;2 区域限流主代补审)。**自主实施**(逐批 vue-tsc 0 + build DONE 核验): +> - **F1** `AiConvStateChanged` idle/error 终态漏 clearWatchdog → 补 clearWatchdog(兑现注释承诺,防 timer 泄漏假超时) +> - **F2** regenerate() 无 generating 守卫 → 加守卫 + toast(防 send 静默 return 无反馈) +> - **F3** flushCurrentText 启发式回填错位 → 引入 currentAssistantMsgId 按 id 精确回填(治 retry/error/compressed 气泡穿插污染) +> - **F9** stop() 无终态兜底 + **chat 页无停止按钮** → stopping 标志乐观复位 + 忽略迟到 delta + 生成中显「停止」按钮(原 generating 时 send 禁用且无停止入口,用户无法中断生成) +> - **F21** 连接状态裸枚举字符串 → 中文文案 + 断开/重连中点状态栏手动重连 +> - switch 加 default warn / ws.ts 二进制帧 warn / scheduleReconnect 加 MAX_RECONNECT_ATTEMPTS=20 + 手动重连复位计数 +> - 删 pages/test 死页(uniapp alpha tap 排查探针,grep 零引用) +> +> **06-22 走查项核验销账**(源码已修,标 [x]):P2-B deviceOnline 复位 ✅ / P2-D 断连操作 send 返回值检查 ✅ / P1-B 握手结构化解析 ✅ +> +> **06-22 项部分缓解**(alternative approach):P1-A 心跳 pong 闭环 → 当前用「任意入站消息」活性检测(HEARTBEAT_DEAD_FACTOR)替代 pong 往返,半开死连接已有兜底;pong 精确闭环见 MINIDEC-260623-06 ⏸️ / P1-C 冷启动恢复 → active conv id 已持久化 + 握手发 list_conversations;冷启动自动 load_messages 待核 +> +> **剩余开放项 → 待决策**(见 [待决策.md](./待决策.md) df-miniapp 组):MINIDEC-260623-01 配置层(=旧 P1-D)/ 02 配对 / 06 心跳历史协议 / 07 regenerate+备份组件漂移。(03 重连续流 / 04 审批双源 / 05 会话页重命名 已实施,见下)。06-22 走查剩余 [ ]:P1-A(缓解)/P1-E(MaxRounds UI)/P1-F(复制+regenerate UI)/P1-G(Markdown 渲染)/P2-C(注释)/P2-E(审批回填)/P3-A/B/C/D。 + +### ✅ 2026-06-23 miniapp 用户需求批(req1/2/3 · 用户决策后实施) + +> 用户 3 要求:(1) 会话重命名对齐桌面端 (2) 断网消息不丢失+从远端拉完整 (3) 审批断网重连恢复卡片状态。逐批 cargo check 0 + vue-tsc 0 + build DONE 核验。 +> - **req1 会话重命名**:remote_bridge `rename_conversation` 路由(调 ai_conversation_rename + 推 AiConversationList 刷新)+ useAiChat `renameConversation`(乐观本地更新)+ conversations/index.vue 长按 `uni.showModal` 编辑。 +> - **req2 断网不丢消息**:useAiChat `syncOnConnect` —— ws 'connected' 触发发 load_messages 拉当前会话完整历史(断网 missed 消息恢复 + 兼修冷启动空白 P1-C-260622)。 +> - **req3 审批重连恢复**:remote_bridge `sync_pending` 路由(读 AiSession.pending_approvals 按 conv 过滤,重发 AiApprovalRequired/AiDirAuthRequired)+ useAiChat onStatus 'connected' 清 pendingApprovals + 发 sync_pending 重建 + handleEvent 同 id 去重防竞态。**审批卡改从 pendingApprovals 独立面板渲染**(与 messages 解耦,避重连 load_messages 替换 messages 的竞态;落地 MINIDEC-04 单一渲染源决策 a),内联工具卡保留状态徽标/参数/结果。 +> - **P1-C-260622 冷启动恢复** 顺带修复(syncOnConnect 初始连接也拉历史 + active conv id 已持久化)。 + +### ✅ 2026-06-23 miniapp 🟡 收尾批(P1-E/F + P2-C/A + P3-D/C · 自主推进) + +> 用户定「自用」后低风险收尾项一次性做完。逐项 vue-tsc 0 + build DONE 核验。 +> - **P1-E MaxRounds 继续/停止**:useAiChat `maxRoundsActive` ref(AiMaxRoundsReached 置 true,continueLoop/stopLoop/send/switch/new 清)+ chat 「已达最大轮次」面板(继续一轮/停止按钮)。 +> - **P1-F 重发 + 复制**:chat 输入栏「重发」按钮(调 regenerate,非生成中且有消息时显)+ 消息 @longpress 复制全文(uni.setClipboardData)。 +> - **P3-D token 用量**:顶栏显 🪙 total(ai.tokenUsage)。 +> - **P2-C 注释陈旧**:relay.ts 路由表 12→14(+ rename/sync_pending)+ remote_bridge.rs 表头补两行。 +> - **P2-A messages 内存上限**:useAiChat watch trim MAX_STORE_MESSAGES=500(渲染另有 visibleMessages slice 200)。 +> - **P3-C mp-html 死依赖**:核验 package.json 已无 + grep 全 src 零引用(陈旧 todo,无需改)。 +> - **MINIDEC-07** 随 P1-F 选 a(regenerate 加 UI 不删)+ 备份组件保留预留,已落。 +> +> **剩余 [ ](非阻塞)**:P1-A 心跳 pong(已缓解=MINIDEC-06 暂缓)/ P3-B manifest appid(真机前置,需注册)。(P1-G/P2-E/P3-A 见下 polish 批已落) + +### ✅ 2026-06-23 miniapp polish 批(workflow wll377z2c 设计 → 串行实施) + +> workflow 3 agent 并行设计(无限流)→ 汇总排序 → 主代串行实施,逐项 vue-tsc 0 + build DONE。 +> - **P2-E 审批失败回填**(low):useAiChat `lastApprovedTc` ref —— approve(approved=true) 记录,device 返 AiError 回填 pendingApprovals + toast「审批操作未生效,请重试」让用户重试;AiApprovalResult/AiToolCallCompleted 确认 → 清;切会话/新建/断连 → 清。 +> - **P1-G Markdown 渲染**(medium):新建 `utils/mdRenderer.ts` —— marked HTML 后处理注入 inline style(pre 深底等宽/code 橙色/a 蓝下划线/table border),规避 marked renderer v18 签名风险(rich-text 不认 class)。chat/index.vue renderMd + MdView.vue 接入。**链接跳转 rich-text 不可行**( 节点事件屏蔽)降级展示+长按复制,跳转留 mp-html 后续。 +> - **P3-A textarea 多行**(high):input→textarea auto-height(max-height 120px + .bar flex-end 对齐)。⚠️ **原生层级遮联想浮层风险待用户实测**(textarea 原生组件渲染在 WebView 之上,可能遮盖 .mention-pop);若遮挡严重,fallback 联想浮层改 cover-view(单独任务,本次未做)。 +> +> **miniapp 自用阶段功能全部闭环**。剩 P1-A(暂缓)/P3-B(appid 真机前置,需你注册)。 + +**与主走查重复(用户项 = 已登记,跳过)**:用户 P1-5(配置硬编码)= P1-D / P1-6(MaxRounds UI)= P1-E / P2-11(deviceOnline 不复位)= P2-B / P2-9(R1 并发防护)= `remote_bridge.rs:27-33` `check_generating_reject` **已实现**(send_message 路由前置 generating 检查)。 + diff --git a/docs/待决策.md b/docs/待决策.md index b036c3e..7476ee5 100644 --- a/docs/待决策.md +++ b/docs/待决策.md @@ -50,6 +50,17 @@ - **待用户操作**:部分场景运行时实测(A 路线场景 2/3)。 - **状态**:🟡 待用户实测 +#### S-260623-01 「自托管」含义澄清 +- **背景**:用户要求设置支持「自主执行(含高危)+ 自托管」。**自主执行含高危已实现** —— `autoExecuteMode` 三档 `low`/`medium`/`all`(AdvancedSection.vue F-#97, 2026-06-22),`all` = 完全 AI 接管含高危(delete/purge/run_command),选时二次确认。设置 → 高级 → AI 自动执行范围。但「自托管」grep 全项目无匹配,含义未明确。 +- **待用户澄清**:「自托管」指什么? +- **选项**: + - a: 自托管 AI 模型 endpoint(用户配自己的模型 API/本地模型,非默认 provider) + - b: 自管执行策略(= autoExecuteMode 已覆盖,无需另做) + - c: 自托管后端服务(用户自部署 df-relay/df-tunnel,非默认 `u-work.1216.top`) + - d: 其他(用户补充) +- **关联**:task105 / memory(设置自主执行已实现) +- **状态**:✅ **自用阶段定案(2026-06-23)** —— 用户决策:小程序当前自用(开发阶段),分发是产品终态但留后续(过渡期靠改 device_id 实现多机)。故「自托管」现阶段 = 已实现的自主执行(autoExecuteMode all 含高危),无另义。分发阶段再做配置层(MINIDEC-01)+ 配对(MINIDEC-02)。 + #### ~~B-260617-11 tauri.conf.json 打包目标收窄确认~~ - **状态**:✅ 已决(2026-06-18) — 已迁入归档。决策:A 临时本地构建,要求高速。提交前 revert 为 `"all"`。 @@ -172,6 +183,92 @@ - **关联**:消息级溯源 P0(CR-10 ✅)/ P1(CR-12 ✅)/ 消息拆分存储设计文档 - **状态**:🟡 待用户拍板(P2 是否现在做 + 策略 a/b)。大改建议用户知情后启动。 +#### BUG-260623-03 审批 pending 无超时兜底(aichat 卡死·架构) +- **背景**:实测会话 4ae73423 末尾 advance_task 触发审批 `__PENDING__` 后,`agentic/mod.rs:1464` loop return,恢复唯一依赖用户主动 ai_approve。全库无审批超时定时器(cache.rs:31 占位标记无时间戳)。用户离开/忘记 → generating=true 永久挂起,会话卡死,用户须手动重发(且该会话 token 已大,重发易触上限)。属 aichat 中断B,非 generating 状态机卡死(generating 已收敛 GeneratingGuard)。 +- **决策点**:审批 pending 超时兜底怎么实现? +- **选项**: + - a: 后端 per-conv 定时器(到期自动 reject + emit 超时,触及 AiSession 单例 + 定时器机制,最彻底) + - b: 前端倒计时提示(用户可见到期,后端不变,最小改动) + - c: 无超时(现状,靠用户手动) +- **推荐**:**b 前端倒计时**(最小改动不触 AiSession;用户可见主动处理)。a 后端定时器最彻底但触及单例大改,归 [[devflow-async-approval-concept]] +- **关联**:memory devflow-async-approval-concept / docs/05-代码审查/aichat-会话实测分析-2026-06-22.md(CR-260622-01 修正) +- **状态**:🟡 待决策 + +### df-miniapp 全功能审查(2026-06-23 workflow wll7qabgr + 主代补审) + +> 6 区域并行审查(chat/会话页/useAiChat/连接层/组件/工程)。已**自主实施**:F1 看门狗 clearWatchdog 兜底 / F2 regenerate 守卫 / F3 flushCurrentText id 精确回填 / F9 stop 终态兜底 + 停止按钮(原无停止入口) / F21 连接状态中文文案 + 手动重连 / switch default 分支 / 二进制帧 warn / scheduleReconnect maxAttempts / 删 test 死页。以下为需决策项。 + +#### MINIDEC-260623-01 relay 配置层范围(F15·产品方向·分发卡点) +- **背景**:config.ts relayHost/deviceId/token 全硬编码(setConfig 零调用方,storage 未接,无设置页)。当前填测试服 wss + 本机 device_id(联调期)。分发后用户无法改连自托管中继 → 连不上。 +- **决策点**:配置层做到什么程度? +- **选项**: + - a: 完整设置页(表单 + setConfig 接 storage 持久化 + getConfig 回退),用户可改 relay/device/token + - b: 仅接 storage 持久化(setConfig 真生效,无 UI,靠代码/build env 注入) + - c: MVP 接受硬编码(仅自用联调),设置页立项后续 +- **推荐**:**b 至少接 storage**(成本极小让配置真生效);a 设置页 UI 视分发排期。依赖 S-260623-01「自托管」含义(c 自托管后端 → 必须 a)。 +- **关联**:S-260623-01 / memory cross-end-rust-backend +- **状态**:⏸️ **暂缓(2026-06-23)** —— 用户决策:当前自用,硬编码够;分发阶段(产品终态)再做设置页。过渡期多机靠改 device_id。 + +#### MINIDEC-260623-02 配对绑定流程(F16·跨端大改) +- **背景**:ControlMessage.pair 类型已定义但从不发送,deviceId/token 靠用户手抄(查桌面端 KV)。无二维码配对/绑定校验链路。 +- **决策点**:配对流程是否本轮做? +- **选项**: + - a: 完整配对(桌面端生成 QR → relay 校验绑定 → miniapp 扫码获 device_id/token) + - b: MVP 过渡(设置页手填 + UI 提示去哪找 device_id/token) + - c: 不做(手抄够用) +- **推荐**:**⏸️ b MVP 过渡**(a 跨端协作工作量大,依赖 MINIDEC-260623-01 设置页先落) +- **关联**:MINIDEC-260623-01 +- **用户已定未来愿景(2026-06-23)**:分发阶段做完整配对授权,三步:① 设备端弹二维码 ② 小程序扫码识别并授权,双方来回点击确认 ③ 授权管理(设定授权的权限范围等)。本轮不做,留专项。 +- **状态**:⏸️ **暂缓(2026-06-23)** —— 当前自用靠手抄 device_id;分发阶段按上述愿景做完整 QR 配对 + 权限范围管理(跨端 df-miniapp/df-relay/桌面端协同,专项立项)。 + +#### MINIDEC-260623-03 WS 重连续流策略(F10·行为差异·需拍板) +- **背景**:watchdog 在 WS 重连后不重启。重连期间 device 续推 AiTextDelta 会丢(断连窗口)或半截文本错位。当前断连 onStatus 已 reset generating + clearWatchdog(连接断肯定停),但重连后续流未处理。 +- **决策点**:重连后续流策略? +- **选项**: + - a: onStatus 'connected' 主动发 load_messages 重新同步整个会话(最稳,但重置视图) + - b: 收到 AiTextDelta 时若 !generating 隐式恢复 + 补 assistant 占位(最平滑,有幽灵续流风险) + - c: 不处理(接受断连窗口该轮丢失) +- **推荐**:**c 现状**(MVP 断连窗口丢失可接受,a/b 复杂度高)。重度依赖移动端弱网再升级 a。 +- **状态**:✅ **已实施 a**(2026-06-23)—— 用户决策「断网不丢消息 + 从远端拉完整」。useAiChat syncOnConnect:ws 'connected' → 发 load_messages 拉完整历史(断网期间 missed 消息恢复 + 兼修冷启动空白 P1-C)。cargo check 0 + vue-tsc 0 + build DONE。 + +#### MINIDEC-260623-04 审批双源状态分裂统一(F4/F5/F6/F13·渲染源决策) +- **背景**:审批状态双写——pendingApprovals 数组 + messages[].toolCalls.status。AiApprovalRequired 双写为源头,AiError/switchConversation 只清 pendingApprovals 一侧(messages 内 tc 留陈旧 pending_approval)→ 可能渲染陈旧审批按钮,点 approve 命中已失效 tool_call。chat 页按 m.toolCalls 内联渲染审批按钮,pendingApprovals 仅顶部徽标计数。 +- **决策点**:统一单一渲染源? +- **选项**: + - a: 以 pendingApprovals 为准(messages tc 仅显示 status 不渲染按钮)—— 改 chat 页渲染逻辑(行为变更) + - b: switchConversation/AiError 清 pendingApprovals 时同步遍历 messages 把 pending_approval 标 rejected —— 改 useAiChat 状态清理(纯后端态,UI 不变) +- **推荐**:**b 同步清理**(最小行为变更,治陈旧按钮根因)。a 渲染源统一更彻底但 UI 改动大。 +- **关联**:BUG-260623-03(审批超时,后端侧) +- **状态**:✅ **已实施 a 单一渲染源**(2026-06-23)—— 用户决策「审批断网重连恢复卡片状态」。审批卡改从 pendingApprovals 独立面板渲染(与 messages 解耦,避重连 load_messages 替换 messages 的竞态);remote_bridge 加 sync_pending 路由(读 AiSession.pending_approvals 按 conv 过滤重发 AiApprovalRequired/AiDirAuthRequired);useAiChat onStatus 'connected' 清 pendingApprovals + 发 sync_pending 重建;handleEvent 加同 id 去重防竞态重复。内联工具卡保留状态徽标/参数/结果(按钮移面板)。cargo 0 + vue-tsc 0 + build DONE。 + +#### MINIDEC-260623-05 会话页管理缺口(删除/重命名·需后端命令) +- **背景**:conversations/index.vue 仅列表/切换/新建/下拉刷新。无删除/重命名(需后端 delete_conversation/rename_conversation 命令 + remote_bridge 路由,当前无)。 +- **决策点**:miniapp 是否需要会话管理? +- **选项**: + - a: 本轮加(后端命令 + bridge 路由 + 会话页长按菜单) + - b: 暂不做(用户回桌面端管理,MVP 仅查看/切换) +- **推荐**:**⏸️ b 暂不做**(miniapp 定位轻量操作终端,会话管理桌面端足够) +- **状态**:✅ **重命名已实施 / 删除暂缓**(2026-06-23)—— 用户决策「小程序对齐桌面端能改会话名」。remote_bridge 加 rename_conversation 路由(调 ai_conversation_rename + 推 AiConversationList 刷新);useAiChat renameConversation 方法(乐观本地更新);conversations/index.vue 长按会话 uni.showModal 编辑。删除会话暂不做(桌面端管理)。cargo 0 + vue-tsc 0 + build DONE。 + +#### MINIDEC-260623-06 心跳/历史替换协议(F8/F20·跨模块·低优先) +- **背景**:(F8)心跳活性检测依赖「任意入站消息」,低活跃场景每 ~60s 误判半开死连接触发无谓重连(relay 无 pong);(F20)AiMessageHistory 整体替换会丢弃正在进行的乐观气泡(device 主动推历史路径难区分 load 响应)。 +- **决策点**:是否本轮改 relay 协议? +- **选项**: + - a: relay 加 pong + 历史事件加 load_id/sync_source flag(跨模块改 df-relay + 后端 events) + - b: 前端缓解(放宽 DEAD_FACTOR / 「仅本地空才替换历史」启发式,语义脆弱) + - c: 暂缓(MVP 低频空闲场景可忍) +- **推荐**:**⏸️ c 暂缓**(跨模块改动 ROI 低) +- **状态**:⏸️ 暂缓 + +#### MINIDEC-260623-07 regenerate 零调用方 + 备份组件漂移(P3 收尾) +- **背景**:(1) useAiChat.regenerate() 零调用方(全死,已加 generating 守卫防御);(2) MdView.vue/MentionInput.vue 因绕工具组件解析 bug 被 chat 页内联,源文件保留备用但已与内联实现漂移(MdView 无 mdCache、MentionInput 是 MVP 占位)——「拆回」时会引入旧实现。 +- **决策点**:regenerate 加 UI(重发按钮)or 删?备份组件同步/删/保留? +- **选项**: + - a: regenerate 加重发按钮 + 备份组件同步内联实现(或删) + - b: regenerate 删减负 + 备份组件保留标注释(预留工具 bug 修复后拆回) +- **推荐**:**b**(regenerate 删减负,备份保留预留意图)。或 a 视移动端重发需求。 +- **状态**:✅ **随 P1-F 选 a**(2026-06-23)—— 🟡 收尾批给 regenerate 加「重发」UI 入口(对齐桌面端),故保留函数不再删;备份组件(MdView/MentionInput)保留预留注释(绕工具解析 bug,未来拆回)。 + --- ## workspace_root 分发适配(编译期 CARGO_MANIFEST_DIR 写死,跨机器/跨平台失效) @@ -200,6 +297,8 @@ **关联**:F-260619-03 去固定根(已删 is_authorized 硬编码放行)/ projects.path 自动授权(reload_allowed_dirs)/ memory [[devflow-project-path-binding]] **状态**:🟡 待决策(workspace_root 运行期动态方案 a/b/c/d)。**分发前必须解决**(否则分发后 AI 文件工具全部失效)。 +**2026-06-23 进展(BUG-260623-01)**:实测会话 6acb7f9b 暴露 write_file/append_file/rename_file 父目录校验**误用 workspace_root**(tool_registry.rs:1112/1418/1555 原用 `starts_with(workspace_root())`)→ 用户授权的其他项目目录(ai-news 等)parent 不 starts_with devflow 源码目录 → 误拒「禁止在项目目录之外创建目录」(用户授权了仍拒)。**已修**:三处改用 `allowed_dirs.is_authorized(parent)` 脱离 workspace_root。**仍写死残留**(待本决策 a/b/c/d 根治):delete_file:1482 trash 目录 / resolve_workspace_path_impl:380 相对路径 join / run_command:1791 working_dir 默认。 + --- ## F-260619-03 路径授权政策:工程内默认免授权(用户 2026-06-20 指令) diff --git a/docs/待审查.md b/docs/待审查.md index 35de9ae..b1b00af 100644 --- a/docs/待审查.md +++ b/docs/待审查.md @@ -23,6 +23,25 @@ ## 当前队列 +### CR-260622-01 AI Chat 真实会话实测分析(84dc36c8·prompt 1.32M/completion 7.5K·3P0+3P1+2P2)— 🟡 待审 + +- **范围**:实测数据反推(**非静态代码审查**)。从生产 DB 会话 `84dc36c8`(D:\Downloads\kms,整理三知识库 HTML)全量 86 条消息反推上下文/工具/agent 行为缺陷。报告 `docs/05-代码审查/aichat-会话实测分析-2026-06-22.md`,分析脚本 `.temp/analyze_session.py`,DB 只读 `%APPDATA%/top.1216.devflow/devflow-dev.db`。 +- **维度**:(a) 独立核验 db 实测数据(token 比/重复 tool 结果/system 污染/时序);(b) 核验源码根因(报告 finding 均为"假设"待证)。 +- **核验方式**:只读 DB(`mode=ro`)+ grep/read 源码,**不信报告结论**(防上下文污染,[[code-review-anti-contamination]])。 +- **待审点(8)**: + - P0-1 压缩标记 `compressed` 未真降 prompt(1.32M)— 核 compress 模块是否替换为摘要还是仅打标记 + - P0-2 `patch_file`/`read_file` 部分路径裸吐文件全文(`raw 6204c`)非 JSON — 核 `tool_registry.rs` 返回序列化分支 + - P0-3 重复 tool 结果(seq 11-14 四份/69-71/83-85 三份同长度同秒)— 核 `ai_messages` 落库去重 / 流式 patch 合并 + - P1-1 过早宣称完成 3 次被推翻,无 checklist 自检 — agent 行为层 + - P1-2 末尾 #82→#85 tool 全返回后无 assistant 回复(中断)— 核 generating 复位/`try_continue` + - P1-3 三独立文件(mysql/redis/linux)整理本可并行却严格串行,无 fan-out 调度 — 印证 [[aichat-b-route-parallel-multiround]] + - P2-1 seq 0 system 消息内容污染 + 时序错乱(晚 seq 1 十小时)— 核 system 注入 + timestamp + - P2-2 同文件反复 read(mysql/linux 各 4×)无缓存 +- **最高杠杆**:P0-2(工具返回改 diff/changed 而非全文)→ prompt 降一个量级。 +- **关联**:[[aichat-techdebt-audit-2026-06-21]] [[devflow-generating-statemachine]] [[aichat-b-route-parallel-multiround]] [[aichat-decision-capability]] + +--- + ### CR-260620-04 Agent 最大轮次支持「不限」(working tree 未提交:0=不限 约定·config.rs clamp 0-50 + mod.rs effective_max 0→usize::MAX + GeneralPanel checkbox + App.vue clamp + i18n labelUnlimited) — ✅ 已审(PASS·⚪2 WATCH·巡检 2026-06-20 独立 grep/read 核验控制流) - **范围**:新功能。约定 0=不限:后端 config.rs:69 clamp(1,50)→(0,50);mod.rs:542 loop 上界算 effective_max(0→usize::MAX,for 到不了上界,靠 stop_flag/收敛/审批退出,达上限暂停 AiMaxRoundsReached 不触发);前端 GeneralPanel 加「不限」checkbox(绑 agentMaxIterations===0)+ input :disabled + clamp 支持 0 + computed unlimited;App.vue:107 clamp 跟进(iter===0?0:...);i18n zh/en desc 加 0=不限 + labelUnlimited。