fix: discord mention handling (#33224) (thanks @thewilloftheshadow) (#33224)

This commit is contained in:
Shadow
2026-03-03 10:32:22 -06:00
committed by GitHub
parent a3112d6c5f
commit d493861c16
18 changed files with 681 additions and 17 deletions

View File

@@ -354,6 +354,238 @@ describe("preflightDiscordMessage", () => {
expect(result?.shouldRequireMention).toBe(false);
});
it("drops guild messages that mention another user when ignoreOtherMentions=true", async () => {
const channelId = "channel-other-mention-1";
const guildId = "guild-other-mention-1";
const client = {
fetchChannel: async (id: string) => {
if (id === channelId) {
return {
id: channelId,
type: ChannelType.GuildText,
name: "general",
};
}
return null;
},
} as unknown as import("@buape/carbon").Client;
const message = {
id: "m-other-mention-1",
content: "hello <@999>",
timestamp: new Date().toISOString(),
channelId,
attachments: [],
mentionedUsers: [{ id: "999" }],
mentionedRoles: [],
mentionedEveryone: false,
author: {
id: "user-1",
bot: false,
username: "Alice",
},
} as unknown as import("@buape/carbon").Message;
const result = await preflightDiscordMessage({
cfg: {
session: {
mainKey: "main",
scope: "per-sender",
},
} as import("../../config/config.js").OpenClawConfig,
discordConfig: {} as NonNullable<
import("../../config/config.js").OpenClawConfig["channels"]
>["discord"],
accountId: "default",
token: "token",
runtime: {} as import("../../runtime.js").RuntimeEnv,
botUserId: "openclaw-bot",
guildHistories: new Map(),
historyLimit: 0,
mediaMaxBytes: 1_000_000,
textLimit: 2_000,
replyToMode: "all",
dmEnabled: true,
groupDmEnabled: true,
ackReactionScope: "direct",
groupPolicy: "open",
threadBindings: createNoopThreadBindingManager("default"),
guildEntries: {
[guildId]: {
requireMention: false,
ignoreOtherMentions: true,
},
},
data: {
channel_id: channelId,
guild_id: guildId,
guild: {
id: guildId,
name: "Guild One",
},
author: message.author,
message,
} as unknown as import("./listeners.js").DiscordMessageEvent,
client,
});
expect(result).toBeNull();
});
it("does not drop @everyone messages when ignoreOtherMentions=true", async () => {
const channelId = "channel-other-mention-everyone";
const guildId = "guild-other-mention-everyone";
const client = {
fetchChannel: async (id: string) => {
if (id === channelId) {
return {
id: channelId,
type: ChannelType.GuildText,
name: "general",
};
}
return null;
},
} as unknown as import("@buape/carbon").Client;
const message = {
id: "m-other-mention-everyone",
content: "@everyone heads up",
timestamp: new Date().toISOString(),
channelId,
attachments: [],
mentionedUsers: [],
mentionedRoles: [],
mentionedEveryone: true,
author: {
id: "user-1",
bot: false,
username: "Alice",
},
} as unknown as import("@buape/carbon").Message;
const result = await preflightDiscordMessage({
cfg: {
session: {
mainKey: "main",
scope: "per-sender",
},
} as import("../../config/config.js").OpenClawConfig,
discordConfig: {} as NonNullable<
import("../../config/config.js").OpenClawConfig["channels"]
>["discord"],
accountId: "default",
token: "token",
runtime: {} as import("../../runtime.js").RuntimeEnv,
botUserId: "openclaw-bot",
guildHistories: new Map(),
historyLimit: 0,
mediaMaxBytes: 1_000_000,
textLimit: 2_000,
replyToMode: "all",
dmEnabled: true,
groupDmEnabled: true,
ackReactionScope: "direct",
groupPolicy: "open",
threadBindings: createNoopThreadBindingManager("default"),
guildEntries: {
[guildId]: {
requireMention: false,
ignoreOtherMentions: true,
},
},
data: {
channel_id: channelId,
guild_id: guildId,
guild: {
id: guildId,
name: "Guild One",
},
author: message.author,
message,
} as unknown as import("./listeners.js").DiscordMessageEvent,
client,
});
expect(result).not.toBeNull();
expect(result?.hasAnyMention).toBe(true);
});
it("ignores bot-sent @everyone mentions for detection", async () => {
const channelId = "channel-everyone-1";
const guildId = "guild-everyone-1";
const client = {
fetchChannel: async (id: string) => {
if (id === channelId) {
return {
id: channelId,
type: ChannelType.GuildText,
name: "general",
};
}
return null;
},
} as unknown as import("@buape/carbon").Client;
const message = {
id: "m-everyone-1",
content: "@everyone heads up",
timestamp: new Date().toISOString(),
channelId,
attachments: [],
mentionedUsers: [],
mentionedRoles: [],
mentionedEveryone: true,
author: {
id: "relay-bot-1",
bot: true,
username: "Relay",
},
} as unknown as import("@buape/carbon").Message;
const result = await preflightDiscordMessage({
cfg: {
session: {
mainKey: "main",
scope: "per-sender",
},
} as import("../../config/config.js").OpenClawConfig,
discordConfig: {
allowBots: true,
} as NonNullable<import("../../config/config.js").OpenClawConfig["channels"]>["discord"],
accountId: "default",
token: "token",
runtime: {} as import("../../runtime.js").RuntimeEnv,
botUserId: "openclaw-bot",
guildHistories: new Map(),
historyLimit: 0,
mediaMaxBytes: 1_000_000,
textLimit: 2_000,
replyToMode: "all",
dmEnabled: true,
groupDmEnabled: true,
ackReactionScope: "direct",
groupPolicy: "open",
threadBindings: createNoopThreadBindingManager("default"),
guildEntries: {
[guildId]: {
requireMention: false,
},
},
data: {
channel_id: channelId,
guild_id: guildId,
guild: {
id: guildId,
name: "Guild One",
},
author: message.author,
message,
} as unknown as import("./listeners.js").DiscordMessageEvent,
client,
});
expect(result).not.toBeNull();
expect(result?.hasAnyMention).toBe(false);
});
it("uses attachment content_type for guild audio preflight mention detection", async () => {
transcribeFirstAudioMock.mockResolvedValue("hey openclaw");