feat(admin): add Memory V2 personal controls and Skill Runtime page
Wire admin UI and API routes to restored Memind personal memory and skill runtime modules, including candidate review and runtime status display. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+107
@@ -98,6 +98,8 @@ export function createAdminApp(services) {
|
||||
loadMindSpaceConfig,
|
||||
updateMindSpaceConfig,
|
||||
memoryV2ConfigService,
|
||||
personalMemoryCandidateStore,
|
||||
skillRuntimeConfigService,
|
||||
wechatScheduleLlmConfigService,
|
||||
adminSystemTestService,
|
||||
systemTestAccountService,
|
||||
@@ -366,6 +368,111 @@ export function createAdminApp(services) {
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
adminApi.get('/memory-v2/status', requireAdmin, async (_req, res) => {
|
||||
const portalBaseUrl = `http://127.0.0.1:${process.env.H5_PORT ?? 8081}`;
|
||||
try {
|
||||
const response = await fetch(`${portalBaseUrl}/api/runtime/status`, {
|
||||
headers: { accept: 'application/json' },
|
||||
signal: AbortSignal.timeout(2500),
|
||||
});
|
||||
if (!response.ok) {
|
||||
return res.status(502).json({
|
||||
ok: false,
|
||||
message: `Memory V2 运行时状态返回 HTTP ${response.status}`,
|
||||
});
|
||||
}
|
||||
const payload = await response.json();
|
||||
return res.json({
|
||||
ok: true,
|
||||
checkedAt: Date.now(),
|
||||
memory: payload?.memory ?? null,
|
||||
});
|
||||
} catch (err) {
|
||||
return res.status(503).json({
|
||||
ok: false,
|
||||
checkedAt: Date.now(),
|
||||
message: err instanceof Error ? err.message : 'Memory V2 运行时不可用',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.get('/memory-v2/candidates', requireAdmin, async (req, res) => {
|
||||
if (!personalMemoryCandidateStore?.listCandidates) {
|
||||
return res.status(503).json({ message: '候选记忆存储未启用' });
|
||||
}
|
||||
try {
|
||||
const status = String(req.query.status ?? 'candidate');
|
||||
const userId = String(req.query.userId ?? '').trim() || null;
|
||||
const limit = Number(req.query.limit ?? 50);
|
||||
const [items, counts] = await Promise.all([
|
||||
personalMemoryCandidateStore.listCandidates({ status, userId, limit }),
|
||||
personalMemoryCandidateStore.countByStatus(),
|
||||
]);
|
||||
return res.json({ items, counts });
|
||||
} catch (err) {
|
||||
const missingTable = err?.code === 'ER_NO_SUCH_TABLE';
|
||||
return res.status(missingTable ? 503 : 400).json({
|
||||
message: missingTable ? '候选记忆表尚未执行本地迁移' : (err instanceof Error ? err.message : '候选记忆读取失败'),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.post('/memory-v2/candidates/:id/accept', requireAdmin, async (req, res) => {
|
||||
if (!personalMemoryCandidateStore?.reviewCandidate) {
|
||||
return res.status(503).json({ message: '候选记忆存储未启用' });
|
||||
}
|
||||
const result = await personalMemoryCandidateStore.reviewCandidate(req.params.id, 'accepted', {
|
||||
reviewedBy: req.currentUser.id,
|
||||
});
|
||||
if (!result.updated) return res.status(409).json({ message: '候选记忆已处理或不存在' });
|
||||
return res.json(result);
|
||||
});
|
||||
|
||||
adminApi.post('/memory-v2/candidates/:id/reject', requireAdmin, async (req, res) => {
|
||||
if (!personalMemoryCandidateStore?.reviewCandidate) {
|
||||
return res.status(503).json({ message: '候选记忆存储未启用' });
|
||||
}
|
||||
const result = await personalMemoryCandidateStore.reviewCandidate(req.params.id, 'rejected', {
|
||||
reviewedBy: req.currentUser.id,
|
||||
});
|
||||
if (!result.updated) return res.status(409).json({ message: '候选记忆已处理或不存在' });
|
||||
return res.json(result);
|
||||
});
|
||||
|
||||
adminApi.get('/skill-runtime/config', requireAdmin, async (_req, res) => {
|
||||
if (!skillRuntimeConfigService?.getAdminConfig) {
|
||||
return res.status(503).json({ message: 'Skill Runtime 配置服务未启用' });
|
||||
}
|
||||
res.json(await skillRuntimeConfigService.getAdminConfig());
|
||||
});
|
||||
|
||||
const updateSkillRuntimeConfig = async (req, res) => {
|
||||
if (!skillRuntimeConfigService?.updateAdminConfig) {
|
||||
return res.status(503).json({ message: 'Skill Runtime 配置服务未启用' });
|
||||
}
|
||||
const result = await skillRuntimeConfigService.updateAdminConfig(req.body?.config ?? req.body ?? {}, {
|
||||
updatedBy: req.currentUser.id,
|
||||
});
|
||||
res.json(result);
|
||||
};
|
||||
|
||||
adminApi.put('/skill-runtime/config', requireAdmin, updateSkillRuntimeConfig);
|
||||
adminApi.patch('/skill-runtime/config', requireAdmin, updateSkillRuntimeConfig);
|
||||
|
||||
adminApi.get('/skill-runtime/catalog', requireAdmin, async (_req, res) => {
|
||||
if (!skillRuntimeConfigService?.listCatalogSummary) {
|
||||
return res.status(503).json({ message: 'Skill Runtime 配置服务未启用' });
|
||||
}
|
||||
res.json({ catalog: await skillRuntimeConfigService.listCatalogSummary() });
|
||||
});
|
||||
|
||||
adminApi.get('/skill-runtime/runtime', requireAdmin, async (_req, res) => {
|
||||
if (!skillRuntimeConfigService?.getPublicRuntimeConfig) {
|
||||
return res.status(503).json({ message: 'Skill Runtime 配置服务未启用' });
|
||||
}
|
||||
res.json(await skillRuntimeConfigService.getPublicRuntimeConfig());
|
||||
});
|
||||
|
||||
adminApi.get('/system-tests/accounts', requireAdmin, async (_req, res) => {
|
||||
if (!systemTestAccountService) {
|
||||
return res.status(503).json({ message: '系统测试账号服务未启用' });
|
||||
|
||||
@@ -29,6 +29,8 @@ export async function bootstrapAdminServices() {
|
||||
updateMindSpaceConfig,
|
||||
} = await importMemind('mindspace-config.mjs');
|
||||
const { createMemoryV2AdminConfigService } = await importMemind('memory-v2-admin-config.mjs');
|
||||
const { createPersonalMemoryCandidateStore } = await importMemind('memory-v2-personal-store.mjs');
|
||||
const { createSkillRuntimeAdminConfigService } = await importMemind('skill-runtime-admin-config.mjs');
|
||||
const { createAssetGatewayConfigService } = await importMemind('asset-gateway.mjs');
|
||||
const { ensureAssetGatewaySchema } = await importMemind('db.mjs');
|
||||
const { createWechatScheduleLlmConfigService } = await importMemind('wechat-schedule-llm-config.mjs');
|
||||
@@ -93,6 +95,11 @@ export async function bootstrapAdminServices() {
|
||||
const memoryV2ConfigService = createMemoryV2AdminConfigService(pool, {
|
||||
env: process.env,
|
||||
});
|
||||
const personalMemoryCandidateStore = createPersonalMemoryCandidateStore(pool);
|
||||
const skillRuntimeConfigService = createSkillRuntimeAdminConfigService(pool, {
|
||||
env: process.env,
|
||||
h5Root,
|
||||
});
|
||||
const wechatScheduleLlmConfigService = createWechatScheduleLlmConfigService(pool, {
|
||||
env: process.env,
|
||||
});
|
||||
@@ -145,6 +152,8 @@ export async function bootstrapAdminServices() {
|
||||
loadMindSpaceConfig,
|
||||
updateMindSpaceConfig,
|
||||
memoryV2ConfigService,
|
||||
personalMemoryCandidateStore,
|
||||
skillRuntimeConfigService,
|
||||
wechatScheduleLlmConfigService,
|
||||
adminSystemTestService,
|
||||
systemTestAccountService,
|
||||
|
||||
@@ -105,6 +105,8 @@ ready
|
||||
loadMindSpaceConfig,
|
||||
updateMindSpaceConfig,
|
||||
memoryV2ConfigService,
|
||||
personalMemoryCandidateStore,
|
||||
skillRuntimeConfigService,
|
||||
wechatScheduleLlmConfigService,
|
||||
adminSystemTestService,
|
||||
systemTestAccountService,
|
||||
@@ -128,6 +130,8 @@ ready
|
||||
loadMindSpaceConfig,
|
||||
updateMindSpaceConfig,
|
||||
memoryV2ConfigService,
|
||||
personalMemoryCandidateStore,
|
||||
skillRuntimeConfigService,
|
||||
wechatScheduleLlmConfigService,
|
||||
adminSystemTestService,
|
||||
systemTestAccountService,
|
||||
|
||||
Reference in New Issue
Block a user