fix(discord): skip bot messages before debounce

This commit is contained in:
Shadow
2026-03-03 11:05:45 -06:00
parent 05446d6b6b
commit 548b15d8e0
3 changed files with 84 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Docs/tool-loop detection config keys: align `docs/tools/loop-detection.md` examples and field names with the current `tools.loopDetection` schema to prevent copy-paste validation failures from outdated keys. (#33182) Thanks @Mylszd.
- Discord/inbound debouncer: skip bot-own MESSAGE_CREATE events before they reach the debounce queue to avoid self-triggered slowdowns in busy servers. Thanks @thewilloftheshadow.
- Discord/presence defaults: send an online presence update on ready when no custom presence is configured so bots no longer appear offline by default. Thanks @thewilloftheshadow.
- Discord/typing cleanup: stop typing indicators after silent/NO_REPLY runs by marking the run complete before dispatch idle cleanup. Thanks @thewilloftheshadow.
- Discord/voice messages: request upload slots with JSON fetch calls so voice message uploads no longer fail with content-type errors. Thanks @thewilloftheshadow.

View File

@@ -0,0 +1,73 @@
import { describe, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/types.js";
import { createDiscordMessageHandler } from "./message-handler.js";
import { createNoopThreadBindingManager } from "./thread-bindings.js";
const BOT_USER_ID = "bot-123";
function createHandlerParams(overrides?: Partial<{ botUserId: string }>) {
const cfg: OpenClawConfig = {
channels: {
discord: {
enabled: true,
token: "test-token",
groupPolicy: "allowlist",
},
},
};
return {
cfg,
discordConfig: cfg.channels?.discord,
accountId: "default",
token: "test-token",
runtime: {
log: vi.fn(),
error: vi.fn(),
exit: (code: number): never => {
throw new Error(`exit ${code}`);
},
},
botUserId: overrides?.botUserId ?? BOT_USER_ID,
guildHistories: new Map(),
historyLimit: 0,
mediaMaxBytes: 10_000,
textLimit: 2000,
replyToMode: "off" as const,
dmEnabled: true,
groupDmEnabled: false,
threadBindings: createNoopThreadBindingManager("default"),
};
}
function createMessageData(authorId: string) {
return {
message: {
id: "msg-1",
author: { id: authorId, bot: authorId === BOT_USER_ID },
content: "hello",
channel_id: "ch-1",
},
channel_id: "ch-1",
};
}
describe("createDiscordMessageHandler bot-self filter", () => {
it("skips bot-own messages before debouncer", async () => {
const handler = createDiscordMessageHandler(createHandlerParams());
await handler(createMessageData(BOT_USER_ID) as never, {} as never);
});
it("processes messages from other users", async () => {
const handler = createDiscordMessageHandler(createHandlerParams());
try {
await handler(
createMessageData("user-456") as never,
{
fetchChannel: vi.fn().mockResolvedValue(null),
} as never,
);
} catch {
// Expected: pipeline fails without full mock, but it passed the filter.
}
});
});

View File

@@ -141,6 +141,16 @@ export function createDiscordMessageHandler(
return async (data, client) => {
try {
// Filter bot-own messages before they enter the debounce queue.
// The same check exists in preflightDiscordMessage(), but by that point
// the message has already consumed debounce capacity and blocked
// legitimate user messages. On active servers this causes cumulative
// slowdown (see #15874).
const msgAuthorId = data.message?.author?.id ?? data.author?.id;
if (params.botUserId && msgAuthorId === params.botUserId) {
return;
}
await debouncer.enqueue({ data, client });
} catch (err) {
params.runtime.error?.(danger(`handler failed: ${String(err)}`));