Files
ai-terminal-assistant/packages/core/src/session/session-store.ts
T
kurihada 66ad1a1ec9 refactor(core): 拆分大型单体文件为模块化子组件
将三个超过 700 行的大型文件重构为模块化架构:

Agent (1033 → ~400 行):
- agent-tool-executor: 工具获取、过滤和执行
- agent-message-handler: 消息构建、流式处理
- agent-mode-manager: 模式切换和权限检查
- agent-vision-handler: 视觉处理委托

CheckpointManager (1015 → ~620 行):
- checkpoint-store: 检查点 CRUD 操作
- checkpoint-rollback: 回滚和撤销操作
- checkpoint-session: 会话跟踪
- checkpoint-events: 事件发射系统

SessionManager (768 → 356 行):
- message-converter: Part ↔ ModelMessage 转换
- session-store: 会话 CRUD 操作
- project-manager: 项目管理
- session-auto-save: 自动保存功能

重构原则: 单一职责、编排器模式、向后兼容 API
2025-12-16 22:07:13 +08:00

237 lines
5.9 KiB
TypeScript

/**
* 会话存储管理
* 负责会话的 CRUD 操作
*/
import type { ModelMessage } from 'ai';
import { SessionStorage, MessageStorage, PartStorage, TodoStorage } from './storage/index.js';
import type { SessionInfo, TodoItem } from './storage/index.js';
import { MessageConverter } from './message-converter.js';
import { generateSessionId } from './id.js';
/**
* 会话摘要(用于列表展示)
*/
export interface SessionSummary {
id: string;
title: string;
workdir: string;
messageCount: number;
createdAt: string;
updatedAt: string;
}
/**
* 运行时会话数据
*/
export interface SessionData {
id: string;
projectId: string;
parentId?: string;
agentName?: string;
createdAt: string;
updatedAt: string;
workdir: string;
title?: string;
messages: ModelMessage[];
discoveredTools: string[];
todos: TodoItem[];
}
/**
* 会话存储管理
*/
export class SessionStore {
private messageConverter: MessageConverter;
constructor() {
this.messageConverter = new MessageConverter();
}
/**
* 创建新会话
*/
async create(projectId: string, workdir: string): Promise<SessionData> {
const sessionInfo = await SessionStorage.create(projectId, workdir);
return {
id: sessionInfo.id,
projectId: sessionInfo.projectId,
createdAt: new Date(sessionInfo.createdAt).toISOString(),
updatedAt: new Date(sessionInfo.updatedAt).toISOString(),
workdir: sessionInfo.workdir,
title: sessionInfo.title,
messages: [],
discoveredTools: sessionInfo.discoveredTools,
todos: [],
};
}
/**
* 加载会话(从存储重建)
*/
async load(projectId: string, sessionId: string): Promise<SessionData | null> {
const sessionInfo = await SessionStorage.get(projectId, sessionId);
if (!sessionInfo) return null;
// 加载消息
const messages = await this.messageConverter.loadFromStorage(sessionId);
// 加载 todos
const todoList = await TodoStorage.get(sessionId);
return {
id: sessionInfo.id,
projectId: sessionInfo.projectId,
parentId: sessionInfo.parentId,
agentName: sessionInfo.agentName,
createdAt: new Date(sessionInfo.createdAt).toISOString(),
updatedAt: new Date(sessionInfo.updatedAt).toISOString(),
workdir: sessionInfo.workdir,
title: sessionInfo.title,
messages,
discoveredTools: sessionInfo.discoveredTools,
todos: todoList?.items || [],
};
}
/**
* 保存会话信息
*/
async save(session: SessionData): Promise<void> {
const sessionInfo: SessionInfo = {
id: session.id,
projectId: session.projectId,
parentId: session.parentId,
agentName: session.agentName,
createdAt: new Date(session.createdAt).getTime(),
updatedAt: Date.now(),
workdir: session.workdir,
title: session.title,
discoveredTools: session.discoveredTools,
stats: {
messageCount: session.messages.length,
inputTokens: 0,
outputTokens: 0,
},
};
await SessionStorage.save(sessionInfo);
}
/**
* 同步消息到存储
*/
async syncMessages(sessionId: string, messages: ModelMessage[]): Promise<void> {
await this.messageConverter.syncToStorage(sessionId, messages);
}
/**
* 更新待办事项
*/
async setTodos(
sessionId: string,
todos: Array<{ content: string; status: 'pending' | 'in_progress' | 'completed' }>
): Promise<TodoItem[]> {
const todoList = await TodoStorage.replace(sessionId, todos);
return todoList.items;
}
/**
* 列出项目的所有会话
*/
async listByProject(projectId: string): Promise<SessionSummary[]> {
const sessions = await SessionStorage.listByProject(projectId);
return this.toSummaries(sessions);
}
/**
* 列出所有会话
*/
async listAll(): Promise<SessionSummary[]> {
const sessions = await SessionStorage.listAll();
return this.toSummaries(sessions);
}
/**
* 删除会话
*/
async delete(projectId: string, sessionId: string): Promise<boolean> {
try {
// 删除会话的消息和 Parts
const messageInfos = await MessageStorage.listBySession(sessionId);
for (const msg of messageInfos) {
await PartStorage.removeByMessage(msg.id);
}
await MessageStorage.removeBySession(sessionId);
// 删除 todos
await TodoStorage.removeBySession(sessionId);
// 删除会话信息
await SessionStorage.remove(projectId, sessionId);
return true;
} catch {
return false;
}
}
/**
* 创建子会话(用于 Task 工具)
*/
createChildSession(
projectId: string,
parentId: string,
agentName: string,
workdir: string,
title?: string
): SessionData {
return {
id: generateSessionId(),
projectId,
parentId,
agentName,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
workdir,
title: title || `子任务 (@${agentName})`,
messages: [],
discoveredTools: [],
todos: [],
};
}
/**
* 保存子会话
*/
async saveChildSession(session: SessionData): Promise<void> {
const sessionInfo: SessionInfo = {
id: session.id,
projectId: session.projectId,
parentId: session.parentId,
agentName: session.agentName,
createdAt: new Date(session.createdAt).getTime(),
updatedAt: Date.now(),
workdir: session.workdir,
title: session.title,
discoveredTools: session.discoveredTools,
};
await SessionStorage.save(sessionInfo);
}
/**
* 转换为摘要列表
*/
private toSummaries(sessions: SessionInfo[]): SessionSummary[] {
return sessions.map((s) => ({
id: s.id,
title: s.title || `会话 ${s.id}`,
workdir: s.workdir,
messageCount: s.stats?.messageCount || 0,
createdAt: new Date(s.createdAt).toISOString(),
updatedAt: new Date(s.updatedAt).toISOString(),
}));
}
}