Files
DevFlow/docs/05-代码审查/aichat交互走查-2026-09-28.md

54 lines
6.7 KiB
Markdown
Raw Permalink 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.
# aichat 交互体验走查报告(2026-09-28)
> 走查代理产出,主代理核验登记。背景:devflow 启动定位=日常 AI 交互调度中枢(替代飞书侧),按「日常主入口」标准走查。
> 方法:per-conv 状态机/流式/审批/失败保文全链路代码走查 + 对照 todo.md 与 05/06 目录历史报告区分已知/新发现 + git 实证回归点。守 session-role-diagnose-only,未改代码。
**总体定性**:aichat 前端交互基建已相当成熟(per-conv 状态机、流式块级 memo、审批超时兜底、失败保文、乐观更新+回滚大量落地),历史登记债绝大多数已销账且与代码相符。本轮新发现集中在两类:**God 组件拆分时丢功能的链路断点**(编辑入口回归丢失为最重)与**多会话并发收口的残留缝隙**(队列/错误气泡/审批徽标的 per-conv 未收尾)。
## 已知已登记(核验确认,不重复报告)
1. useAiSend(562行)/useToolCard(741行) 大文件债(fe-arch P0-1/P0-3)仍成立;useAiEvents 已拆 12 个 composable(WC-P2 销账属实)
2. 信息密度构想:痛点部分缓解(长消息1500字折叠/工具卡分组/归档段折叠已有),会话详情面板不存在、消息恒渲染(B-260618-01 有意移除虚拟滚动)
3. 压缩消息展示符合规范(compressed 原文展开+摘要置顶,MessageList.vue:641-659/843-847)
4. agentic 进度条 max 轮次降级省略(AiChat.vue:50 TODO,后端未透传 max_rounds)
5. 效率走查-2026-08-09 前端项(S2-3/F2-5/S1-2 等)不重复
6. **todo 滞后**:B-260619-04 步骤③「新轮到达自动收起旧轮」标 ⏸️,实际 MessageList.vue:335-341 已落地,建议销账
## 新发现清单(按严重度)
### P1
1. **编辑末条 user 消息入口丢失(回归)**——UX-09 下游链路完整(编辑态 prop/startEditFocus/editMessage 截断重生成全在),但触发按钮不存在:MessageList.vue:36 声明 emit('start-edit') 全文件无触发点;AiChat.vue:37 @start-edit 绑定与 :294-298 startEdit 悬空;MessageItem.vue:20-22 emits 仅 copy;.ai-msg-edit-btn 成死样式(MessageList.vue:1303-1325)。git 实证:2c2b2d7 提取 MessageItem 时按钮未迁移(旧 MessageList:1003 有),f719546 只清悬空声明。用户感知:已发消息想改措辞重问,无任何入口
### P2
2. **审批拒绝原因显示原始 i18n key**——useAiToolEvents.ts:90 与 useAiApproval.ts:90 用 t('ai.aiTool.rejectedHint'),正确 key 是 aiTool.rejectedHint(多加了 ai. 前缀)→ 拒绝后工具卡显示 key 字面量而非「用户拒绝了此操作」
3. **英文环境重试过渡气泡永久残留**——收尾清理按中文硬编码匹配 '正在重试('(useAiLifecycleEvents.ts:62),en 文案是 "retrying (" → 切英文后 AiStreamRetry 气泡收尾时匹配失败不清除
4. **AiError 静默清空该会话排队消息**——useAiLifecycleEvents.ts:166-171 出错即 filter 整个会话队列,无「排队消息已丢弃」提示;对照 drainQueue 失败路径专门不静默丢输入回填队首(useAiSend.ts:296-298),同域行为不一致
5. **全局清队列残留两处(07-17 报告 P1-1 判已修销账,实际未收口)**——useAiApproval.ts:99(审批 IPC 失败 state.queue=[])与 streamingGuard.ts:103(forceResetStreaming,被 per-conv 看门狗超时调用)仍清全部会话队列;streamingGuard.ts:91-94 注释自知「queue 清理由 F-09 统一改」但未改
6. **后台会话终止类错误气泡推错视图**——审批超时气泡(aiShared.ts:178-184)与看门狗超时气泡(useAiStream.ts:104-110)push 到当前活跃视图不按所属 convId 路由;hasCompletedTool 区分文案同样扫错视图(useAiStream.ts:87-97)。用户感知:B 会话后台卡死,A 会话冒「响应中断」
7. **429/额度耗尽无分类提示且重试按钮照显**——friendlyError 仅四类匹配(aiShared.ts:26-32),AiErrorType 无 quota/rate_limit(types.ts:391)→ 429 落 unknown:原始英文直出+canRetry=true,额度未恢复时重试必再败(08-11 实证 429 占 55%;后端 retry.rs:65 亦归 Retryable)
8. **审批徽标跨会话计数误导且点击无反馈**——pendingApprovals 全局数组,TopBar 徽标(AiChat.vue:210)不按当前会话过滤;点击 scrollToFirstPending(MessageList.vue:299-310)在当前视图找不到卡静默 no-op;ApprovalOverlay/浮窗「打开审批面板」同样找不到卡
### P3
9. 消息删除能力缺失(全链无单条删除 IPC 与入口,仅整会话 clearChat)
10. user 消息无时间戳(ai-msg-time 仅 AI 分支渲染 MessageList.vue:1015-1020;.ai-msg-time--user :1267-1269 死样式)
11. compressed 分段死代码(messageSegments 已不产出 compressed 段,kind 类型 :632/sep 模板 :821-827/CSS :1539-1548 残留)
12. 会话级 token 总量只写不读(convTokenTotal 写入 useAiConversations.ts:396/useAiLifecycleEvents.ts:130-135,无 UI 消费——「会话详情面板」构想的现成数据源闲置)
13. 中间错误气泡重试错位(handleRetry 不带 msg 参数 MessageList.vue:592-601,恒重跑末轮而非该错误)
14. 批量审批部分失败无用户提示(useAiApproval.ts:156-159 仅 console.warn)
15. AiToolCallStarted 工具卡丢弃边缘竞态(仅末条 assistant 才 push,useAiToolEvents.ts:26-30)
16. 注释与实现矛盾(AiChat.vue:263-266 新建对话失败注释称错误气泡反馈,实际仅 console.error;实际由 withConvOp 兜底,无用户影响但注释误导)
17. 图片默认上传外部服务 file.1216.top(fileUpload.ts:9 硬编码默认,可 df-file-upload-base 覆盖)——业务域名入代码,对产品分发定位与开源边界是待决策项
## 修复优先建议(按「日常主入口」标准)
- 第一批(日常使用直接受伤):#1 编辑入口回归、#4+#5 排队消息被静默丢、#6 错误气泡推错视图、#7 429 分类
- 第二批(多会话体验):#8 审批徽标、#3 en 气泡残留、#2 i18n key
- 第三批:P3 项随批清理
## 走查覆盖文件
docs/todo.md、docs/06-前端开发/前端架构技术债-2026-06-19.md、docs/05-代码审查/{aichat-对话功能走查-2026-07-17,aichat效率走查-2026-08-09}.md;src/components/{AiChat.vue,ai/MessageList.vue,ai/MessageItem.vue,ai/ChatInput.vue,ai/ApprovalOverlay.vue,ai/EmptyState.vue,ToolCard.vue,ToolCardList.vue,ToolResultBody.vue};src/composables/ai/{useAiSend,useAiEvents,useAiStreamingEvents,useAiToolEvents,useAiLifecycleEvents,useAiApproval,useToolApproval,useToolCardHeader,aiShared,useAiStream,streamingGuard,useAiConversations,useApprovalPopup,fileUpload}.ts;src/stores/ai.ts、src/api/types.ts、src/i18n/zh-CN/{ai,aiTool}.ts、src/i18n/en/ai.ts、crates/df-ai/src/retry.rs(定向)