| 1 | # 会话引用功能架构文档 |
| 2 | |
| 3 | > GitHub Issue: https://github.com/esengine/DeepSeek-Reasonix/issues/3185 |
| 4 | |
| 5 | ## 1. 功能需求 |
| 6 | |
| 7 | 在当前会话中使用 `@` 引用其他会话的聊天记录作为内容发送给 AI。 |
| 8 | |
| 9 | ### 1.1 用户场景 |
| 10 | |
| 11 | - 用户在当前会话中想引用之前会话的对话内容 |
| 12 | - 用户想让 AI 参考之前的对话上下文 |
| 13 | - 用户想合并多个会话的讨论结果 |
| 14 | |
| 15 | ### 1.2 预期行为(P0-MVP) |
| 16 | |
| 17 | ``` |
| 18 | 输入 @ |
| 19 | → 显示原有菜单(文件/目录列表) |
| 20 | → 菜单顶部新增 "past:chats" 选项 |
| 21 | → 选择 past:chats |
| 22 | → 切换到历史会话列表 |
| 23 | → 选择一个会话 |
| 24 | → Composer 上方显示"已引用会话" |
| 25 | → 发送时把该会话历史内容附加到当前 prompt/context |
| 26 | ``` |
| 27 | |
| 28 | --- |
| 29 | |
| 30 | ## 2. 现有代码结构分析 |
| 31 | |
| 32 | ### 2.1 核心文件 |
| 33 | |
| 34 | | 文件 | 作用 | |
| 35 | |------|------| |
| 36 | | `desktop/frontend/src/components/Composer.tsx` | 输入框组件,包含 @ 功能 | |
| 37 | | `desktop/frontend/src/components/FileMenu.tsx` | @ 文件菜单组件 | |
| 38 | | `desktop/frontend/src/components/HistoryPanel.tsx` | 历史会话面板 | |
| 39 | | `desktop/frontend/src/lib/bridge.ts` | 前后端通信接口 | |
| 40 | | `desktop/frontend/src/lib/types.ts` | 类型定义 | |
| 41 | |
| 42 | ### 2.2 现有 @ 功能实现 |
| 43 | |
| 44 | **Composer.tsx 第 257-337 行** 实现了文件引用功能: |
| 45 | |
| 46 | ```typescript |
| 47 | // --- @ file references --- |
| 48 | const atRaw = useMemo(() => { |
| 49 | const m = /(?:^|\s)@([^\s]*)$/.exec(text); |
| 50 | return m ? m[1] : null; |
| 51 | }, [text]); |
| 52 | |
| 53 | // 文件匹配结果 |
| 54 | const atMatches = useMemo(() => { |
| 55 | // 过滤本地目录和搜索结果 |
| 56 | }, [atRaw, atFrag, entries, searchEntries]); |
| 57 | |
| 58 | // 菜单模式判断 |
| 59 | const menuMode: "slash" | "slasharg" | "at" | null = ...; |
| 60 | |
| 61 | // 渲染文件菜单 |
| 62 | {menuMode === "at" && <FileMenu items={atMatches} ... />} |
| 63 | ``` |
| 64 | |
| 65 | ### 2.3 已有的会话 API(可复用) |
| 66 | |
| 67 | ```typescript |
| 68 | interface AppBindings { |
| 69 | // 会话列表 |
| 70 | ListSessions(): Promise<SessionMeta[]>; |
| 71 | |
| 72 | // 会话操作(可复用读取历史) |
| 73 | PreviewSession(path: string): Promise<HistoryMessage[]>; |
| 74 | } |
| 75 | ``` |
| 76 | |
| 77 | --- |
| 78 | |
| 79 | ## 3. P0-MVP 实施方案 |
| 80 | |
| 81 | ### 3.1 设计思路 |
| 82 | |
| 83 | 在现有的 `@` 菜单中添加 "past:chats" 选项,而不是创建新的 `@session:` 语法。 |
| 84 | |
| 85 | **菜单结构:** |
| 86 | ``` |
| 87 | @ |
| 88 | ├── 📁 past:chats ← 新增:选择后显示历史会话列表 |
| 89 | ├── 📁 src/ |
| 90 | ├── 📁 docs/ |
| 91 | ├── 📄 README.md |
| 92 | └── ... |
| 93 | ``` |
| 94 | |
| 95 | ### 3.2 实施路线 |
| 96 | |
| 97 | ``` |
| 98 | 第一步:后端加搜索接口 |
| 99 | ↓ |
| 100 | 第二步:前端 bridge.ts 暴露接口 |
| 101 | ↓ |
| 102 | 第三步:在 @ 菜单中添加 "past:chats" 选项 |
| 103 | ↓ |
| 104 | 第四步:选择 past:chats 后切换到会话列表 |
| 105 | ↓ |
| 106 | 第五步:选择会话后添加到引用区域 |
| 107 | ↓ |
| 108 | 第六步:发送时附加会话上下文 |
| 109 | ``` |
| 110 | |
| 111 | ### 3.3 最小改动文件清单 |
| 112 | |
| 113 | ``` |
| 114 | desktop/frontend/src/lib/types.ts — 添加 SessionReference 类型 |
| 115 | desktop/frontend/src/lib/bridge.ts — 添加 SearchSessions API |
| 116 | desktop/frontend/src/components/Composer.tsx — 扩展 @ 菜单逻辑 |
| 117 | desktop/frontend/src/components/FileMenu.tsx — 扩展菜单支持会话项 |
| 118 | desktop/app.go — 添加 SearchSessions 方法 |
| 119 | desktop/sessions.go — 实现会话搜索逻辑 |
| 120 | ``` |
| 121 | |
| 122 | ### 3.4 类型定义 |
| 123 | |
| 124 | ```typescript |
| 125 | // types.ts |
| 126 | export interface SessionReference { |
| 127 | path: string; |
| 128 | title: string; |
| 129 | preview?: string; |
| 130 | turns?: number; |
| 131 | createdAt?: number; |
| 132 | lastActivityAt?: number; |
| 133 | messages?: HistoryMessage[]; // P0 先不存,发送时再拉取 |
| 134 | } |
| 135 | ``` |
| 136 | |
| 137 | ### 3.5 API 设计 |
| 138 | |
| 139 | ```typescript |
| 140 | // bridge.ts |
| 141 | interface AppBindings { |
| 142 | // 新增:搜索会话 |
| 143 | SearchSessions(query: string): Promise<SessionMeta[]>; |
| 144 | |
| 145 | // 已有:读取会话历史(复用) |
| 146 | PreviewSession(path: string): Promise<HistoryMessage[]>; |
| 147 | } |
| 148 | ``` |
| 149 | |
| 150 | ### 3.6 前端逻辑修改 |
| 151 | |
| 152 | **Composer.tsx 修改:** |
| 153 | |
| 154 | ```typescript |
| 155 | // 1. 添加状态 |
| 156 | const [showPastChats, setShowPastChats] = useState(false); |
| 157 | const [pastChats, setPastChats] = useState<SessionMeta[]>([]); |
| 158 | const [sessionRefs, setSessionRefs] = useState<SessionReference[]>([]); |
| 159 | |
| 160 | // 2. 修改 @ 菜单渲染 |
| 161 | {menuMode === "at" && ( |
| 162 | showPastChats ? ( |
| 163 | // 显示会话列表 |
| 164 | <SessionMenu |
| 165 | items={pastChats} |
| 166 | activeIndex={active} |
| 167 | onPick={pickSession} |
| 168 | onHover={setActive} |
| 169 | /> |
| 170 | ) : ( |
| 171 | // 显示文件列表(原有逻辑) |
| 172 | <> |
| 173 | <button |
| 174 | className="slashmenu__item slashmenu__item--special" |
| 175 | onMouseDown={() => { |
| 176 | setShowPastChats(true); |
| 177 | app.ListSessions().then(setPastChats); |
| 178 | }} |
| 179 | > |
| 180 | <MessageSquare size={13} /> |
| 181 | <span className="slashmenu__name">past:chats</span> |
| 182 | <span className="slashmenu__desc">引用历史会话</span> |
| 183 | </button> |
| 184 | <FileMenu items={atMatches} ... /> |
| 185 | </> |
| 186 | ) |
| 187 | )} |
| 188 | |
| 189 | // 3. 选择会话后的处理 |
| 190 | const pickSession = (session: SessionMeta) => { |
| 191 | // 添加到引用区域 |
| 192 | setSessionRefs(prev => [...prev, { |
| 193 | path: session.path, |
| 194 | title: session.title || session.preview || "Untitled", |
| 195 | preview: session.preview, |
| 196 | turns: session.turns, |
| 197 | createdAt: session.createdAt, |
| 198 | lastActivityAt: session.lastActivityAt, |
| 199 | }]); |
| 200 | |
| 201 | // 重置状态 |
| 202 | setShowPastChats(false); |
| 203 | setText(""); // 清空输入框 |
| 204 | }; |
| 205 | |
| 206 | // 4. 发送时附加会话上下文 |
| 207 | const handleSubmit = async () => { |
| 208 | let context = ""; |
| 209 | |
| 210 | if (sessionRefs.length > 0) { |
| 211 | context = "以下是用户引用的历史会话上下文:\n\n"; |
| 212 | for (const ref of sessionRefs) { |
| 213 | const messages = await app.PreviewSession(ref.path); |
| 214 | const limited = limitMessages(messages, 30, 20000); |
| 215 | context += formatSessionContext(ref.title, limited); |
| 216 | } |
| 217 | context += "\n\n当前用户问题:\n"; |
| 218 | } |
| 219 | |
| 220 | onSubmit(context + text); |
| 221 | }; |
| 222 | ``` |
| 223 | |
| 224 | ### 3.7 限制策略 |
| 225 | |
| 226 | ``` |
| 227 | 最多引用最近 30 条消息 |
| 228 | 或最多 20k 字符 |
| 229 | 超出部分截断,并提示"已截断" |
| 230 | ``` |
| 231 | |
| 232 | ### 3.8 发送时的消息格式 |
| 233 | |
| 234 | ``` |
| 235 | 以下是用户引用的历史会话上下文: |
| 236 | |
| 237 | [会话:修复登录 bug] |
| 238 | 用户:... |
| 239 | 助手:... |
| 240 | 用户:... |
| 241 | |
| 242 | 当前用户问题: |
| 243 | ... |
| 244 | ``` |
| 245 | |
| 246 | --- |
| 247 | |
| 248 | ## 4. 架构图 |
| 249 | |
| 250 | ``` |
| 251 | ┌─────────────────────────────────────────────────────────────┐ |
| 252 | │ Composer.tsx │ |
| 253 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 254 | │ │ @ 菜单逻辑 │ │ |
| 255 | │ │ - 原有:文件/目录列表 │ │ |
| 256 | │ │ - 新增:past:chats 选项(在菜单顶部) │ │ |
| 257 | │ └─────────────────────────────────────────────────────┘ │ |
| 258 | │ │ │ |
| 259 | │ ▼ │ |
| 260 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 261 | │ │ 菜单渲染 │ │ |
| 262 | │ │ - showPastChats=false → FileMenu + past:chats 按钮 │ │ |
| 263 | │ │ - showPastChats=true → SessionMenu (会话列表) │ │ |
| 264 | │ └─────────────────────────────────────────────────────┘ │ |
| 265 | └─────────────────────────────────────────────────────────────┘ |
| 266 | │ |
| 267 | ▼ |
| 268 | ┌─────────────────────────────────────────────────────────────┐ |
| 269 | │ bridge.ts │ |
| 270 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 271 | │ │ 新增 API: │ │ |
| 272 | │ │ - SearchSessions(query): Promise<SessionMeta[]> │ │ |
| 273 | │ │ │ │ |
| 274 | │ │ 复用 API: │ │ |
| 275 | │ │ - ListSessions(): Promise<SessionMeta[]> │ │ |
| 276 | │ │ - PreviewSession(path): Promise<HistoryMessage[]> │ │ |
| 277 | │ └─────────────────────────────────────────────────────┘ │ |
| 278 | └─────────────────────────────────────────────────────────────┘ |
| 279 | │ |
| 280 | ▼ |
| 281 | ┌─────────────────────────────────────────────────────────────┐ |
| 282 | │ desktop/app.go │ |
| 283 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 284 | │ │ 新增方法: │ │ |
| 285 | │ │ - SearchSessions(query string) []SessionMeta │ │ |
| 286 | │ └─────────────────────────────────────────────────────┘ │ |
| 287 | └─────────────────────────────────────────────────────────────┘ |
| 288 | ``` |
| 289 | |
| 290 | --- |
| 291 | |
| 292 | ## 5. UI 设计 |
| 293 | |
| 294 | ### 5.1 @ 菜单(showPastChats=false) |
| 295 | |
| 296 | ``` |
| 297 | ┌─────────────────────────────────────────────────────────────┐ |
| 298 | │ @ ← 用户输入 │ |
| 299 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 300 | │ │ 💬 past:chats 引用历史会话 │ │ |
| 301 | │ ├─────────────────────────────────────────────────────┤ │ |
| 302 | │ │ 📁 src/ │ │ |
| 303 | │ │ 📁 docs/ │ │ |
| 304 | │ │ 📄 README.md │ │ |
| 305 | │ └─────────────────────────────────────────────────────┘ │ |
| 306 | │ │ |
| 307 | │ [输入消息...] [发送] │ |
| 308 | └─────────────────────────────────────────────────────────────┘ |
| 309 | ``` |
| 310 | |
| 311 | ### 5.2 会话列表(showPastChats=true) |
| 312 | |
| 313 | ``` |
| 314 | ┌─────────────────────────────────────────────────────────────┐ |
| 315 | │ @past:chats ← 用户输入 │ |
| 316 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 317 | │ │ 💬 项目架构设计讨论 - 2026-06-04 │ │ |
| 318 | │ │ 💬 数据处理方案 - 2026-06-03 │ │ |
| 319 | │ │ 💬 API 接口设计 - 2026-06-02 │ │ |
| 320 | │ │ ← 返回文件列表 │ │ |
| 321 | │ └─────────────────────────────────────────────────────┘ │ |
| 322 | │ │ |
| 323 | │ [输入消息...] [发送] │ |
| 324 | └─────────────────────────────────────────────────────────────┘ |
| 325 | ``` |
| 326 | |
| 327 | ### 5.3 引用区域 |
| 328 | |
| 329 | ``` |
| 330 | ┌─────────────────────────────────────────────────────────────┐ |
| 331 | │ 📎 引用的会话: │ |
| 332 | │ ┌─────────────────────────────────────────────────────┐ │ |
| 333 | │ │ 📄 项目架构设计讨论 (8 轮) [×] │ │ |
| 334 | │ └─────────────────────────────────────────────────────┘ │ |
| 335 | ├─────────────────────────────────────────────────────────────┤ |
| 336 | │ │ |
| 337 | │ [输入消息...] [发送] │ |
| 338 | └─────────────────────────────────────────────────────────────┘ |
| 339 | ``` |
| 340 | |
| 341 | --- |
| 342 | |
| 343 | ## 6. P1 后续优化(暂不实施) |
| 344 | |
| 345 | - 选择单条/多条消息 |
| 346 | - hover 预览会话详情 |
| 347 | - 截断/缓存优化 |
| 348 | - 国际化翻译 |
| 349 | - 搜索会话功能 |
| 350 | |
| 351 | --- |
| 352 | |
| 353 | ## 7. 验收标准 |
| 354 | |
| 355 | ### P0 验收 |
| 356 | |
| 357 | - [ ] 输入 `@` 显示菜单,包含 "past:chats" 选项 |
| 358 | - [ ] 选择 "past:chats" 显示历史会话列表 |
| 359 | - [ ] 选择会话后显示在引用区域 |
| 360 | - [ ] 可以删除引用的会话 |
| 361 | - [ ] 发送时正确附加会话上下文 |
| 362 | - [ ] 引用内容限制在 30 条消息或 20k 字符内 |
| 363 | - [ ] 超出部分截断并提示 |
| 364 | |
| 365 | ### 测试用例 |
| 366 | |
| 367 | - [ ] 无历史会话时的行为 |
| 368 | - [ ] 引用超大会话时的截断 |
| 369 | - [ ] 与现有 @ 文件引用同时使用 |
| 370 | - [ ] 在不同主题下的显示效果 |
| 371 |