refactor: disable automatic main-agent thread sync pushes
This commit is contained in:
@@ -2882,8 +2882,6 @@ function appendThreadProgressEventInState(
|
||||
return event;
|
||||
}
|
||||
|
||||
const THREAD_STATUS_FULL_SYNC_INTERVAL_MS = 15 * 60_000;
|
||||
|
||||
function normalizeState(raw: Partial<BossState> | undefined): BossState {
|
||||
const base = cloneInitialState();
|
||||
if (!raw) return syncDerivedState(base);
|
||||
@@ -7635,6 +7633,15 @@ function shouldQueueProjectUnderstandingSync(
|
||||
state: BossState,
|
||||
reason: "heartbeat_activity" | "thread_reply" = "heartbeat_activity",
|
||||
) {
|
||||
// 主 Agent 自动向线程发隐藏理解对话当前整体关闭。
|
||||
// 保留现有数据模型,后续如果需要恢复,可在明确产品决策后重新开启。
|
||||
void project;
|
||||
void observedActivityAt;
|
||||
void state;
|
||||
void reason;
|
||||
return false;
|
||||
|
||||
/*
|
||||
if (!isDispatchableThreadProject(project)) {
|
||||
return false;
|
||||
}
|
||||
@@ -7681,6 +7688,7 @@ function shouldQueueProjectUnderstandingSync(
|
||||
task.projectUnderstandingTargetProjectId === project.id &&
|
||||
(task.status === "queued" || task.status === "running"),
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
function buildProjectUnderstandingSyncPrompt(project: Project, reason: "heartbeat_activity" | "thread_reply") {
|
||||
|
||||
@@ -1775,35 +1775,6 @@ function buildDeviceImportResolutionPrompt(params: {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function buildDeviceImportUnderstandingPrompt(params: {
|
||||
deviceName: string;
|
||||
draftId: string;
|
||||
candidateId: string;
|
||||
threadDisplayName: string;
|
||||
folderName: string;
|
||||
lastActiveAt: string;
|
||||
}) {
|
||||
return [
|
||||
"你正在协助 Boss 控制台完成新设备导入前的项目理解。",
|
||||
"请以当前活跃线程的视角,直接总结这个项目当前最关键的信息。",
|
||||
"输出必须是 JSON,对象结构如下:",
|
||||
'{ "projectGoal": "一句中文目标", "currentProgress": "一句中文进度", "technicalArchitecture": "一句中文架构说明", "currentBlockers": "一句中文阻塞说明", "recommendedNextStep": "一句中文建议动作" }',
|
||||
"要求:",
|
||||
"1. 只输出 JSON,不要输出额外解释。",
|
||||
"2. 用中文,句子短而明确。",
|
||||
"3. 如果某项信息不确定,也要明确写出当前已知范围,不要留空。",
|
||||
"",
|
||||
`deviceName: ${params.deviceName}`,
|
||||
`draftId: ${params.draftId}`,
|
||||
`candidateId: ${params.candidateId}`,
|
||||
`threadDisplayName: ${params.threadDisplayName}`,
|
||||
`folderName: ${params.folderName}`,
|
||||
`lastActiveAt: ${params.lastActiveAt}`,
|
||||
"",
|
||||
"请回答当前项目:目标、进度、技术架构、阻塞点、下一步建议。",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
export async function queueDeviceImportResolutionTask(params: {
|
||||
deviceId: string;
|
||||
reviewedBy: string;
|
||||
@@ -1824,35 +1795,7 @@ export async function queueDeviceImportResolutionTask(params: {
|
||||
const selectedCandidates = draft.candidates.filter((candidate) =>
|
||||
draft.selectedCandidateIds.includes(candidate.candidateId),
|
||||
);
|
||||
const understandingTasks = await Promise.all(
|
||||
selectedCandidates
|
||||
.filter((candidate) => candidate.codexThreadRef?.trim())
|
||||
.map((candidate) =>
|
||||
queueMasterAgentTask({
|
||||
projectId: "master-agent",
|
||||
taskType: "conversation_reply",
|
||||
requestMessageId: draft.draftId,
|
||||
requestText: `请总结线程 ${candidate.threadDisplayName} 当前项目目标与进度`,
|
||||
executionPrompt: buildDeviceImportUnderstandingPrompt({
|
||||
deviceName: device.name,
|
||||
draftId: draft.draftId,
|
||||
candidateId: candidate.candidateId,
|
||||
threadDisplayName: candidate.threadDisplayName,
|
||||
folderName: candidate.folderName,
|
||||
lastActiveAt: candidate.lastActiveAt,
|
||||
}),
|
||||
requestedBy: params.reviewedBy,
|
||||
requestedByAccount: params.reviewedBy,
|
||||
deviceId: device.id,
|
||||
deviceImportDraftId: draft.draftId,
|
||||
deviceImportCandidateId: candidate.candidateId,
|
||||
deviceImportCandidateFolderName: candidate.folderName,
|
||||
targetThreadDisplayName: candidate.threadDisplayName,
|
||||
targetCodexThreadRef: candidate.codexThreadRef,
|
||||
targetCodexFolderRef: candidate.codexFolderRef ?? candidate.folderRef,
|
||||
}),
|
||||
),
|
||||
);
|
||||
const understandingTasks: Array<Awaited<ReturnType<typeof queueMasterAgentTask>>> = [];
|
||||
const task = await queueMasterAgentTask({
|
||||
projectId: "master-agent",
|
||||
taskType: "device_import_resolution",
|
||||
|
||||
@@ -83,7 +83,7 @@ async function createAuthedRequestFor(
|
||||
});
|
||||
}
|
||||
|
||||
test("device import draft review queues a master-agent task, then completion writes back a ready resolution and apply still works", async () => {
|
||||
test("device import draft review queues only the resolution task, then completion writes back a ready resolution and apply still works", async () => {
|
||||
await setup();
|
||||
|
||||
const enrollmentResponse = await createEnrollmentRoute(
|
||||
@@ -190,8 +190,7 @@ test("device import draft review queues a master-agent task, then completion wri
|
||||
assert.equal(reviewPayload.task.status, "queued");
|
||||
assert.equal(reviewPayload.draft?.status, "pending_resolution");
|
||||
assert.equal(reviewPayload.resolution, undefined);
|
||||
assert.equal(reviewPayload.understandingTasks?.length, 1);
|
||||
assert.equal(reviewPayload.understandingTasks?.[0]?.status, "queued");
|
||||
assert.equal(reviewPayload.understandingTasks?.length ?? 0, 0);
|
||||
|
||||
const reviewedState = await readState();
|
||||
const resolutionTask = reviewedState.masterAgentTasks.find(
|
||||
@@ -207,8 +206,11 @@ test("device import draft review queues a master-agent task, then completion wri
|
||||
task.deviceImportDraftId === draftPayload.draft?.draftId &&
|
||||
task.status === "queued",
|
||||
);
|
||||
assert.ok(understandingTask, "expected import review to leave a queued thread understanding task trace");
|
||||
assert.equal(understandingTask?.targetThreadDisplayName, "北区试产线回归");
|
||||
assert.equal(
|
||||
understandingTask,
|
||||
undefined,
|
||||
"device import review should no longer auto-queue hidden thread sync tasks",
|
||||
);
|
||||
|
||||
const completionResponse = await completeMasterTaskRoute(
|
||||
await createAuthedRequest(
|
||||
@@ -237,30 +239,6 @@ test("device import draft review queues a master-agent task, then completion wri
|
||||
);
|
||||
assert.equal(completionResponse.status, 200);
|
||||
|
||||
const understandingCompletionResponse = await completeMasterTaskRoute(
|
||||
await createAuthedRequest(
|
||||
`http://127.0.0.1:3000/api/v1/master-agent/tasks/${understandingTask?.taskId}/complete`,
|
||||
"POST",
|
||||
{
|
||||
deviceId: enrollmentPayload.device.id,
|
||||
status: "completed",
|
||||
replyBody: JSON.stringify(
|
||||
{
|
||||
projectGoal: "完成北区试产线树莓派二代接入与联调。",
|
||||
currentProgress: "已经完成线程导入准备,当前在核对设备接线和控制链路。",
|
||||
technicalArchitecture: "前台是 Next.js 控制台,设备端通过 local-agent 与 Codex 线程联动。",
|
||||
currentBlockers: "还缺少树莓派二代的串口稳定性验证。",
|
||||
recommendedNextStep: "先确认接线和串口日志,再继续设备控制指令联调。",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
),
|
||||
{ params: Promise.resolve({ taskId: understandingTask?.taskId ?? "" }) },
|
||||
);
|
||||
assert.equal(understandingCompletionResponse.status, 200);
|
||||
|
||||
const completedState = await readState();
|
||||
const completedDraft = completedState.deviceImportDrafts.find(
|
||||
(draft) => draft.deviceId === enrollmentPayload.device.id,
|
||||
@@ -291,13 +269,8 @@ test("device import draft review queues a master-agent task, then completion wri
|
||||
}>;
|
||||
understandingTasks?: Array<{ taskId: string; status: string }>;
|
||||
};
|
||||
assert.equal(refreshedDraftPayload.projectUnderstandings?.length, 1);
|
||||
assert.equal(refreshedDraftPayload.projectUnderstandings?.[0]?.threadDisplayName, "北区试产线回归");
|
||||
assert.match(
|
||||
refreshedDraftPayload.projectUnderstandings?.[0]?.projectGoal ?? "",
|
||||
/树莓派二代接入与联调/,
|
||||
);
|
||||
assert.equal(refreshedDraftPayload.understandingTasks?.[0]?.status, "completed");
|
||||
assert.equal(refreshedDraftPayload.projectUnderstandings?.length ?? 0, 0);
|
||||
assert.equal(refreshedDraftPayload.understandingTasks?.length ?? 0, 0);
|
||||
|
||||
const applyResponse = await applyImportDraftRoute(
|
||||
await createAuthedRequest(
|
||||
@@ -321,23 +294,13 @@ test("device import draft review queues a master-agent task, then completion wri
|
||||
assert.ok(importedProject, "expected selected candidate to become a real chat window");
|
||||
assert.equal(importedProject?.threadMeta.threadDisplayName, "北区试产线回归");
|
||||
assert.equal(importedProject?.threadMeta.folderName, "北区试产线");
|
||||
assert.equal(importedProject?.projectUnderstanding?.projectGoal, "完成北区试产线树莓派二代接入与联调。");
|
||||
assert.match(importedProject?.projectUnderstanding?.technicalArchitecture ?? "", /local-agent 与 Codex 线程联动/);
|
||||
assert.equal(importedProject?.projectUnderstanding?.sourceKind, "device_import");
|
||||
assert.ok(importedProject?.threadMeta.lastProjectUnderstandingSyncedAt);
|
||||
assert.equal(importedProject?.projectUnderstanding, undefined);
|
||||
assert.equal(importedProject?.threadMeta.lastProjectUnderstandingSyncedAt, undefined);
|
||||
|
||||
const importedMemories = nextState.masterAgentMemories.filter(
|
||||
(memory) => memory.projectId === importedProject?.id,
|
||||
);
|
||||
assert.equal(importedMemories.length, 5);
|
||||
assert.equal(
|
||||
importedMemories.find((memory) => memory.title === "项目目标 · 北区试产线回归")?.content,
|
||||
"完成北区试产线树莓派二代接入与联调。",
|
||||
);
|
||||
assert.match(
|
||||
importedMemories.find((memory) => memory.title === "下一步建议 · 北区试产线回归")?.content ?? "",
|
||||
/确认接线和串口日志/,
|
||||
);
|
||||
assert.equal(importedMemories.length, 0);
|
||||
|
||||
const device = nextState.devices.find((item) => item.id === enrollmentPayload.device.id);
|
||||
assert.deepEqual(device?.projects, ["北区试产线"]);
|
||||
@@ -394,7 +357,7 @@ test("device import draft review queues a master-agent task, then completion wri
|
||||
assert.equal(appliedResolution?.status, "applied");
|
||||
});
|
||||
|
||||
test("imported thread projects queue hidden understanding sync tasks on newer activity and refresh project understanding", async () => {
|
||||
test("imported thread projects append progress events on newer activity without queuing hidden understanding sync tasks", async () => {
|
||||
await setup();
|
||||
|
||||
const enrollmentResponse = await createEnrollmentRoute(
|
||||
@@ -493,7 +456,7 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
task.deviceImportCandidateId &&
|
||||
task.status === "queued",
|
||||
);
|
||||
assert.ok(initialUnderstandingTask);
|
||||
assert.equal(initialUnderstandingTask, undefined);
|
||||
|
||||
assert.equal(
|
||||
(
|
||||
@@ -524,34 +487,6 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
200,
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
(
|
||||
await completeMasterTaskRoute(
|
||||
await createAuthedRequest(
|
||||
`http://127.0.0.1:3000/api/v1/master-agent/tasks/${initialUnderstandingTask.taskId}/complete`,
|
||||
"POST",
|
||||
{
|
||||
deviceId: enrollmentPayload.device.id,
|
||||
status: "completed",
|
||||
replyBody: JSON.stringify(
|
||||
{
|
||||
projectGoal: "让智能看板项目能够稳定接入主控面板。",
|
||||
currentProgress: "已经完成导入前梳理,准备开始界面和设备联调。",
|
||||
technicalArchitecture: "Android 原生端连接 Boss Web,再通过 local-agent 对接 Codex 线程。",
|
||||
currentBlockers: "还缺少设备端实时推送状态的统一协议。",
|
||||
recommendedNextStep: "先对齐状态推送协议,再做前后端联调。",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
),
|
||||
{ params: Promise.resolve({ taskId: initialUnderstandingTask.taskId }) },
|
||||
)
|
||||
).status,
|
||||
200,
|
||||
);
|
||||
|
||||
const applyResponse = await applyImportDraftRoute(
|
||||
await createAuthedRequest(
|
||||
`http://127.0.0.1:3000/api/v1/devices/${enrollmentPayload.device.id}/import-draft/apply`,
|
||||
@@ -567,7 +502,7 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
(project) => project.threadMeta.codexThreadRef === "thread-smart-board",
|
||||
);
|
||||
assert.ok(importedProject);
|
||||
assert.equal(importedProject?.projectUnderstanding?.currentProgress, "已经完成导入前梳理,准备开始界面和设备联调。");
|
||||
assert.equal(importedProject?.projectUnderstanding, undefined);
|
||||
const progressEventsBefore = currentState.threadProgressEvents.filter(
|
||||
(event) => event.projectId === importedProject?.id,
|
||||
).length;
|
||||
@@ -599,7 +534,7 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
task.projectUnderstandingReason === "heartbeat_activity" &&
|
||||
task.status === "queued",
|
||||
);
|
||||
assert.ok(hiddenSyncTask);
|
||||
assert.equal(hiddenSyncTask, undefined);
|
||||
|
||||
const progressEventsAfter = currentState.threadProgressEvents.filter(
|
||||
(event) => event.projectId === importedProject?.id,
|
||||
@@ -608,41 +543,11 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
assert.equal(progressEventsAfter[0]?.eventType, "progress_updated");
|
||||
assert.match(progressEventsAfter[0]?.summary ?? "", /北区试产线回归|新活动/);
|
||||
|
||||
assert.equal(
|
||||
(
|
||||
await completeMasterTaskRoute(
|
||||
await createAuthedRequest(
|
||||
`http://127.0.0.1:3000/api/v1/master-agent/tasks/${hiddenSyncTask.taskId}/complete`,
|
||||
"POST",
|
||||
{
|
||||
deviceId: enrollmentPayload.device.id,
|
||||
status: "completed",
|
||||
replyBody: JSON.stringify(
|
||||
{
|
||||
projectGoal: "让智能看板项目能够稳定接入主控面板。",
|
||||
currentProgress: "已完成状态推送协议对齐,正在推进前后端联调。",
|
||||
technicalArchitecture: "Android 原生端连接 Boss Web,再通过 local-agent 对接 Codex 线程。",
|
||||
currentBlockers: "还缺少最终的真机联调回归。",
|
||||
recommendedNextStep: "先完成真机联调,再收口回归问题。",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
),
|
||||
{ params: Promise.resolve({ taskId: hiddenSyncTask.taskId }) },
|
||||
)
|
||||
).status,
|
||||
200,
|
||||
);
|
||||
|
||||
currentState = await readState();
|
||||
|
||||
const refreshedProject = currentState.projects.find((project) => project.id === importedProject?.id);
|
||||
assert.equal(refreshedProject?.projectUnderstanding?.currentProgress, "已完成状态推送协议对齐,正在推进前后端联调。");
|
||||
assert.match(refreshedProject?.projectUnderstanding?.technicalArchitecture ?? "", /Android 原生端连接 Boss Web/);
|
||||
assert.equal(refreshedProject?.projectUnderstanding?.sourceKind, "thread_sync");
|
||||
assert.ok(refreshedProject?.threadMeta.lastProjectUnderstandingSyncedAt);
|
||||
assert.equal(refreshedProject?.projectUnderstanding, undefined);
|
||||
assert.equal(refreshedProject?.threadMeta.lastProjectUnderstandingSyncedAt, undefined);
|
||||
|
||||
assert.equal(
|
||||
currentState.masterAgentMemories.find(
|
||||
@@ -650,7 +555,7 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
memory.projectId === refreshedProject?.id &&
|
||||
memory.title === "项目进度 · 智能看板主线程",
|
||||
)?.content,
|
||||
"已完成状态推送协议对齐,正在推进前后端联调。",
|
||||
undefined,
|
||||
);
|
||||
assert.equal(
|
||||
currentState.masterAgentMemories.find(
|
||||
@@ -658,16 +563,14 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac
|
||||
memory.projectId === refreshedProject?.id &&
|
||||
memory.title === "下一步建议 · 智能看板主线程",
|
||||
)?.content,
|
||||
"先完成真机联调,再收口回归问题。",
|
||||
undefined,
|
||||
);
|
||||
|
||||
const masterAgentProject = currentState.projects.find((project) => project.id === "master-agent");
|
||||
const collaborationNotice = (masterAgentProject?.messages ?? [])
|
||||
.map((message) => message.body)
|
||||
.find((body) => body.includes("协同推进"));
|
||||
assert.match(collaborationNotice ?? "", /主 Agent 已同步:智能看板主线程/);
|
||||
assert.match(collaborationNotice ?? "", /不会中断你继续直接控制线程开发/);
|
||||
assert.ok(!(collaborationNotice ?? "").includes("可接手"));
|
||||
assert.equal(collaborationNotice, undefined);
|
||||
});
|
||||
|
||||
test("heartbeat candidates no longer auto-create chat windows from legacy projects when import draft is present", async () => {
|
||||
|
||||
Reference in New Issue
Block a user