docs: 对话类型统一重构方案(消除多智能体模式全局状态)
This commit is contained in:
parent
165c771cc7
commit
d5b1e2c3af
214
docs/conversation_type_unification_plan.md
Normal file
214
docs/conversation_type_unification_plan.md
Normal file
@ -0,0 +1,214 @@
|
||||
# 对话类型统一重构方案:消除「多智能体模式」全局状态
|
||||
|
||||
> 状态:方案已确认(v2,含用户设计修正),实施中
|
||||
> 撰写日期:2026-08-09
|
||||
> 关联记忆:`multi_agent_mode_design`(本方案实施后将取代其前端部分)
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与问题
|
||||
|
||||
当前「多智能体模式」是一个**全局标签页状态**,由三样东西共同维持:
|
||||
|
||||
- 路由前缀:`/multiagent/<id>` vs `/<id>`
|
||||
- 全局布尔:`multiAgentMode`(app 级状态,37 处引用、18 个文件)
|
||||
- 列表过滤:所有对话列表请求携带 `multi_agent_mode=0|1`,两种模式的对话互相不可见
|
||||
|
||||
这套设计在双模式并行使用时暴露了一串耦合 bug(2026-08 实录):
|
||||
|
||||
1. 多智能体标签页(工作区1)+ 传统标签页(工作区2)互拽视图——socket 用户级广播无条件跟随。
|
||||
2. 多智能体模式下,侧边栏「按项目分组」的项目旁新建按钮把对话建成了传统模式——每个新建入口都要手动"继承模式",漏一个就是一个 bug。
|
||||
3. 修复过程中发现同类耦合点越修越多(共享 session 工作区、创建落点、URL 前缀拼接……)。
|
||||
|
||||
**根因**:模式分裂本身制造了双标签页使用需求(两类对话只能在各自页面看到),而全局模式状态与共享 session、用户级广播交织出 N 个耦合点,修补式修复无法穷尽。
|
||||
|
||||
**产品决断**(用户拍板):多智能体是**对话的属性**,不是应用的模式。单标签页、单当前工作区是设计如此(后端对话级隔离已保证同/跨工作区多对话并行);两类对话进入同一个页面后,双标签页场景自然消失。
|
||||
|
||||
## 2. 目标 / 非目标
|
||||
|
||||
### 目标
|
||||
|
||||
- 删除全局「多智能体模式」状态;对话类型(`normal` | `multi_agent`)**创建时确定、之后不可变**,权威存储于对话 `metadata.multi_agent_mode`(现有字段,零迁移)。
|
||||
- 侧边栏两类对话**左右切换显示**(单类型视图 + 滑动动画),平铺列表与按项目分组两种视图套用同一规则。
|
||||
- 输入栏底行(发送按钮所在行)`+` 按钮**左侧**新增「智能体/多智能体」类型选择按钮。
|
||||
- URL 统一为 `/<id>`;`/multiagent/<id>`、`/multiagent/new` 做兼容重定向。
|
||||
- 打开对话时从 metadata 恢复类型(现有 `enterConversation` 机制),渲染/terminal/上下文走对应路径。
|
||||
|
||||
### 非目标(明确不做)
|
||||
|
||||
- **不改多智能体运行时**:Team Leader、子智能体管理、消息池派发、多智能体消息渲染(`isMultiAgentMessage` 按消息级 metadata 判断)全部保留。
|
||||
- **不做类型转换**:普通对话不能"升级"为多智能体。
|
||||
- **不改分开存储**:多智能体对话仍由独立 conversation manager 存储。
|
||||
- **不做多标签页/多设备视图跟随**:各视图独立是设计前提。
|
||||
- **不改后端**:列表继续用现有 `multi_agent_mode=0|1` 服务端过滤(此时它是用户显式控制的视图过滤器,语义正确),端点全部保留。
|
||||
|
||||
## 3. 已确认的设计决策
|
||||
|
||||
| # | 决策点 | 结论 |
|
||||
|---|--------|------|
|
||||
| 1 | 类型选择器位置 | 输入栏**最下面固定行**(发送按钮所在行),`+` 按钮**左侧**的独立按钮;**不在 + 菜单内部** |
|
||||
| 2 | 侧边栏呈现 | **左右切换**(一次只显示一个类型),控件位置:平铺模式(单工作区)放在「搜索对话」下面;分组模式(多工作区)放在**工作区标题行、新建对话等按钮的左边** |
|
||||
| 3 | 切换动画 | 点击后对话记录显示区域**整体向左滑出**,多智能体列表**从右侧滑入**;切回时动画反向 |
|
||||
| 4 | URL 方案 | 统一 `/<id>` 为主路由;`/multiagent/<id>` 重定向到 `/<id>` |
|
||||
| 5 | 类型可变性 | 创建时确定,**不可变**;打开对话从 metadata 恢复 |
|
||||
| 6 | 工作区模型 | 单当前工作区维持设计,session 权威 |
|
||||
|
||||
**实施细节默认**(用户可否决):
|
||||
|
||||
- 侧边栏类型过滤器:`sidebarConversationType`(`'normal' | 'multi_agent'`),单一全局状态、localStorage 持久化、默认 `'normal'`,同时驱动平铺/分组两种视图的列表请求(`maParam` 由它生成)与切换动画方向。
|
||||
- 侧边栏新建按钮(含项目分组旁按钮):创建**当前过滤器显示的类型**(看着多智能体列表点新建,就建多智能体对话,立即出现在当前视图中)。
|
||||
- /new 页首条消息创建:按输入栏选择器的 `newConversationType`。
|
||||
- 空过滤器下(某工作区无该类型对话):列表区域显示该类型的空态。
|
||||
|
||||
## 4. 技术地基(已验证,2026-08-09 代码核对)
|
||||
|
||||
| 验证点 | 结论 | 位置 |
|
||||
|--------|------|------|
|
||||
| 聊天执行的模式判定 | ✅ 已是**对话 metadata 驱动**:加载对话时 `self.multi_agent_mode = bool(meta.get("multi_agent_mode", False))`,chat_flow 全部读 terminal 实例标志 | `core/web_terminal.py:438-443`、`server/chat_flow_task_main.py` 多处 |
|
||||
| 列表服务端过滤 | ✅ `multi_agent_mode=0|1` 过滤已支持且分页正确(每个 manager 各自分页);侧边栏切换器继续用它,**后端零改动** | `utils/context_manager/conversation_mixin.py:388`、`server/conversation.py:524` |
|
||||
| 按 ID 定位对话归属 | ✅ 按文件存在性跨两个存储目录解析,类型无关 | `conversation_mixin.py:86` |
|
||||
| 对话元数据前端恢复 | ✅ `enterConversation` 统一加载协议已读 `meta.multi_agent_mode`(重构后写入对话类型) | `bootstrap.ts:66` |
|
||||
| 前端模式状态规模 | 37 处引用、18 个文件,绝大多数是 `isMultiAgent ? A : B` 分支 | 见 §6 改动地图 |
|
||||
| 数据迁移 | ✅ 零迁移;旧对话缺字段时后端有 `/api/multiagent/rebuild-index` 补全机制(当前在 `/multiagent/new` bootstrap 触发,重构后改为 `/new` 首次进入或应用启动时触发一次) | `route.ts bootstrapRoute` |
|
||||
|
||||
## 5. 总体设计
|
||||
|
||||
### 5.1 状态模型:从「全局模式」到「对话类型 + 两个局部选择状态」
|
||||
|
||||
**删除**:
|
||||
- `app/state.ts` 的 `multiAgentMode` 全局布尔
|
||||
- `watchers.ts` 的 multiAgentMode → conversation store 同步
|
||||
- `stores/conversation.ts` 的 `multiAgentMode` patch
|
||||
|
||||
**新增**(三个语义单一的状态,替代原来一个语义混杂的全局模式):
|
||||
|
||||
| 状态 | 语义 | 生命周期 |
|
||||
|------|------|----------|
|
||||
| `currentConversationType: 'normal' \| 'multi_agent' \| null` | 已打开对话的类型 | `enterConversation` 从 `meta.multi_agent_mode` 落地;空对话态为 `null` |
|
||||
| `newConversationType: 'agent' \| 'multi_agent'` | 输入栏选择器的待创建类型 | localStorage 持久化,默认 `'agent'` |
|
||||
| `sidebarConversationType: 'normal' \| 'multi_agent'` | 侧边栏过滤器当前显示的类型 | localStorage 持久化,默认 `'normal'` |
|
||||
|
||||
**派生规则**:打开对话后所有「是否多智能体」判断读 `currentConversationType`;/new 空态的创建判断读 `newConversationType`;侧边栏列表/新建按钮读 `sidebarConversationType`。三者互不复用。
|
||||
|
||||
### 5.2 路由统一
|
||||
|
||||
- 主路由:`/<id>`(`stripConversationPrefix` 的 `conv_` 前缀美化保留,与类型无关)。
|
||||
- `/multiagent/new` → `replaceState` 到 `/new`。
|
||||
- `/multiagent/<id>` → 正常 `enterConversation` 加载(类型从 meta 恢复),成功后 `replaceState` 到 `/<id>`。
|
||||
- `isExplicitNewConversationRoute()` 收缩为只判 `new`。
|
||||
- `enterConversation` 的 `urlPrefix` 参数删除。
|
||||
|
||||
### 5.3 输入栏类型选择器(新 UI)
|
||||
|
||||
- **位置**:输入栏最下面固定行(发送按钮所在行),`+` 按钮**左侧**,独立于 + 菜单。
|
||||
- **形态**:参考 `permission-switcher`(批准方式菜单)——按钮显示当前值 + caret,点击展开下拉:
|
||||
- 「智能体」——单智能体对话(默认)
|
||||
- 「多智能体」——Team Leader + 子智能体协作
|
||||
- **空对话(/new)**:可选,选中写 `newConversationType` + localStorage。
|
||||
- **已有对话**:显示该对话类型,**禁用态**(类型不可变)。
|
||||
- QuickMenu 内现有 `toggle-agent-mode` 入口(`@toggle-agent-mode` 事件链)移除。
|
||||
- 样式遵守 AGENTS.md §5.5:无 glow、语义 token、固定高度、菜单不透明、内部滚动。
|
||||
|
||||
### 5.4 侧边栏左右切换
|
||||
|
||||
**控件**(分段切换,两项:普通对话 / 多智能体对话,或反向顺序):
|
||||
|
||||
- 平铺模式(单工作区):放在「搜索对话」输入框下面。
|
||||
- 分组模式(多工作区):放在工作区标题行,新建对话等按钮的**左边**(所有工作区分组共享同一个过滤器状态,控件在每个分组标题行重复出现或仅当前展开组——实施时按 DOM 结构定,优先每行都有,保证所见即所得)。
|
||||
|
||||
**动画**:点击切换后,对话记录显示区域**整体向左滑出**,目标类型列表**从右侧滑入**;切回时反向。实现:两个列表 pane 包一层 `overflow:hidden` 轨道,`transform: translateX` + transition(普通→多智能体方向向左,反向向右);Vue `<Transition mode="out-in">` 自定义类或双 pane 轨道均可,以不引起高度跳动为准。
|
||||
|
||||
**列表请求**:继续携带 `maParam`,但来源从「全局模式」改为「侧边栏过滤器状态」;切换时重置 offset 重新加载。分组视图 `loadWorkspaceConversations` 同理。
|
||||
|
||||
### 5.5 创建链路
|
||||
|
||||
| 入口 | 类型来源 | 端点 |
|
||||
|------|----------|------|
|
||||
| /new 首条消息(send.ts) | `newConversationType` | `'multi_agent'` → `/api/multiagent/conversations`(`preserve_mode:true`),否则 `/api/conversations` |
|
||||
| 侧边栏「新建对话」(blank 行为) | `sidebarConversationType` | 同上 |
|
||||
| 项目分组旁新建按钮 | `sidebarConversationType` | 同上 + 该项目 `workspace_id` |
|
||||
|
||||
创建成功后统一 `/<id>` 跳转。
|
||||
|
||||
### 5.6 后端改动
|
||||
|
||||
**零改动**。列表过滤、创建端点、类型恢复全部复用现有能力。(原计划的合并列表分页修正取消——不合并,改为显式过滤。)
|
||||
|
||||
## 6. 改动地图
|
||||
|
||||
### 6.1 前端(18 个文件,多数为删除分支)
|
||||
|
||||
| 文件 | 改动要点 |
|
||||
|------|----------|
|
||||
| `app/state.ts` | 删 `multiAgentMode`;加 `currentConversationType`、`newConversationType`、`sidebarConversationType` |
|
||||
| `app/watchers.ts` | 删 multiAgentMode watch 及路由模式推导 |
|
||||
| `app/methods/ui/route.ts` | bootstrapRoute 删 multiagent 模式分支,改为重定向;`isExplicitNewConversationRoute` 收缩;rebuild-index 触发时机迁移 |
|
||||
| `app/methods/ui/mode.ts` | `toggle-agent-mode` 相关方法清理 |
|
||||
| `app/methods/conversation/bootstrap.ts` | meta → `currentConversationType`;删 `urlPrefix` 与模式前缀拼接 |
|
||||
| `app/methods/conversation/load.ts` | `maParam` 改由 `sidebarConversationType` 生成 |
|
||||
| `app/methods/conversation/action.ts` | 创建按 `sidebarConversationType` 选调端点;删 URL 模式前缀 |
|
||||
| `app/methods/message/send.ts` | 首条消息创建按 `newConversationType`;URL 统一 `/<id>` |
|
||||
| `app/methods/search.ts` | 搜索过滤来源改为 `sidebarConversationType`(或全类型,实施时定) |
|
||||
| `app/methods/taskPolling/sync.ts` | 删 URL 前缀拼接 |
|
||||
| `app/methods/ui/hostWorkspace.ts` | 工作区切换后统一跳 `/new` |
|
||||
| `stores/conversation.ts` | 分组加载 `maParam` 改来源;删 `multiAgentMode` patch |
|
||||
| `stores/subAgent.ts` | 核对模式依赖(验证点 V3) |
|
||||
| `composables/useLegacySocket.ts` | `conversation_resolved` 等处 URL 前缀删除 |
|
||||
| `components/input/InputComposer.vue` | 底行 `+` 左侧新增类型选择器;删 `multi-agent-mode` prop 透传 |
|
||||
| `components/input/QuickMenu.vue` | 移除 `toggle-agent-mode` 入口 |
|
||||
| `components/sidebar/ConversationSidebar.vue` | 切换控件(两处位置)+ 双 pane 滑动动画 + 按类型渲染 |
|
||||
| `App.vue` | 删模式相关 props/事件透传 |
|
||||
|
||||
### 6.2 文档与记忆
|
||||
|
||||
- `AGENTS.md` §11 多智能体模式章节重写为「对话类型」模型
|
||||
- 项目记忆 `multi_agent_mode_design` 标注被本方案取代(前端部分);新增 `conversation_type_model` 记忆
|
||||
|
||||
## 7. 历史修复的取舍(2026-08-09 评估)
|
||||
|
||||
| 批次 | 结论 | 理由 |
|
||||
|------|------|------|
|
||||
| `be061bec` stop_flags 任务级隔离 | **保留** | 真 bug(任意并行对话互相停止),与模式架构无关,新世界同样需要 |
|
||||
| `165c771c` 网络权限实例级快照 + 快捷窗口残留 | **保留** | 真 bug(进程级 env 污染后台指令网络),与模式架构无关 |
|
||||
| 未提交的广播过滤批(6 文件:socket 防拽视图/工作区本地化/显式 workspace_id/新建模式继承) | **已回退** | 错误路线:给双标签页耦合打补丁;新模式下该场景被设计消除,且新建继承等改动将被重构重写 |
|
||||
|
||||
回退后基线 = `165c771c`(即"第一次说这个问题"时的状态 + 两个独立真修复)。
|
||||
|
||||
## 8. 风险与缓解
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|------|------|
|
||||
| `enterConversation` 删 `urlPrefix` 后调用方未对齐 | 全仓搜索 `urlPrefix` 逐一核对;手测刷新恢复 |
|
||||
| 切换动画引起列表高度跳动/滚动位置丢失 | 双 pane 轨道 + 固定容器高度;切换时保留各自滚动位置 |
|
||||
| 分组视图每行都放控件导致拥挤 | 实施时评审 DOM 结构,必要时仅当前展开组显示 |
|
||||
| `/multiagent/*` 旧链接(App 历史、书签)失效 | 重定向保留;Android App 下次发版同步 |
|
||||
| 暗藏的的模式依赖(subAgent store、监控动画等) | 实施收尾时全仓 grep `multiAgentMode`/`multi_agent` 清零 |
|
||||
|
||||
## 9. 实施时验证点
|
||||
|
||||
- **V3**:`stores/subAgent.ts` 的 `multiAgentMode` 具体用途
|
||||
- **V4**:QuickMenu 内 `toggle-agent-mode` 的现有处理链(App.vue → mode.ts)
|
||||
- **V5**:`App.vue` 中 `multiAgentMode` 的 props 透传链
|
||||
- **V6**:分组模式工作区标题行的按钮组构成(确定切换控件插入点)
|
||||
|
||||
## 10. 实施阶段与验证计划
|
||||
|
||||
- **阶段 A(状态与路由)**:状态层三态替换 + 路由统一/重定向 → 构建通过
|
||||
- **阶段 B(输入栏选择器)**:底行 `+` 左侧按钮 + 创建链路 → 构建通过
|
||||
- **阶段 C(侧边栏切换)**:控件 + 滑动动画 + 列表过滤来源切换 → 构建通过
|
||||
- **阶段 D(清理)**:残留 grep 清零 + 文档/记忆更新 + 冒烟
|
||||
|
||||
**手测清单**(完成后请用户实测):
|
||||
1. /new 页输入栏左侧选「多智能体」发首条消息 → 创建多智能体对话,URL 为 `/<id>`
|
||||
2. 侧边栏切换控件:普通 ↔ 多智能体,列表滑动动画方向正确
|
||||
3. 平铺/分组两种视图切换控件位置符合 §3-#2
|
||||
4. 打开多智能体对话 → 选择器显示「多智能体」禁用态,Team Leader 路径正常
|
||||
5. 刷新页面 → 对话类型正确恢复;旧 `/multiagent/<id>` 链接重定向正常
|
||||
6. 切工作区 → 列表随过滤器类型正确加载;分组旁新建按钮创建的类型 = 当前过滤器类型
|
||||
|
||||
## 11. 提交策略
|
||||
|
||||
1. 回退错误路线未提交改动(已完成,无痕)
|
||||
2. **本方案文档 commit**(`docs:` 单独一个)
|
||||
3. 重构实施:阶段 A-C 一个 `refactor` commit(或按需拆分),阶段 D 文档更新并入
|
||||
4. 工作区存在用户自己的未提交改动(`tools_execution.py`、`modules/multi_agent/tools.py`、`toolRenderers.ts`、`PersonalizationDrawer.vue`、`personalization.ts`、`agent_context.py`),任何 commit 不得混入
|
||||
Loading…
Reference in New Issue
Block a user