


























@@ -1,7 +1,7 @@
11import { beforeEach, describe, expect, it, vi } from "vitest";
22import type { OpenClawConfig } from "../../config/config.js";
33import { createAcpDispatchDeliveryCoordinator } from "./dispatch-acp-delivery.js";
4-import type { ReplyDispatcher } from "./reply-dispatcher.js";
4+import { createReplyDispatcher, type ReplyDispatcher } from "./reply-dispatcher.js";
55import { buildTestCtx } from "./test-ctx.js";
66import { createAcpTestConfig } from "./test-fixtures/acp-runtime.js";
77@@ -240,6 +240,93 @@ describe("createAcpDispatchDeliveryCoordinator", () => {
240240expect(coordinator.getRoutedCounts().block).toBe(0);
241241});
242242243+it("waits for direct block dispatcher delivery before resolving block delivery", async () => {
244+const delivered: unknown[] = [];
245+let releaseDelivery: (() => void) | undefined;
246+let markDeliveryStarted: (() => void) | undefined;
247+const deliveryStarted = new Promise<void>((resolve) => {
248+markDeliveryStarted = resolve;
249+});
250+const deliveryGate = new Promise<void>((resolve) => {
251+releaseDelivery = resolve;
252+});
253+const dispatcher = createReplyDispatcher({
254+deliver: async (payload) => {
255+delivered.push(payload);
256+markDeliveryStarted?.();
257+await deliveryGate;
258+},
259+});
260+const coordinator = createAcpDispatchDeliveryCoordinator({
261+cfg: createAcpTestConfig(),
262+ctx: buildTestCtx({
263+Provider: "visiblechat",
264+Surface: "visiblechat",
265+SessionKey: "agent:codex-acp:session-1",
266+}),
267+ dispatcher,
268+inboundAudio: false,
269+shouldRouteToOriginating: false,
270+});
271+272+let deliverySettled = false;
273+const deliveryPromise = coordinator.deliver("block", { text: "hello" }, { skipTts: true });
274+void deliveryPromise.then(() => {
275+deliverySettled = true;
276+});
277+278+await deliveryStarted;
279+280+expect(delivered).toEqual([{ text: "hello" }]);
281+expect(deliverySettled).toBe(false);
282+283+releaseDelivery?.();
284+await expect(deliveryPromise).resolves.toBe(true);
285+expect(deliverySettled).toBe(true);
286+});
287+288+it("stops waiting for direct block delivery when the ACP dispatch aborts", async () => {
289+const delivered: unknown[] = [];
290+const controller = new AbortController();
291+let releaseDelivery: (() => void) | undefined;
292+let markDeliveryStarted: (() => void) | undefined;
293+const deliveryStarted = new Promise<void>((resolve) => {
294+markDeliveryStarted = resolve;
295+});
296+const deliveryGate = new Promise<void>((resolve) => {
297+releaseDelivery = resolve;
298+});
299+const dispatcher = createReplyDispatcher({
300+deliver: async (payload) => {
301+delivered.push(payload);
302+markDeliveryStarted?.();
303+await deliveryGate;
304+},
305+});
306+const coordinator = createAcpDispatchDeliveryCoordinator({
307+cfg: createAcpTestConfig(),
308+ctx: buildTestCtx({
309+Provider: "visiblechat",
310+Surface: "visiblechat",
311+SessionKey: "agent:codex-acp:session-1",
312+}),
313+ dispatcher,
314+inboundAudio: false,
315+shouldRouteToOriginating: false,
316+abortSignal: controller.signal,
317+});
318+319+const deliveryPromise = coordinator.deliver("block", { text: "hello" }, { skipTts: true });
320+await deliveryStarted;
321+controller.abort();
322+323+await expect(deliveryPromise).resolves.toBe(true);
324+expect(delivered).toEqual([{ text: "hello" }]);
325+326+releaseDelivery?.();
327+await dispatcher.waitForIdle();
328+});
329+243330it("strips split TTS directives from visible ACP block delivery", async () => {
244331const dispatcher = createDispatcher();
245332const coordinator = createAcpDispatchDeliveryCoordinator({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。