

























@@ -2727,6 +2727,68 @@ describe("dispatchReplyFromConfig", () => {
27272727expect(replyResolver).toHaveBeenCalledTimes(1);
27282728});
272927292730+it("keeps message-tool-only delivery mode on duplicate inbound returns", async () => {
2731+setNoAbort();
2732+const cfg = emptyConfig;
2733+const ctx = buildTestCtx({
2734+Provider: "telegram",
2735+Surface: "telegram",
2736+ChatType: "channel",
2737+To: "telegram:chat:123",
2738+MessageSid: "msg-tool-only-duplicate",
2739+SessionKey: "agent:main:telegram:channel:123",
2740+});
2741+const replyResolver = vi.fn(async () => ({ text: "hi" }) as ReplyPayload);
2742+2743+const first = await dispatchReplyFromConfig({
2744+ ctx,
2745+ cfg,
2746+dispatcher: createDispatcher(),
2747+ replyResolver,
2748+});
2749+const duplicate = await dispatchReplyFromConfig({
2750+ ctx,
2751+ cfg,
2752+dispatcher: createDispatcher(),
2753+ replyResolver,
2754+});
2755+2756+expect(replyResolver).toHaveBeenCalledTimes(1);
2757+expect(first.sourceReplyDeliveryMode).toBe("message_tool_only");
2758+expect(duplicate.sourceReplyDeliveryMode).toBe("message_tool_only");
2759+});
2760+2761+it("does not mark duplicate inbound returns as tool-only when message is unavailable", async () => {
2762+setNoAbort();
2763+const cfg = { tools: { allow: ["read"] } } as OpenClawConfig;
2764+const ctx = buildTestCtx({
2765+Provider: "telegram",
2766+Surface: "telegram",
2767+ChatType: "channel",
2768+To: "telegram:chat:123",
2769+MessageSid: "msg-tool-unavailable-duplicate",
2770+SessionKey: "agent:main:telegram:channel:123",
2771+});
2772+const replyResolver = vi.fn(async () => ({ text: "visible fallback" }) as ReplyPayload);
2773+2774+const first = await dispatchReplyFromConfig({
2775+ ctx,
2776+ cfg,
2777+dispatcher: createDispatcher(),
2778+ replyResolver,
2779+});
2780+const duplicate = await dispatchReplyFromConfig({
2781+ ctx,
2782+ cfg,
2783+dispatcher: createDispatcher(),
2784+ replyResolver,
2785+});
2786+2787+expect(replyResolver).toHaveBeenCalledTimes(1);
2788+expect(first.sourceReplyDeliveryMode).toBeUndefined();
2789+expect(duplicate.sourceReplyDeliveryMode).toBeUndefined();
2790+});
2791+27302792it("keeps local discord exec approval tool prompts when the native runtime is inactive", async () => {
27312793setNoAbort();
27322794const cfg = {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。