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:
@@ -0,0 +1,109 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { resolveGoalBindingForAgentRun } from './goal-run-resolve.mjs';
|
||||
|
||||
function createGoalRunServiceStub(overrides = {}) {
|
||||
return {
|
||||
async createGoalRun(input) {
|
||||
return {
|
||||
id: 'goal-new',
|
||||
title: input.title,
|
||||
checkpoints: [{ id: 'cp-new', title: '启动', status: 'pending' }],
|
||||
currentCheckpointId: 'cp-new',
|
||||
};
|
||||
},
|
||||
async getGoalRun({ goalRunId }) {
|
||||
if (goalRunId === 'goal-existing') {
|
||||
return {
|
||||
id: 'goal-existing',
|
||||
status: 'active',
|
||||
checkpoints: [{ id: 'cp-2', status: 'pending' }],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
},
|
||||
async startNextCheckpoint({ goalRunId }) {
|
||||
return {
|
||||
goalRunId,
|
||||
checkpointId: goalRunId === 'goal-existing' ? 'cp-2' : 'cp-new',
|
||||
};
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test('resolveGoalBindingForAgentRun returns null when feature disabled', async () => {
|
||||
const binding = await resolveGoalBindingForAgentRun({
|
||||
goalRunService: createGoalRunServiceStub(),
|
||||
userId: 'user-1',
|
||||
userMessage: { content: [{ type: 'text', text: '帮我分阶段完成产品规划' }] },
|
||||
env: { GOAL_RUN_ENABLED: '0' },
|
||||
});
|
||||
assert.equal(binding, null);
|
||||
});
|
||||
|
||||
test('resolveGoalBindingForAgentRun creates goal for goal_run intent', async () => {
|
||||
const calls = [];
|
||||
const binding = await resolveGoalBindingForAgentRun({
|
||||
goalRunService: createGoalRunServiceStub({
|
||||
async createGoalRun(input) {
|
||||
calls.push(input);
|
||||
return {
|
||||
id: 'goal-new',
|
||||
title: input.title,
|
||||
checkpoints: [{ id: 'cp-new' }],
|
||||
};
|
||||
},
|
||||
}),
|
||||
userId: 'user-canary',
|
||||
userMessage: {
|
||||
content: [{ type: 'text', text: '帮我分阶段完成下季度产品规划' }],
|
||||
metadata: { displayText: '帮我分阶段完成下季度产品规划' },
|
||||
},
|
||||
sessionId: 'session-1',
|
||||
env: {
|
||||
GOAL_RUN_ENABLED: '1',
|
||||
GOAL_RUN_CANARY_USER_IDS: 'user-canary',
|
||||
},
|
||||
});
|
||||
assert.deepEqual(binding, {
|
||||
goalRunId: 'goal-new',
|
||||
goalCheckpointId: 'cp-new',
|
||||
});
|
||||
assert.equal(calls[0].sourceSessionId, 'session-1');
|
||||
});
|
||||
|
||||
test('resolveGoalBindingForAgentRun resumes explicit goal_run_id', async () => {
|
||||
const binding = await resolveGoalBindingForAgentRun({
|
||||
goalRunService: createGoalRunServiceStub(),
|
||||
userId: 'user-canary',
|
||||
userMessage: { content: [{ type: 'text', text: '继续' }] },
|
||||
body: { goal_run_id: 'goal-existing' },
|
||||
env: {
|
||||
GOAL_RUN_ENABLED: '1',
|
||||
GOAL_RUN_CANARY_USER_IDS: 'user-canary',
|
||||
},
|
||||
});
|
||||
assert.deepEqual(binding, {
|
||||
goalRunId: 'goal-existing',
|
||||
goalCheckpointId: 'cp-2',
|
||||
});
|
||||
});
|
||||
|
||||
test('resolveGoalBindingForAgentRun uses router goal_run flag', async () => {
|
||||
const binding = await resolveGoalBindingForAgentRun({
|
||||
goalRunService: createGoalRunServiceStub(),
|
||||
chatIntentRouter: {
|
||||
async classify() {
|
||||
return { decision: { flags: ['goal_run'] } };
|
||||
},
|
||||
},
|
||||
userId: 'user-canary',
|
||||
userMessage: { content: [{ type: 'text', text: '整理一下思路' }] },
|
||||
env: {
|
||||
GOAL_RUN_ENABLED: '1',
|
||||
GOAL_RUN_CANARY_USER_IDS: 'user-canary',
|
||||
},
|
||||
});
|
||||
assert.equal(binding?.goalRunId, 'goal-new');
|
||||
});
|
||||
Reference in New Issue
Block a user