feat(goal-run): add multi-checkpoint goal orchestration with H5 and admin surfaces.

Persist goal runs in MySQL, bind agent runs to checkpoints, expose awaiting-approval
UX in chat, and add admin inspection routes with local verify scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-01 17:03:16 +08:00
parent 43bc8bbc2b
commit 666db0b939
47 changed files with 4417 additions and 4 deletions
+147
View File
@@ -90,6 +90,153 @@ test('admin memory-v2 config routes expose config and runtime state', async () =
}
});
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 = {