refactor(storage): 统一消息存储到 Core 层

问题:Server 端只存储最终文本响应,工具调用的中间消息丢失。

解决方案:
- Agent.chat() 返回 ChatResult,包含完整消息链
- Server SessionManager 简化为只管理会话元数据
- 消息 API 改为从 Core Storage 读取
- 移除 Server 端的消息存储和 addMessage 方法

影响范围:
- core: Agent.chat() 返回类型变更
- server: SessionManager 接口变更,移除消息存储
- server: GET /sessions/:id/messages 从 Core 读取
- server: 移除 POST /sessions/:id/messages 端点
This commit is contained in:
2025-12-15 10:04:22 +08:00
parent a657af9bb7
commit 6342a46e59
14 changed files with 273 additions and 503 deletions
+22 -30
View File
@@ -2,6 +2,8 @@
* SessionManager Mock 工厂
*
* 提供会话管理器的 mock 实现
*
* 注意:消息存储已移至 Core 层,SessionManager 只负责会话元数据管理
*/
import { vi } from 'vitest';
@@ -13,6 +15,7 @@ export interface MockSession {
createdAt: number;
updatedAt: number;
workdir?: string;
messageCount: number;
}
export interface MockMessage {
@@ -27,8 +30,6 @@ export interface MockMessage {
*/
export function createMockSessionManager() {
const sessions = new Map<string, MockSession>();
const messages = new Map<string, MockMessage[]>();
let messageIdCounter = 1;
const manager = {
// 初始化
@@ -48,44 +49,40 @@ export function createMockSessionManager() {
createdAt: Date.now(),
updatedAt: Date.now(),
workdir: data?.workdir ?? process.cwd(),
messageCount: 0,
};
sessions.set(id, session);
messages.set(id, []);
return session;
}),
delete: vi.fn(async (id: string) => {
const existed = sessions.has(id);
sessions.delete(id);
messages.delete(id);
return existed;
}),
list: vi.fn(() => Array.from(sessions.values())),
// 消息管理
addMessage: vi.fn(async (sessionId: string, msg: { role: 'user' | 'assistant'; content: string }) => {
const msgList = messages.get(sessionId) || [];
const newMsg: MockMessage = {
id: `msg-${messageIdCounter++}`,
role: msg.role,
content: msg.content,
timestamp: Date.now(),
};
msgList.push(newMsg);
messages.set(sessionId, msgList);
return newMsg;
}),
getMessages: vi.fn((id: string) => messages.get(id) || []),
// 状态更新
updateStatus: vi.fn((id: string, status: 'idle' | 'busy') => {
const session = sessions.get(id);
if (session) {
session.status = status;
session.updatedAt = Date.now();
return session;
}
return undefined;
}),
// 更新消息计数
updateMessageCount: vi.fn((id: string, count: number) => {
const session = sessions.get(id);
if (session) {
session.messageCount = count;
session.updatedAt = Date.now();
return session;
}
return undefined;
}),
updateSessionName: vi.fn(async (id: string, name: string) => {
@@ -98,26 +95,20 @@ export function createMockSessionManager() {
return null;
}),
// Storage 访问
getStorage: vi.fn(() => null),
getProjectId: vi.fn((_sessionId: string) => 'default-project'),
// 测试辅助方法
_addSession: (session: MockSession) => {
sessions.set(session.id, session);
messages.set(session.id, []);
},
_addMessage: (sessionId: string, message: MockMessage) => {
const msgList = messages.get(sessionId) || [];
msgList.push(message);
messages.set(sessionId, msgList);
},
_clear: () => {
sessions.clear();
messages.clear();
messageIdCounter = 1;
},
_getSessions: () => sessions,
_getMessages: () => messages,
};
return manager;
@@ -134,6 +125,7 @@ export function createTestSession(overrides: Partial<MockSession> = {}): MockSes
createdAt: Date.now(),
updatedAt: Date.now(),
workdir: '/test/workdir',
messageCount: 0,
...overrides,
};
}