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
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* 会话存储管理
|
||||
* 负责会话的 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(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user