# 会话管理功能实现计划 ## 需求概述 实现一个会话管理功能store,为每个会话保存一个memory,在本地持久化保存。支持新建会话和切换到历史会话。 ## 现有代码分析 1. **Store结构** (`src/stores/`):使用Pinia + pinia-plugin-persistedstate进行持久化 - `index.ts`:配置持久化插件 - `modules/counter.ts`、`user.ts`、`routeCache.ts`:示例store 2. **类型定义** (`src/types/chat.ts`):已有`ChatMessage`接口 3. **API定义** (`src/api/agent/index.ts`):`StreamApiParams`包含`memory`对象(`thread`和`resource`字段) 4. **聊天页面** (`src/pages/llm-chat/index.vue`):当前单会话实现,未使用memory参数 ## 用户需求确认 - **UI交互**:下拉菜单切换会话 - **数据结构**:扩展会话结构(包含消息列表、memory对象等) - **页面集成**:组合式组件 - **memory管理**:前端管理(生成thread/resource) - **标题生成**:自动生成(从第一条消息内容) ## 待解决的问题 1. memory中`thread`和`resource`字段的具体生成规则? 2. 会话标题自动生成的详细规则(截取字数、处理空消息等)? 3. 是否需要会话删除、重命名功能? 4. 持久化数据迁移和版本兼容性考虑? ## 详细设计 ### 1. 类型定义 创建 `src/types/session.ts` 定义以下接口: ```typescript export interface SessionMemory { thread: string; // 会话线程ID,前端生成(如UUID或会话ID) resource: string; // 资源标识,前端生成(如固定值或动态标识) } export interface ChatSession { id: string; // 会话唯一标识(UUID) title: string; // 会话标题(自动生成) createdAt: Date; // 创建时间 updatedAt: Date; // 最后更新时间 messages: ChatMessage[]; // 消息列表(引用现有ChatMessage类型) memory: SessionMemory; // 会话memory } // 扩展现有ChatMessage类型(可选),添加sessionId字段 // 或者在store中通过关联关系管理 ``` ### 2. 会话管理Store 创建 `src/stores/modules/chatSession.ts`: ```typescript import { defineStore } from 'pinia' import type { ChatSession, SessionMemory } from '@/types/session' import type { ChatMessage } from '@/types/chat' interface ChatSessionState { sessions: ChatSession[] // 所有会话 currentSessionId: string | null // 当前会话ID } // 生成唯一ID和memory的辅助函数 const generateId = () => crypto.randomUUID() const generateMemory = (sessionId: string): SessionMemory => ({ thread: sessionId, resource: 'webagent_chat' // 固定资源标识,可根据需要调整 }) const generateTitle = (firstMessage: string): string => { const maxLength = 20 return firstMessage.length > maxLength ? firstMessage.substring(0, maxLength) + '...' : firstMessage } export const useChatSessionStore = defineStore('chatSession', () => { const state = reactive({ sessions: [], currentSessionId: null }) // 获取当前会话 const currentSession = computed(() => state.sessions.find(s => s.id === state.currentSessionId) ) // 创建新会话 const createSession = (initialMessage?: string) => { const sessionId = generateId() const now = new Date() const session: ChatSession = { id: sessionId, title: initialMessage ? generateTitle(initialMessage) : '新会话', createdAt: now, updatedAt: now, messages: [], memory: generateMemory(sessionId) } state.sessions.push(session) state.currentSessionId = sessionId return session } // 切换到指定会话 const switchSession = (sessionId: string) => { const session = state.sessions.find(s => s.id === sessionId) if (session) { state.currentSessionId = sessionId } } // 更新会话(添加消息、更新标题等) const updateSession = (sessionId: string, updates: Partial) => { const index = state.sessions.findIndex(s => s.id === sessionId) if (index !== -1) { state.sessions[index] = { ...state.sessions[index], ...updates, updatedAt: new Date() } } } // 添加消息到当前会话 const addMessageToCurrentSession = (message: ChatMessage) => { const session = currentSession.value if (session) { const messages = [...session.messages, message] updateSession(session.id, { messages }) // 如果是第一条消息且标题为默认值,自动生成标题 if (messages.length === 1 && session.title === '新会话') { const title = generateTitle(message.content) updateSession(session.id, { title }) } } } // 删除会话 const deleteSession = (sessionId: string) => { state.sessions = state.sessions.filter(s => s.id !== sessionId) if (state.currentSessionId === sessionId) { state.currentSessionId = state.sessions[0]?.id || null } } return { // 状态 sessions: computed(() => state.sessions), currentSessionId: computed(() => state.currentSessionId), currentSession, // 方法 createSession, switchSession, updateSession, addMessageToCurrentSession, deleteSession } }, { persist: true // 启用持久化 }) ``` ### 3. 组合式组件 创建 `src/composables/useSessionManager.ts`: ```typescript import { useChatSessionStore } from '@/stores/modules/chatSession' import type { ChatMessage } from '@/types/chat' export function useSessionManager() { const sessionStore = useChatSessionStore() // 初始化:如果没有会话,创建一个默认会话 const initialize = () => { if (sessionStore.sessions.length === 0) { sessionStore.createSession() } } // 获取当前会话的memory(用于API调用) const getCurrentSessionMemory = () => { return sessionStore.currentSession?.memory } // 处理新消息:添加到当前会话,返回更新后的memory const handleNewMessage = (message: ChatMessage) => { sessionStore.addMessageToCurrentSession(message) return getCurrentSessionMemory() } // 新建会话(带可选初始消息) const newSession = (initialMessage?: string) => { return sessionStore.createSession(initialMessage) } return { // 状态 sessions: sessionStore.sessions, currentSession: sessionStore.currentSession, currentSessionId: sessionStore.currentSessionId, // 方法 initialize, getCurrentSessionMemory, handleNewMessage, newSession, switchSession: sessionStore.switchSession, deleteSession: sessionStore.deleteSession } } ``` ### 4. UI组件 - 下拉菜单切换器 创建 `src/components/SessionSelector.vue`: ```vue ``` ### 5. 修改现有llm-chat页面 更新 `src/pages/llm-chat/index.vue`: 主要修改: 1. 在页面顶部添加SessionSelector组件 2. 初始化会话管理器 3. 修改handleSend函数以使用会话memory 4. 消息存储从本地数组改为会话store 关键修改点: ```typescript // 在script setup顶部引入 import { useSessionManager } from '@/composables/useSessionManager' import SessionSelector from '@/components/SessionSelector.vue' // 替换现有的messages状态 const sessionManager = useSessionManager() const messages = computed(() => sessionManager.currentSession?.messages || []) // 修改handleSend函数 function handleSend(text: string) { if (!text.trim()) return // 添加用户消息到会话 const userMessage: ChatMessage = { id: Date.now(), content: text, sender: 'user', timestamp: new Date(), status: 'sent' } const memory = sessionManager.handleNewMessage(userMessage) // 创建AI消息占位符 const aiMessage: ChatMessage = { id: Date.now() + 1, content: '', sender: 'ai', timestamp: new Date(), status: 'sending' } sessionManager.handleNewMessage(aiMessage) // 调用streamApi,传递memory参数 streamApi( { message: text, options: { memory // 传递当前会话的memory } }, // ... 其他回调保持不变 ) } // 在模板中添加SessionSelector ``` ### 6. API调用调整 修改 `src/api/agent/index.ts` 中的streamApi调用: - 确保memory参数正确传递 - 如果memory为undefined,不传递options或传递空对象 ### 7. 持久化考虑 - 使用现有的pinia-plugin-persistedstate机制 - 会话数据会随store自动持久化到localStorage - 注意:大量消息可能导致localStorage超出限制,未来可考虑分页或清理旧消息 ## 实施步骤(详细) 1. **创建类型定义** (`src/types/session.ts`) - 定义SessionMemory和ChatSession接口 2. **实现会话store** (`src/stores/modules/chatSession.ts`) - 基于现有store模式 - 包含完整的CRUD操作 3. **实现组合式组件** (`src/composables/useSessionManager.ts`) - 提供高层API给UI组件使用 4. **实现UI组件** (`src/components/SessionSelector.vue`) - 下拉菜单切换器 - 新建会话按钮 5. **集成到现有页面** (`src/pages/llm-chat/index.vue`) - 引入SessionSelector组件 - 修改消息处理逻辑 - 初始化会话管理器 6. **测试验证** - 新建会话功能 - 切换历史会话 - memory数据持久化 - 标题自动生成 7. **优化和调整** - 根据实际使用反馈调整UI - 考虑性能优化(大量消息处理) ## 注意事项 1. **数据迁移**:现有单会话用户的平滑迁移 2. **性能**:大量消息时的存储和渲染性能 3. **用户体验**:会话切换的流畅性 4. **错误处理**:网络错误、存储失败等情况 5. **浏览器兼容性**:localStorage和UUID生成