





















@@ -5,6 +5,7 @@ import {
55type ChannelBotLoopProtectionFacts,
66} from "openclaw/plugin-sdk/inbound-reply-dispatch";
77import type { ReplyPayload } from "openclaw/plugin-sdk/reply-dispatch-runtime";
8+import * as runtimeEnvModule from "openclaw/plugin-sdk/runtime-env";
89import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
910import type { DiscordMessagePreflightContext } from "./message-handler.preflight.js";
1011@@ -211,6 +212,7 @@ let createDiscordDirectMessageContextOverrides: typeof import("./message-handler
211212let threadBindingTesting: typeof import("./thread-bindings.js").testing;
212213let createThreadBindingManager: typeof import("./thread-bindings.js").createThreadBindingManager;
213214let processDiscordMessage: typeof import("./message-handler.process.js").processDiscordMessage;
215+let formatDiscordReplySkip: typeof import("./message-handler.process.js").formatDiscordReplySkip;
214216let notifyDiscordInboundEventOutboundSuccess: typeof import("../inbound-event-delivery.js").notifyDiscordInboundEventOutboundSuccess;
215217216218vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({
@@ -373,7 +375,8 @@ beforeAll(async () => {
373375await import("./message-handler.test-harness.js"));
374376({ testing: threadBindingTesting, createThreadBindingManager } =
375377await import("./thread-bindings.js"));
376-({ processDiscordMessage } = await import("./message-handler.process.js"));
378+({ processDiscordMessage, formatDiscordReplySkip } =
379+await import("./message-handler.process.js"));
377380({ notifyDiscordInboundEventOutboundSuccess } = await import("../inbound-event-delivery.js"));
378381});
379382@@ -2745,3 +2748,55 @@ describe("processDiscordMessage draft streaming", () => {
27452748expect(draftStream.update).not.toHaveBeenCalled();
27462749});
27472750});
2751+2752+describe("processDiscordMessage deliver-lambda abort logging", () => {
2753+it("emits logVerbose with formatDiscordReplySkip when deliver fires on a pre-aborted signal", async () => {
2754+// Capture logVerbose calls via the ESM namespace binding. We rely on the
2755+// same vi.spyOn pattern used in native-command.model-picker.test.ts so the
2756+// production module keeps its real logVerbose import while the test still
2757+// sees every invocation that the deliver lambda surfaces.
2758+const verboseSpy = vi.spyOn(runtimeEnvModule, "logVerbose").mockImplementation(() => {});
2759+2760+const abortController = new AbortController();
2761+// Drive the dispatcher so deliver actually runs: abort the signal inside
2762+// the dispatch mock and then queue a single block reply via the captured
2763+// dispatcher. The mocked createReplyDispatcherWithTyping (see line ~229)
2764+// routes sendBlockReply straight into the deliver lambda, where the very
2765+// first gate is `if (isProcessAborted(abortSignal)) return;` — the line
2766+// the PR added the logVerbose call to.
2767+dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
2768+abortController.abort();
2769+await params?.dispatcher.sendBlockReply({ text: "post-abort block payload" });
2770+return { queuedFinal: false, counts: { final: 0, tool: 0, block: 1 } };
2771+});
2772+2773+const ctx = await createAutomaticSourceDeliveryContext({
2774+abortSignal: abortController.signal,
2775+cfg: {
2776+messages: {
2777+ackReaction: "👀",
2778+},
2779+session: { store: "/tmp/openclaw-discord-process-test-sessions.json" },
2780+},
2781+});
2782+2783+await runProcessDiscordMessage(ctx);
2784+2785+// The base test harness routes through guild g1 / channel c1 (see
2786+// createBaseDiscordMessageContext) so the deliver lambda receives the
2787+// matching deliver target and session key from ctxPayload.SessionKey.
2788+const dispatchedSessionKey = getLastDispatchCtx()?.SessionKey;
2789+expect(dispatchedSessionKey).toBeTypeOf("string");
2790+const expectedLog = formatDiscordReplySkip({
2791+kind: "block",
2792+reason: "aborted before delivery",
2793+target: "channel:c1",
2794+sessionKey: dispatchedSessionKey,
2795+});
2796+const verboseCalls = verboseSpy.mock.calls.map((call) => call[0]);
2797+expect(verboseCalls).toContain(expectedLog);
2798+// Restore so other tests sharing this worker (isolate=false) keep the
2799+// real logVerbose binding.
2800+verboseSpy.mockRestore();
2801+});
2802+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。