165 lines
5.0 KiB
JavaScript
165 lines
5.0 KiB
JavaScript
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 : '删除长期记忆失败',
|
|
});
|
|
}
|
|
});
|
|
}
|