diff --git a/src/lib/boss-data.ts b/src/lib/boss-data.ts index 2bc2dda..80bfb4f 100644 --- a/src/lib/boss-data.ts +++ b/src/lib/boss-data.ts @@ -5743,9 +5743,10 @@ function appendDispatchExecutionResultInState( } const device = state.devices.find((item) => item.id === payload.completedByDeviceId); + const targetProject = state.projects.find((item) => item.id === payload.targetProjectId); const threadTitle = payload.targetThreadDisplayName?.trim() || - state.projects.find((item) => item.id === payload.targetProjectId)?.threadMeta.threadDisplayName || + targetProject?.threadMeta.threadDisplayName || payload.targetThreadId; if (execution.status === "completed" || execution.status === "failed") { @@ -5771,6 +5772,7 @@ function appendDispatchExecutionResultInState( } let mirroredResult: Message | null = null; + let mirroredThreadResult: Message | null = null; let masterSummary: Message | null = null; if (payload.status === "completed") { @@ -5783,6 +5785,12 @@ function appendDispatchExecutionResultInState( body: payload.rawThreadReply.trim(), kind: "text", }); + mirroredThreadResult = pushProjectLedgerMessage(state, payload.targetProjectId, { + sender: "device", + senderLabel: `${threadTitle} · ${device?.name ?? payload.completedByDeviceId}`, + body: payload.rawThreadReply.trim(), + kind: "text", + }); masterSummary = pushProjectLedgerMessage(state, payload.groupProjectId, { sender: "master", senderLabel: "主 Agent", @@ -5808,6 +5816,7 @@ function appendDispatchExecutionResultInState( return { execution: { ...execution }, mirroredResult, + mirroredThreadResult, masterSummary, }; } @@ -5828,6 +5837,8 @@ export async function appendDispatchExecutionResult(payload: { ); publishBossEvent("project.messages.updated", { projectId: payload.groupProjectId }); publishBossEvent("conversation.updated", { projectId: payload.groupProjectId }); + publishBossEvent("project.messages.updated", { projectId: payload.targetProjectId }); + publishBossEvent("conversation.updated", { projectId: payload.targetProjectId }); return result; } @@ -6134,6 +6145,10 @@ export async function completeMasterAgentTask(payload: { }); publishBossEvent("project.messages.updated", { projectId: result.projectId }); publishBossEvent("conversation.updated", { projectId: result.projectId }); + if (result.dispatchExecution?.targetProjectId) { + publishBossEvent("project.messages.updated", { projectId: result.dispatchExecution.targetProjectId }); + publishBossEvent("conversation.updated", { projectId: result.dispatchExecution.targetProjectId }); + } return result; } diff --git a/tests/dispatch-execution-result.test.ts b/tests/dispatch-execution-result.test.ts index 43e1027..b087400 100644 --- a/tests/dispatch-execution-result.test.ts +++ b/tests/dispatch-execution-result.test.ts @@ -221,6 +221,18 @@ test("POST /api/v1/master-agent/tasks/[taskId]/complete mirrors raw thread repli message.body.includes("主 Agent 汇总:线程A已返回阻塞点整理"), ); assert.ok(masterSummary, "expected master-agent summary to be appended after the raw thread reply"); + + const targetThreadMessages = + nextState.projects.find((project) => project.id === execution.targetProjectId)?.messages ?? []; + const mirroredThreadReply = targetThreadMessages.find( + (message) => + message.sender === "device" && + message.body.includes("线程A已经完成阻塞点整理"), + ); + assert.ok( + mirroredThreadReply, + "expected raw thread reply to also be mirrored back to the target single-thread conversation", + ); }); test("POST /api/v1/master-agent/tasks/[taskId]/complete is idempotent for repeated dispatch execution completions", async () => {