




















@@ -377,7 +377,11 @@ describe("tryDispatchAcpReply", () => {
377377channelPluginMocks.getChannelPlugin.mockClear();
378378messageActionMocks.runMessageAction.mockReset();
379379messageActionMocks.runMessageAction.mockResolvedValue({ ok: true as const });
380-ttsMocks.maybeApplyTtsToPayload.mockClear();
380+ttsMocks.maybeApplyTtsToPayload.mockReset();
381+ttsMocks.maybeApplyTtsToPayload.mockImplementation(async (paramsUnknown: unknown) => {
382+const params = paramsUnknown as { payload: unknown };
383+return params.payload;
384+});
381385ttsMocks.resolveTtsConfig.mockReset();
382386ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
383387mediaUnderstandingMocks.applyMediaUnderstanding.mockReset();
@@ -393,7 +397,7 @@ describe("tryDispatchAcpReply", () => {
393397globalThis.fetch = originalFetch;
394398});
395399396-it("routes ACP block output to originating channel", async () => {
400+it("routes default ACP output to the originating channel as a final reply", async () => {
397401setReadyAcpResolution();
398402mockRoutedTextTurn("hello");
399403@@ -404,14 +408,17 @@ describe("tryDispatchAcpReply", () => {
404408shouldRouteToOriginating: true,
405409});
406410407-expect(result?.counts.block).toBe(1);
411+expect(result?.counts.block).toBe(0);
412+expect(result?.counts.final).toBe(1);
408413expect(routeMocks.routeReply).toHaveBeenCalledWith(
409414expect.objectContaining({
410415channel: "telegram",
411416to: "telegram:thread-1",
417+payload: expect.objectContaining({ text: "hello" }),
412418}),
413419);
414420expect(dispatcher.sendBlockReply).not.toHaveBeenCalled();
421+expect(dispatcher.sendFinalReply).not.toHaveBeenCalled();
415422});
416423417424it("persists ACP transcript when routed delivery fails", async () => {
@@ -1187,18 +1194,18 @@ describe("tryDispatchAcpReply", () => {
11871194);
11881195});
118911961190-it("does not deliver final fallback text when routed block text was already visible", async () => {
1197+it("does not add a fallback when routed ACP text was already delivered as final", async () => {
11911198setReadyAcpResolution();
11921199ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
11931200queueTtsReplies({ text: "CODEX_OK" }, {} as ReturnType<typeof ttsMocks.maybeApplyTtsToPayload>);
11941201const { result } = await runRoutedAcpTextTurn("CODEX_OK");
119512021196-expect(result?.counts.block).toBe(1);
1197-expect(result?.counts.final).toBe(0);
1203+expect(result?.counts.block).toBe(0);
1204+expect(result?.counts.final).toBe(1);
11981205expect(routeMocks.routeReply).toHaveBeenCalledTimes(1);
11991206});
120012071201-it("does not deliver final fallback text when routed discord block text was already visible", async () => {
1208+it("routes default ACP text as one final reply to Discord", async () => {
12021209setReadyAcpResolution();
12031210ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
12041211queueTtsReplies(
@@ -1216,8 +1223,8 @@ describe("tryDispatchAcpReply", () => {
12161223originatingTo: "channel:1478836151241412759",
12171224});
121812251219-expect(result?.counts.block).toBe(1);
1220-expect(result?.counts.final).toBe(0);
1226+expect(result?.counts.block).toBe(0);
1227+expect(result?.counts.final).toBe(1);
12211228expect(routeMocks.routeReply).toHaveBeenCalledTimes(1);
12221229expect(routeMocks.routeReply).toHaveBeenCalledWith(
12231230expect.objectContaining({
@@ -1228,7 +1235,7 @@ describe("tryDispatchAcpReply", () => {
12281235);
12291236});
123012371231-it("does not deliver final fallback text when routed Slack block text was already visible", async () => {
1238+it("routes default ACP text as one final reply to Slack", async () => {
12321239setReadyAcpResolution();
12331240ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
12341241queueTtsReplies(
@@ -1246,8 +1253,8 @@ describe("tryDispatchAcpReply", () => {
12461253originatingTo: "channel:C123",
12471254});
124812551249-expect(result?.counts.block).toBe(1);
1250-expect(result?.counts.final).toBe(0);
1256+expect(result?.counts.block).toBe(0);
1257+expect(result?.counts.final).toBe(1);
12511258expect(routeMocks.routeReply).toHaveBeenCalledTimes(1);
12521259expect(routeMocks.routeReply).toHaveBeenCalledWith(
12531260expect.objectContaining({
@@ -1258,7 +1265,7 @@ describe("tryDispatchAcpReply", () => {
12581265);
12591266});
126012671261-it("does not deliver final fallback text when direct block text was already visible", async () => {
1268+it("delivers default Telegram ACP text directly as a final reply", async () => {
12621269setReadyAcpResolution();
12631270ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
12641271queueTtsReplies({ text: "CODEX_OK" }, {} as ReturnType<typeof ttsMocks.maybeApplyTtsToPayload>);
@@ -1278,13 +1285,14 @@ describe("tryDispatchAcpReply", () => {
12781285expect(result?.counts.final).toBe(0);
12791286expect(counts.block).toBe(0);
12801287expect(counts.final).toBe(0);
1281-expect(dispatcher.sendBlockReply).toHaveBeenCalledWith(
1288+expect(result?.queuedFinal).toBe(true);
1289+expect(dispatcher.sendBlockReply).not.toHaveBeenCalled();
1290+expect(dispatcher.sendFinalReply).toHaveBeenCalledWith(
12821291expect.objectContaining({ text: "CODEX_OK" }),
12831292);
1284-expect(dispatcher.sendFinalReply).not.toHaveBeenCalled();
12851293});
128612941287-it("does not deliver final fallback text when direct discord block text was already visible", async () => {
1295+it("delivers default Discord ACP text directly as a final reply", async () => {
12881296setReadyAcpResolution();
12891297ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
12901298queueTtsReplies(
@@ -1307,13 +1315,14 @@ describe("tryDispatchAcpReply", () => {
13071315expect(result?.counts.final).toBe(0);
13081316expect(counts.block).toBe(0);
13091317expect(counts.final).toBe(0);
1310-expect(dispatcher.sendBlockReply).toHaveBeenCalledWith(
1318+expect(result?.queuedFinal).toBe(true);
1319+expect(dispatcher.sendBlockReply).not.toHaveBeenCalled();
1320+expect(dispatcher.sendFinalReply).toHaveBeenCalledWith(
13111321expect.objectContaining({ text: "Received." }),
13121322);
1313-expect(dispatcher.sendFinalReply).not.toHaveBeenCalled();
13141323});
131513241316-it("does not deliver final fallback text when direct Slack block text was already visible", async () => {
1325+it("delivers default Slack ACP text directly as a final reply", async () => {
13171326setReadyAcpResolution();
13181327ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
13191328queueTtsReplies(
@@ -1336,13 +1345,14 @@ describe("tryDispatchAcpReply", () => {
13361345expect(result?.counts.final).toBe(0);
13371346expect(counts.block).toBe(0);
13381347expect(counts.final).toBe(0);
1339-expect(dispatcher.sendBlockReply).toHaveBeenCalledWith(
1348+expect(result?.queuedFinal).toBe(true);
1349+expect(dispatcher.sendBlockReply).not.toHaveBeenCalled();
1350+expect(dispatcher.sendFinalReply).toHaveBeenCalledWith(
13401351expect.objectContaining({ text: "Slack says hi." }),
13411352);
1342-expect(dispatcher.sendFinalReply).not.toHaveBeenCalled();
13431353});
134413541345-it("treats visible telegram ACP block delivery as a successful final response", async () => {
1355+it("treats Telegram ACP final delivery as a successful final response", async () => {
13461356setReadyAcpResolution();
13471357ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
13481358queueTtsReplies({ text: "CODEX_OK" }, {} as ReturnType<typeof ttsMocks.maybeApplyTtsToPayload>);
@@ -1359,13 +1369,13 @@ describe("tryDispatchAcpReply", () => {
13591369});
1360137013611371expect(result?.queuedFinal).toBe(true);
1362-expect(dispatcher.sendBlockReply).toHaveBeenCalledWith(
1372+expect(dispatcher.sendBlockReply).not.toHaveBeenCalled();
1373+expect(dispatcher.sendFinalReply).toHaveBeenCalledWith(
13631374expect.objectContaining({ text: "CODEX_OK" }),
13641375);
1365-expect(dispatcher.sendFinalReply).not.toHaveBeenCalled();
13661376});
136713771368-it("preserves final fallback when direct block text is filtered by channels without a visibility override", async () => {
1378+it("delivers default ACP text as final for channels without a visibility override", async () => {
13691379setReadyAcpResolution();
13701380ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
13711381queueTtsReplies({ text: "CODEX_OK" }, {} as ReturnType<typeof ttsMocks.maybeApplyTtsToPayload>);
@@ -1385,9 +1395,8 @@ describe("tryDispatchAcpReply", () => {
13851395expect(result?.counts.final).toBe(0);
13861396expect(counts.block).toBe(0);
13871397expect(counts.final).toBe(0);
1388-expect(dispatcher.sendBlockReply).toHaveBeenCalledWith(
1389-expect.objectContaining({ text: "CODEX_OK" }),
1390-);
1398+expect(result?.queuedFinal).toBe(true);
1399+expect(dispatcher.sendBlockReply).not.toHaveBeenCalled();
13911400expect(dispatcher.sendFinalReply).toHaveBeenCalledWith(
13921401expect.objectContaining({ text: "CODEX_OK" }),
13931402);
@@ -1450,6 +1459,12 @@ describe("tryDispatchAcpReply", () => {
14501459it("honors the configured default account for ACP projector chunking when AccountId is omitted", async () => {
14511460setReadyAcpResolution();
14521461const cfg = createAcpTestConfig({
1462+acp: {
1463+enabled: true,
1464+stream: {
1465+deliveryMode: "live",
1466+},
1467+},
14531468channels: {
14541469discord: {
14551470defaultAccount: "work",
@@ -1489,7 +1504,7 @@ describe("tryDispatchAcpReply", () => {
14891504);
14901505});
149115061492-it("does not add a second routed payload when routed block text was already visible", async () => {
1507+it("does not add a second routed payload when routed final text was already visible", async () => {
14931508setReadyAcpResolution();
14941509ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "final" });
14951510queueTtsReplies({ text: "Task completed" }, {
@@ -1498,21 +1513,21 @@ describe("tryDispatchAcpReply", () => {
14981513} as MockTtsReply);
14991514const { result } = await runRoutedAcpTextTurn("Task completed");
150015151501-expect(result?.counts.block).toBe(1);
1502-expect(result?.counts.final).toBe(0);
1516+expect(result?.counts.block).toBe(0);
1517+expect(result?.counts.final).toBe(1);
15031518expect(routeMocks.routeReply).toHaveBeenCalledTimes(1);
15041519expectRoutedPayload(1, {
15051520text: "Task completed",
15061521});
15071522});
150815231509-it("skips fallback when TTS mode is all (blocks already processed with TTS)", async () => {
1524+it("skips fallback when TTS mode is all and final delivery already succeeded", async () => {
15101525setReadyAcpResolution();
15111526ttsMocks.resolveTtsConfig.mockReturnValue({ mode: "all" });
15121527const { result } = await runRoutedAcpTextTurn("Response");
151315281514-expect(result?.counts.block).toBe(1);
1515-expect(result?.counts.final).toBe(0);
1529+expect(result?.counts.block).toBe(0);
1530+expect(result?.counts.final).toBe(1);
15161531expect(routeMocks.routeReply).toHaveBeenCalledTimes(1);
15171532});
15181533此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。