function assertRouter(api) { if ( !api || typeof api.get !== 'function' || typeof api.post !== 'function' || typeof api.delete !== 'function' ) { throw new Error( 'attachPortalUserMemoryRoutes requires an Express-compatible router', ); } } export function attachPortalUserMemoryRoutes( api, { getMemoryV2 = () => null, getTkmindProxy = () => null, ensureUserMemoryCapability = async () => null, ownsAgentSession = async () => false, loadUserVisibleConversation = async () => [], syncUserMemoriesIntoSession = async () => false, resolveUserMemoryItems = async () => [], } = {}, ) { assertRouter(api); api.post('/user-memory/v1/remember-recent', async (req, res) => { const memoryV2 = getMemoryV2(); const memoryStatus = await memoryV2?.getStatus?.().catch(() => null); if (!memoryStatus?.enabled) { return res.status(503).json({ message: '长期记忆功能未启用' }); } if (!getTkmindProxy()) { return res.status(503).json({ message: '会话代理尚未就绪' }); } const capabilityState = await ensureUserMemoryCapability(req, res); if (!capabilityState) return; const sessionId = String(req.body?.sessionId ?? '').trim(); if (!sessionId) { return res.status(400).json({ message: '缺少 sessionId' }); } const owns = await ownsAgentSession(req.currentUser.id, sessionId); if (!owns) { return res.status(403).json({ message: '无权访问该会话' }); } try { const messages = await loadUserVisibleConversation( sessionId, req.currentUser.id, ); const result = await memoryV2.write({ userId: req.currentUser.id, sessionId, messages, }); const syncedToSession = await syncUserMemoriesIntoSession( req.currentUser.id, sessionId, ); const memories = await resolveUserMemoryItems(req.currentUser.id, { sessionId, limit: 200, }); return res.json({ ok: true, analyzed: result.analyzed ?? 0, memories: result.memories ?? 0, totalMemories: memories.length, syncedToSession, }); } catch (err) { return res.status(500).json({ message: err instanceof Error ? err.message : '保存长期记忆失败', }); } }); api.post('/user-memory/v1/sync', async (req, res) => { const memoryV2 = getMemoryV2(); const memoryStatus = await memoryV2?.getStatus?.().catch(() => null); if (!memoryStatus?.enabled) { return res.status(503).json({ message: '长期记忆功能未启用' }); } const capabilityState = await ensureUserMemoryCapability(req, res); if (!capabilityState) return; const sessionId = String(req.body?.sessionId ?? '').trim(); if (!sessionId) { return res.status(400).json({ message: '缺少 sessionId' }); } const owns = await ownsAgentSession(req.currentUser.id, sessionId); if (!owns) { return res.status(403).json({ message: '无权访问该会话' }); } try { const result = await memoryV2.compact({ userId: req.currentUser.id, sessionId, }); const syncedToSession = await syncUserMemoriesIntoSession( req.currentUser.id, sessionId, ); const memories = await resolveUserMemoryItems(req.currentUser.id, { sessionId, limit: 200, }); return res.json({ ok: true, analyzed: result.analyzed ?? 0, memories: result.memories ?? 0, totalMemories: memories.length, syncedToSession, }); } catch (err) { return res.status(500).json({ message: err instanceof Error ? err.message : '刷新长期记忆失败', }); } }); api.get('/user-memory/v1/items', async (req, res) => { const capabilityState = await ensureUserMemoryCapability(req, res); if (!capabilityState) return; try { const memoryV2 = getMemoryV2(); const items = (await memoryV2.listMemories?.({ userId: req.currentUser.id, status: String(req.query?.status ?? 'active'), limit: req.query?.limit, offset: req.query?.offset, })) ?? []; return res.json({ ok: true, items }); } catch (err) { return res.status(500).json({ message: err instanceof Error ? err.message : '读取长期记忆失败', }); } }); api.delete('/user-memory/v1/items/:memoryId', async (req, res) => { const capabilityState = await ensureUserMemoryCapability(req, res); if (!capabilityState) return; try { const memoryV2 = getMemoryV2(); const result = (await memoryV2.forgetMemory?.({ userId: req.currentUser.id, memoryId: req.params.memoryId, })) ?? { ok: false, skipped: true, reason: 'unavailable' }; if (result.skipped) return res.status(409).json(result); return res.json(result); } catch (err) { return res.status(500).json({ message: err instanceof Error ? err.message : '删除长期记忆失败', }); } }); }