






















@@ -865,7 +865,7 @@ describe("task-registry", () => {
865865});
866866});
867867868-it("delivers ACP completion to the requester channel when a delivery origin exists", async () => {
868+it("queues delegated ACP completion to the requester session when a delivery origin exists", async () => {
869869await withTaskRegistryTempDir(async (root) => {
870870process.env.OPENCLAW_STATE_DIR = root;
871871resetTaskRegistryMemoryForTest();
@@ -903,6 +903,104 @@ describe("task-registry", () => {
903903904904await waitForAssertion(() =>
905905expectRecordFields(requireTaskByRunId("run-delivery"), {
906+status: "succeeded",
907+deliveryStatus: "pending",
908+}),
909+);
910+expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
911+expect(peekSystemEvents("agent:main:main")).toEqual([
912+expect.stringContaining("Background task ready for review: ACP background task"),
913+]);
914+});
915+});
916+917+it("keeps direct delegated ACP completions pending so parent-review handoffs can retry", async () => {
918+await withTaskRegistryTempDir(
919+async (root) => {
920+process.env.OPENCLAW_STATE_DIR = root;
921+hoisted.sendMessageMock.mockResolvedValue({
922+channel: "notifychat",
923+to: "notifychat:123",
924+via: "direct",
925+});
926+927+const task = createTaskRecord({
928+runtime: "acp",
929+ownerKey: "agent:main:main",
930+scopeKind: "session",
931+requesterOrigin: {
932+channel: "notifychat",
933+to: "notifychat:123",
934+},
935+childSessionKey: "agent:main:acp:child",
936+runId: "run-delivery-retry",
937+task: "Investigate issue",
938+status: "succeeded",
939+deliveryStatus: "pending",
940+});
941+942+await waitForAssertion(() =>
943+expect(peekSystemEvents("agent:main:main")).toEqual([
944+expect.stringContaining("Background task ready for review: ACP background task"),
945+]),
946+);
947+expectRecordFields(requireTaskById(task.taskId), {
948+deliveryStatus: "pending",
949+});
950+951+resetSystemEventsForTest();
952+reloadTaskRegistryFromStore();
953+await maybeDeliverTaskTerminalUpdate(task.taskId);
954+955+expectRecordFields(requireTaskById(task.taskId), {
956+deliveryStatus: "pending",
957+});
958+expect(peekSystemEvents("agent:main:main")).toEqual([
959+expect.stringContaining("Background task ready for review: ACP background task"),
960+]);
961+expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
962+},
963+{ durableStore: true },
964+);
965+});
966+967+it("delivers non-delegated ACP completion to the requester channel when a delivery origin exists", async () => {
968+await withTaskRegistryTempDir(async (root) => {
969+process.env.OPENCLAW_STATE_DIR = root;
970+resetTaskRegistryMemoryForTest();
971+hoisted.sendMessageMock.mockResolvedValue({
972+channel: "notifychat",
973+to: "notifychat:123",
974+via: "direct",
975+});
976+977+createTaskRecord({
978+runtime: "acp",
979+ownerKey: "agent:main:main",
980+scopeKind: "session",
981+requesterOrigin: {
982+channel: "notifychat",
983+to: "notifychat:123",
984+threadId: "321",
985+},
986+runId: "run-direct-delivery",
987+task: "Investigate issue",
988+status: "running",
989+deliveryStatus: "pending",
990+startedAt: 100,
991+});
992+993+emitAgentEvent({
994+runId: "run-direct-delivery",
995+stream: "lifecycle",
996+data: {
997+phase: "end",
998+endedAt: 250,
999+},
1000+});
1001+1002+await waitForAssertion(() =>
1003+expectRecordFields(requireTaskByRunId("run-direct-delivery"), {
9061004status: "succeeded",
9071005deliveryStatus: "delivered",
9081006}),
@@ -999,7 +1097,7 @@ describe("task-registry", () => {
9991097});
10001098expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
10011099expect(peekSystemEvents(ownerKey)).toEqual([
1002-"Background task done: ACP background task (run run-grou).",
1100+expect.stringContaining("Background task ready for review: ACP background task"),
10031101]);
10041102expect(hasPendingHeartbeatWake()).toBe(true);
10051103});
@@ -1124,7 +1222,7 @@ describe("task-registry", () => {
11241222);
11251223const events = peekSystemEvents("agent:main:main");
11261224expect(events).toHaveLength(1);
1127-expect(events[0]).toContain("Background task done: ACP background task");
1225+expect(events[0]).toContain("Background task ready for review: ACP background task");
11281226expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
11291227});
11301228});
@@ -1204,11 +1302,14 @@ describe("task-registry", () => {
12041302},
12051303});
120613041207-await waitForAssertion(() =>
1208-expectRecordFields(sentMessageCall(), {
1209-content: "Background task done: ACP background task (run run-deta).",
1210-}),
1211-);
1305+await waitForAssertion(() => {
1306+const events = peekSystemEvents("agent:main:main");
1307+expect(events).toHaveLength(1);
1308+expect(events[0]).toBe(
1309+"Background task ready for review: ACP background task (run run-deta). Next: parent will review/verify before calling it done.",
1310+);
1311+});
1312+expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
12121313});
12131314});
12141315@@ -1279,14 +1380,15 @@ describe("task-registry", () => {
12791380terminalOutcome: "succeeded",
12801381});
128113821282-await waitForAssertion(() =>
1283-expectRecordFields(sentMessageCall(), {
1284-content:
1285-"Background task done: ACP background task (run run-succ). Created /tmp/file.txt and verified contents.",
1286-}),
1287-);
1288-expect(peekSystemEvents("agent:main:main")).toStrictEqual([]);
1289-expect(hasPendingHeartbeatWake()).toBe(false);
1383+await waitForAssertion(() => {
1384+const events = peekSystemEvents("agent:main:main");
1385+expect(events).toHaveLength(1);
1386+expect(events[0]).toBe(
1387+"Background task ready for review: ACP background task (run run-succ). Created /tmp/file.txt and verified contents. Next: parent will review/verify before calling it done.",
1388+);
1389+});
1390+expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
1391+expect(hasPendingHeartbeatWake()).toBe(true);
12901392});
12911393});
12921394@@ -1419,15 +1521,18 @@ describe("task-registry", () => {
14191521await maybeDeliverTaskTerminalUpdate(directTask.taskId);
14201522await maybeDeliverTaskTerminalUpdate(spawnedTask.taskId);
142115231422-expect(hoisted.sendMessageMock).toHaveBeenCalledTimes(1);
1524+expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
14231525expect(countMatching(listTaskRecords(), (task) => task.runId === "run-shared-delivery")).toBe(
142415261,
14251527);
14261528expectRecordFields(requireTaskByRunId("run-shared-delivery"), {
14271529taskId: directTask.taskId,
14281530task: "Spawn ACP child",
1429-deliveryStatus: "delivered",
1531+deliveryStatus: "pending",
14301532});
1533+expect(peekSystemEvents("agent:main:main")).toEqual([
1534+expect.stringContaining("Background task ready for review: ACP background task"),
1535+]);
14311536});
14321537});
14331538@@ -2764,12 +2869,10 @@ describe("task-registry", () => {
27642869});
27652870await flushAsyncWork();
276628712767-expectRecordFields(sentMessageCall(), {
2768-channel: "guildchat",
2769-to: "guildchat:123",
2770-content: "Background task done: ACP background task (run run-quie).",
2771-});
2772-expect(peekSystemEvents("agent:main:main")).toStrictEqual([]);
2872+expect(hoisted.sendMessageMock).not.toHaveBeenCalled();
2873+expect(peekSystemEvents("agent:main:main")).toEqual([
2874+"Background task ready for review: ACP background task (run run-quie). Next: parent will review/verify before calling it done.",
2875+]);
27732876relay.dispose();
27742877vi.useRealTimers();
27752878});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。