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[];
|
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 实例接口
|
* Agent 实例接口
|
||||||
*/
|
*/
|
||||||
interface AgentInstance {
|
interface AgentInstance {
|
||||||
setRegistry(registry: unknown): void;
|
setRegistry(registry: unknown): void;
|
||||||
|
setSessionManager(manager: SessionManagerInstance): void;
|
||||||
chat(message: string, onStream?: (chunk: string) => void): Promise<ChatResult>;
|
chat(message: string, onStream?: (chunk: string) => void): Promise<ChatResult>;
|
||||||
getToolCount(): { core: number; discovered: number; total: number };
|
getToolCount(): { core: number; discovered: number; total: number };
|
||||||
getContextUsageFormatted(): string;
|
getContextUsageFormatted(): string;
|
||||||
@@ -106,6 +127,7 @@ interface AgentRegistryInterface {
|
|||||||
*/
|
*/
|
||||||
interface CoreModule {
|
interface CoreModule {
|
||||||
Agent: AgentConstructor;
|
Agent: AgentConstructor;
|
||||||
|
SessionManager: SessionManagerConstructor;
|
||||||
toolRegistry: ToolRegistry;
|
toolRegistry: ToolRegistry;
|
||||||
loadConfig: () => unknown;
|
loadConfig: () => unknown;
|
||||||
saveConfig: (config: Record<string, unknown>) => void;
|
saveConfig: (config: Record<string, unknown>) => void;
|
||||||
@@ -124,6 +146,9 @@ let coreModule: CoreModule | null = null;
|
|||||||
// Agent 实例缓存(每个 session 一个)
|
// Agent 实例缓存(每个 session 一个)
|
||||||
const agentCache: Map<string, AgentInstance> = new Map();
|
const agentCache: Map<string, AgentInstance> = new Map();
|
||||||
|
|
||||||
|
// SessionManager 实例缓存(每个 session 一个)
|
||||||
|
const sessionManagerCache: Map<string, SessionManagerInstance> = new Map();
|
||||||
|
|
||||||
// 配置错误缓存(用于向客户端返回友好错误)
|
// 配置错误缓存(用于向客户端返回友好错误)
|
||||||
let lastConfigError: { provider: string; message: string } | null = null;
|
let lastConfigError: { provider: string; message: string } | null = null;
|
||||||
|
|
||||||
@@ -182,7 +207,7 @@ export function isCoreAvailable(): boolean {
|
|||||||
*
|
*
|
||||||
* @returns Agent 实例,或 null(Core 不可用或配置错误)
|
* @returns Agent 实例,或 null(Core 不可用或配置错误)
|
||||||
*/
|
*/
|
||||||
export function getOrCreateAgent(sessionId: string): AgentInstance | null {
|
export async function getOrCreateAgent(sessionId: string): Promise<AgentInstance | null> {
|
||||||
// 清除之前的配置错误
|
// 清除之前的配置错误
|
||||||
lastConfigError = null;
|
lastConfigError = null;
|
||||||
|
|
||||||
@@ -205,6 +230,12 @@ export function getOrCreateAgent(sessionId: string): AgentInstance | null {
|
|||||||
const permissionManager = coreModule.getPermissionManager();
|
const permissionManager = coreModule.getPermissionManager();
|
||||||
permissionManager.setAskCallback(createServerPermissionCallback(sessionId));
|
permissionManager.setAskCallback(createServerPermissionCallback(sessionId));
|
||||||
|
|
||||||
|
// 创建并初始化 SessionManager(用于消息持久化)
|
||||||
|
const sessionMgr = await getOrCreateSessionManager(sessionId);
|
||||||
|
if (sessionMgr) {
|
||||||
|
agent.setSessionManager(sessionMgr);
|
||||||
|
}
|
||||||
|
|
||||||
agentCache.set(sessionId, agent);
|
agentCache.set(sessionId, agent);
|
||||||
return agent;
|
return agent;
|
||||||
} catch (error) {
|
} 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 实例
|
* 销毁 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);
|
agentCache.delete(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +318,7 @@ export async function processMessage(sessionId: string, content: string): Promis
|
|||||||
emitStatusEvent(sessionId, 'processing', { message: '正在处理...' });
|
emitStatusEvent(sessionId, 'processing', { message: '正在处理...' });
|
||||||
|
|
||||||
// 获取 Agent
|
// 获取 Agent
|
||||||
const agent = getOrCreateAgent(sessionId);
|
const agent = await getOrCreateAgent(sessionId);
|
||||||
|
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
// 检查是否为配置错误
|
// 检查是否为配置错误
|
||||||
|
|||||||
@@ -134,13 +134,30 @@ sessionsRouter.get('/:id/messages', async (c) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为消息添加 ID(Core 的 ModelMessage 格式没有 id 字段)
|
// 为消息添加 ID 并转换内容格式(AI SDK 格式 -> 字符串)
|
||||||
const messagesWithId = sessionData.messages.map(
|
const messagesWithId = sessionData.messages.map(
|
||||||
(msg: { role: string; content: unknown }, index: number) => ({
|
(msg: { role: string; content: unknown }, index: number) => {
|
||||||
...msg,
|
// 转换 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}`,
|
id: `${msg.role}-${id}-${index}`,
|
||||||
|
role: msg.role,
|
||||||
|
content,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
})
|
};
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
|
|||||||
Reference in New Issue
Block a user