fix(server): 修复消息持久化问题
- 在 adapter.ts 中为 Agent 绑定 Core SessionManager - 添加 getOrCreateSessionManager 函数创建和恢复会话 - 修改 getOrCreateAgent 为异步函数 - 在 sessions.ts 中转换 AI SDK 消息格式为字符串
This commit is contained in:
@@ -47,11 +47,32 @@ interface ChatResult {
|
||||
messages: unknown[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Session Manager 接口(Core 的 SessionManager)
|
||||
*/
|
||||
interface SessionManagerInstance {
|
||||
init(workdir: string): Promise<unknown>;
|
||||
getSession(): { id: string; messages: unknown[] } | null;
|
||||
setMessages(messages: unknown[]): Promise<void>;
|
||||
setDiscoveredTools(tools: string[]): Promise<void>;
|
||||
save(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
restoreSession(sessionId: string): Promise<unknown | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Session Manager 构造函数接口
|
||||
*/
|
||||
interface SessionManagerConstructor {
|
||||
new (): SessionManagerInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Agent 实例接口
|
||||
*/
|
||||
interface AgentInstance {
|
||||
setRegistry(registry: unknown): void;
|
||||
setSessionManager(manager: SessionManagerInstance): void;
|
||||
chat(message: string, onStream?: (chunk: string) => void): Promise<ChatResult>;
|
||||
getToolCount(): { core: number; discovered: number; total: number };
|
||||
getContextUsageFormatted(): string;
|
||||
@@ -106,6 +127,7 @@ interface AgentRegistryInterface {
|
||||
*/
|
||||
interface CoreModule {
|
||||
Agent: AgentConstructor;
|
||||
SessionManager: SessionManagerConstructor;
|
||||
toolRegistry: ToolRegistry;
|
||||
loadConfig: () => unknown;
|
||||
saveConfig: (config: Record<string, unknown>) => void;
|
||||
@@ -124,6 +146,9 @@ let coreModule: CoreModule | null = null;
|
||||
// Agent 实例缓存(每个 session 一个)
|
||||
const agentCache: Map<string, AgentInstance> = new Map();
|
||||
|
||||
// SessionManager 实例缓存(每个 session 一个)
|
||||
const sessionManagerCache: Map<string, SessionManagerInstance> = new Map();
|
||||
|
||||
// 配置错误缓存(用于向客户端返回友好错误)
|
||||
let lastConfigError: { provider: string; message: string } | null = null;
|
||||
|
||||
@@ -182,7 +207,7 @@ export function isCoreAvailable(): boolean {
|
||||
*
|
||||
* @returns Agent 实例,或 null(Core 不可用或配置错误)
|
||||
*/
|
||||
export function getOrCreateAgent(sessionId: string): AgentInstance | null {
|
||||
export async function getOrCreateAgent(sessionId: string): Promise<AgentInstance | null> {
|
||||
// 清除之前的配置错误
|
||||
lastConfigError = null;
|
||||
|
||||
@@ -205,6 +230,12 @@ export function getOrCreateAgent(sessionId: string): AgentInstance | null {
|
||||
const permissionManager = coreModule.getPermissionManager();
|
||||
permissionManager.setAskCallback(createServerPermissionCallback(sessionId));
|
||||
|
||||
// 创建并初始化 SessionManager(用于消息持久化)
|
||||
const sessionMgr = await getOrCreateSessionManager(sessionId);
|
||||
if (sessionMgr) {
|
||||
agent.setSessionManager(sessionMgr);
|
||||
}
|
||||
|
||||
agentCache.set(sessionId, agent);
|
||||
return agent;
|
||||
} catch (error) {
|
||||
@@ -223,10 +254,56 @@ export function getOrCreateAgent(sessionId: string): AgentInstance | null {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建 SessionManager 实例
|
||||
*/
|
||||
async function getOrCreateSessionManager(sessionId: string): Promise<SessionManagerInstance | null> {
|
||||
if (!coreModule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查缓存
|
||||
if (sessionManagerCache.has(sessionId)) {
|
||||
return sessionManagerCache.get(sessionId)!;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取 session 的工作目录
|
||||
const serverSessionManager = getSessionManager();
|
||||
const session = serverSessionManager.get(sessionId);
|
||||
const workdir = session?.workdir || process.cwd();
|
||||
|
||||
// 创建新的 Core SessionManager
|
||||
const sessionMgr = new coreModule.SessionManager();
|
||||
|
||||
// 初始化(这会创建或加载项目)
|
||||
await sessionMgr.init(workdir);
|
||||
|
||||
// 尝试恢复指定的 session(如果存在)
|
||||
const restored = await sessionMgr.restoreSession(sessionId);
|
||||
if (restored) {
|
||||
console.log(`[Agent] Restored session ${sessionId} with ${(restored as { messages: unknown[] }).messages?.length || 0} messages`);
|
||||
}
|
||||
|
||||
sessionManagerCache.set(sessionId, sessionMgr);
|
||||
return sessionMgr;
|
||||
} catch (error) {
|
||||
console.error(`[Agent] Failed to create SessionManager for ${sessionId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁 Agent 实例
|
||||
*/
|
||||
export function destroyAgent(sessionId: string): void {
|
||||
export async function destroyAgent(sessionId: string): Promise<void> {
|
||||
// 关闭并清理 SessionManager
|
||||
const sessionMgr = sessionManagerCache.get(sessionId);
|
||||
if (sessionMgr) {
|
||||
await sessionMgr.close();
|
||||
sessionManagerCache.delete(sessionId);
|
||||
}
|
||||
|
||||
agentCache.delete(sessionId);
|
||||
}
|
||||
|
||||
@@ -241,7 +318,7 @@ export async function processMessage(sessionId: string, content: string): Promis
|
||||
emitStatusEvent(sessionId, 'processing', { message: '正在处理...' });
|
||||
|
||||
// 获取 Agent
|
||||
const agent = getOrCreateAgent(sessionId);
|
||||
const agent = await getOrCreateAgent(sessionId);
|
||||
|
||||
if (!agent) {
|
||||
// 检查是否为配置错误
|
||||
|
||||
@@ -134,13 +134,30 @@ sessionsRouter.get('/:id/messages', async (c) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 为消息添加 ID(Core 的 ModelMessage 格式没有 id 字段)
|
||||
// 为消息添加 ID 并转换内容格式(AI SDK 格式 -> 字符串)
|
||||
const messagesWithId = sessionData.messages.map(
|
||||
(msg: { role: string; content: unknown }, index: number) => ({
|
||||
...msg,
|
||||
id: `${msg.role}-${id}-${index}`,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
(msg: { role: string; content: unknown }, index: number) => {
|
||||
// 转换 AI SDK 内容格式为字符串
|
||||
let content: string;
|
||||
if (typeof msg.content === 'string') {
|
||||
content = msg.content;
|
||||
} else if (Array.isArray(msg.content)) {
|
||||
// AI SDK 格式: [{type: "text", text: "..."}, ...]
|
||||
content = msg.content
|
||||
.filter((block: { type?: string }) => block.type === 'text')
|
||||
.map((block: { text?: string }) => block.text || '')
|
||||
.join('');
|
||||
} else {
|
||||
content = String(msg.content);
|
||||
}
|
||||
|
||||
return {
|
||||
id: `${msg.role}-${id}-${index}`,
|
||||
role: msg.role,
|
||||
content,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
return c.json({
|
||||
|
||||
Reference in New Issue
Block a user