/** * 会话管理器 * 作为编排器,委托具体工作给各个子模块 */ import type { ModelMessage } from 'ai'; import * as storage from './storage/index.js'; import type { TodoItem } from './storage/index.js'; // 子模块 import { SessionStore, type SessionData, type SessionSummary } from './session-store.js'; import { ProjectManager, type ProjectMetadata } from './project-manager.js'; import { SessionAutoSave } from './session-auto-save.js'; // 重新导出类型 export type { SessionData, SessionSummary, ProjectMetadata }; /** * 会话管理器 * 提供高级会话操作接口,使用新的三层存储结构 */ export class SessionManager { private currentSession: SessionData | null = null; private storageDir?: string; // 子模块 private store: SessionStore; private projectManager: ProjectManager; private autoSave: SessionAutoSave; constructor(storageDir?: string) { this.storageDir = storageDir; this.store = new SessionStore(); this.projectManager = new ProjectManager(); this.autoSave = new SessionAutoSave(); } // ============================================================================ // 初始化 // ============================================================================ /** * 初始化 - 尝试恢复或创建新会话 */ async init(workdir: string): Promise { // 初始化存储 await storage.initStorage(this.storageDir); // 获取或创建项目 await this.projectManager.getOrCreate(workdir); // 尝试加载当前会话 const currentSessionId = await this.getCurrentSessionId(); if (currentSessionId) { const projectId = this.projectManager.getProjectId()!; const existing = await this.store.load(projectId, currentSessionId); if (existing && existing.workdir === workdir) { this.currentSession = existing; this.startAutoSave(); return this.currentSession; } } // 创建新会话 const projectId = this.projectManager.getProjectId()!; this.currentSession = await this.store.create(projectId, workdir); await this.store.save(this.currentSession); await this.setCurrentSessionPointer(this.currentSession.id); this.startAutoSave(); return this.currentSession; } // ============================================================================ // 会话获取 // ============================================================================ /** * 获取当前会话 */ getSession(): SessionData | null { return this.currentSession; } /** * 获取当前项目 */ getProject(): ProjectMetadata | null { return this.projectManager.getProject(); } /** * 获取当前会话 ID */ getSessionId(): string | undefined { return this.currentSession?.id; } // ============================================================================ // 会话操作 // ============================================================================ /** * 保存当前会话 */ async save(): Promise { if (!this.currentSession) return; await this.store.save(this.currentSession); } /** * 清空当前会话并创建新会话 */ async newSession(workdir?: string): Promise { if (!this.projectManager.isInitialized()) { throw new Error('Project not initialized. Call init() first.'); } const newWorkdir = workdir || this.currentSession?.workdir || process.cwd(); // 如果工作目录变化,需要切换项目 if (workdir && workdir !== this.projectManager.getProject()?.workdir) { await this.projectManager.switchProject(workdir); } const projectId = this.projectManager.getProjectId()!; this.currentSession = await this.store.create(projectId, newWorkdir); await this.store.save(this.currentSession); await this.setCurrentSessionPointer(this.currentSession.id); return this.currentSession; } /** * 恢复指定会话 */ async restoreSession(sessionId: string): Promise { if (!this.projectManager.isInitialized()) { throw new Error('Project not initialized. Call init() first.'); } const projectId = this.projectManager.getProjectId()!; const session = await this.store.load(projectId, sessionId); if (!session) return null; this.currentSession = session; await this.setCurrentSessionPointer(sessionId); return session; } /** * 列出当前项目的历史会话 */ async listSessions(): Promise { const projectId = this.projectManager.getProjectId(); if (!projectId) { return this.listAllSessions(); } return this.store.listByProject(projectId); } /** * 列出所有项目的会话 */ async listAllSessions(): Promise { return this.store.listAll(); } /** * 删除历史会话 */ async deleteSession(sessionId: string): Promise { const projectId = this.projectManager.getProjectId(); if (!projectId) return false; return this.store.delete(projectId, sessionId); } // ============================================================================ // 消息操作 // ============================================================================ /** * 批量设置消息(用于同步整个对话历史) */ async setMessages(messages: ModelMessage[]): Promise { if (!this.currentSession) return; this.currentSession.messages = messages; await this.store.syncMessages(this.currentSession.id, messages); await this.store.save(this.currentSession); } /** * 添加消息 */ async addMessage(message: ModelMessage): Promise { if (!this.currentSession) return; this.currentSession.messages.push(message); await this.setMessages(this.currentSession.messages); } /** * 获取对话历史 */ getMessages(): ModelMessage[] { return this.currentSession?.messages || []; } // ============================================================================ // 工具和待办操作 // ============================================================================ /** * 设置已发现的工具 */ async setDiscoveredTools(tools: string[]): Promise { if (!this.currentSession) return; this.currentSession.discoveredTools = tools; await this.store.save(this.currentSession); } /** * 获取已发现的工具 */ getDiscoveredTools(): string[] { return this.currentSession?.discoveredTools || []; } /** * 更新待办事项 */ async setTodos( todos: Array<{ content: string; status: 'pending' | 'in_progress' | 'completed' }> ): Promise { if (!this.currentSession) return; const items = await this.store.setTodos(this.currentSession.id, todos); this.currentSession.todos = items; } /** * 获取待办事项 */ getTodos(): TodoItem[] { return this.currentSession?.todos || []; } // ============================================================================ // 子会话操作 // ============================================================================ /** * 创建子会话(用于 Task 工具) */ createChildSession(parentId: string, agentName: string, title?: string): SessionData { if (!this.projectManager.isInitialized()) { throw new Error('Project not initialized. Call init() first.'); } const projectId = this.projectManager.getProjectId()!; const workdir = this.currentSession?.workdir || process.cwd(); return this.store.createChildSession(projectId, parentId, agentName, workdir, title); } /** * 保存子会话 */ async saveChildSession(session: SessionData): Promise { await this.store.saveChildSession(session); } // ============================================================================ // 自动保存 // ============================================================================ /** * 启动自动保存 */ private startAutoSave(): void { this.autoSave.start(() => this.save()); } /** * 停止自动保存 */ stopAutoSave(): void { this.autoSave.stop(); } /** * 关闭管理器(保存并停止自动保存) */ async close(): Promise { this.stopAutoSave(); await this.save(); } // ============================================================================ // 清理 // ============================================================================ /** * 清理旧会话 */ async cleanup(keepCount: number = 50): Promise { const sessions = await this.listAllSessions(); if (sessions.length <= keepCount) { return 0; } const toDelete = sessions.slice(keepCount); let deletedCount = 0; for (const session of toDelete) { if (await this.deleteSession(session.id)) { deletedCount++; } } return deletedCount; } // ============================================================================ // 辅助方法 // ============================================================================ /** * 获取当前会话 ID(从存储) */ private async getCurrentSessionId(): Promise { try { const pointer = await storage.read<{ sessionId: string }>(['current-session']); return pointer.sessionId; } catch { return null; } } /** * 设置当前会话指针 */ private async setCurrentSessionPointer(sessionId: string): Promise { await storage.write(['current-session'], { sessionId }); } /** * 获取存储目录 */ getStorageDir(): string { return this.storageDir || storage.getDefaultStorageDir(); } } // 导出默认实例 export const sessionManager = new SessionManager();