Integrate master agent runtime orchestration updates

This commit is contained in:
kris
2026-04-16 04:41:46 +08:00
parent e0c0ea1814
commit 39be49630f
81 changed files with 9283 additions and 448 deletions

View File

@@ -7,6 +7,7 @@ import { NextRequest } from "next/server";
let runtimeRoot = "";
let postMessageRoute: (typeof import("../src/app/api/v1/projects/[projectId]/messages/route"))["POST"];
let getProjectRoute: (typeof import("../src/app/api/v1/projects/[projectId]/route"))["GET"];
let getDispatchPlansRoute: (typeof import("../src/app/api/v1/projects/[projectId]/dispatch-plans/route"))["GET"];
let confirmDispatchPlanRoute: (typeof import("../src/app/api/v1/projects/[projectId]/dispatch-plans/[planId]/confirm/route"))["POST"];
let rejectDispatchPlanRoute: (typeof import("../src/app/api/v1/projects/[projectId]/dispatch-plans/[planId]/reject/route"))["POST"];
@@ -29,8 +30,9 @@ async function setup() {
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [messageModule, plansModule, confirmModule, rejectModule, retryModule, reminderModule, data, auth] = await Promise.all([
const [messageModule, projectModule, plansModule, confirmModule, rejectModule, retryModule, reminderModule, data, auth] = await Promise.all([
import("../src/app/api/v1/projects/[projectId]/messages/route.ts"),
import("../src/app/api/v1/projects/[projectId]/route.ts"),
import("../src/app/api/v1/projects/[projectId]/dispatch-plans/route.ts"),
import("../src/app/api/v1/projects/[projectId]/dispatch-plans/[planId]/confirm/route.ts"),
import("../src/app/api/v1/projects/[projectId]/dispatch-plans/[planId]/reject/route.ts"),
@@ -41,6 +43,7 @@ async function setup() {
]);
postMessageRoute = messageModule.POST;
getProjectRoute = projectModule.GET;
getDispatchPlansRoute = plansModule.GET;
confirmDispatchPlanRoute = confirmModule.POST;
rejectDispatchPlanRoute = rejectModule.POST;
@@ -334,6 +337,234 @@ test("POST /api/v1/projects/[projectId]/dispatch-plans/[planId]/confirm confirms
assert.equal(executionTask?.orchestrationBackendLabel, "Boss Native Orchestrator");
});
test("GET /api/v1/projects/[projectId]/dispatch-plans includes execution summaries after confirmation", async () => {
const { groupProject, dispatchPlan } = await createDispatchPlanForTest();
const approvedTargetProjectId = dispatchPlan.targets[0]?.projectId;
assert.ok(approvedTargetProjectId, "expected a recommended target project");
const confirmResponse = await confirmDispatchPlanRoute(
await createAuthedRequest(
`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}/dispatch-plans/${dispatchPlan.planId}/confirm`,
"POST",
{ approvedTargetProjectIds: [approvedTargetProjectId] },
),
{ params: Promise.resolve({ projectId: groupProject.id, planId: dispatchPlan.planId }) },
);
assert.equal(confirmResponse.status, 200);
const response = await getDispatchPlansRoute(
await createAuthedRequest(
`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}/dispatch-plans`,
"GET",
),
{ params: Promise.resolve({ projectId: groupProject.id }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
plans: Array<{
planId: string;
executions?: Array<{
executionId: string;
targetProjectId: string;
targetThreadId: string;
status: string;
resultMessageId?: string;
}>;
}>;
};
assert.equal(payload.ok, true);
assert.equal(payload.plans[0]?.planId, dispatchPlan.planId);
assert.ok(payload.plans[0]?.executions?.[0], "expected confirmed plan to expose its execution summaries");
assert.equal(payload.plans[0]?.executions?.[0]?.targetProjectId, approvedTargetProjectId);
assert.equal(payload.plans[0]?.executions?.[0]?.status, "queued");
});
test("GET /api/v1/projects/[projectId] includes group dispatch and participant state for the chat surface", async () => {
const { groupProject, dispatchPlan } = await createDispatchPlanForTest();
const response = await getProjectRoute(
await createAuthedRequest(`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}`, "GET"),
{ params: Promise.resolve({ projectId: groupProject.id }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
dispatchPlans?: Array<{
planId: string;
status?: string;
summary?: string;
targets?: Array<{ projectId: string; threadDisplayName: string }>;
executions?: Array<{ executionId: string; status: string }>;
}>;
participantsPayload?: {
projectId: string;
participants: Array<{ projectId: string; status?: string; canOpenProject?: boolean }>;
repairRequired: boolean;
};
};
assert.equal(payload.ok, true);
assert.equal(payload.dispatchPlans?.[0]?.planId, dispatchPlan.planId);
assert.equal(payload.dispatchPlans?.[0]?.status, "pending_user_confirmation");
assert.ok(payload.dispatchPlans?.[0]?.summary, "expected project detail to include dispatch summary");
assert.ok(payload.dispatchPlans?.[0]?.targets?.length, "expected project detail to include dispatch targets");
assert.equal(payload.dispatchPlans?.[0]?.targets?.[0]?.projectId, dispatchPlan.targets[0]?.projectId);
assert.ok(payload.participantsPayload, "expected project detail to include participantsPayload");
assert.equal(payload.participantsPayload?.projectId, groupProject.id);
assert.equal(payload.participantsPayload?.repairRequired, false);
assert.ok((payload.participantsPayload?.participants.length ?? 0) >= 2);
assert.equal(payload.participantsPayload?.participants[0]?.status, "active");
assert.equal(payload.participantsPayload?.participants[0]?.canOpenProject, true);
});
test("GET /api/v1/projects/[projectId] includes dispatch execution summaries after confirmation", async () => {
const { groupProject, dispatchPlan } = await createDispatchPlanForTest();
const approvedTargetProjectId = dispatchPlan.targets[0]?.projectId;
assert.ok(approvedTargetProjectId, "expected a recommended target project");
const confirmResponse = await confirmDispatchPlanRoute(
await createAuthedRequest(
`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}/dispatch-plans/${dispatchPlan.planId}/confirm`,
"POST",
{ approvedTargetProjectIds: [approvedTargetProjectId] },
),
{ params: Promise.resolve({ projectId: groupProject.id, planId: dispatchPlan.planId }) },
);
assert.equal(confirmResponse.status, 200);
const response = await getProjectRoute(
await createAuthedRequest(`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}`, "GET"),
{ params: Promise.resolve({ projectId: groupProject.id }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
dispatchPlans?: Array<{
planId: string;
executions?: Array<{
executionId: string;
targetProjectId: string;
targetThreadId: string;
status: string;
}>;
}>;
};
assert.equal(payload.ok, true);
assert.equal(payload.dispatchPlans?.[0]?.planId, dispatchPlan.planId);
assert.ok(payload.dispatchPlans?.[0]?.executions?.[0], "expected project detail to include confirmed execution summaries");
assert.equal(payload.dispatchPlans?.[0]?.executions?.[0]?.targetProjectId, approvedTargetProjectId);
assert.equal(payload.dispatchPlans?.[0]?.executions?.[0]?.status, "queued");
});
test("GET /api/v1/projects/[projectId] marks invalid group members as repair-required in detail payload", async () => {
const singles = await ensureTwoSingleThreadProjects();
const groupProject = await createProjectGroupChat({
sourceProjectId: singles[0].id,
memberProjectIds: [singles[1].id],
createdBy: "17600003315",
});
const state = await readState();
await writeState({
...state,
projects: state.projects.map((project) =>
project.id === groupProject.id
? {
...project,
groupMembers: [
{
projectId: "master-agent",
deviceId: "mac-studio",
threadId: "master-agent-thread",
threadDisplayName: "主 Agent 汇总",
folderName: "主控线程",
},
],
}
: project,
),
});
const response = await getProjectRoute(
await createAuthedRequest(`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}`, "GET"),
{ params: Promise.resolve({ projectId: groupProject.id }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
participantsPayload?: {
repairRequired: boolean;
validParticipantCount: number;
invalidParticipantCount: number;
participants: Array<{ projectId: string; status?: string; canOpenProject?: boolean }>;
};
};
assert.equal(payload.ok, true);
assert.equal(payload.participantsPayload?.repairRequired, true);
assert.equal(payload.participantsPayload?.validParticipantCount, 0);
assert.equal(payload.participantsPayload?.invalidParticipantCount, 1);
assert.equal(payload.participantsPayload?.participants[0]?.projectId, "master-agent");
assert.equal(payload.participantsPayload?.participants[0]?.status, "invalid_target");
assert.equal(payload.participantsPayload?.participants[0]?.canOpenProject, true);
});
test("GET /api/v1/projects/[projectId] marks missing group members as repair-required in detail payload", async () => {
const singles = await ensureTwoSingleThreadProjects();
const groupProject = await createProjectGroupChat({
sourceProjectId: singles[0].id,
memberProjectIds: [singles[1].id],
createdBy: "17600003315",
});
const state = await readState();
await writeState({
...state,
projects: state.projects.map((project) =>
project.id === groupProject.id
? {
...project,
groupMembers: [
{
projectId: "missing-project-1",
deviceId: "mac-studio",
threadId: "missing-thread-1",
threadDisplayName: "丢失线程引用",
folderName: "异常引用",
},
],
}
: project,
),
});
const response = await getProjectRoute(
await createAuthedRequest(`http://127.0.0.1:3000/api/v1/projects/${groupProject.id}`, "GET"),
{ params: Promise.resolve({ projectId: groupProject.id }) },
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
participantsPayload?: {
repairRequired: boolean;
validParticipantCount: number;
invalidParticipantCount: number;
participants: Array<{ projectId: string; status?: string; canOpenProject?: boolean }>;
};
};
assert.equal(payload.ok, true);
assert.equal(payload.participantsPayload?.repairRequired, true);
assert.equal(payload.participantsPayload?.validParticipantCount, 0);
assert.equal(payload.participantsPayload?.invalidParticipantCount, 1);
assert.equal(payload.participantsPayload?.participants[0]?.projectId, "missing-project-1");
assert.equal(payload.participantsPayload?.participants[0]?.status, "missing_project");
assert.equal(payload.participantsPayload?.participants[0]?.canOpenProject, false);
});
test("confirming a dispatch plan with rememberLightReminder persists the group reminder preference", async () => {
const { groupProject, dispatchPlan } = await createDispatchPlanForTest();
const approvedTargetProjectId = dispatchPlan.targets[0]?.projectId;