文档: 架构方案文档(意图识别论证+多主题愿景/论证+文档物理分类+边界清晰化)

squash合并:
- 意图识别层论证(8维度+10业界佐证)
- 多主题上下文管理愿景+并存论证+补充论证(多轮agentic)
- 架构设计文档物理分类(四子目录+INDEX+命名规范+引用同步+边界清晰化)
- 前端架构技术债清单归档
This commit is contained in:
2026-06-19 15:04:04 +08:00
parent f1a06732fd
commit 998a2f243d
73 changed files with 1083 additions and 80 deletions

View File

@@ -0,0 +1,295 @@
# AIChat 交互体验改进方案
> 创建: 2026-06-14 | 状态: 待讨论
> 范围: 消息发送、流式渲染、对话管理、错误恢复、技能/Provider、窗口布局等非授权类交互
---
## 一、消息输入与发送
### 1.1 无法编辑已发送消息
**现象**:用户发出消息后发现措辞有误,只能重新打一条新消息。无法像 ChatGPT/Claude 那样编辑上一条用户消息并重新生成。
**根因**`sendMessage`useAiSend.tspush 后的消息是只追加不可变的。前端没有编辑入口,后端 `ai_chat_send` 也没有"替换最后一条 user 消息并重跑"的语义。
**方案**
- 用户消息气泡 hover 显示"编辑"按钮
- 点击后消息内容回填到输入框,用户修改后发送时后端截断该消息之后的所有历史(含 AI 回复),重新跑 agentic loop
- 后端新增 `ai_chat_edit` 命令,接收 `message + 截断位置`,替换 messages 数组中对应 user 消息并清掉后续消息,然后走正常 `run_agentic_loop`
### 1.2 无法重新生成 AI 回复
**现象**AI 回答不满意时没有"重新生成"按钮,只能重新措辞追问。
**根因**`AiChat.vue` 的 AI 消息气泡上没有任何操作按钮。后端也没有 `ai_regenerate` 命令。
**方案**
- AI 消息气泡 hover 显示操作栏(复制 | 重新生成)
- "重新生成":后端删除最后一条 AI 消息,用倒数第二条 user 消息重新触发 `run_agentic_loop`
- 后端新增 `ai_regenerate` 命令
### 1.3 无法一键复制消息内容
**现象**:代码或文本只能手动选中复制。流式渲染中选中文字会被后续 delta 打断。
**根因**:消息气泡上没有复制按钮。
**方案**
- AI 消息气泡 hover 显示"复制"按钮
- 点击后 `navigator.clipboard.writeText(msg.content)`toast 提示"已复制"
- 代码块单独提供"复制代码"按钮hover 代码块右上角浮出)
### 1.4 缺少 `@` 实体引用
**现象**用户无法在输入时引用某个项目、任务或文件。描述需求时无法精确指定上下文AI 可能猜错对象。
**根因**:输入框只有 `/` 技能联想,没有 `@` 实体引用机制。
**方案**
- 输入框支持 `@` 触发实体联想浮层(复用技能联想的 popover 架构)
- 联想源:项目列表、任务列表、最近编辑的文件
- 选中后在消息中展开为 `[项目: u-desk]` 等标记文本,后端 system prompt 注入对应实体的上下文摘要
### 1.5 输入框高度过紧
**现象**textarea 最大高度 120px约 5-6 行),超过后内部滚动。用户写长提示词时看不到全貌。
**根因**`autoResize``Math.min(el.scrollHeight, 120)` 限制太紧。
**方案**
- 最大高度提升到 200px约 10 行),超过后再内部滚动
- 或改为可拖拽调整高度(底部 resize handle
---
## 二、流式渲染与消息展示
### 2.1 流式渲染中无法稳定选中文字
**现象**AI 正在流式输出时,用户尝试选中已渲染的文字,新的 delta 触发 DOM 更新导致选区丢失。
**根因**`renderContent` 在流式时返回 `streamingHtml.value`rAF 节流重 parse每次更新都 `v-html` 替换整个 DOM 子树,浏览器选区被清除。
**方案**
- 方案 A推荐检测到用户正在选择文字时`selectionchange` 事件 + 选区非空且在消息容器内),暂停 rAF 流式 parse选区结束后恢复
- 方案 B流式渲染时在已完成的块blockCache 命中的块)上使用独立 DOM 节点不参与 v-html 替换,仅末块动态更新
### 2.2 代码块无语法高亮、无复制按钮
**现象**Markdown 代码块只有纯文本渲染,没有语法高亮,也没有一键复制按钮。
**根因**`useMarkdown` composable 配置了 marked + DOMPurify但没有集成 highlight.js / Prism 等高亮器。
**方案**
- 集成 highlight.js体积小、语言全在 marked renderer 的 `code` 回调中调用 `hljs.highlightAuto` 或按 info string 指定语言
- 代码块右上角浮出"复制"按钮纯前端hover 显示)
- 高亮器按需加载(与 marked 一样后台预热,不阻塞首屏)
### 2.3 历史消息无分页懒加载
**现象**:切换对话时 `switchConversation` 一次性加载全部 messages 到 `state.messages`。超长对话可能一次加载几百条消息。
**根因**`switchConversation`useAiConversations.ts直接 `state.messages = rawMsgs.filter().map()`,无分页。
**方案**
- 首次加载最近 50 条,滚动到顶部时加载更多(前端 slice + 后端支持 offset/limit 查询 messages
- 或前端全量加载但虚拟滚动只渲染可视区域(见 7.2
### 2.4 消息不显示时间戳
**现象**:消息气泡上不显示发送时间。用户无法判断某条消息是多久前发的。
**根因**:模板中 AI/用户消息都没有渲染 `msg.timestamp`
**方案**
- 消息气泡下方或侧边以极小字号9px+ dim 颜色展示相对时间(`formatRelativeZh`
- hover 时 tooltip 展示完整时间
---
## 三、对话管理
### 3.1 对话搜索缺失
**现象**:侧栏对话列表只能滚动浏览,没有搜索框。对话多了之后找不到特定对话。
**根因**:侧栏 `.ai-conv-list` 直接渲染 `groupedActive`,上方只有"新建"按钮,没有搜索输入框。
**方案**
- 侧栏 header 下方增加搜索输入框(实时过滤 `state.conversations`,匹配 title
- 搜索时取消分组,按相关度/时间平铺展示
- 支持 `Ctrl+K` 快捷键聚焦搜索框
### 3.2 对话无法置顶
**现象**:没有置顶或收藏功能。重要对话会被新对话挤到下面。
**根因**:对话列表只按 `updated_at` 排序,无 `pinned` 字段。
**方案**
- `ai_conversations` 表增加 `pinned INTEGER DEFAULT 0`
- 排序逻辑改为 `pinned DESC, updated_at DESC`
- 侧栏对话项 hover 显示"置顶/取消置顶"按钮(图钉图标)
### 3.3 对话无法导出
**现象**:无法将对话导出为 Markdown / JSON / 文本文件。
**根因**:没有导出 IPC 命令和前端入口。
**方案**
- 后端新增 `ai_conversation_export(conv_id, format)` 命令,支持 `markdown` / `json` / `txt` 三种格式
- 前端侧栏对话项 hover 显示"导出"按钮,或对话操作菜单中提供
- Markdown 格式:`## 用户` / `## 助手` 交替,代码块保留围栏
### 3.4 新建对话强制中断已有生成
**现象**:用户在 AI 生成中点"新建对话",后端 `ai_conversation_create` 会强制复位 `generating=false` + 置 `stop_flag`,中断当前生成。
**根因**`commands.rs ai_conversation_create``if session.generating` 分支主动结束生成B-260615-10 设计)。
**方案**
- 生成中点"新建对话"时弹 ConfirmDialog"当前对话正在生成,确定要新建对话并中断吗?"
- 用户确认后才执行中断+新建;取消则不操作
- 或改为不中断:新对话仅切换视图,旧对话后台继续生成(需 AiSession 多实例化支持,属远期方案)
---
## 四、错误处理与恢复
### 4.1 错误气泡无操作入口
**现象**:错误气泡只显示一行文字(如 `[GLM-4] AI 调用失败(HTTP 401): Unauthorized`),没有"重试"按钮或"去设置"链接。
**根因**`AiError` 事件只携带 `error: String`,前端 `handleEvent` push 一条 `isError: true` 的消息气泡,无操作按钮。
**方案**
- 错误气泡底部增加操作按钮区:
- **重试**:取上一条 user 消息重新发送(调 `ai_chat_send`
- **去设置**(仅 401/403/Provider 未配置时显示):跳转到 Settings → AI Tab
- 错误消息结构扩展:后端 `AiError` 增加 `error_type: Option<ErrorType>` 枚举(`auth` / `network` / `timeout` / `provider_config` / `unknown`),前端据此决定显示哪些按钮
### 4.2 流式中断丢失已生成文本
**现象**网络波动导致流式中断idle timeout 或 mid-stream error已接收的文本被丢弃`stream_llm` return None → `agentic.rs` emit AiError 并退出),用户看到错误气泡,之前生成的几百字全部丢失。
**根因**`stream_llm` 遇到错误时 `return None`,不保留已接收的部分文本。`agentic.rs` 收到 None 后直接结束。
**方案**
- `stream_llm` mid-stream error 时改为返回 `Some((partial_text, tool_calls, usage))` + 一个 `incomplete: bool` 标志
- `agentic.rs` 收到 incomplete=true 时:
- 已有文本正常入库(标注 `truncated`
- emit `AiCompleted`(而非 AiError让前端正常展示已生成内容
- 在消息末尾追加系统提示:"⚠ 响应因网络中断不完整"
- 前端 AI 消息气泡底部显示"继续生成"按钮(用最后一条 user 消息重新触发,后端识别不完整消息做续写或重跑)
---
## 五、技能与 Provider
### 5.1 Provider 切换零反馈
**现象**:点击 provider bar 循环切换 provider`cycleProvider`),切换后只在 bar 上显示名字变化,没有 toast 或动画反馈。
**根因**`cycleProvider` 直接调 `store.setProvider`,无 UI 反馈。
**方案**
- 切换后 toast 提示"已切换到 {providerName}"
- provider bar 切换时加 0.15s 淡入动画
- bar 上增加 provider 状态指示model 名称小字展示)
### 5.2 技能联想不展示参数用法
**现象**:技能联想浮层显示 name + description + source但不显示技能的参数格式或示例。选中后 placeholder 里的 `argument_hint` 太短。
**根因**:浮层设计只展示概要信息,`argument_hint` 仅在选中后作为 placeholder 显示。
**方案**
- 联想浮层每项增加一行参数提示(`argument_hint` 以等宽字体小字展示)
- 选中技能后输入框上方 chip 展示完整的参数格式说明(而非仅 name + description
- 或选中技能后自动在输入框填入模板骨架(如 `/commit `),光标定位到参数位置
---
## 六、窗口与布局
### 6.1 侧栏宽度不可调
**现象**:侧栏固定 160px不可拖拽调整宽度。长对话标题被截断。
**根因**`.ai-conv-sidebar { width: 160px; min-width: 160px; }` 硬编码。
**方案**
- 侧栏右边缘增加 2px 拖拽条(`cursor: col-resize`
- 拖拽时实时更新 width范围 120~280px
- 宽度持久化到 `df-ai-ui` 设置(与 sidebarOpen/maximized 同存)
### 6.2 分离窗口关闭后生成态不同步
**现象**:分离窗口关闭时,如果正在生成,主窗口虽然 `panelOpen=true` 恢复,但 `state.streaming` / `state.currentText` 可能不同步——如果生成中的对话不是主窗口当前活跃对话,主窗口看不到生成态。
**根因**:分离窗口关闭走 `closeDetachedWindow`,清了 localStorage 快照,但主窗口的状态依赖事件路由自然恢复。
**方案**
- 分离窗口关闭时,主窗口检测 `state.generatingConvId` 非空,自动切换到正在生成的对话
- 或在主窗口 header 显示"对话 X 正在生成中"提示条,点击切换过去
---
## 七、其他交互细节
### 7.1 无键盘快捷键
**现象**:除了 Enter 发送 / Shift+Enter 换行,没有其他快捷键。
**方案**
| 快捷键 | 功能 |
|--------|------|
| `Ctrl+N` | 新建对话 |
| `Ctrl+K` | 搜索对话 |
| `Ctrl+L` | 清空当前对话 |
| `Ctrl+Shift+C` | 复制最后一条 AI 消息 |
| `Ctrl+R` | 重新生成最后一条 AI 回复 |
| `Esc` | 关闭面板(嵌入模式)/ 关闭窗口(分离模式) |
| `Ctrl+B` | 切换侧栏 |
### 7.2 消息列表无虚拟滚动
**现象**:消息列表直接 `v-for` 渲染所有消息,长对话几百条消息全量渲染 DOM滚动卡顿。
**根因**:没有使用虚拟滚动库。
**方案**
- 集成 `vue-virtual-scroller` 或自研 IntersectionObserver 懒渲染
- 仅渲染可视区域 ±缓冲区的消息节点
- 注意:流式渲染的最后一条消息需要始终保持挂载
### 7.3 空状态无引导
**现象**:首次打开 AI Chat有 provider 配置),空状态只显示标题+提示语,没有示例问题或快捷操作。
**方案**
- 空状态展示 3-4 个示例问题卡片(如"帮我创建一个新项目"、"查看当前任务列表"、"分析这段代码的问题"
- 点击卡片自动填入输入框并发送
- 无 provider 配置时展示"去配置 AI Provider"引导按钮
### 7.4 对话标题生成对用户不透明
**现象**:对话标题由后端 `ensure_conversation_title` 异步生成,侧栏对话从"新对话"突然变成某个标题,没有过渡。
**方案**
- 标题生成后加 0.3s 淡入动画
- 或在标题前加小图标标识"AI 自动生成"(可 hover 查看)
---
## 八、落地优先级
| 批次 | 痛点 | 理由 |
|------|------|------|
| **第一批** | 2.1 流式选中文字、1.2+1.3 消息操作栏(复制/重新生成、4.1 错误重试、4.2 断线保文 | 每次对话都会遇到,最高频痛点 |
| **第二批** | 2.2 代码高亮+复制、3.1 对话搜索、7.1 键盘快捷键、3.4 新建不中断生成 | 显著提升日常效率 |
| **第三批** | 1.1 编辑重发、1.4 `@` 引用、3.3 导出、7.2 虚拟滚动、6.1 侧栏可调 | 按需推进,锦上添花 |
| **第四批** | 2.3 分页加载、2.4 时间戳、3.2 置顶、5.1+5.2 技能/Provider 反馈、7.3+7.4 空状态/标题 | 打磨细节 |

View File

@@ -0,0 +1,102 @@
# 构想:AI Chat 信息密度优化 — 折叠 + 会话详情面板 — 2026-06-14
> 性质:功能升级构想(瞬时灵感),未实现。记录作为后期优化参考。
## 背景
提高 AI chat 对话区有用信息密度。当前长回复/代码块/历史轮次全展开,信息密度低,关键内容被淹没。两个构想:① 卡片与消息折叠策略;② 会话详情面板组件。
---
## 构想一:卡片与消息折叠
### 当前折叠现状(2026-06-14 探索)
**已有折叠**:
- 工具卡片:卡片级折叠(`ToolCardList.vue` expandedCards)+ read_file 内容级折叠(expandedTools,max-height 180px + 渐隐)+ list_directory max-height 220px + 通用 result max-height 100px。
- `shouldKeepOpen`:running/pending_approval/rejected/write_file 保持展开。
- auto-collapse(`AiChat.vue:639-667` watch):新内容追加时收起旧已完成/已拒绝卡。
- 侧栏归档分组可折叠。
**未折叠(可优化)**:
- AI 消息正文:template `AiChat.vue:191-198` `v-html` 全展开,长 markdown 无截断。
- 代码块:markdown `pre code` 无折叠(`:1103-1118` 仅样式)。
- 用户消息:`ai-msg-bubble--user` 全展开(`:1058`)。
- 同消息多 toolCall:逐卡渲染,无聚合。
- 历史 agent 轮次:每轮独立气泡全展开,无折叠。
### 可折叠优化点
| 对象 | 当前 | 折叠策略建议 |
|------|------|-------------|
| AI 消息正文 | 全展开 | >N 行(如 15)截断 + 渐隐 + "展开"(复用 read_file 卡的 max-height + ::after 模式);折叠态显示首行摘要 |
| 代码块 | 全展开 | >20 行折叠,显示"展开 N 行";默认显示首尾几行 |
| 用户消息 | 全展开 | >5 行折叠为摘要 + "展开" |
| 同消息多 toolCall | 逐卡 | ≥3 个聚合成"完成 N 个工具调用 [展开]",展开后逐卡(已有 auto-collapse 配合) |
| 历史 agent 轮次 | 每轮全展开 | 非最新轮折叠为单行(轮次标识 + 文本摘要 + 工具数),点击展开 |
| 错误消息 | 各自气泡 | 连续多条错误可堆叠折叠 |
### 设计原则
- 折叠态必须有**摘要**(避免光秃秃):AI 消息取首行/工具卡已有 `toolResultSummary`
- 最新/活跃内容默认展开,历史默认折叠(与现有 auto-collapse 一致)。
- 流式生成中不折叠(避免重渲染抖动,与 H1 流式重解析问题联动)。
- 折叠状态可记忆(同会话内持久,刷新重置)。
---
## 构想二:会话详情面板
> 在 AI Chat 对话面板增加"会话详情"功能组件,聚合展示当前会话的全维度信息。
### 功能建议
**1. 当前会话整体信息**
- 标题 / provider / model / conversation_id
- token 总量(prompt + completion,来自 conversation 表累加字段)
- 消息数 / 工具调用数 / 审批数(通过/拒绝/待审)
- 创建时间 / 更新时间 / 持续时长
**2. 历史整体对话**
- 侧栏已有对话列表;详情面板补:搜索(标题/内容)、按时间/provider/状态筛选、批量归档/删除、导出(Markdown/JSON)。
**3. 审计类能力**
- 工具执行时间线(来自 `ai_tool_executions` 表:tool_name / arguments / result / status / risk_level / requested_at / executed_at / decided_by)。
- 风险分布(Low/Medium/High 统计)、审批通过率。
- token 消耗趋势(按轮次/按时间)。
- 决策记录跳转(若有 DecisionJournal 关联)。
**4. 快捷获取某类信息**
- 按工具类型筛选(只看 read_file / 只看 create_project)。
- 按风险/状态筛选(只看待审批)。
- 关键词搜消息全文。
- 时间范围筛选。
### 后端数据支撑(已有,无需新建)
| 数据 | 来源 |
|------|------|
| 对话元信息 + token | `conversations` 表(title/model/provider_id/prompt_tokens/completion_tokens/messages),`conversation.rs` 累加 |
| 工具执行审计 | `ai_tool_executions` 表,`audit.rs` 写入 + `list_pending` / `find_by_tool_call_id` 查询 |
| 消息全文 | `ai_conversation_detail` IPC(已返回 messages JSON) |
**待补 IPC**:工具执行按 conversation 聚合查询(现有 list_pending / find_by_tool_call_id,需加 by_conversation 全量时间线);token 趋势(按轮次拆分,当前只存总量)。
### 组件设想
- 入口:header 加"详情"按钮,或对话项右键菜单。
- 形态:侧滑面板(drawer,不离开对话)/ modal / 独立路由(/ai-detail/:id)。
- 结构:Tab 分「概览 / 审计时间线 / 消息检索」。
---
## 评估
| 构想 | 复杂度 | 依赖 | 建议 |
|------|--------|------|------|
| 折叠策略 | 中 | 纯前端,复用现有 max-height 模式 | 优先做 AI 消息正文 + 代码块折叠,收益最大 |
| 会话详情面板 | 中高 | 前端新组件 + 后端补聚合 IPC | 审计时间线最有价值(数据已在),先做概览 + 审计两 tab |
两者都与信息密度相关:折叠压缩单条信息,详情面板聚合全局信息。可并行推进。
## 关联
- 折叠与 [[devflow-aichat-review-pending]] H1(流式重解析)联动——流式中不折叠,完成后折叠。
- 会话详情审计能力复用 audit.rs 已有审计表。

View File

@@ -0,0 +1,299 @@
# aichat 审查报告 — 2026-06-14
> 性质:只审查不改代码。本报告汇总本次会话对 devflow AI chat 全链路的核对发现。
> 增补:2026-06-14 追加「修复进度」表AC1/AC2、AR-3、FR-S4、FR-R4、FR-R5 对照 commit 36d68dd / 4b5f096 标已完成),并在 §8 优先级表 AR-3 行内联标注。
> 二次增补:2026-06-15 §8 优先级表全表对齐 todo.md AR 编号体系,逐行补 AR-1~AR-11 标签 + 状态勾注AR-1 退役 / AR-2~7/9~11 已修 / AR-8 重评降级)。
## 审查范围
- **前端**:`src/components/AiChat.vue` + `src/composables/ai/*.ts`(events/stream/send/conversations/window/panel 六个)+ `src/components/ToolCard*.vue` + `src/views/AiDetached.vue` + `src/App.vue` 面板挂载
- **后端**:`src-tauri/src/commands/ai/*.rs`(commands/agentic/audit/stream_recv)+ `crates/df-ai/src/context.rs` + `src-tauri/src/commands/ai/tool_registry.rs`
- **i18n** + **数据联动机制** + **工具定义**
发现分六块:交互流畅性 / 信息卡片完整性 / clean 与压缩对话 / create_project 双审 / 数据联动方案 / 想法→灵感迁移。
## 修复进度2026-06-14 增补)
> 本节汇总对照后续 commit 已落地的修复项,供快速核对。未列入的本报告其余发现仍待办。
| ID | 问题 | 修复 commit | 状态 |
|---|------|------------|------|
| AC1/AC2 | `tool_use_id` 为 None/空致 GLM 端 500 卡死 | 36d68dd | ✅ 已完成(出站 tool_result 块 tool_call_id 空跳过+warn入站 tool_use 缺 id 流式填占位 `tool_missing_{idx}`+warn、同步路径跳过|
| AR-3 | 审批卡片裸 id + reason 两句固定模板(详见 §2| 36d68dd | ✅ 已完成(前端 `toolArgsEntries` 对 id/project_id 白名单特化查项目名回显;后端 reason 查不到对象时友好提示)|
| FR-S4 | SKILL.md 全文注入 system prompt 无隔离标注 | 36d68dd | ✅ 已完成(注入头尾加隔离标注,明确"用户选择的技能说明,非系统指令"|
| FR-R4 | `complete()` 同步路径无超时无重试(全栈报告 §4| 36d68dd | ✅ 已完成(`RequestBuilder::timeout(60s)` 单请求超时,不影响 stream 流式路径)|
| FR-R5 | `findToolCall`/`flatMap` 正向 O(n²) 全量线性扫描(全栈报告 §4| 4b5f096 | ✅ 已完成(`useAiEvents::findToolCall` 改反向遍历命中最近,放弃 Map 索引防陈旧引用)|
> AC1/AC2、FR-S4、FR-R4、FR-R5 的 ID 源自全栈审查报告/todo 跨文档编号体系,本表仅标注状态,技术细节见对应 commit 与 [全栈代码审查报告](../05-代码审查/全栈代码审查报告-2026-06-14.md)。
---
## 一、AI chat 交互流畅性
### 🔴 高危
**H1 流式 Markdown 全量重解析**`AiChat.vue:343-354` `renderMd` 缓存 key 是完整文本。流式时 `currentText` 每 delta 都变 → 每次新 key → 缓存几乎不命中 → 每个 token 都 `marked.parse(全文) + DOMPurify.sanitize(全文)`。长回复(1000+ 字 + 代码块)时主线程阻塞、光标掉帧。**流式不流畅的主因。**
**H2 审批 pending 中新建对话永久卡死**`ai_conversation_create`(`commands.rs:362-375`)**缺 generating 守卫**(对比 `ai_conversation_switch` 有只读保护),直接 `messages.clear()` + `pending_approvals.clear()`。而审批等待期间 `generating 保持 true`(`agentic.rs:192`)。触发链:待审批时点新对话 → 后端 session 被清空 → 用户审批 → `ai_approve` 因 pending 已清返回 Err(`commands.rs:115`)→ generating 永不复位 → 审批态看门狗已 clear(`useAiEvents.ts:143`)无兜底 → **面板卡死需重启**
**H3 审批态 stop 无本地兜底**`stopChat`(`useAiSend.ts:111-113`)只 `await aiApi.stopChat()`,不改 `state.streaming`,依赖后端 `AiCompleted`。审批态 stop 后端确实 emit(`commands.rs:241`),但审批态看门狗已 clear(`useAiEvents.ts:143`),若 `AiCompleted` 竞态丢失 → streaming 永久 true 无兜底 → 卡死。
### 🟡 中危
**M1 流式 delta 无节流**`stream_recv.rs` 逐 chunk `app.emit(AiTextDelta)`,前端同步 `state.currentText += delta`。每 delta:IPC 序列化 + Vue reactive + renderMd 全量解析(叠加 H1)+ scrollToBottom。后端无 50ms 合批,前端无 rAF/throttle。
**M2 scrollToBottom 高频强制滚**`AiChat.vue:625-633` watch `currentText``onContentChange` → 在底部则 `nextTick(scrollToBottom)`。每 delta 强制 `scrollTop = scrollHeight`,大 DOM 重排掉帧。
**M3 Low 工具失败语义冲突**`audit.rs` Low 工具失败 emit `AiError`,但 `process_tool_calls` 返回 `pending_count=0`,`agentic.rs:195` 续下一轮。前端收 AiError 置 streaming=false + 错误气泡,后端 loop 仍跑,后续 delta 继续追加(handleEvent delta 分支不检查 streaming),最终 AiCompleted 又 flushCurrentText 写残留文本 → 一次错误又"完成",状态紊乱。
**M4 friendlyError 硬编码中文**`useAiEvents.ts:42-48` 错误提示硬编码中文,绕过 i18n。看门狗超时文案(`useAiStream.ts:29`)同样。en 用户看到中文。
**M5 分离窗口与主窗口 state 完全隔离** — 独立 webview → 独立 JS realm → 独立 `state` 单例。localStorage 只快照生成态初始文本,不解决双向同步。detach 后两窗口 messages/conversations 各自独立,一边操作另一边看不到。
**M6 AiChat 卸载不调 stopListener**`AiChat.vue``onUnmounted`。面板 v-if 开关销毁重建 AiChat,但 `stopListener`(`useAiEvents.ts:240`)从不调用,Tauri listener 累积泄漏(幂等防住重复注册,但旧 listener 不释放)。
### 🟢 低危
**L1 队列续发失败丢消息**`useAiSend.ts:25-29` `drainQueue``queue.shift()``void sendMessage`,IPC 失败时 catch 回滚 streaming + 移除空气泡,但消息已 shift 丢失无回滚入队。理论竞态,正常路径(AiCompleted 时后端 generating 已 false)不撞。
**L2 生成中切 provider 无守卫**`AiChat.vue:458-464` `cycleProvider` 生成中可切,当前回复仍用旧 provider(spawn 快照),provider bar 立即显示新名 → 用户误判。
**L3 handleKeydown Escape 分支冗余**`AiChat.vue:532-536``:554-558` 两处 Escape 判断,逻辑可工作但分叉冗余。
**L4 selectSkill/clearSkill 未 autoResize**`:409-419` 清空 inputText 不调 autoResize,textarea 可能残留高度。
**L5 deep watch + JSON.stringify 快照**`AiChat.vue:639-667` watch messages(deep)每次 `JSON.stringify` 整数组。流式 delta 不触发,工具密集轮次时开销可见。
---
## 二、信息卡片完整性(审批/工具卡片)
> 用户反馈:"只有 1 个 ID,根本不知道审批要做什么"。核对所有 Medium/High 审批工具。
### 三层缺陷
**缺陷 1 — 审批 reason 两句固定模板**(`audit.rs:179-182`):
```rust
let reason = match risk_level {
RiskLevel::High => "高风险操作,必须人工批准".to_string(),
_ => "创建操作,请确认是否执行".to_string(),
};
```
所有 High 文案相同,所有 Medium 文案相同,**不含操作对象**。
**缺陷 2 — id/project_id 原样展示**(`ToolCard.vue:149-169` `toolArgsEntries` + `formatArgValue`):字符串直接展示(截断 300),`id`/`project_id` 以裸值出现。
**缺陷 3 — 完成态 resultSummary 缺 delete/restore/purge 分支**(`ToolCard.vue:272-288`):这三类完成后只显示 header + 裸 JSON `{"deleted":true,"id":"..."}`
### 逐工具核对表
| 工具 | 风险 | args | 裸 id | 审批卡片可见性 |
|------|------|------|-------|--------------|
| **delete_project** | High | `id` | id | 🔴 "Delete Project" + `id=proj_xxx` + 模板 reason,完全不知删哪个 |
| **restore_project** | High | `id` | id | 🔴 同上 |
| **purge_project** | High | `id` | id | 🔴 永久删除却不知删啥 |
| update_project | Med | `id, field, value` | id | 🟡 改什么可读,对象不可读 |
| bind_directory | Med | `id, path` | id | 🟡 path 可读,哪个项目不可读(用户实测反馈) |
| create_task | Med | `project_id, title, ...` | project_id | 🟡 title 可读,归哪个项目不可读 |
| create_project | Med | `name, description` | 无 | ✅ |
| create_idea | Med | `title, ...` | 无 | ✅ |
| write_file | Med | `path, content` | 无 | ✅ |
| run_workflow | High | `name, dag` | 无 | 🟡 name 可读,dag 庞大 |
**9 个审批工具:3 个完全不可用,3 个对象不可读,仅 3 个完整。**
### 修复方向
- P0 后端 emit `AiApprovalRequired` 前按工具查对象名拼 reason(如"删除项目「前端重构」(id=xxx),移入回收站")。
- P0 前端 `toolArgsEntries` 对 id/project_id 特化(查 store 或后端 args 补 `__label`)。
- P1 `toolResultSummary` 补 delete/restore/purge case。
- P1 `toolDisplayName` CRUD 类从 args 取 name/title 拼上。
---
## 三、clean(清空对话)与压缩对话
### clean — ❌ 具备但不可用
| 维度 | 状态 |
|------|------|
| 后端 `ai_chat_clear` | ✅ `commands.rs:215-220` |
| 前端 `clearChat` | ✅ `useAiPanel.ts:89-96` |
| **UI 入口** | ❌ 零组件调用(grep clearChat 仅命中 api/composable/store,AiChat.vue 无按钮) |
| 语义 | ❌ 只清内存 session 不删 DB,刷新恢复 |
### 压缩对话 — ❌ 不具备
- 无显式压缩/总结功能(grep compress/compact/summarize 仅命中 context.rs 的"裁剪")。
-`/compact` 命令、无压缩技能、无对话总结。
- 唯一相关:`ContextManager.build_for_request`(`context.rs:215-264`)预算感知裁剪——超 token 预算(默认 128k,0.85 安全 → budget ≈102k)自动丢弃旧消息,保留工具三元组原子性 + 最近 6 条(保护区)。
- 裁剪机制本身良好(三元组原子、视图不污染持久化、有测试),但**是滑动窗口丢弃非摘要压缩**,且 128k 窗口日常难触发。
---
## 四、create_project 双审双 API(用户实测痛点)— ⚠️ 半成品(2026-06-14 核对)
### 现状:已改一半
- ✅ schema 已加 `path`/`stack`(`tool_registry.rs:148-151`),描述已改"可选传 path/stack 一步完成"(`:147`)
-**handler 仍写死 `path: None, stack: None`(`:162`),未读 args** → schema 假支持
### 后果
LLM 见 schema 有 path 会传,handler 忽略 → 建出空项目 → 仍需 `bind_directory` 二审。**双审未解,反变误导**(schema 承诺了 handler 不兑现)。比原始"schema 无 path"更糟。
### 待改(别再加 schema,已加完)
handler 从 args 读 `path`/`stack`,复用 IPC `create_project`(`project.rs:43-83`)的校验+防重复+`scan::detect_stack` 探测逻辑。`bind_directory` 保留改绑用。
### 关联
handler 接上后 `bind_directory` 使用频率大降(只剩改绑),第二章 bind_directory 信息缺口随之缓解;但 bind_directory 仍需补信息完整性。
---
## 五、数据变更联动刷新方案
> 需求:AI chat 工具执行产生数据变更 → 左侧已打开视图(Projects/Tasks/Ideas/Dashboard)自动刷新。
### 现状缺口
- `useProjectStore` 单例持 projects/tasks/ideas,各 view onMounted 调 loadXxx(Ideas.vue:444 / ProjectDetail.vue:412 / Dashboard.vue:212)。
- **无应用级事件总线**(grep mitt/EventBus 零匹配)。
- AI 工具执行 emit `AiToolCallCompleted`,前端**只更新 ToolCard,不通知 project store** → 视图不刷新。
### 方案对比
| 方案 | 机制 | 优 | 缺 |
|------|------|----|----|
| **A 后端 emit 数据变更事件(推荐)** | 工具成功后 emit `df-data-changed {entity,action,id?}`,各 store 监听刷新 | 后端是真相源埋点准;store 自治解耦;可扩展到手动 CRUD | 需后端埋点 |
| B 前端据 `AiToolCallCompleted.name` 推断 | handleEvent 映射 entity 调 loadXxx | 零后端改动 | ai composable 耦合 project store;ai_approve 路径不走 AiToolCallCompleted 会漏 |
| C store watch AI 状态 | project store watch ai.lastToolCall | — | 跨 store 耦合最重 |
### 推荐方案 A 要点
- **后端埋点**:`audit.rs:206-214`(Low 执行成功)+ `commands.rs:148-184`(ai_approve 成功),按 tool name 映射 entity,emit `df-data-changed`。失败不 emit;run_workflow 不改实体表不 emit。
- **tool→entity 映射**:create/update/delete/restore/purge/bind_directory=project;create task=task;create/update idea=idea。
- **前端监听**:`useProjectStore` 创建时 listen,debounce + rAF 合并(一轮多 tool 只刷一次),加 loaded 标志仅刷新已加载实体。
- 分离窗口独立 realm 各自 listen 各自刷新(天然支持)。
- **未拍板**:A vs B;是否扩展到手动 CRUD 全局实时同步。
---
## 六、「想法→灵感」中文文案迁移残留
> 产品决定"想法"改称"灵感",迁移半途。
### 用户可见(必改)
- `src/i18n/zh-CN/ideas.ts:18/42/65/68/71/75` — 详情/操作/模态框 6 处(页头已改灵感,这些漏改)
- `src/i18n/zh-CN/aiTool.ts:24``ideaCount: '{n} 条想法'`(AI 工具结果摘要)
- `src/i18n/zh-CN/projectDetail.ts:9/24/25/26` — 阶段标签/来源想法
- `src/stores/project.ts:150/160` — 错误 toast
### 后端用户可见
- `src-tauri/src/commands/idea.rs:105/108/148/152/179` — 错误信息(toast)
- `src-tauri/src/commands/ai/tool_registry.rs:112/230` — LLM 工具描述(AI 回复会用"想法")
### en 版
用 Ideas/Idea(英文术语),若产品要求统一 Inspiration 也需改,待定。
### docs + crates 注释
大量"想法"(低优先),含文件名 `docs/03-模块文档/想法探索-对抗式评估-2026-06-12.md`
### 根因
上次迁移只改 ideas.ts 页头区,详情/操作/模态框 + 其他 i18n + 后端错误 + LLM 工具描述未跟进。
---
## 七、设计亮点(明确无问题)
| 机制 | 评价 |
|------|------|
| 流式看门狗(`useAiStream.ts`) | 无数据超时兜底,130s > 后端 120s 留余量 |
| generating 复位先于 emit(`agentic.rs:74/170/228`) | 保证前端收 AiCompleted 时后端已可接下条 |
| 错误路径 AiError 覆盖全 | idle/流中断/chunk error/provider 失败,无静默失败 |
| 工具卡片折叠自治 + auto-collapse | shouldKeepOpen 保留 running/pending/rejected/write_file |
| 审批乐观更新 + IPC 失败不回滚 | `useAiSend.ts:80-98` 防按钮卡死 |
| Markdown 懒加载 + 历史消息缓存 | 首屏不阻塞,已完成消息命中缓存 |
| 回到底部智能判断 | isNearBottom 避免上滑被打断 |
| ContextManager 裁剪 | 三元组原子、视图不污染持久化、测试覆盖 |
---
## 八、修复优先级
| 优先 | 问题 | 方向 |
|------|------|------|
| P0 | H1 流式 Markdown 重解析 ✅ **退役**AR-12026-06-15— 自研块级 memo 取代splitBlocks O(末块)+rAF 节流),详见 [流式渲染调研 §5](./aichat流式Markdown渲染调研-2026-06-15.md) | 流式态纯文本/增量渲染,完成后再 markdown;rAF 合并 |
| P0 | H2 审批态新建对话卡死 ✅ **已修**AR-2commit 057a212 | `ai_conversation_create` 加 generating 守卫 |
| P0 | 第二章 审批卡片裸 id + reason 模板 ✅ **已修**AR-3commit 36d68dd| 后端 reason 拼对象名;前端 id→name |
| P0 | 第四章 create_project 双审 ✅ **已修**AR-4commit 057a212— schema 加 path/stack + handler 合并绑定 | handler 读 args 的 path/stack,复用 IPC `project.rs:43-83` 探测逻辑 |
| P1 | H3 审批态 stop 无兜底 ✅ **已修**AR-5commit 9e2aeff— stopChat 本地先复位 streaming + clearStreamWatchdog | stopChat 本地先复位 streaming |
| P1 | M3 Low 工具失败语义 ✅ **已修**AR-6commit f82dd8b— Low 失败非 AiError错误回填 tool_result 让 LLM 自处理 | 统一 AiError 后 loop 也退出,或不 emit AiError |
| P1 | 第三章 clean 无入口 ✅ **已修**AR-7commit 9e2aeff— clear_messages 真删 + 垃桶按钮二次确认 | AiChat 加清空按钮 + 后端真删当前对话消息 |
| P2 | M1+M2 delta 节流 + 滚动 🔄 **重评降级**AR-82026-06-15— 前端 rAF 节流已被 ARC-08 覆盖;剩后端 50ms 合批 + 滚动跟随 | 后端 50ms 合批 / 前端 rAF |
| P2 | M4 friendlyError i18n ✅ **已修**AR-9commit 9e2aeff— 全走 i18n.global.t + zh/en 双语补 key | 抽 i18n key |
| P2 | 第六章 灵感迁移残留 ✅ **已修**AR-10commit 65c475b— 13 文件批量统一 | i18n + 后端错误 + LLM 描述统一改 |
| P2 | 第五章 数据联动 ✅ **已修**AR-11commit dc27e79— 方案 A 后端 emit `df-data-changed` + store listen 已 attach | 方案 A 后端 emit + store 监听 |
---
## 九、write_file 覆盖事故与可靠性风险2026-06-14 实测)
### 事故经过
会话 `3473fcb7`2026-06-14 22:16AI 拟对 `PROGRESS.md` 做 3 处精准更新(头部当前阶段、全局问题 #9 状态、新增 #10),但**误用 `write_file`(全文覆盖语义)只传了头部 3 行 content**,把原 **762行/72KB** 覆盖成 **248字节**。AI 自查发现msg[59-61]尝试凭记忆重建恢复write_file 17956 字符),**但该恢复写入未生效**(会话中断),用户无感知「恢复失败」。
### 暴露的潜在问题
| # | 问题 | 性质 | 修法方向 |
|---|------|------|----------|
| FR-S7 | write_file 覆盖已有非空文件无确认/备份 | **根因** | 覆盖非空文件前自动备份 `.bak`;或检测目标存在强制走 edit_file |
| 关联-1 | 写入后无「预期 vs 实际」校验 | 可靠性 | write_file 返回新旧大小,差异巨大(如原 72KB→新 248B时 warn/阻断 |
| 关联-2 | AI 自恢复失败无感知 | agent 可靠性 | 工具失败/中断需明确通知用户,不静默吞掉 |
| 备份 | DB 50KB 截断致无法从 DB 完整恢复 | 备份策略 | 长文档丢失仅 git 可救;考虑关键文件写前 git 快照 |
### 恢复方式与教训
DB 中 PROGRESS.md 原文已被 `TRUNCATE_THRESHOLD=50KB``conversation.rs:55`截断头尾拼接、中段省略AI 重建版仅 17.9KB 残缺。**最终靠 `git restore PROGRESS.md`HEAD 版本 762行/72KB 完整)恢复**。教训:本地文档类资产的实际保护层是 **git** 而非 DB 会话历史——会话历史是「对话快照」非「文件备份」。
### 关联待办
- `todo.md` FR-S7write_file 覆盖保护)— P0 安全
---
## 十、文件工具系统性走查2026-06-143-agent review 之外的补充走查)
`tool_registry.rs` 实际注册 **3 个文件工具**`read_file`(:394) / `list_directory`(:428) / `write_file`(:444)。其余 edit_file/delete_file/rename_file/move_file/search_content/append_file **均未实现**——功能缺口,迫使 LLM 滥用 write_file 全量覆写,**放大 FR-S7 危害**。
### P0 — 阻断
| # | 问题 | 位置 | 修法方向 |
|---|------|------|----------|
| **FR-S8** | **路径 sandbox 系统性逃逸**:①`validate_path` 子串 `..` 检测对**绝对路径无效**`C:\Windows\...` 不含 `..` 绕过②canonicalize 仅对**已存在路径**跑write_file 新建文件 + symlink 父目录场景失效③Windows `Path::starts_with` 大小写敏感而文件系统不敏感,可误判/漏判 | :19-21, :53-69 | 统一 canonicalize不存在路径取最长存在前缀+ 大小写不敏感 prefix 比较 + parent 也校验 |
| FR-S7(放大) | write_file 定级 Medium 可自动批准 + 非原子覆写,覆写任意已存在非空文件即数据丢失(见 §9 | :446, :461 | 覆写非空文件升 High 审批 + `.bak` 备份 + 原子写(tmp→rename) |
### P1 — 重要
| # | 问题 | 位置 |
|---|------|------|
| P1-1 | write_file 非原子写:中途崩溃留半截文件丢原内容(叠加 FR-S7 数据彻底丢失) | :461 |
| P1-2 | write_file `create_dir_all(parent)` 不校验 parentworkspace 内 symlink 父目录可写逃逸 | :457-460 |
| P1-3 | read_file 1MB 按**字节** + `read_to_string` 对非 UTF-8/二进制直接失败无降级 | :409, :413 |
| P1-4 | read_file offset 无上限校验超范围静默返空limit 无硬上限 | :415-419 |
| P1-5 | list_directory 噪音目录仍作为 entry 返回仅不深入max_depth=2 写死无文档 | :437, :439, :500 |
| P1-6 | list_directory `DirEntry::metadata()` **跟随 symlink**symlink 目录被当普通目录递归(信息泄露 + 与 P1-2/FR-S8 形成逃逸组合拳) | :491-492 |
| P1-7 | `validate_path` 黑名单**子串匹配**:易误伤(`appdata-collector` 项目)易绕过(漏 `.config`/`.kube`/Program Files冗余弱层 | :22-29 |
### P2 — 次要
list_directory 子目录无权限读整层 bail:484/ read_file 错误回显完整绝对路径泄露(:406/ write_file bytes_written 字节非字符易误导(:463/ max_entries off-by-one:486/ to_str 非 UTF-8 路径笼统报错(:401/ 未实现工具缺口edit/delete/rename/move/search/append 迫使滥用 write_file
### 总结
框架方向正确schema+risk+handler 同源、双层校验、FR-S2 TOCTOU+1MB 已修),但 **sandbox 实现层有系统性缺口**:子串黑名单(弱)+ 词法 starts_withWindows 大小写坑)+ canonicalize 只覆盖存在路径(新建漏)。优先级:**FR-S8 统一 canonicalize > P1-6/P1-2 symlink 不跟随 > FR-S7 原子写+升审批**。
关联 todoFR-S7覆盖保护、FR-S8sandbox 逃逸)。
---
## 附:相关 memory(指针)
- `devflow-aichat-review-pending.md`
- `devflow-idea-inspiration-migration.md`
- `devflow-data-change-sync.md`
三者在 memory 中仅留指针,详情以本报告为准。

View File

@@ -0,0 +1,64 @@
# 构想:对话 AI 异步审批 — 2026-06-14
> 性质:功能升级构想,未实现。记录用户提出的方向 + 可行性评估。
## 构想
对话 AI 的对话与审批改成**异步审批**:审批 pending 时不卡住整个对话,用户可继续聊别的,审批挂着随时处理。
## 痛点:当前同步审批卡住对话
当前审批是同步阻塞模型:
1. LLM 返回 Medium/High `tool_calls``process_tool_calls`(`audit.rs:170-191`)推 `pending_approvals` + 占位 `tool_result`("需要用户审批,等待确认")→ agentic loop `return`(`agentic.rs:184-192`),**`generating` 保持 true**。
2. 等待期间:`session.generating = true` → 新 `ai_chat_send` 直接 `Err("AI 正在生成中")`(`commands.rs:45`)→ 前端 `sendMessage` 把新消息入队(`useAiSend.ts:36`),`streaming = true` 输入框变停止按钮。
3. 用户必须先审批(或 stop)才能继续对话。**整个对话被审批阻塞。**
典型困扰:AI 提出待审批操作,用户想先问个别的(比如"等等,这个项目之前是不是建过?"),被阻塞,必须先处理审批。
## 难点分析
异步审批的真正难点不在 UI,而在 **agent loop 的语义**:
- 同步模型:LLM 发 tool_call → 占位 tool_result → loop 挂起 → 审批后 tool_result 替换为真实结果 → LLM 据真实结果生成下一步。上下文连贯。
- 异步模型:若审批 pending 时对话继续,LLM 已基于"占位结果"生成后续 → 审批结果回流时上下文已前进 → 不一致。
核心瓶颈是 `AiSession` 单例 + `generating` 单标志互斥(防并发混乱)。异步审批 + 并发对话需要 AiSession 多实例化或 sub-session——正是 [[aichat-arch-extensibility]] 记录的"剩四空壳/AiSession 单例未动"部分,属 B 路线。
## 方案分两档
### 档位一:轻量 — 跨对话异步(推荐先做)
审批 pending 的对话挂起(释放 generating 锁),用户**切到别的对话**继续聊,审批在原对话挂着,通过后结果回流原对话。
- 触及:AiSession 从单例 → 多对话独立状态(每对话一个活跃 loop 槽)。
- 不触及:同对话内 agent loop 语义不变(同对话内审批仍阻塞)。
- 复杂度:中等,是 B 路线(AiSession 多实例化)的一部分。
- 价值:解决"审批时想干别的"主诉求(切对话即可),不破坏 agent 语义。
### 档位二:完整 — 同对话异步
审批不阻塞同一对话,用户在同一对话里继续发消息,审批通过后工具结果作为新上下文回流。
- 触及:agent loop 语义重设计——LLM 上下文如何处理"待执行工具"(标记转审批?LLM 基于"已转人工"假设继续?)。
- 可能形态:审批转独立审批队列/通知中心,对话流遇到待审批工具不阻塞,告知"有 N 个待审批"后继续;审批通过后台执行工具,结果追加为新消息。
- 复杂度:高,接近重做 agent loop。
- 风险:LLM 上下文一致性、工具结果时效性、多任务并发安全。
## 评估
| 维度 | 档位一(跨对话异步) | 档位二(同对话异步) |
|------|---------------------|----------------------|
| 解决主诉求 | ✅ 切对话即可继续 | ✅ 同对话继续 |
| 架构改动 | AiSession 多实例化 | agent loop 语义重设计 |
| 与 B 路线 | 一部分 | 接近独立重做 |
| 风险 | 中(并发状态管理) | 高(上下文一致性) |
| 建议 | 先做 | 评估后定 |
**建议**:作为 B 路线一部分,先做档位一(跨对话异步),需先完成 AiSession 多实例化。档位二待 agent 能力升级时再评估。
## 关联
- 触及 [[aichat-arch-extensibility]] 记录的 AiSession 单例瓶颈。
- 与 [[aichat-roadmap-ab-split]] B 路线(补决策/并发能力)相关。
- 当前同步审批的其他问题(审批态 stop 卡死、新建对话破坏 session)见 `aichat审查报告-2026-06-14.md` H2/H3,异步化时一并解决。

View File

@@ -0,0 +1,284 @@
# AIChat 授权功能体验改进方案
> 创建: 2026-06-14 | 状态: 待讨论
## 一、当前授权机制概览
### 1.1 核心流程
```
用户发送消息
→ Agentic Loop (最多 10 轮)
→ LLM 流式响应
→ 解析 tool_calls
→ 按风险等级分流:
├─ Low Risk → 自动并行执行join_all
├─ Medium → 暂停循环,等待人工审批
└─ High → 暂停循环,等待人工审批
→ 审批通过 → 执行工具 → try_continue_agent_loop 恢复循环
→ 审批拒绝 → tool_result="用户拒绝了此操作" → 恢复循环让 LLM 自行决策
```
### 1.2 工具风险分级矩阵
| 风险等级 | 工具 | 执行方式 |
|---------|------|---------|
| **Low** | `list_projects`, `list_tasks`, `list_ideas`, `list_trash`, `read_file`, `list_directory` | 自动执行,并行 `join_all` |
| Medium | `create_project`, `create_task`, `create_idea`, `update_project`, `update_task`, `bind_directory`, `write_file` | 需人工审批 |
| **High** | `delete_project`, `restore_project`, `purge_project`, `delete_task`, `run_workflow`, `run_command` | 需人工审批 |
### 1.3 已实现的亮点
- **审计留痕**`ai_tool_executions` 表完整记录每次工具调用的状态、风险等级、决策者、请求时间和执行时间
- **断点恢复**:应用重启后通过 `restore_pending_approvals()` 从数据库重建内存中的待审批状态
- **审批卡片可读化**`build_approval_reason()` 解析工具参数,拼接人类可读的审批理由
- **generating 状态 RAII 守护**`GeneratingGuard` 确保无论正常退出还是 panic`generating` 标志都能复位
- **数据变更联动刷新**:工具执行成功后自动 emit `df-data-changed` 事件,前端自动刷新列表
- **安全防护**API Key 存 OS keyring、文件路径双层校验、write_file 覆盖前自动 .bak 备份 + 原子写
### 1.4 关键代码位置
| 模块 | 文件 | 职责 |
|------|------|------|
| 工具注册表 | `src-tauri/src/commands/ai/tool_registry.rs` | 工具定义 + 风险等级 + handler 同源 |
| 审批处理 | `src-tauri/src/commands/ai/audit.rs` | 工具调用审计 + pending 审批恢复 + 审批后状态回填 |
| Agentic 循环 | `src-tauri/src/commands/ai/agentic.rs` | 流式接收 → 工具执行 → 结果回传 LLM → 循环 |
| IPC 命令 | `src-tauri/src/commands/ai/commands.rs` | `ai_approve` / `ai_chat_send` / `ai_chat_stop` 等 |
| 审批卡片 UI | `src/components/ToolCard.vue` | 卡片渲染 + 参数展示 + 批准/拒绝按钮 |
| 卡片列表 | `src/components/ToolCardList.vue` | 多卡片折叠管理 |
| 聊天面板 | `src/components/AiChat.vue` | 消息列表 + 审批转发 + 输入区 |
| AI Store | `src/stores/ai.ts` | 模块级单例 state |
| 发送/审批 | `src/composables/ai/useAiSend.ts` | `approveToolCall` 乐观更新 + IPC 调用 |
---
## 二、用户体验痛点分析
### 痛点 1逐个审批无法批量操作
**现象**:当 AI 一次返回多个 Medium/High 工具调用时(比如同时创建 3 个任务 + 写 2 个文件),用户需要逐个点批准/拒绝。
**根因**`process_tool_calls`audit.rs把每个待审批工具都推入 `pending_approvals` HashMap前端为每个 pending 渲染独立的 ToolCard每个卡片只有自己的"批准/拒绝"按钮。`ToolCardList.vue` 没有批量操作入口。
**影响**:高频交互场景下审批变成体力活,用户体验疲劳。
### 痛点 2审批阻塞整个对话期间无法输入
**现象**:审批等待期间 `generating=true`,用户虽然能上滑看历史,但无法发送新消息(`sendMessage` 会入队),也无法预知还有多少审批在排队。
**根因**`ai_chat_send`commands.rs:46检查 `session.generating` 为 true 时拒绝新消息。审批等待期间 `generating` 保持 true`agentic.rs``guard.disarm()` 保持 true 以便 `try_continue` 续生成)。
**影响**:用户处于"被动等待"状态,无法并行做其他事。
### 痛点 3Medium 和 High 体验无差异
**现象**:两者都弹同样的审批卡片、同样的按钮,交互流程完全一致。
**根因**`process_tool_calls`audit.rs:103-120中 Medium 和 High 走同一个 `pending_approvals.insert` 分支,区别仅在 `build_approval_reason` 的文案后缀("请确认是否执行" vs "高风险,需人工批准")。
**影响**High 操作(如 `purge_project` 不可恢复)缺乏足够的警示力度,容易误操作。
### 痛点 4write_file 审批信息不够直观
**现象**`write_file` 是 Medium 风险,审批卡片只展示 path 和 content 参数。content 可能是几百行代码,在审批卡片里以 `formatArgValue` 截断到 300 字符展示。
**根因**`ToolCard.vue``toolArgsEntries``displayArgValue``formatArgValue` 对超长值统一截断到 300 字符。
**影响**:用户无法看清要写入的完整内容,只能盲目批准。尤其覆盖已有文件时,用户不知道会改什么。
### 痛点 5审批后无进度反馈
**现象**:点击"批准"后,卡片乐观置 `running`,但用户不知道:
- 工具正在执行还是已执行完等待 LLM 续生成
- 还有多少待审批在排队
- 整个 agentic 循环进行到第几轮
**根因**:前端没有全局的 agentic 循环进度指示器。`AiAgentRound` 事件虽然通知了轮次,但没有在 UI 上持久化展示。
**影响**:用户对系统状态缺乏掌控感,尤其在多轮工具调用时。
### 痛点 6审批卡片可能被滚出视口
**现象**:当消息很多时,审批卡片可能被新消息推到上方滚出视口。
**根因**`AiChat.vue``collapseInactive` 不会收起 `pending_approval` 卡片,但也不会自动滚动到 pending 卡片。没有全局徽标提醒。
**影响**:用户可能看不到待审批项,对话看起来"卡住了"但不知道在等什么。
---
## 三、改进方案
### P0 — 快速改善体感
#### 3.1 批量审批
**方案**:当同一轮有多个 pending 时,在 ToolCardList 顶部显示"全部批准(N) / 全部拒绝"按钮。
**改动范围**
- `ToolCardList.vue`:新增批量操作栏,监听 toolCalls 中 pending_approval 数量
- `useAiSend.ts`:新增 `approveAll(rejectAll)` 方法,循环调用 `ai_approve`
**交互**
```
┌─────────────────────────────────┐
│ ⏳ 3 项待审批 │
│ [✓ 全部批准] [✕ 全部拒绝] │
├─────────────────────────────────┤
│ [工具卡片 1 - pending] │
│ [工具卡片 2 - pending] │
│ [工具卡片 3 - pending] │
└─────────────────────────────────┘
```
#### 3.2 审批计数器 + 跳转
**方案**:在输入框上方或 header 显示 `⏳ 2 项待审批`,点击跳转到第一个 pending 卡片。
**改动范围**
- `AiChat.vue`header 区域增加审批徽标
- `ToolCardList.vue`:暴露 `scrollToFirstPending` 方法
**交互**
```
┌──────────────────────────────────┐
│ 🤖 助手 ⏳2 [+][×] │ ← 徽标在 header
├──────────────────────────────────┤
│ ...消息列表... │
│ ┌─ 工具卡片 (pending) ──┐ │ ← 点击徽标滚动到此
│ │ 创建任务XXX │ │
│ │ [批准] [拒绝] │ │
│ └────────────────────────┘ │
├──────────────────────────────────┤
│ [输入框] │
└──────────────────────────────────┘
```
#### 3.3 write_file diff 预览
**方案**write_file 审批时,如果文件已存在,展示前后对比 diff 而非裸 content。
**改动范围**
- 后端 `tool_registry.rs`write_file handler 在执行前读取旧文件内容,返回 diff 信息(或前端请求 diff
- `ToolCard.vue`pending_approval + name=write_file 时渲染 diff 视图
**交互**
```
┌─ 写入文件 src/main.rs (待审批) ──────┐
│ │
│ - fn main() { │ ← 红色:删除行
│ - println!("hello"); │
│ + fn main() { │ ← 绿色:新增行
│ + println!("hello, world"); │
│ + setup_logging(); │
│ │
│ ⚠ 覆盖已有文件 (23→45 行) │
│ [查看完整内容] [批准] [拒绝] │
└───────────────────────────────────────┘
```
---
### P1 — 增强控制力
#### 3.4 会话级授权 Session Trust
**方案**:引入会话级信任机制,替代全局宽松模式。用户在当前对话中一次性授权某目录的写/执行权限,后续该对话内同类操作自动放行。切换对话或新建对话时信任清空。
**配置项**
```
当前会话信任目录:
✅ E:/wk-lab/devflow/src (Write + Execute)
✅ E:/wk-lab/devflow/docs (Write)
+ 添加目录...
```
**改动范围**
- 前端Settings 或对话 header 新增「信任管理」入口
- 后端:`AiSession` 增加 `trusted_dirs: HashSet<(PathBuf, TrustLevel)>`
- `audit.rs``process_tool_calls` 先查 session trust命中则跳过 pending
**安全边界**
- 仅纯读取操作list_*/read_*/list_directory保持自动放行
- 所有 create/update/bind/write/delete 操作默认需审批或 session-trust
- bind_directory 归类为修改操作
- 信任仅限当前会话内存,不持久化
#### 3.5 High 二次确认
**方案**delete/purge/run_command 等高风险操作,批准后弹出二次确认。
**改动范围**
- `ToolCard.vue`High 风险 + approved=true 时,先弹 inline 确认("确定要永久删除?此操作不可恢复"
- 或用现有 `ConfirmDialog` 组件
**交互**
```
第一次点击"批准":
→ 卡片内弹出确认提示
→ "确定要永久删除项目「XXX」此操作不可恢复"
→ [确认删除] [取消]
第二次点击"确认删除":
→ 才真正执行 ai_approve
```
#### 3.6 审批超时(前端定时器)
**方案**:前端侧 5 分钟超时自动拒绝,避免对话永久卡住。超时策略独立于 Webhook 等外部动作路径。
**改动范围**
- 前端:`useAiSend.ts` 在 pending 时启动 5min 定时器,超时自动调 `ai_approve(id, false)`
- 不改后端 AiSession 结构(远期 Webhook 走独立路径)
---
### P2 — 信息透明度
#### 3.7 Agentic 进度条
**方案**:在消息区域底部显示循环进度。
**改动范围**
- `AiChat.vue`:底部增加进度指示条
- `useAiEvents.ts`:处理 `AiAgentRound` 事件时更新进度
**交互**
```
┌──────────────────────────────────┐
│ ...消息列表... │
│ │
│ 🔄 循环 3/10 · ⏳2待审批 · ✅5完成 │ ← 底部进度条
├──────────────────────────────────┤
│ [输入框] │
└──────────────────────────────────┘
```
#### 3.8 审计历史面板
**方案**:独立页面展示 `ai_tool_executions` 表的审计记录。
**改动范围**
- 后端:新增 `list_tool_executions` IPC 命令(查询审计表)
- 前端:新增 `AuditLog.vue` 视图,表格展示历史记录
**展示字段**
| 时间 | 工具 | 风险 | 状态 | 决策者 | 参数摘要 | 结果摘要 |
|------|------|------|------|--------|---------|----------|
---
## 四、实施优先级建议
| 优先级 | 改进项 | 预估工作量 | 用户价值 |
|--------|--------|-----------|---------|
| **P0** | 3.1 批量审批 | 0.5 天 | 🔥🔥🔥 |
| **P0** | 3.2 审批计数器 + 跳转 | 0.5 天 | 🔥🔥🔥 |
| **P0** | 3.3 write_file diff 预览 | 1 天 | 🔥🔥 |
| **P1** | 3.4 会话级授权 Session Trust | 1.5 天 | 🔥🔥🔥 |
| **P1** | 3.5 High 二次确认 | 0.5 天 | 🔥 |
| **P1** | 3.6 审批超时(前端5min) | 0.5 天 | 🔥 |
| **P2** | 3.7 Agentic 进度条 | 0.5 天 | 🔥🔥 |
| **P2** | 3.8 审计历史面板 | 1 天 | 🔥 |
**建议第一批落地**P0 三项(批量审批 + 计数器 + diff 预览),总计约 2 天工作量,覆盖最高频的体验痛点。

View File

@@ -0,0 +1,146 @@
# AI Chat 流式 Markdown 渲染调研2026-06-15
> 范围:`AiChat.vue` 流式渲染优化。当前 AR-1 修复commit f58743e用「流式纯文本短路」防掉帧副作用是流式过程无格式。本调研找不掉帧且有格式的更好方案。
> 方法3 路并行调研(机制方案 / 现成库 / Vue3 落地)+ 主代理整合。
> 性质:调研 + 方案,**未实施**。
> 关联:[aichat审查报告-2026-06-14.md](aichat审查报告-2026-06-14.md) AR-1[近期改动代码审查-2026-06-15.md](../05-代码审查/近期改动代码审查-2026-06-15.md) §亮点「renderMd 流式纯文本短路」。
---
## §1 问题根因
现状(`src/components/AiChat.vue:200,347`
```vue
<div v-html="renderMd(text, isLastAi(msg) && store.state.streaming)"></div>
```
```js
function renderMd(text, isStreaming=false){
if (isStreaming || !mdReady) return escapeHtml(text) // 流式纯文本短路
return _purify.sanitize(_marked.parse(text))
}
```
掉帧两因素叠加:
- **(A) 解析成本**:每个 delta 全量 `marked.parse()` O(N)N 随回复增长,后期单帧解析几十 ms。
- **(B) 重渲染成本**`v-html` 整段替换触发子树重布局。
当前方案牺牲「流式格式」躲掉 (A)(B),但 delta 20-80ms 一个,流式时用户看到裸 markdown 源码(`#``-`、```` ``` ```` 符号),结束才出格式。
---
## §2 五大机制对比
| 机制 | 消除瓶颈 | 流式有格式 | 成本 | 适用 | 独立够吗 |
|---|---|---|---|---|---|
| 1. rAF 批量节流 | 中(砍频率) | 是 | 低 | 全部 | 否(长文本单次仍重) |
| 2. 块级 diff + memo | **高**(砍到 O(末块) | 是 | 低-中 | 全部 | **基本够(主流首选)** |
| 3. Web Worker 解析 | 高(主线程归零) | 是 | 中 | 超长文档/重 sanitize | 通常与 2 叠加 |
| 4a. 代码块延迟高亮 | 高(代码块零成本) | 代码块流式无色 | 低 | 有代码块 | 仅代码块,需叠加 |
| 4b. shiki-stream 增量高亮 | 高 | 代码块流式有色 | 中 | 有代码块 | 仅代码块 |
| 5. 虚拟滚动 | 中(砍 DOM 不砍 parse | 是 | 中 | 长会话消息列表 | 否 |
**机制 2块级 diff + memo是业界主流首选**——Vercel AI SDK 官方 cookbook 做法。原理:`marked.lexer()` 按双换行/代码围栏切块,每块独立 memoize只有「正在生长的末块」重 parse已完成块缓存跳过。解析成本从 O(全文) 降到 O(末块)。
**大厂可见行为**ChatGPT / Claude / Gemini 流式时均有格式,代码块流式时等宽 + 基本着色。Chrome 官方文档明确反对「整篇重 parse + innerHTML 替换」(正是当前实现),推荐 streaming-markdown 增量 append。
**rAF 实测数据**SitepointReact 18.3 生产构建 M2朴素逐 token setState 平均 commit 18ms80 token/s 达 52ms 可见卡顿rAF 批量后 3-5ms。
---
## §3 现成库评估
| 库 | Vue3 兼容 | 流式 | 安全 | 维护 | 结论 |
|---|---|---|---|---|---|
| **markstream-vue** | ✅ 原生组件 | ✅ 双模式(虚拟窗口 + 增量批处理) | ✅ 内置 safe HTML | ✅ 2.2k star / open issue 2 / 近乎日更 / 尤雨溪背书 / 1.0 稳定 | **首选** |
| streamdown (Vercel) | ❌ React 绑定 + 强绑 Tailwind/shadcn | ✅ | ✅ rehype-harden | ✅ | 仅参考issue #19 求 Vue 版未解决) |
| streaming-markdown | ⚠️ callback 驱动需自己接线 | ✅ token 级 | ❌ 需自配 | 功能不全 | 参考 |
| marked当前用 | ✅ | ❌ 无官方流式 API | ❌ 需自配 DOMPurify | ✅ 36.9k star | 不直用做流式层 |
| markdown-it | ✅ | ❌ 无原生流式 | - | ✅ | 同上 |
| antfu/shiki-stream | ✅ 组件 | ✅ 增量高亮 | - | ✅ 511 star | 代码块高亮专库 |
**核心结论**:有 Vue3 原生可直接用的流式 markdown 库 **markstream-vue**尤雨溪推荐命中全部诉求——流式有格式、不掉帧、TS-first、内置 sanitize、`final` prop 解未闭合 token 卡死。内部已含 marked + Shiki + sanitize 组合,等于替你造好轮子。
**降级路径**:若样式侵入太重,只用其解析内核 `stream-markdown-parser`(框架无关纯函数)+ 现有 DOMPurify 自控渲染。
---
## §4 落地方案(递进)
### 方案 ArAF 节流渲染(最小改动)
流式时 `requestAnimationFrame` 每帧最多 parse 一次(封顶 60fps`v-html` 绑响应式 `streamingHtml`。流式结束取消 rAF + 强制最终渲染落 mdCache。
- 性能:频率从「每 delta」降到「每帧」主线程有空隙让浏览器 paint。
- 观感:流式全程有格式;**瑕疵**:未闭合代码块(末尾 ```)会闪烁。
- 成本:低(~60 行)。
- 风险:超长回答(>20k 字)每帧 parse 全文仍偏重。
```js
const streamingHtml = ref('')
let rafId = null, lastStreamText = ''
function scheduleStreamParse(text){
if (rafId !== null) return
rafId = requestAnimationFrame(()=>{
rafId = null
if (text === lastStreamText) return
lastStreamText = text
streamingHtml.value = _purify.sanitize(_marked.parse(text))
})
}
watch(()=>store.state.streaming,(s,old)=>{
if(old && !s){ if(rafId) cancelAnimationFrame(rafId); rafId=null; lastStreamText=''; streamingHtml.value='' }
})
onBeforeUnmount(()=>{ if(rafId) cancelAnimationFrame(rafId) })
```
### 方案 B方案 A + 代码块流式降级(体验最佳,推荐起步)
在 A 基础上,流式期把 fenced code 块正则抠出降级为纯文本(`<pre class="md-code-streaming">`),其余正常 marked。流式结束一次完整 marked 替换。
- 消掉方案 A 的「未闭合代码块闪烁」瑕疵——AI 回答大量含代码块,高频可见。
- 成本:中(~100 行 + CSS
- **推荐起步方案**A→B 平滑叠加B 只替换 `doStreamParse` 一个函数,不返工)。
### 方案 CWeb Worker彻底解耦
marked+sanitize 移 Worker主线程零 parse。Worker 内 DOMPurify 需 jsdom shim或换 `sanitize-html` 免 DOM
- 成本:高(~150 行 + worker 文件 + jsdom
- 适用:极端长回答/多会话。方案 B 不够再上。
### 方案 D换库直上 markstream-vue
用 `<MarkdownRender :content :final />` 替换整个 renderMd 手写层。
- 成本:中(库接入 + 样式对接)。
- 收益:省自造轮子,拿到虚拟窗口 + 增量高亮 + 未闭合处理全套。
- 风险:样式侵入、新依赖、迁移工作量需评估。
---
## §5 推荐结论
**两条路,按风险偏好二选一**
| 路线 | 方案 | 收益 | 风险 | 工作量 |
|---|---|---|---|---|
| **保守(自研改造)** | 方案 BrAF 节流 + 代码块降级) | 流式全程有格式、不掉帧、消代码块闪烁、无新依赖 | 超长回答边界需观察 | 中(~100 行 + CSS |
| **激进(换库)** | 方案 Dmarkstream-vue | 同上 + 虚拟窗口 + 增量高亮 + 长期省维护 | 新依赖、样式侵入、迁移成本 | 中-高 |
**渐进建议**:先上方案 B 跑通(验证 rAF 节流 + 代码块降级在当前 delta 频率下不掉帧)→ 观察长回答边界 → 若需更强能力(虚拟窗口/增量高亮)再评估换 markstream-vue。
**当前 AR-1 临时方案(流式纯文本短路)由方案 D 替换后退役**——纯增量收益,流式全程有格式。
> **决策2026-06-15选方案 D**(换 markstream-vue。理由自研块级 memo 与 D 复杂度接近D 白送 shiki 代码高亮 + 虚拟窗口 + 未闭合 token 修复器,自研只在「坚决不引新依赖」时才划算。落地 todo:ARC-260615-08。
>
> **决策转向2026-06-15同日复盘方案 D 试装后弃用,改自研块级 memo方案 B 增强版)**。复盘markstream-vue@1.0.1 接入 + vue-tsc 通过无技术障碍,但「样式 100% 还原现有 .ai-md」成本高且脆——markstream DOM 异构于 marked 输出(代码块 `.code-block-container` chrome 结构 / 暗色 `--ms-*` 变量体系依赖 `.dark` class 而 DevFlow 用 `[data-theme]` / prose 作用域 `.markstream-vue`4 处对接且随 markstream 升级易漂移。用户优先级是「保留原样式」>「虚拟窗口/shiki 高级能力」,转自研块级 memomarked 输出标准 HTML → .ai-md 样式零对接,借鉴 §2 机制 2块级 memo业界主流实现 splitBlocks代码围栏整体一块/非代码双换行切)+ 前块缓存命中 O(末块) + 末块不缓存处理未闭合 token + rAF 节流。结论:**自研块级 memo = 方案 B 增强rAF + 真块级 memo非仅代码块降级零新依赖、零样式对接、D 级流式性能**。§5 原决策表「自研只在坚决不引新依赖时才划算」判断在「不要高级能力、要原样式」前提下反转——此时自研反而最优。落地ARC-260615-08 自研版已实施vue-tsc exit 0待 dev 运行时验证。
---
## 来源
- [Best practices to render streamed LLM responses — Chrome for Developers](https://developer.chrome.com/docs/ai/render-llm-responses)streaming-markdown 增量 append、Paint flashing 验证)
- [Markdown Chatbot with Memoization — Vercel AI SDK Cookbook](https://ai-sdk.dev/cookbook/next/markdown-chatbot-with-memoization)(块级 diff + memo 官方实现)
- [Streaming Backends & React: Controlling the Re-render Chaos — Sitepoint](https://www.sitepoint.com/streaming-backends-react-controlling-re-render-chaos/)rAF 实测数据)
- [antfu/shiki-stream — GitHub](https://github.com/antfu/shiki-stream)
- [markstream-vue — GitHub](https://github.com/Simon-He95/markstream-vue)
- [vercel/streamdown — GitHub](https://github.com/vercel/streamdown)
- [HuggingFace chat-ui: webworker for markdown parsing #1733](https://huggingface.co/spaces/jdelavande/chat-ui-energy/commit/7d6fc19984864d960f2875391858ea067b030dc6)
- [shikijs/shiki Discussion #891](https://github.com/shikijs/shiki/discussions/891)GrammarState 流式高亮底层)

View File

@@ -0,0 +1,145 @@
# 产品定位调整报告
> 从"想法到代码"到"想法到创作"的升级转型
## 📊 背景分析
### 原定位的问题
- 过于狭窄:只面向开发者
- 竞争激烈:代码工具市场已饱和
- 限制场景:无法满足多元化的创作需求
### 新定位的优势
- **普适性强**:覆盖所有创作者
- **场景多样**:技术、商业、教育、创意
- **价值更大**:从单一工具到创作平台
## 🎯 新产品定位
### 核心价值主张
**"从想法到创作成果的全流程管理平台"**
### 目标用户画像
| 用户类型 | 创作内容 | 使用场景 |
|---------|---------|---------|
| **开发者** | 代码、技术文档 | 项目开发、技术分享 |
| **产品经理** | 需求文档、原型方案 | 产品规划、项目提案 |
| **设计师** | 设计方案、创意文档 | 设计展示、概念提案 |
| **研究者** | 学术论文、分析报告 | 研究、报告撰写 |
| **内容创作者** | 博客、课程、培训 | 知识分享、教育 |
### 核心功能矩阵
| 功能模块 | 代码创作 | 文档创作 | 演示创作 | 内容创作 |
|---------|---------|---------|---------|---------|
| **想法池** | ✓ | ✓ | ✓ | ✓ |
| **对抗评估** | ✓ | ✓ | ✓ | ✓ |
| **任务管理** | ✓ | ✓ | ✓ | ✓ |
| **工作流引擎** | ✓ | ✓ | ✓ | ✓ |
| **模板系统** | ✓ | ✓ | ✓ | ✓ |
| **协作功能** | ✓ | ✓ | ✓ | ✓ |
## 🔄 功能升级规划
### Phase 1: 基础创作支持
- [x] 代码创作(现有)
- [ ] Markdown 文档编辑器
- [ ] PPT 演示文稿生成器
- [ ] 文档模板库
### Phase 2: 智能创作辅助
- [ ] AI 内容生成
- [ ] 自动格式化
- [ ] 多格式导出
- [ ] 版本管理
### Phase 3: 创作生态
- [ ] 创作市场
- [ ] 团队协作
- [ ] 知识库集成
- [ ] 发布平台
## 📈 产品差异化
### 竞争优势
1. **全流程覆盖**:从想法到发布
2. **对抗式评估**:独特的质量控制机制
3. **本地优先**:数据安全、隐私保护
4. **跨平台支持**:桌面端 + Web 端
### 差异化场景
- **学术研究**:论文写作 + 代码实现
- **产品设计**:需求文档 + 原型设计
- **技术培训**:课程内容 + 示例代码
- **创意策划**:概念方案 + 可视化展示
## 🎨 视觉识别调整
### 品牌口号
- **原**"本地优先的开发流程工具"
- **新**"创意工作流的私人助手"
### 颜色系统
保持现有的紫色系作为主色,增加:
- 橙色:创意和活力
- 绿色:成长和产出
- 蓝色:专业和可靠
### 图标体系
- 🧠 思维导图
- ✍️ 创作工具
- 📊 产出展示
- 🚀 发布分享
## 📋 实施计划
### 短期1个月
- 更新文档和营销材料
- 完成文档创作基础功能
- 发布 V2.0 版本
### 中期3个月
- 完成演示文稿生成器
- 实现模板系统
- 上线创作市场 Beta
### 长期6个月
- 建立创作者生态
- 集成协作功能
- 考虑 SaaS 服务
## 🎯 成功指标
### 用户增长
- 月活跃用户1000+
- 创作者留存率:>60%
- 日均创作次数:>3/用户
### 内容质量
- 作品发布率:>40%
- 用户满意度:>4.5/5
- 重复使用率:>50%
### 业务指标
- 付费转化率:>5%
- 平均客单价:$50
- 年营收目标:$100K
## 🔮 未来展望
### 5年愿景
成为**创作者的首选工作平台**,连接想法与世界的桥梁。
### 技术演进
- AI 驱动的智能创作
- 虚拟现实创作空间
- 区块链确权和版权保护
### 社会价值
- 降低创作门槛
- 促进知识分享
- 支持创意经济
---
**总结**:从"想法到代码"到"想法到创作"不是功能减少,而是价值升级。我们不再局限于技术工具,而是成为所有创作者的伙伴。

View File

@@ -0,0 +1,344 @@
# 构想: 任务推进全局设计AI-First 推进链) — 2026-06-14
> 性质: 架构设计 / 实现方案
> 关联: df-workflow · AiNode/HumanNode · knowledge 状态机范式 · devflow AI-First 定位kms/devflow_ai_first_model.html
> 修订:
> - 多角度对抗论证收敛kind/状态机不抽层/范围精简)
> - 对抗性验证升级5 维度:收口/并发/崩溃/一致性/前端)
> - **AI-First 定位确认**:任务由 AI 执行→AI 自审→人工最终核对(人从操作者转为审批者)
---
## 定位AI-First 推进链(核心转向)
devflow 是 AI-First 工具。任务推进**不是人点按钮的操作流,是 AI 的执行流**
```
todo ──AI执行──▶ in_progress ──AI自审──▶ review_ready ──人工核对──▶ done
AiNode AiNode HumanNode
AI 干活 AI 审 AI 的活 人最终把关 AI 产出
```
- **AI 执行**:任务内容由 AI 干(写代码、改文件、跑测试)。干完自动推进,人不必手动点「开始」。
- **AI 自审**AI 审 AI 自己的产出code review结构化结论。审过推进审出问题退回重做。
- **人工最终核对**:人在 merge 关卡最终把关 AI 产出。**这是 AI-First 的核心契约——人监督 AI**,不是人确认自己的活。
**advance_task 的默认触发者从「人」变成「AI」**(执行/自审完成事件触发),人可介入/覆盖/微调。人从「操作者」转为「审批者」。
### 这修复了对抗验证的 merge 零因果批评
对抗验证 Agent 4 批评「单人场景 merge 审批零因果——自审自批≈手切」。**AI 执行 + 人工核对**正好修复merge 不再是人确认自己的活,而是**人监督 AI 的活**——从形式主义升级为实质关卡。
---
## 背景
项目管理任务维护目前**只能创建,不能推进**——前端状态标签纯展示无入口。根因缺「推进编排层」:状态字段、工作流引擎、分支表、状态机范式各干各的,且**完全缺 AI 执行层**。
## 痛点
| 已有能力 | 位置 | 现状 |
|---|---|---|
| 任务状态字段(裸 String无值域校验 | `models.rs:52` | 无状态机、无联动、前端不暴露 |
| 工作流引擎ScriptNode/HumanNode/**AiNode** | `df-workflow/*` + `df-nodes/*` | 三种节点现成AiNode 注释明示设计意图「AI 分析→人工审批」,但推进链没用上 |
| 分支表状态 | `models.rs:69` | 语义同构,未联动 |
| 状态机范式 | `knowledge.rs:53` | 只在 knowledge 用 |
| **AI 执行能力** | `df-ai` provider + `ai_node.rs` | AiNode 通用 LLM 调用现成agent 级「写代码改文件」能力渐进 |
---
## 核心模型AI-First 推进链 + 状态机
### 状态机AI 推进 + 退回 + 旁路)
```
AI执行闸门 AI自审闸门 人工核对闸门
todo ───────────▶ in_progress ──────────▶ review_ready ──────────▶ done
▲ │ │
└── AI自审block/人工拒绝 ┘ │ (AI 重做)
abandoned (任意态可放弃,终态不可逆)
```
**退回边** `review_ready → in_progress`AI 自审 block 或人工拒绝 → 退回让 AI 重做。AI 推进下退回比人推进更频繁AI 反复审自己),故 loop 管理必要。
### 闸门策略(三闸门各司其职,都必需)
| 边 | 闸门 | 节点 | 阶段一 | 阶段二 |
|---|---|---|---|---|
| `start` | **AI 执行** | AiNode/agent | ✅ 必需(最小形态) | + git worktreecode kind |
| `ready` | **AI 自审** | AiNode | ✅ 必需 | + lint/test 真校验 |
| `merge` | **人工核对** | HumanNode | ✅ 必需(人监督 AI | + git merge 副作用 |
| `abandon` | 无 | — | 直接转 | 直接转 |
三闸门都必需不再是「merge 强制 + start/ready 关闭」——AI 推进链上每环都有节点把关。
### ⚠️ 失败路径定义(含 AI 执行/自审失败)
| 失败场景 | 工作流结果 | 任务状态 | 反馈 |
|---|---|---|---|
| **AI 执行失败**agent 报错/超时) | failed | 保持 todo | 「AI 执行失败:<错误>」,人可重试或介入手干 |
| **AI 自审 block**(审出严重问题) | failed | **退回 in_progress**AI 重做) | 「AI 自审未通过:<问题清单>」 |
| **AI 自审 warn**(轻微问题) | completed带警告 | 推进到 review_ready | 警告附在任务上,人核对时可见 |
| **人工拒绝** | failed | **退回 in_progress**AI 重做) | 「人工核对未通过:<意见>」 |
| **闸门脚本失败**(阶段二 lint/test | failed | 保持推进前 | 「闸门失败」 |
| **审批超时/取消** | failed/Err | 保持推进前 | 「超时/已取消」 |
| **应用崩溃** | running 孤儿 | 保持推进前,可重新推进 | 启动提示「检测到中断的推进」 |
**关键**AI 自审/人工核对的「拒绝/block」→ 退回 in_progress 让 AI 重做不是退回给人干——AI-First 下人是审批者不是执行者)。
### AI 自审结果处理(建议性 vs 强制)
AiNode 输出纯文本,要判通过与否得约定结构化输出 + 解析:
```json
{ "verdict": "pass" | "warn" | "block", "issues": [...], "summary": "..." }
```
- `pass`:推进;`warn`:推进但带警告;`block`:退回 in_progress
- 默认 AI 自审走 verdict 判定(非纯建议),否则 AI 推进链断在人审前
- 人审merge仍是最终关卡可覆盖 AI 自审结论
---
## AI 执行层(新增,核心缺口)
任务内容由谁干——这是原方案的最大盲区。AI-First 下由 AI 执行。
### 实现形态
- **AiNode/agent 执行**start 闸门触发 AiNode或更复杂的 agent 编排)干活——读任务描述 + 项目上下文 → 写代码/改文件/跑测试 → 产出 diff
- **执行能力渐进**阶段一最小形态AiNode 跑执行 prompt / 接现有 AI 工具链),阶段二+ 逐步增强agent 多步、文件操作、git worktree 内执行)
- **执行产出**:代码 diff / 文件变更 / 测试结果,供下游 AI 自审节点消费
### advance_task 触发者变更
- **默认**AI 执行完成事件 → 自动触发 advance_task(start→推进)
- AI 自审完成 → 触发 advance_task(ready→推进或退回)
- 人工核对完成 → 触发 advance_task(merge→done)
- **人可介入**:任何节点人能手动推进/覆盖/接手(人转手干)
---
## 【P0】状态机收口对抗验证最高优先级
### 致命漏洞update_task 是公开旁路
`task.rs:74` update_task 白名单含 `"status"``crud.rs:291`),任意调用方一行绕过所有闸门和状态机。且 `crud tests:249` 单测固化旁路。AI 推进下更危险——AI agent 若能调 update_task 改 status整个 AI 执行/自审/核对链形同虚设。
### 收口措施
1. 从 tasks 白名单**移除 `"status"`**
2. **advance_task 成为 status 唯一写入路径**AI 触发也走它)
3. 删除/改写 `update_field_allows_tasks_status` 单测
4. advance_task 内联 `validate_task_status` 值域校验
---
## 状态集清理(非「定稿」)
对抗验证纠误:前端早已 5 态,后端 enum 多 3 个僵尸死状态InReview/Testing/Blocked 零使用。是「清理僵尸」非「7→5 定稿」。
措施:删后端 enum 死状态 + `merged→done` 改名 + 迁移前抽样 + status 值域校验。
```sql
-- 迁移幂等conn.transaction() 包裹)
UPDATE tasks SET status='done' WHERE status='merged';
```
---
## 任务类型:阶段一不加 kind
对抗验证:阶段一 code/generic 行为零差异,违反 YAGNI。阶段二 git 联动需要区分时再加 kindALTER + 回填 generic`tags` 保留承担语义标注doc/design
**AI 推进下的 kind 意义**:阶段二+ AI 执行内容按 kind 分化code 任务 AI 写代码、doc 任务 AI 写文档、design 任务 AI 出图)。阶段一 AI 执行最小形态不区分,随能力增强再分。
---
## 状态机实现:不抽层 + 下沉 SQL
enum 补 `can_transition_to`(不新建 state_machine.rsknowledge validate_transition 源码验证是空壳):
```rust
impl TaskStatus {
pub fn can_transition_to(&self, to: &TaskStatus) -> bool {
match (self, to) {
(Todo, InProgress | Abandoned) => true,
(InProgress, ReviewReady | Abandoned) => true,
(ReviewReady, Done | Abandoned | InProgress) => true, // 可退回AI 重做)
_ => false,
}
}
}
```
**状态机下沉 SQL**TOCTOU 根治advance_task 的校验+写入合并为带前置条件的 UPDATE
```sql
UPDATE tasks SET status=:new, updated_at=:now
WHERE id=:id AND status=:expected -- affected_rows==0 即状态已变,拒绝
```
终态保护:`AND status NOT IN ('done','abandoned')`
---
## loop 管理AI 推进下必需)
AI 自审/人工核对退回 → AI 重做 → 再审 → 可能反复。加 `review_rounds: i32` 计数,退回时 +1
- 任务卡显示「第 N 轮 review」迭代可见性
- 可选:轮数过高提示「是否卡住」(不强制终止——单人/AI 决定何时 done
- 强制终止/阈值不做over-engineering
---
## 并发与一致性护栏(对抗验证新增)
AI 推进下并发更常见(多个任务并行 AI 执行)。护栏不变:
1. **per-task 互斥锁**`task_locks: Arc<Mutex<HashMap<String, Arc<Mutex<()>>>>>`
2. **闸门工作流去重**:起 run_workflow 前查 running/interrupted 工作流
3. **WorkflowEvent 加 execution_id** + 转发过滤(防多任务事件串台)
4. **审批请求带 task_id**task_id + execution_id + node_id 三元组)
---
## 数据一致性:跨表事务
`crud.rs` 无跨表事务advance_task 多表写task.status + workflow.status + 阶段二 branches/projects半成品无法回滚。promote_idea 补偿范式不适用更新型。
措施:**补 `Database.transaction()`**OwnedTransactionadvance_task 事务内提交。迁移幂等column_exists + WHERE + conn.transaction 包裹。tags 写入校验。
---
## 崩溃恢复对抗验证新增AI 推进下更关键)
AI 执行/自审是长时异步过程,崩溃恢复更关键:
1. **启动孤儿清理**`UPDATE workflow_executions SET status='interrupted' WHERE status='running'`
2. **审批请求持久化**HumanNode 阻塞前落库node_executions status='pending'),启动恢复
3. **AI 执行状态持久化**AI 执行(长时)需 checkpoint崩溃后能恢复或安全重做阶段二+
4. **审批拒绝语义化**HumanNode/AiNode 区分同意/拒绝/block拒绝走失败路径不当 Ok
5. **重复触发守卫**advance_task 入口检查 running/interrupted 工作流
---
## 前端改造(对抗验证新增 + AI 推进适配)
1. **pendingApprovals 数组化**(按 execution_id 索引)
2. **liveEvents 按 task 路由**event payload 加 task_idstore 改 liveEventsByTask
3. **任务卡 AI 推进可视化**显示当前在哪个环节AI 执行中/AI 自审中/待人工核对/第 N 轮)
4. **按钮防重入**advancingTaskIds: Set
5. **确认式更新**:等 IPC/workflow 事件再刷 task非乐观更新
6. **AI 产出展示**AI 执行的 diff、AI 自审的意见清单,供人核对时查看
7. **统一错误桥接**:全局 watch state.error → Message.error
8. **回调判定**run_workflow 完成回调 advance_task 条件 `task_id.is_some()`
---
## 两阶段落地
### 阶段一AI-First 推进链 + 工程护栏
**推进链**
- 状态集清理(删僵尸 + merged→done+ enum 补 can_transition_to
- **状态机收口**(移除 status 白名单 + advance_task 唯一入口 + 值域校验)← P0
- advance_task + 状态机下沉 SQL + on_task_advanced 空钩子
- **AI 执行闸门**AiNode 最小形态)+ **AI 自审闸门**AiNode 结构化 verdict+ **人工核对闸门**HumanNode
- **失败路径定义**AI 执行失败/AI 自审 block/人工拒绝→退回重做)
- **loop 管理**review_rounds 计数)
- per-task 锁 + 闸门去重、跨表事务、WorkflowEvent 加 execution_id、启动孤儿清理 + 审批持久化
- WorkflowRecord 填值 + event payload 加 task_id
- 前端pendingApprovals/liveEventsByTask/advancingTaskIds/确认式更新/AI 推进可视化
**触发者**advance_task 支持 AI 事件触发 + 人手动介入双通道。
### 阶段二Git + 联动 + AI 执行增强
- 加 kind 字段code kind 闸门脚本换 git 命令串start/ready 接真 git/lint/test
- AI 执行增强agent 多步、worktree 内执行、文件操作)
- 填 on_task_advanced分支联动 + 项目 completed含边界守卫
- BranchRecord 加 worktree_path
### Git 集成:直接外部命令
git 是 ScriptNode/AiNode 一串命令,不特殊化。不建 worktree.rs/df-git crate不做 git 检测框架。硬依赖 git ≥2.20。非 code 任务不依赖 git。
### 联动策略
阶段一剥离分支联动和项目 completed~90 行 + 边界漏洞),阶段二填钩子返工 <30 行。
---
## 落地改动点(阶段一,按优先级)
| 级 | # | 文件 | 改动 |
|---|---|---|---|
| **P0** | 1 | `crud.rs`+`task.rs` | 移除 status 白名单 + advance_task 唯一入口 + 值域校验 + 改单测 |
| **P0** | 2 | `task.rs` | advance_task + 状态机下沉 SQL + on_task_advanced 空钩子 + **支持 AI 事件触发** |
| **P0** | 3 | 闸门 DAG 模板 | **AI 执行AiNode+ AI 自审AiNode verdict+ 人工核对HumanNode三闸门** |
| **P0** | 4 | `human_node.rs`+`ai_node.rs`+`executor.rs` | **审批/自审拒绝语义化**block/拒绝走失败路径不当 Ok |
| **P1** | 5 | `task.rs`/`models.rs` | **review_rounds 计数**(退回 +1 |
| **P1** | 6 | `state.rs` | per-task 锁 + 闸门去重 |
| **P1** | 7 | `db.rs`/`crud.rs` | 补 Database.transaction() + 事务包裹 |
| **P1** | 8 | `events.rs`+`workflow.rs` | WorkflowEvent 加 execution_id + 转发过滤 |
| **P1** | 9 | `state.rs` init | 启动孤儿清理 + 审批持久化恢复 |
| **P1** | 10 | `types.rs` | 删 enum 僵尸 + 补 can_transition_to |
| **P1** | 11 | 迁移 | merged→done幂等 + 事务)|
| **P1** | 12 | `workflow.rs` | run_workflow 加 task_id/project_id + event payload 加 task_id + 完成回调 |
| **P1** | 13 | `models.rs` | TaskRecord 加 tagskind 推阶段二)+ review_rounds + 白名单 |
| **P1** | 14 | 前端 `project.ts`/vue | pendingApprovals 数组 + liveEventsByTask + advancingTaskIds + 确认式更新 + **AI 推进环节可视化** + **AI 产出/diff 展示** |
| **P2** | 15 | `constants`+i18n | merged→done 键名 + tags + review_rounds 文案 + AI 环节文案 |
| **P2** | 16 | `project.ts` | 全局 error 桥接 |
---
## 决策护栏(触发反转条件)
| 决策 | 反转条件 |
|---|---|
| AI-First 推进AI 执行→自审→人核对) | AI 执行能力长期不足/不可靠 → 退回人执行 + AI 辅助审 |
| 阶段一不加 kind | 阶段二 doc/design 真要 AI 执行不同内容;或按 kind 统计 |
| 状态机不抽层 | 第三处状态机需统一审计 |
| 阶段一剥离联动 | 用户验收反馈「想看到项目自动完成」 |
| 不提前集成 git | worktree 异常恢复需 Rust 逻辑 |
| 状态机收口 | 出现「需批量脚本直接改 status」运维场景 → 另开受控入口 |
| AI 自审走 verdict 判定(非纯建议) | AI 自审误判率高 → 降级为建议性,人审全权 |
---
## 决策清单(人定取舍 · why
| # | 决策 | 否决备选 | why |
|---|---|---|---|
| 1 | **AI-First 推进链**AI 执行→AI 自审→人工核对) | 人点按钮推进 | devflow 是 AI-First 工具,任务是 AI 的执行流非人的操作流 |
| 2 | **advance_task 默认 AI 触发**,人可介入 | 仅人触发 | AI 执行/自审完成自动推进;人转审批者 |
| 3 | **AI 自审走 verdict 判定**pass/warn/block | 纯建议 | AI 推进链需 AI 自审能阻断,否则断在人审前 |
| 4 | **人工核对 = 人监督 AI**(非自审自批) | 人确认自己的活 | 修复 merge 零因果AI-First 核心契约 |
| 5 | **拒绝/block → 退回 AI 重做**(非退回人干) | 退回人执行 | AI-First 下人是审批者不是执行者 |
| 6 | **loop 管理 review_rounds**AI 推进必需) | 无计数 | AI 反复审自己,循环比人推进频繁 |
| 7 | 状态机收口(移除 update_task status | 保留旁路 | 对抗验证旁路让状态机形同虚设AI 推进下更危险 |
| 8 | 阶段一不加 kind阶段二再加 | 阶段一二分 | 对抗验证:阶段一零行为差异 |
| 9 | 状态机不抽层enum 补方法 | 抽通用层 | 源码验证空壳 |
| 10 | 状态机下沉 SQLWHERE 前置) | 纯内存校验 | 对抗验证:根治 TOCTOU |
| 11 | 失败路径全覆盖(含 AI 执行/自审失败) | 只描述快乐路径 | 对抗验证:拒绝被当成功是语义反转 |
| 12 | 补跨表事务 | 无事务多写 | 对抗验证:半成品无法回滚 |
| 13 | 崩溃恢复(孤儿清理+审批持久化+AI 执行 checkpoint | 纯内存 | AI 执行长时异步,崩溃恢复更关键 |
| 14 | WorkflowEvent 加 execution_id | 全局单通道 | 对抗验证:多任务事件串台 |
| 15 | 状态集清理后端僵尸(非 7→5 定稿) | 当作待决策 | 对抗验证:前端早已 5 态 |
| 16 | 闸门三必需AI执行/AI自审/人工核对) | merge 强制+其余关 | AI 推进链每环都有节点把关 |
| 17 | 阶段一剥离联动 | 顺带联动 | ~90 行+边界漏洞 |
| 18 | 预留 on_task_advanced 钩子 | 不预留 | 阶段二补是挂插件 |
| 19 | git=闸门脚本调外部命令 | worktree.rs/df-git crate | YAGNI |
| 20 | merged→done迁移 | 文案分流 | 命名中性化 |
| 21 | 前端 pendingApprovals 数组 + 确认式更新 + AI 环节可视化 | 单值/乐观 | 对抗验证多任务并发AI 推进需环节可见 |
---
## 演进记录
1. **多角度论证收敛**kind 二分、状态机不抽层、阶段一范围精简、闸门策略
2. **对抗性验证升级5 维度)**:状态机收口/并发/崩溃恢复/一致性/前端——挖出 P0 致命项(旁路、审批拒绝=成功、TOCTOU、纯内存
3. **AI-First 定位确认**:任务由 AI 执行→AI 自审→人工最终核对。补执行层原方案最大盲区advance_task 触发者改 AIAI 审/loop 升必需merge 升级为「人监督 AI」实质关卡

View File

@@ -0,0 +1,110 @@
# 前后端类型对齐
> 创建: 2026-06-10 | 状态: 初稿
---
> ## 实施状态(2026-06-18 核对)
>
> **本设计文档已大面积过时,正文枚举表不再反映真实代码。** 以下为实际落地形态(以 `crates/df-types/src/types.rs` 为准)
>
> **类型契约机制 — 未采用 ts-rs 代码生成,仍手写 types.ts**
> - ts-rs 依赖:`Cargo.lock` 0 处、`crates/df-types/Cargo.toml` 无 ts-rs 依赖、全 crate 无 `build.rs`、无 `#[ts_rs]`/`#[derive(TS)]` 标注。memory「未做/手写 types.ts」属实。
> - 前端类型手维护:`src/api/types.ts:1` 注释「TypeScript 类型定义 — 与 Rust Record 结构体严格对齐」。
> - 「ts-rs 代码生成」仍列在 todo`docs/todo.md:122`(ARC-260615-07 架构清理项之一)。
>
> **Crate 重命名 — df-core 改名 df-types 已完成**
> - workspace 下无 `crates/df-core` 目录(`ls` 核验 "df-core NOT FOUND");类型定义现居 `crates/df-types/src/{types.rs,events.rs,error.rs,lib.rs}`。
> - 正文出现的 `df-core/src/types.rs` 路径全部应读作 `crates/df-types/src/types.rs`。
>
> **枚举对齐 — 正文 PascalCase 表全部过时,实际为 snake_case 序列化 + 枚举值数已变**
> - 正文写 `#[serde] PascalCase "Created"` 字符串值;实际 `crates/df-types/src/types.rs:51/89/130/195/233` 全部 `#[serde(rename_all = "snake_case")]`,前端/DB 存小写 snake_case。
> - **TaskStatus**:正文 6 值(Created/BranchCreated/InProgress/ReviewReady/Merged/Abandoned) → 实际 **7 值**(`types.rs:131-146`)`todo / in_progress / in_review / testing / done / blocked / cancelled`。正文 6 个枚举名已无一存在。前端 7 态对齐见 `src/constants/project.ts:55`(D-260616-01)。
> - **IdeaStatus**:正文 8 值(Draft/Evaluating/Scored/Hot/Promoted/Parked/Merged/Discarded) → 实际 **6 值**(`types.rs:52-65`)`draft / pending_review / approved / rejected / promoted / archived`。正文 8 个枚举名已无一存在。
> - **ProjectStatus**:正文 4 值(Active/Paused/Completed/Archived) → 实际 **7 值**(`types.rs:90-105`)`planning / in_progress / testing / releasing / completed / paused / cancelled`。
> - **WorkflowStatus**(正文误标 "WorkflowRunStatus"):正文 6 值(Pending/Running/Paused/Completed/Failed/Cancelled) → 实际 **6 值**(`types.rs:195-208`)`pending / running / paused / completed / failed / cancelled`(枚举名同正文,序列化改 snake_case枚举名 WorkflowStatus 非 WorkflowRunStatus)。
> - **NodeStatus / BranchStatus / Priority** 正文未列,实际见 `types.rs:233-248 / 272-281 / 301-312`。
> - **ID 类型**:正文「所有 ID = UUID v4」与实际 `types.rs:10-28` `pub type XId = String` + `new_id()` 一致(未漂移)。
>
> **校验能力追加**`TaskStatus::is_valid` / `valid_values`(`types.rs:165-183`)用于落库前拦截拼写错误(R-P1-5 修复),正文未涉及。
>
> 原文以下设计正文保持不变,作为历史设计记录;当前真实枚举/类型契约形态以上方"实施状态"为准,查阅请直接读 `crates/df-types/src/types.rs`。
---
## 概述
DevFlow 前端 (TypeScript) 和后端 (Rust) 通过 Tauri IPC 和 JSON 序列化通信。两侧的类型定义必须保持一致。
## 类型映射
### 基础类型
| Rust | TypeScript | 说明 |
|------|-----------|------|
| `String` | `string` | 文本字段 |
| `i64` | `number` | 时间戳 (Unix timestamp) |
| `Option<String>` | `string \| null` | 可空字段 |
| `Vec<String>` | `string[]` | 数组 (JSON 序列化) |
| `bool` | `boolean` | 布尔值 |
### ID 类型
| 实体 | Rust | TypeScript | 格式 |
|------|------|-----------|------|
| 所有 ID | `String` | `string` | UUID v4 |
所有 ID 统一使用 UUID v4 字符串,便于前后端传递。
### 枚举对齐
#### IdeaStatus (8 值)
| Rust | TypeScript |
|------|-----------|
| `Draft` | `"Draft"` |
| `Evaluating` | `"Evaluating"` |
| `Scored` | `"Scored"` |
| `Hot` | `"Hot"` |
| `Promoted` | `"Promoted"` |
| `Parked` | `"Parked"` |
| `Merged` | `"Merged"` |
| `Discarded` | `"Discarded"` |
#### TaskStatus (6 值)
| Rust | TypeScript |
|------|-----------|
| `Created` | `"Created"` |
| `BranchCreated` | `"BranchCreated"` |
| `InProgress` | `"InProgress"` |
| `ReviewReady` | `"ReviewReady"` |
| `Merged` | `"Merged"` |
| `Abandoned` | `"Abandoned"` |
#### WorkflowRunStatus (6 值)
| Rust | TypeScript |
|------|-----------|
| `Pending` | `"Pending"` |
| `Running` | `"Running"` |
| `Paused` | `"Paused"` |
| `Completed` | `"Completed"` |
| `Failed` | `"Failed"` |
| `Cancelled` | `"Cancelled"` |
#### ProjectStatus (4 值)
| Rust | TypeScript |
|------|-----------|
| `Active` | `"Active"` |
| `Paused` | `"Paused"` |
| `Completed` | `"Completed"` |
| `Archived` | `"Archived"` |
## 约定
1. 枚举值使用 PascalCase 字符串,前后端保持一致
2. JSON 字段(如 `scores``tags`)在 Rust 侧用 `TEXT` 存储 JSON 字符串,前端解析为对象/数组
3. 时间字段统一用 `i64` (Unix timestamp),前端用 `new Date(ts * 1000)` 转换
4. 新增枚举值时Rust 和 TypeScript 两侧必须同步更新

View File

@@ -0,0 +1,148 @@
# 多主题上下文管理愿景
> 来源:用户架构愿景(2026-06-19)。未来方向,非近期实施。
> 关联:[意图识别层论证](./意图识别层论证-2026-06-19.md)(主题检测前置) / F-15 上下文管理(基础已落地)
## 愿景
**无感多主题对话(交织并行)**:同一对话中多主题**交织并行**(A-B-A-B,非线性前 A 后 B 分段),系统自动识别主题归属 + 多主题上下文并存 + 交织路由,实现:
-**省 token**:每主题独立摘要,非全历史(交织场景 A-B 混杂,主题隔离收益更大)
-**提速**:短上下文(当前主题摘要),LLM 处理快
-**提精准**:主题聚焦(B 噪声不干扰 A 处理),LLM 注意力集中,回复更准
### 场景(交织并行,用户深化)
```
消息1 → 主题 A(新,如"处理 bug X")
消息2 → 主题 B(新,A 仍活跃,如"加 feature Y")
消息3 → 主题 A(补充,A-B 交织)
消息4 → 主题 B(补充,A-B 并行)
```
**关键**:多主题**同时活跃 + 交织**(非"前 A 段|后 B 段"线性,非"一主题完成才切")。主题数不定(2+)。
### 意图识别 = 核心前置(用户深化)
**多主题并存 → 每消息必须识别"归属哪个主题"**(否则无法路由:消息3 是 A 补充还是新主题 C?)。
- **意图识别**(输入意图/会话意图)= 多主题并存的**前置依赖**(每消息主题归属)
- 多主题并存是意图识别的**核心应用场景**
- 两者**绑定**:做多主题并存,必须先做意图识别
- **触发条件调整**:多主题并存需求 = 意图识别的强触发(非仅图片/文档输入 或 工具>40)
## 与 F-09 多会话的关系(架构复用)
- **F-09 多会话**(已落地 d899c58)= **会话级隔离**(conv_id,`HashMap<conv_id, PerConvState>`)
- **多主题并行** = **会话内主题级隔离**(topic = 轻量会话)
- **架构复用**:F-09 per_conv 模式 → 会话内 topic 层级
```
conv_id(会话)
└─ topics: HashMap<topic_id, {messages, summary, last_active}>
├─ topic A(消息1,3...)
├─ topic B(消息2,4...)
└─ ...
```
**多主题 = F-09 多会话的"会话内"深化**(topic 级 per-conv)。PerConvState/ContextManager 隔离模式复用到 topic 层。
## 与现有架构关系
| 现有 | 现状 | 愿景进化 |
|---|---|---|
| **F-15 上下文管理**(分段 archived_segment / 压缩 compressed) | ✅ 已落地(commit 4194842 等),按 **token 阈值**(budget*0.6)触发压缩 | **主题感知**:按主题边界分段,非 token 阈值 |
| **ContextManager**(context.rs) | 单摘要/单分段 | **多摘要并存**(每主题一份) |
| **意图识别**(预留 coordinator/intent.rs) | 空白(近期不做) | **主题检测前置**(主题=意图维度;图片/文档输入时启动) |
| **router**(模型路由) | 静态 weight | 主题/意图→模型(远期) |
## 多主题识别与摘要
### 主题切换检测
- **embedding 相似度**:当前消息 vs 历史主题向量,相似度低于阈值 = 新主题
- **LLM 分类**:fast model 判主题归属(准但延迟)
- **关键词/规则**:主题关键词变化(快但弱)
- **渐进**:规则→embedding→LLM(随规模升级)
### 每主题独立摘要
- 主题段(主题边界内消息)→ LLM 摘要 → **多摘要并存**(ContextManager 扩展:HashMap<topic_id, summary>)
- 复用 F-15 `compress_prompt` 四段式(意图/决策/文件/约束),按主题
- 摘要触发:主题切换时(非 token 阈值)
### 上下文按主题分段
- 当前:`build_eviction_units` 三元组(保护区 + 可压缩)
- 愿景:主题边界分段(每主题一段,切换时归档前主题 + 摘要)
## 智能摘要切换
### 当前主题识别
- 用户消息 → 归属主题(检测:延续当前主题 / 切换新主题 / 回到旧主题)
### 上下文路由(主题→摘要)
- 当前主题摘要 + 关键历史(其他主题摘要压缩/可选展开)
- 无感切换(用户不手动切,系统自动选摘要)
### 场景
- 用户聊主题 A(代码)→ 切主题 B(闲聊)→ 回主题 A:系统保留 A 摘要,B 切换时归档,回 A 时恢复 A 摘要(非全历史 reload)
## 收益量化(预估)
- **省 token**:多主题对话,每主题摘要 ~500-1000 token,vs 全历史 ~5-10K token(累积),**降幅 80%+**(长对话多主题)
- **提速**:短上下文(当前主题),LLM 首 token 快 + 处理快
- **提精准**:主题聚焦,LLM 不被跨主题噪声干扰
## 可行性
| 组件 | 实现 | 基础 |
|---|---|---|
| 主题检测 | embedding/LLM/关键词 | 新增(intent.rs 扩展) |
| 多主题摘要 | ContextManager 扩展(HashMap<topic, summary>) | F-15 压缩基础 |
| 智能切换 | 上下文路由(topic→summary) | 新增 |
| 持久化 | 每主题摘要落 DB | conversation 扩展 |
## 实现路径(远期,分阶段)
1. **主题检测**(规则/embedding):消息→主题标签
2. **主题分段**:ContextManager 按主题边界分段(替代 token 阈值)
3. **多主题摘要**:每主题 LLM 摘要 + HashMap 存
4. **智能切换**:当前主题识别 + 摘要路由
5. **持久化**:主题摘要落 DB(跨会话恢复)
## 风险评估(用户深化·误判代价不对称)
### 误判代价不对称(核心风险)
- **不做多主题**(全历史 A-B 混杂):LLM 信息在,可能跑题但**用户可纠正**(信息未丢)
- **多主题误判**(消息3[A 补充]误判为 B):路由 B 上下文 → LLM 用 B 回 A → **完全错位**(比全历史更糟,信息丢失)
**误判 > 不隔离代价**。意图识别准确性是**硬约束**(必须高准确,否则不如不做)。
### fallback 策略(前提,降误判代价)
- **低置信度→全历史**:意图识别不确定时**不隔离**(安全降级,避免走偏)
- **摘要并存**:即使误判 A/B 摘要都在,信息不丢(LLM 可选/用户纠正)
- **用户显式纠正**:"这是 A 主题"→ 重新路由(手动 override)
### 复杂度 vs 收益 vs 准确性
- **复杂度**(高):主题识别(意图瓶颈)+ 多主题上下文管理(HashMap/交织路由/摘要)+ 持久化
- **收益**(中,长对话交织):省 token + 提精准
- **准确性风险**(高):embedding/LLM 分类中文意图+交织主题挑战大,准确率不够→误判走偏→比不做更糟
## 结论(近期不值得,远期可行)
- **近期不值得**:复杂度高 + 意图准确性瓶颈 + 误判代价不对称 → ROI 低。F-15(token 阈值)+ F-09(多会话手动切)够用
- **远期可行**:意图识别准确率有保障(技术成熟/数据积累)+ 长对话交织场景多时,**fallback 是前提**(低置信度降级全历史)
## 触发条件(何时做)
- 当前 F-15(token 阈值压缩)够用,多主题是**长对话多主题场景**优化
- 触发:用户反馈长对话跨主题时上下文混乱 / token 成本高 / 回复跑题
- 依赖:意图识别(主题检测)**准确率有保障 + fallback 健壮**(非仅预留就绪)
## 与意图识别关系
- **主题识别 = 意图识别的一种**(主题是意图维度:代码/闲聊/搜索/项目/...)
- 意图识别预留(图片/文档输入时启动),主题摘要可**先于完整意图识别**(主题检测独立于模型路由)
- 两者共享前置层(coordinator/intent.rs 落地)
## 备注
- 用户原话:「多主题识别与摘要 + 智能摘要切换 → 无感多主题对话 + 上下文压缩(省 token)+ 提速 + 提精准」
- 这是**远期愿景**,近期 F-15(token 阈值)够用。触发条件达成时启动。

View File

@@ -0,0 +1,60 @@
# 多主题并存补充论证:多轮模式(agentic 意图识别)
> 来源:multitopic-analysis 子代理补充(IRCoT/ReAct/Reflexion/FLARE/AwN/ECLAIR/Copilot/Cursor 硬数据)+ 用户深化(多轮请求上下文 + 实体 NER + 异步预热 + 边界场景)。
> 对原报告(多主题并存论证-2026-06-19.md)维度 2/3/4/6/8 的修正。纯论证,不改代码。
## 核心修正
**原报告**:准确率天花板是硬约束(SOTA 55.8/73%,不可绕过)。
**修正**:agentic 多轮模式**确实能突破天花板**(硬数据支撑),准确率从被动分类 55.8/73% → 可能 85%+。
## 突破证据(SOTA 硬数据)
| 模式 | 增益 | 来源 |
|---|---|---|
| IRCoT(检索+CoT 交替) | QA F1 **+7~15** | ACL 2023 |
| ReAct(推理+行动) | 准确率 **+30%** | NeurIPS 2022 |
| Reflexion(反思修正) | pass@1 **91% vs 80%**(+11%) | NeurIPS 2023 |
| Agentic RAG(多跳) | 34% → 89%(+55pp) | Medium |
## 但仍有约束(修正不改变近期结论)
1. **>90% 仍是硬线**:devflow 有副作用工具(销账/状态机/文件写),Reflexion 91% 是上限非保证,**须沙箱实测**(不能假设 devflow 场景达标)
2. **增益对场景敏感**:FLARE 大场景仅 56.5%;简单请求多轮无收益反增延迟
3. **边界场景 30-50% fallback 不变**:多轮不消除边界(模糊/跨主题/新主题),ROI 仍稀释
4. **三重栈复杂度**:多轮编排 + 实体 NER + 异步预热 ~1300-1700 行 + 意图层先决(远期重投入)
5. **异步预热解"慢"**(关键技术):Copilot(sub-200ms 日 4 亿次)/ Cursor(生产落地)证明可行,但实现复杂度最高(草稿预分析 + 就绪判断 + 取消/重试 + 状态隔离)
6. **主动澄清 vs 无感张力**:业界范式(AwN/ECLAIR)倾向"低置信→主动问用户",违反"无感"愿景
## 修正后分阶段路径
```
近期(0-3月):不做(原结论不变)
- 多轮是有前景的远期方向,但当前技术栈不具备(意图层未落/异步预热未建/多轮未验证)
中期(3-12月,低风险试点,按 ROI 排序):
1. 用户显式标主题(零误判)
2. 意图识别层 intent.rs 工具级落地(独立ROI + 多主题先决)
3. 半自动高门槛(embedding>95%才隔离,多轮暂不上)
远期(12+月,完整 agentic 多主题):
技术栈:意图层(稳定) + 异步预热(解延迟) + 多轮编排(IRCoT/Reflexion) + 实体NER
触发(全部满足):准确率实测>90% + 异步预热就绪 + 意图层稳定 + 真实痛点
顺序锁定:意图层 → 异步预热 → 多轮+NER(不可颠倒)
```
## 关键风险
- **不能假设 devflow 场景多轮一定达>90%**:Reflexion 91% 是受控 benchmark,devflow 交织主题 + 副作用工具更难,**必须沙箱实测**
- **"继续"/"1"短指代消息**:全历史 LLM 天然消解(零逻辑,可靠);多主题下需路由(继承上一条主题),若上一条误判则错误传播
## Sources
- [IRCoT (ACL 2023)](https://aclanthology.org/2023.acl-long.557/)
- [ReAct (NeurIPS 2022)](https://arxiv.org/abs/2210.03629)
- [Reflexion (NeurIPS 2023)](https://arxiv.org/abs/2303.11366)
- [FLARE 复测 56.5%](https://beancount.io/bean-labs/research-logs/2026/05/18/flare-active-retrieval-augmented-generation)
- [AwN Learning to Ask](https://arxiv.org/html/2409.00557v3)
- [ECLAIR (AAAI)](https://ojs.aaai.org/index.php/aaai/article/view/35152/37307)
- [GitHub Copilot 工程](https://github.blog/ai-and-ml/github-copilot/the-road-to-better-completions-building-a-faster-smarter-github-copilot-with-a-new-custom-model/)
- [Cursor + Fireworks](https://fireworks.ai/blog/cursor)

View File

@@ -0,0 +1,72 @@
# 多主题并存(交织并行)多角度论证
> 来源:multitopic-analysis 子代理 8 维度论证 + WebSearch SOTA 硬数据 + 业界产品派/学术派佐证。
> 纯架构论证,不改代码。供架构决策。
## TL;DR
**近期不做自动多主题路由**。SOTA 准确率天花板(55.8/73%)远低>90% 硬阈值 + devflow 有副作用工具(误判不可逆) + 边界场景 30-50% 降级稀释 ROI + 业界零参照(头部产品全用物理隔离)。
## 核心结论(数据驱动)
### 1. 准确率天花板是硬约束(不可绕过)
- **TopiOCQA F1 = 55.8**(最贴近 A-B-A-B 交织 SOTA,TACL 2022)→ 误判率 25-45%
- **MultiWOZ DST JGA ≈ 73.6%**(受控,开放域更差)
- devflow 硬阈值(有副作用工具):**需 >90-95%** 才值得做
- **当前 SOTA 远低于阈值** → 自动路由不具备落地条件
### 2. 误判代价不对称(因 devflow 有副作用工具)
- 不做多主题(全历史):信息冗余但**都在**,可逆
- 多主题误判(消息3[A]误判 B):信息**错误路由**,LLM 用 B 回 A → **完全错位**
- devflow 工具(销账/状态机/文件写)**不可逆** → 误判触发不可逆副作用,**比全历史更糟**
### 3. 业界零参照(头部产品全用物理隔离)
- ChatGPT:Projects(用户手动分会话)
- Claude/Claude Code:memory 按 Project 隔离
- Cursor 2.0:子代理 + git worktree 物理隔离
- Devin 2.0:拆任务到隔离 VM
- Cline:Tasks 独立会话,跨 session 不传上下文
- **无一做单会话内自动主题路由** → devflow 若做是先行者(高风险)
### 4. 边界场景频率致命稀释 ROI
- 新主题/通用寒暄(15-25%)+ 模糊不能明确 A/B(10-15%)+ 跨主题对比(5-10%)= **30-50% 消息降级全历史**
- 代价 100% 承担(复杂度+误判风险),收益只作用于 50-70% 消息 → **ROI 为负**
### 5. 长上下文不救场
- **lost-in-the-middle**(Liu et al. TACL 2023,被引 4690+):长上下文 U 型退化
- A-B-A-B 切回旧主题 A 时,A 历史信息可能落在"中间段"被遗忘 → 即使全历史也在,关键信息仍可能丢
## 分阶段路径
| 阶段 | 触发条件 | 动作 |
|---|---|---|
| **近期**(0-3月) | 现状(29工具,单provider,中短对话) | **不做**,F-09+F-15 够用,储备设计 |
| **中期**(3-12月) | 用户主动反馈痛点 | 试点**显式标主题**(用户手动标,零误判)或**半自动 fallback**(高门槛>95%才隔离) |
| **远期**(12+月) | 准确率>90% + 意图层稳定 + 真实痛点(三者齐备) | 完整自动多主题 + 强 fallback |
**中期试点原则**:**绝不直接上全自动路由**。优先"用户显式标主题"(零误判)或"半自动高门槛"(embedding>95% 才隔离,其余全历史)。
## fallback 是硬要求(任何阶段)
- **置信度必须**(低→全历史不隔离)
- **业界范式**:Rasa/工业对话系统用"阈值+双层 fallback(OOS/低置信澄清)",非"自动全历史兜底"
- "低置信→全历史"看似安全,实则(a)token 高 (b)放大 lost-in-the-middle (c)边界 30-50% 触发 → **多主题愿景在边界退化为不做多主题**
## 与 F-09 关系(架构可行但非瓶颈)
- F-09 多会话(已落地 d899c58)铺路 85%:per_conv/ContextManager/压缩/持久化可复用到 topic 层
- 多主题 = F-09 的"会话内"深化(topic 级 per-conv),架构改动 ~650-800 行
- **架构就绪 ≠ 值得做**:真正瓶颈是准确率天花板 + 误判代价,非架构
## Sources
- [TopiOCQA F1=55.8](https://direct.mit.edu/tacl/article/doi/10.1162/tacl_a_00471/110550/)
- [MultiWOZ 2.4 JGA≈73.6%](https://github.com/smartyfh/multiwoz2.4)
- [Lost in the Middle](https://arxiv.org/abs/2307.03172)
- [RAG 错误不可逆](https://aclanthology.org/2026.eacl-long.147.pdf)
- [Pinecone Less is More](https://www.pinecone.io/blog/why-use-retrieval-instead-of-larger-context/)
- [Rasa Failing Gracefully](https://medium.com/rasa-blog/failing-gracefully-with-rasa-8ead6b43f2f4)
- [Claude memory per-project](https://simonwillison.net/2025/Sep/12/claude-memory/)
- [Cursor 2.0 parallel agents](https://medium.com/towards-data-engineering/parallel-ai-agents-in-cursor-2-0-a-practical-guide-e808f89cffb9)
- [Devin Manage Devins](https://cognition.ai/blog/devin-can-now-manage-devins)
- [Cline Tasks](https://docs.cline.bot/core-workflows/task-management)

View File

@@ -0,0 +1,143 @@
# DevFlow 对抗论证裁决报告
> 创建: 2026-06-11 | 方法: 三路对抗论证(市场/技术/需求) | 结论: 方向有价值scope 必须砍
---
## 一、论证方法
用"魔法打败魔法":三个独立 AI 代理分别从不同立场攻击这个项目,互不可见,最后综合裁决。
| 代理 | 立场 | 综合评分 |
|------|------|---------|
| 市场分析师 | 竞品全景 + 市场数据(带外部信源) | **4/10 — 不建议以当前形态推进** |
| 技术架构师 | 13 crate2026-06-12 评审时数2026-06-14 删 5 僵尸 crate现 8/ Tauri / 引擎 / AI 可行性 | **2.7/5 — 可行但必须砍 scope** |
| 恶魔代言人 | 逐功能质疑需求真实性 | **核心成立60% 功能该砍** |
---
## 二、三方共识(站不住脚的地方)
### 共识 1🔴 Scope 失控是最大风险
- 8 个核心功能横跨 4-5 个产品类别PM + 工作流 + AI 编排 + 代码分析 + 知识库)
- 22,745 字架构文档、16 张表、13 crate评审时点数2026-06-14 裁定为 8 crate—— **这是操作系统的野心,不是 MVP 的规划**
- 现实工时v1.0 全功能需全职 8-12 个月 / 业余 1.5-2 年
- 历史教训Firebase/Heroku/全生命周期 API 平台都被"组件化组合"打败
### 共识 2🔴 身份危机 — 无法一句话说清
- Cursor = "AI 编辑器"Linear = "快的 issue 追踪器"DevFlow =
- "全流程"不是定位,是定位的缺失
### 共识 3🔴 部分功能是伪需求(对个人开发者)
| 功能 | 需求方评分 | 市场方评分 | 裁决 |
|------|-----------|-----------|------|
| 插件系统 (WASM) | 1/5 | — | **砍掉**(为 0 个用户设计生态) |
| 经验进化(自动沉淀) | 1/5 | 3/10 | **砍掉**(技术上无法落地,连骨架都是空的) |
| 需求-测试追溯 | 1/5 | — | **砍掉**(企业需求硬塞给个人) |
| 多模型路由 + Agent 协作 | — | 4/10 | **砍掉**OpenClaw/大厂赛道,无法竞争) |
| 想法池(完整版) | 2/5 | 2/10 | **降级**(简化为列表+对抗式评估) |
| 决策留痕(独立子系统) | 2/5 | 4/10 | **降级**(字段级方案,不建独立体系) |
### 共识 4🟡 AI 信任危机的时代背景
- Stack Overflow 2025开发者对 AI 信任度从 40% 跌至 29%
- 66% 开发者花更多时间修复 AI 的"差不多对"代码
- **定位必须从"AI 帮你做事"转向"AI 帮你控制流程"**——AI 是副驾驶,不是自动驾驶
---
## 三、三方冲突点的调和
### 冲突 1DAG 工作流引擎
- 需求方:**5/5 必须有**(产品的灵魂,本地工作流有空白)
- 市场方:**2/10 伪需求**GitHub Actions 已免费解决)
**裁决**:两者都对,但说的是不同的东西。
- GitHub Actions 解决的是 **仓库内 CI/CD**push 触发、云端跑)
- DevFlow 的空隙是 **本地的、跨项目的、AI 参与的交互式流程**(不依赖 push、可以有人工审批节点、能调用本地资源
- **保留 DAG 引擎,但作为内部基础设施,不作为对外卖点**。用户看到的是"一键执行编码→审查→测试流程",而不是"DAG 编辑器"
### 冲突 2标注系统
- 需求方:**1/5 砍掉**IDE 已解决)
- 市场方:**6.5/10 全场最高差异化机会**"扫描代码库 FIXME/TODO → AI 批量处理 → 关联任务"是真空地带)
**裁决**:需求方批的是"在文档/测试报告上加标注"的重模式(确实没人用);市场方挺的是"代码库 TODO 扫描器 + AI 处理"的轻模式。
- **采用轻模式**:扫描代码 TODO/FIXME → 汇总 → AI 生成处理建议 → 一键转任务
- 砍掉"任意实体标注"的重设计
---
## 四、站得住脚的部分
1. **本地优先** — Obsidian 证明了本地优先工具有大市场订阅疲劳52% 用户因此退订)反推一次性付费
2. **Tauri 技术栈** — 比 Electron 小 96%选型正确4/5
3. **引擎代码质量** — 拓扑排序算法正确、trait 设计合理、依赖树无环
4. **任务绑 Git 分支** — 6/10最有价值的业务功能做深"任务→分支→提交→合并→关单"全链路有空间
5. **对抗式想法评估** — 这是本次论证方法本身的产品化,市场上没有工具这么做
---
## 五、调整方案
### 5.1 产品定位调整
**旧**AI 原生的产研操作系统,从想法到上线的全流程编排(❌ 无法一句话说清)
**新****本地优先的个人开发流程驾驶舱 — 把想法、任务、分支和 AI 流程放进一个不联网也能跑的桌面应用**
一句话版本「你的项目流程本地跑AI 辅助,数据不出门」
### 5.2 功能调整清单
| 功能 | 原计划 | 调整后 |
|------|--------|--------|
| DAG 工作流引擎 | 对外核心卖点 | ✅ 保留为内部引擎UI 上呈现为"流程模板一键执行" |
| 任务+分支 | 一般功能 | ✅ **升级为核心**:任务→分支→工作流→合并全链路 |
| 想法池 | 完整漏斗系统 | ⬇️ 简化:列表 + **对抗式评估**(正方/反方/分析师三路论证,差异化卖点) |
| 标注系统 | 任意实体标注 | ⬇️ 简化:代码库 TODO/FIXME 扫描器 + AI 批处理 |
| 决策留痕 | 独立子系统 | ⬇️ 降级:关键操作自动写决策字段,无独立 UI |
| AI 编排 | 多模型路由+四 Agent | ⬇️ 砍:单 Provider (Claude) + AI 节点,无 Agent 协作 |
| 阶段插件 | 5 阶段 | ⬇️ 3 个内置流程模板(编码/测试/发布) |
| 8 种节点 | 全部实现 | ⬇️ Phase 1 只做 Shell/AI/SubflowGit 用 Shell 调 CLI |
| 需求-测试追溯 | 完整体系 | ❌ 砍掉v2.0 团队版再说) |
| 经验进化 | 自动沉淀引擎 | ❌ 砍掉(降为手动 Snippet 收藏Phase 5 再议) |
| 插件系统 | WASM/动态加载 | ❌ 砍掉v2.0 再说) |
**砍掉比例:约 60%,与三方建议一致。**
### 5.3 架构调整
- **13 crate 保留目录结构**评审时点2026-06-14 裁定删除 5 个僵尸 crate df-evolve/df-plugin/df-stages/df-task/df-traceability现实际 8 crate但 Phase 1 只激活 6 个:
`df-core / df-workflow / df-storage / df-execute / df-nodes / src-tauri`
- 其余 7 个 crate 标记为 `[预留]`,从 workspace 默认构建中保留但不再投入开发
- Git 操作走 Shell CLI不引入 libgit2技术报告建议省 1-2 周)
### 5.4 Phase 重排
| Phase | 旧目标 | 新目标 |
|-------|--------|--------|
| 1 | 引擎骨架(含一切基础) | **跑通一条 Shell→AI→Shell 工作流 + 任务/分支 CRUD + 前端真数据** |
| 2 | AI 集成(多模型) | Claude 单 Provider + AI 节点 + 想法对抗式评估 |
| 3 | 想法池+多项目 | TODO 扫描器 + 3 个流程模板 |
| 4 | 节点丰富+阶段插件 | 任务→分支→合并全链路Git 深度集成) |
| 5 | 体验打磨 v1.0 | 打磨 + 自用验证 3 个月 → 决定是否对外 |
### 5.5 验证策略调整
市场报告的最重要建议:**先验证再深投**。
- DevFlow 首先是**自用工具**(管理 wk-* 工作空间的真实项目)
- 自用 3 个月,记录每天真实打开次数
- 如果自己都不用,停止投入;如果离不开它,再考虑对外
---
## 六、裁决结论
> **方向有价值,形态要收敛。** "本地优先 + 任务分支驱动 + AI 辅助流程"是真空隙;"全流程操作系统"是幻觉。砍掉 60% 的功能不是失败,是论证的胜利——它们本来会消耗 6-9 个月却没人用。
>
> 同时,本次论证方法本身(三路对抗)被产品化为想法池的"对抗式评估"功能,详见 `docs/03-模块文档/想法探索-对抗式评估-2026-06-12.md`。这是 DevFlow 吃自己的狗粮的第一个案例。

View File

@@ -0,0 +1,129 @@
# 工作流审批子系统对抗审查报告
> 2026-06-14 · 多代理审查(31 agents / 5 维度 × 对抗验证) + 主代理独立复核 + 二轮对抗论证
> 范围: df-workflow/{executor,state,eventbus}.rs · df-nodes/human_node.rs · df-core/events.rs · src-tauri/{commands/workflow,state}.rs · src/stores/project.ts · src/api/{types,workflow}.ts · src/views/ProjectDetail.vue
> 方法: workflow fan-out 审查 → 每发现独立对抗验证(默认反驳) → 主代理读源码复核 criticals → 二轮对抗论证(存在性/可达性/危害三维)
## TL;DR
1. **头号 bug [P0 阻断]**: `human_node.rs:41``HumanApprovalRequest``.await``EventBus::send` 是 async fn`let _ = async_fn()` 丢弃 Future 未 poll → body 不执行 → **Request 从未进入 channel**。审批链最上游断裂。
2. **①②(前端契约失配) 被头号遮蔽**: Request 没发 → 前端 `onEvent` 收不到 → type 匹配分支不可达。修 41 行后 ①② 才显形为 critical。
3. **当前 UI 无 human 节点 DAG 入口**: `demoDag` 仅 script 节点AI 工具 `run_workflow` 返回提示不执行。审批相关 9 项发现现实触发率=0全部潜伏。
4. **根因**: 审批功能前端从未端到端跑通41 行 await 漏掉即铁证),单测绿但不覆盖 human→前端弹窗→审批→返回链路。
---
## 0. 头号发现 [P0]
### 0.1 缺陷定位
`crates/df-nodes/src/human_node.rs:41-47`
```rust
let _ = ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest {
execution_id: ctx.execution_id.clone(),
node_id: ctx.node_id.clone(),
title: title.to_string(),
description: description.to_string(),
options: options.clone(),
}); // ← 无 .await
```
### 0.2 机制
- `EventBus::send` 签名 (`eventbus.rs:33`): `pub async fn send(&self, event: WorkflowEvent)` — async fn。
- `let _ = async_fn()` 求值得 Future绑定 `_` 后语句结束立即 drop**Future 零 poll**。
- async fn body (`self.sender.send(event)`) 仅在 Future 被 poll 时执行 → 此处永不执行 → Request 未进 broadcast channel。
### 0.3 对抗自检(排除假阳)
| 质疑 | 核实 |
|------|------|
| 测试为何 pass? | `normal_approval_returns_decision` 的 helper `send_response``send(...).await`(`human_node.rs:172` 有 await) 发的是 **Response**HumanNode 的 Request 那行没 await。测试只断言 Response 被 rx 收到并返回 decision**不验证 Request 是否发出**。绿测不能证伪。 |
| 编译器为何不报? | `let _ = expr` 合法通配符绑定async fn 生成的 Future 默认无 `#[must_use]`,零 warning。 |
| 是否误用同步 fn? | `eventbus.rs:44` `emit_human_approval_request` 是同步 fn(返 Result),但 HumanNode 未用它,用的是 async `send`。 |
| 多代理为何漏? | 审查聚焦前端契约(①②)与串扰(③),未逐行核 HumanNode 内 send 调用点是否 await。主代理二轮读 human_node.rs 全文才发现。 |
### 0.4 触发路径
`human_node.rs:38 subscribe → :41 send(无await)` → Request 未发 → `workflow.rs` 转发任务 rx 收不到 → 前端 `onEvent` 不触发 `HumanApprovalRequest` 分支 → `pendingApproval` 恒 null → 弹窗不开 → HumanNode `select!` 阻塞至 `:86 sleep_until(deadline)` 默认 3600s 超时 → Err → 工作流 failed。
### 0.5 修复
```diff
- let _ = ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest { ... });
+ ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest { ... }).await;
```
---
## 1. 反转结论
### 1.1 ①② 被头号遮蔽(降级: 当前不可达)
-`project.ts:214` `payload.event?.type === 'HumanApprovalRequest'`大驼峰vs 后端 `events.rs:18` `#[serde(tag="type", rename_all="snake_case")]` → 序列化值 `'human_approval_request'`,永不匹配。
-`project.ts:215` `payload.event.data` —— event 是 `WorkflowEvent` 本体扁平结构(`{type, execution_id, node_id, title, description, options}`),无 `data` 包装层 → undefined。
- 两者代码层面确凿,但 Request 未发(§0 遮蔽) → 前端收不到事件 → 分支不可达。**修 41 行后 ①② 立即变 critical**。
### 1.2 当前 UI 无 human 节点入口(多数发现现实触发率=0
| 证据 | 位置 |
|------|------|
| 前端唯一 DAG = demoDag仅 3 个 script 节点 | `ProjectDetail.vue:271-273` |
| AI 工具 run_workflow 返回提示不执行 DAG | `tool_registry.rs:346-350` |
| runDemoWorkflow 按钮 disabled=workflowRunning 防重入 | `ProjectDetail.vue:281-289` |
→ 审批相关发现(①②④⑤⑦⑧⑨⑩)全部潜伏在未接入路径。
---
## 2. 逐条对抗裁定
| # | 定位 | 存在性(代码层) | 现实可达性 | 危害校正 | 裁定 |
|---|------|---------------|-----------|---------|------|
| **0** | human_node.rs:41 | 确凿 缺await | human DAG 运行即必现UI 无入口 | Request 不发,链最上游断 | **真·潜伏头号 P0** |
| ① | project.ts:214 | 确凿 snake_case | 被0遮蔽+无human入口 | 潜伏修0后才显形 | 降级: 当前不可达 |
| ② | project.ts:215 | 确凿 flat无data | 同① 双重遮蔽 | 潜伏 | 降级: 同① |
| ③ | workflow.rs:67-97 | 确凿 全局bus+Node*无exec_id+matches!只看变体 | 需并发工作流UI防重入+AI不执行 | 审批路由不坏(Request自带exec_id),仅日志串扰+提前break | 真实架构缺陷现实触发0危害被夸大 |
| ④ | project.ts:15-21 | 确凿 单槽 | 三重遮蔽(0+无入口+单流) | 潜伏 | 真实,潜伏 |
| ⑤ | project.ts:208-261 | 确凿 无终态监听 | 同④;"稍后"按钮可视觉关 | UX退化非卡死 | 真实,危害偏低 |
| ⑥ | state.rs:106 | 确凿 直接insert | 需⑦竞态命中 | snapshot()零调用方(死代码)DB不受影响 | **真实但无害** |
| ⑦ | project.ts:228 | 确凿 无互斥 | 需0+①②+入口全通+双击+500ms窗口 | 窄窗口 | 真实,潜伏 |
| ⑧ | workflow.rs:171 | 确凿 无校验(对比cancel有registry守卫) | 需human+超时窗口 | 诊断损失非功能损坏 | 真实,潜伏 |
| ⑨ | human_node.rs:73-81 | 确凿 warn+continue | 需256积压当前无节点发NodeProgress每节点≤2事件需128+并发节点 | 概率近0 | 真实,当前不可达 |
| ⑩ | workflow.rs:91-97 | 确凿 Lagged+Closed死代码(bus持于AppState全程) | 同⑨ 需256积压 | DB终态仍正确仅task泄漏 | 真实,当前不可达 |
| ⑪ | workflow.rs:140 | 确凿 String::new() | demoDag失败即触发 | 低危: error字段含first_err.context"节点X失败"failed_node冗余空 | **真实且当前可达,危害低** |
---
## 3. 根因
审批功能前端从未端到端验证。证据链:
1. `B-260614-03a` 重写 HumanNode `execute`(subscribe→send→select!) 时引入 `:41` await 缺失7 单测全绿未抓(单测不覆盖 Request 发出)。
2. 前端无 human 节点 DAG 入口,无任何集成测试覆盖 human→弹窗→审批→返回链路。
3. ①② 是前后端契约层断裂,`types.ts:127` `event.type: string` 弱类型无编译期拦截。
→ 单测绿 + 无端到端测试 = 这批潜伏 bug 的存活土壤。
---
## 4. 修复优先级
| 序 | 动作 | 优先级 | 依赖 | 会暴露 |
|---|------|--------|------|--------|
| 1 | 补 human 节点端到端集成测试(含human的DAG→运行→断言前端收到Request+弹窗开) | P0 | 无 | 0+①+② |
| 2 | human_node.rs:41 加 .await | P0 | 测试暴露后修 | — |
| 3 | project.ts:214 type→snake_case; :215 取 event 本体字段; types.ts event.type 收窄字面量联合 | P0(修2后) | 2 | — |
| 4 | ③ Node*事件补 execution_id + 转发过滤 | P2 | 并发工作流时 | — |
| 5 | ④⑤ pendingApproval 改 Map + 终态清空 | P2 | 2③后 | — |
| 6 | ⑥ set_cancelled 查终态 no-op | P3 | 无(无消费者零危害) | — |
| 7 | ⑦⑧⑨⑩⑪ | P2-P3 | 见§2 | — |
---
## 附: 多代理 workflow 元数据
- 31 agents / 5 维度(concurrency / state-machine / error-handling / lifecycle / frontend-contract) × 对抗验证
- 26 原始发现 → 12 确认 / 11 反驳 / 3 验证代理因 API 限流未跑(主代理手动补判)
- 验证阶段正确识别 `executor.rs:124` 三条为 not-a-bug(B-03b-R1 已修,`:127` 有 is_cancelled guard + test_cancelled_node_skips_set_failed)
- 漏抓头号(§0): 因未核 send await主代理二轮复核补

View File

@@ -0,0 +1,106 @@
# 意图识别层(通用前置)多角度论证
> 来源:intent-analysis 子代理 8 维度论证 + WebSearch 10 业界佐证 + devflow 源码核验。
> 纯架构论证,不改代码。供架构决策。
## 核心结论
1. **方向正确**:意图识别作为通用前置层(每消息),服务四下游(工具预选/模型路由/上下文策略/审批预估)——业界共识(TianPan/NVIDIA/LangChain 佐证),用户洞察准确。
2. **当前不急**:devflow 29 工具处于业界"产品派不做意图层"临界点(Claude Code <20 工具不分类 / OpenAI 原生 tool_choice 非前置),痛点不致命(未到 417 工具崩 20% 线)。
3. **近期建议**:精简工具描述降 token(零架构改动,立即可做)。
4. **中期触发**(工具>40 或多模型用户):上**方式 A 规则**(零延迟零成本纯赚),落 `intent.rs` + tool domain 标签。
5. **远期升级**(工具>80 或 MCP):**方式 D 两阶段**(规则兜底 + Flash 分类),警惕 Tool RAG 生产退化(《340 Tools》反例)。
6. **落地约束**:意图层只在 `agentic/mod.rs` loop 入口生效一次,不进 loop 体;输出"子集扩充+模型建议"非"硬性裁剪";None fallback 全量零回归。
7. **架构兼容**:与双轨/审计/provider 工厂三高杠杆零冲突;`coordinator.rs` 空壳保留 B 路线多 Agent,意图层独立落 `intent.rs`
## 痛点量化(现状)
- **工具全量下发**:`agentic/mod.rs:423 tool_definitions()` 全 29 工具 schema 每消息塞 request,~6000-8000 token/消息(中位估算)。
- **模型路由静态化**:`router.rs:56-63` TaskRequirements 硬编码 needs_tool_use=true/modalities=[Text],闲聊和写代码走同模型。
- **coordinator.rs 空壳**:B 路线占位(L5-30),意图识别无落脚点。
- **上下文策略纯阈值**:`agentic/mod.rs:513-641` 自动压缩按 token>budget*0.6,不按意图。
## 实现方式对比
| 方式 | 延迟 | token | 准确 | 推荐 |
|---|---|---|---|---|
| A.规则/关键词 | <1ms | 0 | 中(中文意图,覆盖70%+) | ⭐ 近期 |
| B.embedding | 10-50ms | 0+1次embedding | 中 | ✗ ROI低(单用户桌面) |
| C.fast model | 300-800ms | ~200-500 | 高 | 中期补(盈亏工具>40+多模型) |
| D.两阶段(A+C) | 混合 | 混合 | 高 | ⭐ 远期 |
## 收益量化(方式 A 规则,中期)
- 工具子集降 token:29→8-12 子集,**省 4000-5000 token/消息,降幅 60%**。
- 模型路由省成本:60% 闲聊→Flash(¥0.0014/M)/ 40% 工具→Plus(¥5/M),**混合均价降 60%**(多模型用户)。
- 决策准确:工具数 <10 时 LLM 选错概率显著降(反推 417→20% 数据)。
- 审批预估前置:前端预判 High 风险,提前提示。
## 盈亏平衡(方式 C fast model)
| 维度 | 阈值 | devflow 现状 | 值得上 C? |
|---|---|---|---|
| 工具数 | >40 | 29 | 临界,即将 |
| 多模型 | 用户配 Flash+Plus | 多数单 provider | 多数无收益 |
| 延迟容忍 | 接受 +500ms 首字 | 流式敏感 | 负面 |
**结论**:方式 A 规则零成本纯赚(近期可上);方式 C 盈亏在"工具>40 且多模型"之后。
## 风险 + fallback
| 风险 | 缓解 |
|---|---|
| 意图误判(漏工具) | **子集扩充非裁剪**(project+file 兜底,18 工具仍<29) |
| 单点故障 | None fallback 全量工具(零回归) |
| 延迟敏感 | 方式 A 无延迟;C 需并行/异步预热 |
| Flash 超时/非法 | fallback 全量/规则结果 |
**关键设计原则**:意图层是"加权推荐"非"硬性裁剪";None 时全量(现状)零回归。
## 业界佐证(WebSearch 10 来源)
**学术/框架派**(主张前置意图层):
- TianPan《Intent Classification Layer》(417 工具崩 20%,论证需专用前置层)
- NVIDIA AIQ《Intent Classifier》(单次 LLM 多输出:意图+元响应+判定)
- Medium《Intent-to-Action Layer》(prompt→intent→structure→policy→route→tools→execution)
- LangChain《Context Engineering》(RAG 工具描述,只发相关工具)
- Red Hat《Tool RAG》(企业级工具扩展解法)
**产品派**(工具可控时不做前置):
- OpenAI function calling(tool_choice 是"约束"非"前置分类",意图责任留开发者)
- Claude Code 子代理(任务级路由,非消息级;<20 核心工具不做意图层)
**反例(警惕)**:《OpenAI 340 Tools 生产案例》——语义工具选择初期有效但准确率随时间退化,需持续监控。
**定价**:智谱 GLM Plus ¥5/M vs Flash ¥0.0014/M(500倍差,意图路由省钱空间)。
## devflow 整合(改动面)
| 模块 | 现状 | 接入点 | 改动 |
|---|---|---|---|
| coordinator.rs | B 路线空壳 | 保留(多Agent) | 不动 |
| **intent.rs**(新增) | — | 意图识别落点 | ~200 行(规则引擎+Intent 枚举) |
| tool_registry.rs | tool_definitions() 全量 | 加 tool_definitions_subset(intent) + 工具 domain 标签 | ~50 行 + 29 register 加 domain |
| agentic/mod.rs | loop 外 tool_defs | loop 入口插意图识别 | ~30 行(入口加调用) |
| router.rs | 静态 TaskRequirements | 意图→TaskRequirements 构造 | agentic 构造点改,router 不动 |
**总计 ~300-400 行,中等改动**。与双轨/审计/provider 工厂零冲突。
## 分阶段路径(触发条件)
```
近期(29工具,单provider):精简工具描述(零架构),储备设计(本文档)
中期(工具>40 或多模型):方式A规则(intent.rs + domain标签 + subset + 模型路由)
远期(工具>80 或MCP):方式D两阶段(A规则兜底+C Flash分类),警惕Tool RAG退化
```
## Sources
- [TianPan Intent Classification](https://tianpan.co/blog/2026-04-16-intent-classification-agent-routers)
- [NVIDIA AIQ Intent Classifier](https://docs.nvidia.com/aiq-blueprint/2.0.0/architecture/agents/intent-classifier.html)
- [LangChain Context Engineering](https://www.langchain.com/blog/context-engineering-for-agents)
- [Red Hat Tool RAG](https://next.redhat.com/2025/11/26/tool-rag-the-next-breakthrough-in-scalable-ai-agents/)
- [OpenAI 340 Tools 反例](https://pub.towardsai.net/openai-function-calling-works-great-until-you-have-340-tools-12-tenants-real-production-traffic-fe02da116e39)
- [Claude Code Subagents](https://www.builder.io/blog/claude-code-subagents)
- [OpenAI Function Calling](https://developers.openai.com/api/docs/guides/function-calling)
- [智谱定价](https://open.bigmodel.cn/pricing)