Files
memind/admin-routes.test.mjs
T
john 6f3e53a56a 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>
2026-08-01 17:14:06 +08:00

705 lines
24 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import express from 'express';
import { once } from 'node:events';
import { createAdminApi } from './admin-routes.mjs';
async function startTestServer(router) {
const app = express();
app.use('/admin-api', router);
const server = app.listen(0, '127.0.0.1');
await once(server, 'listening');
const address = server.address();
return {
server,
baseUrl: `http://127.0.0.1:${address.port}`,
close: async () => {
server.close();
await once(server, 'close');
},
};
}
test('admin memory-v2 config routes expose config and runtime state', async () => {
const updates = [];
const router = createAdminApi({
jsonBody: express.json(),
getToken() {
return 'token-admin';
},
userAuth: {
async getMe(token) {
if (token !== 'token-admin') return null;
return { id: 'admin-1', role: 'admin' };
},
},
llmProviderService: null,
memoryV2ConfigService: {
async getAdminConfig() {
return { config: { chatIntentRouter: { enabled: true } }, updatedAt: 123 };
},
async updateAdminConfig(patch, { updatedBy }) {
updates.push({ patch, updatedBy });
return { config: patch, updatedAt: 456, updatedBy };
},
async getRuntimeState() {
return { source: 'admin-db', overrides: { MEMIND_CHAT_LLM_ROUTER_ENABLED: '1' } };
},
},
plazaPosts: null,
plazaOps: null,
wechatAdmin: null,
subscriptionService: null,
});
const server = await startTestServer(router);
try {
const configRes = await fetch(`${server.baseUrl}/admin-api/memory-v2/config`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(configRes.status, 200);
assert.deepEqual(await configRes.json(), {
config: { chatIntentRouter: { enabled: true } },
updatedAt: 123,
});
const updateRes = await fetch(`${server.baseUrl}/admin-api/memory-v2/config`, {
method: 'PATCH',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({ chatIntentRouter: { enabled: false } }),
});
assert.equal(updateRes.status, 200);
assert.deepEqual(updates, [{
patch: { chatIntentRouter: { enabled: false } },
updatedBy: 'admin-1',
}]);
const runtimeRes = await fetch(`${server.baseUrl}/admin-api/memory-v2/runtime`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(runtimeRes.status, 200);
assert.deepEqual(await runtimeRes.json(), {
source: 'admin-db',
overrides: { MEMIND_CHAT_LLM_ROUTER_ENABLED: '1' },
});
} finally {
await server.close();
}
});
test('admin memory-v2 metrics and candidate review routes', async () => {
const router = createAdminApi({
jsonBody: express.json(),
getToken() {
return 'token-admin';
},
userAuth: {
async getMe(token) {
if (token !== 'token-admin') return null;
return { id: 'admin-1', role: 'admin' };
},
},
memoryV2AdminOpsService: {
async getProductMetrics() {
return {
window: { since: '7d', sinceMs: 1, untilMs: 2 },
userId: null,
events: {
memory_candidate_saved: 3,
memory_promoted: 2,
memory_resolved_injected: 1,
memory_recall_hit: 1,
},
sources: {},
};
},
async getShadowAudit() {
return {
falseStoreRate: 0,
autoAcceptRate: 0.1,
resolveHitRate: 0.5,
suspiciousCandidateCount: 0,
pgvectorLagUserCount: 0,
};
},
async countCandidatesByStatus() {
return { candidate: 4, accepted: 2 };
},
async listCandidates() {
return [{
id: 'cand-1',
userId: 'user-1',
sessionId: 'session-1',
memoryType: 'episodic',
content: '请记住我喜欢美式咖啡',
importance: 0.9,
confidence: 0.9,
status: 'candidate',
policyReason: 'explicit_memory_request',
createdAt: 1000,
updatedAt: 1000,
}];
},
async reviewCandidate(id, status, { reviewedBy }) {
assert.equal(id, 'cand-1');
assert.equal(status, 'accepted');
assert.equal(reviewedBy, 'admin-1');
return { updated: true, status, reviewedAt: 2000 };
},
},
llmProviderService: null,
memoryV2ConfigService: null,
plazaPosts: null,
plazaOps: null,
wechatAdmin: null,
subscriptionService: null,
});
const server = await startTestServer(router);
try {
const metricsRes = await fetch(`${server.baseUrl}/admin-api/memory-v2/metrics`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(metricsRes.status, 200);
const metricsBody = await metricsRes.json();
assert.equal(metricsBody.metrics.events.memory_candidate_saved, 3);
assert.equal(metricsBody.candidateCounts.candidate, 4);
const listRes = await fetch(`${server.baseUrl}/admin-api/memory-v2/candidates`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(listRes.status, 200);
const listBody = await listRes.json();
assert.equal(listBody.items.length, 1);
const reviewRes = await fetch(`${server.baseUrl}/admin-api/memory-v2/candidates/cand-1/review`, {
method: 'POST',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({ status: 'accepted' }),
});
assert.equal(reviewRes.status, 200);
assert.deepEqual(await reviewRes.json(), {
ok: true,
updated: true,
status: 'accepted',
reviewedAt: 2000,
});
} finally {
await server.close();
}
});
test('admin goal-runs routes expose summary, list, and detail', async () => {
const router = createAdminApi({
jsonBody: express.json(),
getToken() {
return 'token-admin';
},
userAuth: {
async getMe(token) {
if (token !== 'token-admin') return null;
return { id: 'admin-1', role: 'admin' };
},
},
goalRunAdminOpsService: {
getRuntime() {
return { enabled: true, canaryUserIds: ['user-1'], canaryMode: true };
},
async countByStatus() {
return { active: 2, completed: 1 };
},
async listGoals() {
return [{
id: 'goal-1',
userId: 'user-1',
username: 'john2',
title: '产品规划',
intentSummary: '分阶段完成',
status: 'active',
priority: 5,
sourceChannel: 'h5',
sourceSessionId: null,
currentCheckpointId: 'cp-1',
checkpointCount: 2,
activeAgentRunCount: 1,
createdAt: 1000,
updatedAt: 2000,
completedAt: null,
}];
},
async getGoalDetail(goalRunId) {
if (goalRunId !== 'goal-1') return null;
return {
id: 'goal-1',
userId: 'user-1',
username: 'john2',
title: '产品规划',
intentSummary: '分阶段完成',
status: 'active',
priority: 5,
sourceChannel: 'h5',
sourceSessionId: null,
sourceMessageId: null,
currentCheckpointId: 'cp-1',
context: null,
memorySnapshot: null,
createdAt: 1000,
updatedAt: 2000,
completedAt: null,
checkpoints: [{
id: 'cp-1',
goalRunId: 'goal-1',
sequence: 1,
title: '调研',
description: null,
status: 'running',
agentRunId: 'run-1',
outputSummary: null,
userFeedback: null,
approvedAt: null,
createdAt: 1000,
updatedAt: 2000,
startedAt: 1500,
completedAt: null,
}],
agentRuns: [{
id: 'run-1',
status: 'running',
requestId: 'req-1',
goalCheckpointId: 'cp-1',
createdAt: 1000,
updatedAt: 2000,
completedAt: null,
}],
canaryEnabled: true,
};
},
async approveCheckpoint({ goalRunId, checkpointId, feedback, reviewedBy }) {
assert.equal(goalRunId, 'goal-1');
assert.equal(checkpointId, 'cp-1');
assert.equal(feedback, 'looks good');
assert.equal(reviewedBy, 'admin-1');
return { id: 'goal-1', status: 'active', checkpoints: [] };
},
async cancelGoal({ goalRunId, reviewedBy }) {
assert.equal(goalRunId, 'goal-1');
assert.equal(reviewedBy, 'admin-1');
return { id: 'goal-1', status: 'cancelled', checkpoints: [] };
},
},
});
const server = await startTestServer(router);
try {
const summaryRes = await fetch(`${server.baseUrl}/admin-api/goal-runs/summary`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(summaryRes.status, 200);
const summaryBody = await summaryRes.json();
assert.equal(summaryBody.counts.active, 2);
assert.equal(summaryBody.runtime.enabled, true);
const listRes = await fetch(`${server.baseUrl}/admin-api/goal-runs`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(listRes.status, 200);
const listBody = await listRes.json();
assert.equal(listBody.items[0].id, 'goal-1');
const detailRes = await fetch(`${server.baseUrl}/admin-api/goal-runs/goal-1`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(detailRes.status, 200);
const detailBody = await detailRes.json();
assert.equal(detailBody.goal.checkpoints.length, 1);
const approveRes = await fetch(`${server.baseUrl}/admin-api/goal-runs/goal-1/checkpoints/cp-1/approve`, {
method: 'POST',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({ feedback: 'looks good' }),
});
assert.equal(approveRes.status, 200);
const cancelRes = await fetch(`${server.baseUrl}/admin-api/goal-runs/goal-1/cancel`, {
method: 'POST',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({}),
});
assert.equal(cancelRes.status, 200);
} finally {
await server.close();
}
});
test('admin orchestrator routes expose a versioned plug-in control plane', async () => {
const updates = [];
const state = {
config: {
mode: 'off',
primaryEngine: 'langgraph',
fallbackEngine: 'native',
serviceUrl: '',
requestTimeoutMs: 5000,
rolloutPercent: 0,
userAllowlist: [],
workflowAllowlist: ['code-run-v1'],
fallbackToNative: true,
requireHealthy: true,
},
configVersion: 1,
runtime: { effective: false, reason: 'mode_off' },
engines: [{ id: 'native', configured: true }, { id: 'langgraph', configured: false }],
};
const router = createAdminApi({
jsonBody: express.json(),
getToken() {
return 'token-admin';
},
userAuth: {
async getMe() {
return { id: 'admin-1', role: 'admin' };
},
},
llmProviderService: null,
memoryV2ConfigService: null,
orchestratorConfigService: {
async getAdminConfig() {
return state;
},
async updateAdminConfig(config, context) {
updates.push({ config, context });
return { ...state, config: { ...state.config, ...config }, configVersion: 2 };
},
async getRuntimeState(options) {
assert.deepEqual(options, { probe: true });
return {
...state,
source: 'admin-db',
serviceHealth: { ok: true, status: 'healthy' },
};
},
},
orchestratorObservabilityService: {
async listExecutionPlans(options) {
assert.deepEqual(options, {
hours: '24',
limit: '50',
selection: 'candidate',
});
return {
metrics: { decisions: 3, candidateSelections: 2 },
plans: [{ runId: 'run-plan-1', candidateEngine: 'langgraph' }],
};
},
async getCanaryReadiness() {
return {
ready: false,
recommendation: 'keep_shadow',
blockers: ['sample_volume'],
samples: { eligibleObservations: 1 },
};
},
async listShadowRuns(options) {
assert.deepEqual(options, { hours: '12', limit: '25', status: 'failed' });
return {
metrics: { observations: 1, successes: 0, failures: 1 },
runs: [{ runId: 'run-shadow-1', shadowStatus: 'failed' }],
};
},
async getShadowRun(runId) {
assert.equal(runId, 'run-shadow-1');
return {
native: { runId, status: 'succeeded' },
remote: { available: true, events: [{ type: 'workflow_validated' }] },
};
},
},
plazaPosts: null,
plazaOps: null,
wechatAdmin: null,
subscriptionService: null,
});
const server = await startTestServer(router);
try {
const configResponse = await fetch(`${server.baseUrl}/admin-api/orchestrator/config`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(configResponse.status, 200);
assert.equal((await configResponse.json()).config.mode, 'off');
const updateResponse = await fetch(`${server.baseUrl}/admin-api/orchestrator/config`, {
method: 'PATCH',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({ config: { mode: 'shadow', serviceUrl: 'http://127.0.0.1:8093' } }),
});
assert.equal(updateResponse.status, 200);
assert.equal((await updateResponse.json()).configVersion, 2);
assert.deepEqual(updates, [{
config: { mode: 'shadow', serviceUrl: 'http://127.0.0.1:8093' },
context: { updatedBy: 'admin-1' },
}]);
const runtimeResponse = await fetch(`${server.baseUrl}/admin-api/orchestrator/runtime`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(runtimeResponse.status, 200);
const runtimeBody = await runtimeResponse.json();
assert.equal(runtimeBody.source, 'admin-db');
assert.equal(runtimeBody.serviceHealth.status, 'healthy');
const shadowRunsResponse = await fetch(
`${server.baseUrl}/admin-api/orchestrator/shadow-runs?hours=12&limit=25&status=failed`,
{ headers: { cookie: 'h5_user_session=token-admin' } },
);
assert.equal(shadowRunsResponse.status, 200);
assert.equal((await shadowRunsResponse.json()).metrics.failures, 1);
const executionPlansResponse = await fetch(
`${server.baseUrl}/admin-api/orchestrator/execution-plans?hours=24&limit=50&selection=candidate`,
{ headers: { cookie: 'h5_user_session=token-admin' } },
);
assert.equal(executionPlansResponse.status, 200);
const executionPlansBody = await executionPlansResponse.json();
assert.equal(executionPlansBody.metrics.decisions, 3);
assert.equal(executionPlansBody.plans[0].candidateEngine, 'langgraph');
const readinessResponse = await fetch(
`${server.baseUrl}/admin-api/orchestrator/canary-readiness`,
{ headers: { cookie: 'h5_user_session=token-admin' } },
);
assert.equal(readinessResponse.status, 200);
const readinessBody = await readinessResponse.json();
assert.equal(readinessBody.ready, false);
assert.deepEqual(readinessBody.blockers, ['sample_volume']);
const shadowRunResponse = await fetch(
`${server.baseUrl}/admin-api/orchestrator/shadow-runs/run-shadow-1`,
{ headers: { cookie: 'h5_user_session=token-admin' } },
);
assert.equal(shadowRunResponse.status, 200);
assert.equal((await shadowRunResponse.json()).remote.available, true);
} finally {
await server.close();
}
});
test('admin system disclosure policy routes version config through the injected control-plane service', async () => {
const updates = [];
const config = {
enabled: true,
mode: 'shadow',
refusalText: '不提供内部技术信息。',
productNames: ['tkmind'],
selfReferences: ['本系统'],
categories: { architecture: true },
};
const router = createAdminApi({
jsonBody: express.json(),
getToken() {
return 'token-admin';
},
userAuth: {
async getMe() {
return { id: 'admin-1', role: 'admin' };
},
},
llmProviderService: null,
memoryV2ConfigService: null,
systemDisclosurePolicyService: {
async getAdminConfig() {
return { config, policyVersion: 2, source: 'admin-db' };
},
async updateAdminConfig(patch, context) {
updates.push({ patch, context });
return { config: patch, policyVersion: 3, source: 'admin-db' };
},
getRuntimeState() {
return { config, policyVersion: 2, source: 'admin-db', refreshedAt: 123 };
},
},
plazaPosts: null,
plazaOps: null,
wechatAdmin: null,
subscriptionService: null,
});
const server = await startTestServer(router);
try {
const getResponse = await fetch(`${server.baseUrl}/admin-api/system-disclosure-policy/config`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(getResponse.status, 200);
assert.equal((await getResponse.json()).policyVersion, 2);
const updateResponse = await fetch(`${server.baseUrl}/admin-api/system-disclosure-policy/config`, {
method: 'PUT',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({ config: { ...config, mode: 'enforce' } }),
});
assert.equal(updateResponse.status, 200);
assert.equal((await updateResponse.json()).policyVersion, 3);
assert.deepEqual(updates, [{
patch: { ...config, mode: 'enforce' },
context: { updatedBy: 'admin-1' },
}]);
const runtimeResponse = await fetch(`${server.baseUrl}/admin-api/system-disclosure-policy/runtime`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(runtimeResponse.status, 200);
assert.equal((await runtimeResponse.json()).refreshedAt, 123);
} finally {
await server.close();
}
});
test('admin MindSearch routes persist only through injected control-plane service', async () => {
const updates = [];
const testedServices = [];
const router = createAdminApi({
jsonBody: express.json(), getToken() { return 'token-admin'; },
userAuth: { async getMe() { return { id: 'admin-1', role: 'admin' }; } },
llmProviderService: null, memoryV2ConfigService: null,
mindSearchConfigService: {
async getAdminConfig() { return { config: { enabled: false, mode: 'off', providers: { searxng: false, github: false, reader: false } }, source: 'env' }; },
async updateAdminConfig(patch, context) { updates.push({ patch, context }); return { config: { enabled: true, mode: 'shadow', providers: { searxng: true, github: false, reader: false } }, source: 'admin' }; },
async getRuntimeState() { return { effective: false, mode: 'off' }; },
async testService(serviceId) { testedServices.push(serviceId); return { ok: true, serviceId, latencyMs: 3 }; },
},
plazaPosts: null, plazaOps: null, wechatAdmin: null, subscriptionService: null,
});
const server = await startTestServer(router);
try {
const config = await fetch(`${server.baseUrl}/admin-api/mindsearch/config`, { headers: { cookie: 'h5_user_session=token-admin' } });
assert.equal(config.status, 200);
const update = await fetch(`${server.baseUrl}/admin-api/mindsearch/config`, { method: 'PATCH', headers: { 'content-type': 'application/json', cookie: 'h5_user_session=token-admin' }, body: JSON.stringify({ enabled: true, mode: 'shadow' }) });
assert.equal(update.status, 200);
assert.deepEqual(updates, [{ patch: { enabled: true, mode: 'shadow' }, context: { updatedBy: 'admin-1' } }]);
const runtime = await fetch(`${server.baseUrl}/admin-api/mindsearch/runtime`, { headers: { cookie: 'h5_user_session=token-admin' } });
assert.deepEqual(await runtime.json(), { effective: false, mode: 'off' });
const serviceTest = await fetch(`${server.baseUrl}/admin-api/mindsearch/services/searxng/test`, { method: 'POST', headers: { cookie: 'h5_user_session=token-admin' } });
assert.deepEqual(await serviceTest.json(), { ok: true, serviceId: 'searxng', latencyMs: 3 });
assert.deepEqual(testedServices, ['searxng']);
} finally { await server.close(); }
});
test('admin asset gateway routes preserve an explicit, admin-only control plane', async () => {
const calls = [];
const router = createAdminApi({
jsonBody: express.json(),
getToken() { return 'token-admin'; },
userAuth: { async getMe() { return { id: 'admin-1', role: 'admin' }; } },
llmProviderService: null,
memoryV2ConfigService: null,
assetGatewayConfigService: {
async getConfig() { return { enabled: false, plugins: [] }; },
async updateGlobalConfig(payload, context) { calls.push({ type: 'global', payload, context }); return { enabled: true }; },
async updatePluginConfig(pluginId, payload, context) {
calls.push({ type: 'plugin', pluginId, payload, context });
return { ok: true, config: { enabled: true, plugins: [] } };
},
},
plazaPosts: null,
plazaOps: null,
wechatAdmin: null,
subscriptionService: null,
});
const server = await startTestServer(router);
try {
const read = await fetch(`${server.baseUrl}/admin-api/asset-gateway/config`, {
headers: { cookie: 'h5_user_session=token-admin' },
});
assert.equal(read.status, 200);
assert.deepEqual(await read.json(), { enabled: false, plugins: [] });
const update = await fetch(`${server.baseUrl}/admin-api/asset-gateway/plugins/asset-generate`, {
method: 'PUT',
headers: { 'content-type': 'application/json', cookie: 'h5_user_session=token-admin' },
body: JSON.stringify({ enabled: true, provider: 'flux-schnell' }),
});
assert.equal(update.status, 200);
assert.equal(calls[0].pluginId, 'asset-generate');
assert.equal(calls[0].context.updatedBy, 'admin-1');
} finally {
await server.close();
}
});
test('admin system test route executes shared validation service', async () => {
const calls = [];
const router = createAdminApi({
jsonBody: express.json(),
getToken() {
return 'token-admin';
},
userAuth: {
async getMe(token) {
if (token !== 'token-admin') return null;
return { id: 'admin-1', role: 'admin' };
},
},
llmProviderService: null,
memoryV2ConfigService: null,
adminSystemTestService: {
async runSkillValidation(input) {
calls.push(input);
return {
ok: true,
selectedSkill: input.skillName,
account: { username: input.username },
summary: { passed: 1, warnings: 0, failed: 0 },
steps: [],
issues: [],
};
},
},
plazaPosts: null,
plazaOps: null,
wechatAdmin: null,
subscriptionService: null,
});
const server = await startTestServer(router);
try {
const response = await fetch(`${server.baseUrl}/admin-api/system-tests/skill-validation`, {
method: 'POST',
headers: {
'content-type': 'application/json',
cookie: 'h5_user_session=token-admin',
},
body: JSON.stringify({
username: 'john',
password: 'secret',
skillName: 'service-integration-smoke',
}),
});
assert.equal(response.status, 200);
assert.deepEqual(calls, [{
username: 'john',
password: 'secret',
skillName: 'service-integration-smoke',
}]);
assert.equal((await response.json()).ok, true);
} finally {
await server.close();
}
});