From b8fcb65f7369427b30043f4a0e074a6c8b57aea0 Mon Sep 17 00:00:00 2001 From: kurihada Date: Mon, 15 Dec 2025 10:45:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(server):=20=E4=BF=AE=E5=A4=8D=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=8C=81=E4=B9=85=E5=8C=96=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 adapter.ts 中为 Agent 绑定 Core SessionManager - 添加 getOrCreateSessionManager 函数创建和恢复会话 - 修改 getOrCreateAgent 为异步函数 - 在 sessions.ts 中转换 AI SDK 消息格式为字符串 --- packages/server/src/agent/adapter.ts | 83 +++++++++++++++++++++++++- packages/server/src/routes/sessions.ts | 29 +++++++-- 2 files changed, 103 insertions(+), 9 deletions(-) diff --git a/packages/server/src/agent/adapter.ts b/packages/server/src/agent/adapter.ts index bf2f090..0b79940 100644 --- a/packages/server/src/agent/adapter.ts +++ b/packages/server/src/agent/adapter.ts @@ -47,11 +47,32 @@ interface ChatResult { messages: unknown[]; } +/** + * Session Manager 接口(Core 的 SessionManager) + */ +interface SessionManagerInstance { + init(workdir: string): Promise; + getSession(): { id: string; messages: unknown[] } | null; + setMessages(messages: unknown[]): Promise; + setDiscoveredTools(tools: string[]): Promise; + save(): Promise; + close(): Promise; + restoreSession(sessionId: string): Promise; +} + +/** + * 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; 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) => void; @@ -124,6 +146,9 @@ let coreModule: CoreModule | null = null; // Agent 实例缓存(每个 session 一个) const agentCache: Map = new Map(); +// SessionManager 实例缓存(每个 session 一个) +const sessionManagerCache: Map = 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 { // 清除之前的配置错误 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 { + 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 { + // 关闭并清理 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) { // 检查是否为配置错误 diff --git a/packages/server/src/routes/sessions.ts b/packages/server/src/routes/sessions.ts index 37ffda4..b74cb37 100644 --- a/packages/server/src/routes/sessions.ts +++ b/packages/server/src/routes/sessions.ts @@ -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({