feat(memory-v2): close Phase A with auto-review, product events, and H5 recall UI.
Add candidate auto-review pipeline, shadow audit tooling, admin metrics page, and user-visible memory recall hints in chat with phase-a readiness checks. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -31,6 +31,7 @@ function plazaRouteError(res, req, error) {
|
||||
* @param {object} deps.userAuth
|
||||
* @param {object|null} deps.llmProviderService
|
||||
* @param {object|null} deps.memoryV2ConfigService
|
||||
* @param {object|null} deps.memoryV2AdminOpsService
|
||||
* @param {object|null} deps.goalRunAdminOpsService
|
||||
* @param {object|null} deps.orchestratorConfigService
|
||||
* @param {object|null} deps.orchestratorObservabilityService
|
||||
@@ -51,6 +52,7 @@ export function createAdminApi({
|
||||
assetGatewayConfigService,
|
||||
imageMakeAdminConfigService,
|
||||
memoryV2ConfigService,
|
||||
memoryV2AdminOpsService,
|
||||
goalRunAdminOpsService,
|
||||
orchestratorConfigService,
|
||||
orchestratorObservabilityService,
|
||||
@@ -233,6 +235,81 @@ export function createAdminApi({
|
||||
return res.json(result);
|
||||
});
|
||||
|
||||
adminApi.get('/memory-v2/metrics', requireAdmin, async (req, res) => {
|
||||
if (!memoryV2AdminOpsService?.getProductMetrics) {
|
||||
return res.status(503).json({ message: 'Memory V2 指标服务未启用' });
|
||||
}
|
||||
try {
|
||||
const since = String(req.query?.since ?? '7d').trim() || '7d';
|
||||
const userId = String(req.query?.userId ?? '').trim() || null;
|
||||
const metrics = await memoryV2AdminOpsService.getProductMetrics({ since, userId });
|
||||
const audit = await memoryV2AdminOpsService.getShadowAudit({ since, userId });
|
||||
const counts = await memoryV2AdminOpsService.countCandidatesByStatus();
|
||||
return res.json({ metrics, audit, candidateCounts: counts });
|
||||
} catch (err) {
|
||||
return res.status(500).json({
|
||||
message: err instanceof Error ? err.message : '读取 Memory V2 指标失败',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.get('/memory-v2/candidates', requireAdmin, async (req, res) => {
|
||||
if (!memoryV2AdminOpsService?.listCandidates) {
|
||||
return res.status(503).json({ message: 'Memory V2 候选服务未启用' });
|
||||
}
|
||||
try {
|
||||
const status = String(req.query?.status ?? 'candidate').trim() || 'candidate';
|
||||
const userId = String(req.query?.userId ?? '').trim() || null;
|
||||
const limit = Number(req.query?.limit ?? 50);
|
||||
const offset = Number(req.query?.offset ?? 0);
|
||||
const items = await memoryV2AdminOpsService.listCandidates({ status, userId, limit, offset });
|
||||
return res.json({ items, status, limit, offset });
|
||||
} catch (err) {
|
||||
return res.status(400).json({
|
||||
message: err instanceof Error ? err.message : '读取候选记忆失败',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.post('/memory-v2/candidates/auto-review', requireAdmin, async (req, res) => {
|
||||
if (!memoryV2AdminOpsService?.runAutoReview) {
|
||||
return res.status(503).json({ message: 'Memory V2 候选服务未启用' });
|
||||
}
|
||||
try {
|
||||
const userId = String(req.body?.userId ?? '').trim() || null;
|
||||
const limit = Number(req.body?.limit ?? 200);
|
||||
const result = await memoryV2AdminOpsService.runAutoReview({ userId, limit });
|
||||
return res.json({ ok: true, ...result });
|
||||
} catch (err) {
|
||||
return res.status(500).json({
|
||||
message: err instanceof Error ? err.message : '自动审核候选记忆失败',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.post('/memory-v2/candidates/:id/review', requireAdmin, async (req, res) => {
|
||||
if (!memoryV2AdminOpsService?.reviewCandidate) {
|
||||
return res.status(503).json({ message: 'Memory V2 候选服务未启用' });
|
||||
}
|
||||
const status = String(req.body?.status ?? '').trim();
|
||||
if (!['accepted', 'rejected'].includes(status)) {
|
||||
return res.status(400).json({ message: 'status 必须是 accepted 或 rejected' });
|
||||
}
|
||||
try {
|
||||
const result = await memoryV2AdminOpsService.reviewCandidate(req.params.id, status, {
|
||||
reviewedBy: req.currentUser.id,
|
||||
});
|
||||
if (!result.updated) {
|
||||
return res.status(409).json({ message: '候选不存在或已审核' });
|
||||
}
|
||||
return res.json({ ok: true, ...result });
|
||||
} catch (err) {
|
||||
return res.status(400).json({
|
||||
message: err instanceof Error ? err.message : '审核候选记忆失败',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.get('/goal-runs/runtime', requireAdmin, async (_req, res) => {
|
||||
if (!goalRunAdminOpsService?.getRuntime) {
|
||||
return res.status(503).json({ message: 'Goal Run 管理服务未启用' });
|
||||
|
||||
Reference in New Issue
Block a user