fix(discord): do not bypass requireMention for configuredBinding channels

This commit is contained in:
gfzhx 2026-03-28 20:57:04 +08:00 committed by Ayaan Zaidi
parent 7e7e45c2f3
commit d458e1d05c
3 changed files with 89 additions and 2 deletions

View File

@ -305,7 +305,7 @@ describe("preflightDiscordMessage configured ACP bindings", () => {
author: message.author,
message,
}),
guildEntries: createAllowedGuildEntries(true),
guildEntries: createAllowedGuildEntries(false),
}),
);

View File

@ -766,6 +766,93 @@ describe("preflightDiscordMessage", () => {
expect(result).not.toBeNull();
expect(result?.wasMentioned).toBe(true);
});
it("drops guild message without mention when channel has configuredBinding and requireMention: true", async () => {
const conversationRuntime = await import("openclaw/plugin-sdk/conversation-runtime");
const channelId = "ch-binding-1";
const bindingRoute = {
bindingResolution: {
record: {
targetSessionKey: "agent:main:acp:binding:discord:default:abc",
targetKind: "session",
},
} as never,
route: { agentId: "main", matchedBy: "binding.channel" } as never,
boundSessionKey: "agent:main:acp:binding:discord:default:abc",
boundAgentId: "main",
};
const routeSpy = vi
.spyOn(conversationRuntime, "resolveConfiguredBindingRoute")
.mockReturnValue(bindingRoute);
const ensureSpy = vi
.spyOn(conversationRuntime, "ensureConfiguredBindingRouteReady")
.mockResolvedValue({ ok: true });
try {
const result = await runGuildPreflight({
channelId,
guildId: "guild-1",
message: createDiscordMessage({
id: "m-binding-1",
channelId,
content: "hello without mention",
author: { id: "user-1", bot: false, username: "alice" },
}),
discordConfig: {} as DiscordConfig,
guildEntries: {
"guild-1": { channels: { [channelId]: { allow: true, requireMention: true } } },
},
});
expect(result).toBeNull();
} finally {
routeSpy.mockRestore();
ensureSpy.mockRestore();
}
});
it("allows guild message with mention when channel has configuredBinding and requireMention: true", async () => {
const conversationRuntime = await import("openclaw/plugin-sdk/conversation-runtime");
const channelId = "ch-binding-2";
const bindingRoute = {
bindingResolution: {
record: {
targetSessionKey: "agent:main:acp:binding:discord:default:def",
targetKind: "session",
},
} as never,
route: { agentId: "main", matchedBy: "binding.channel" } as never,
boundSessionKey: "agent:main:acp:binding:discord:default:def",
boundAgentId: "main",
};
const routeSpy = vi
.spyOn(conversationRuntime, "resolveConfiguredBindingRoute")
.mockReturnValue(bindingRoute);
const ensureSpy = vi
.spyOn(conversationRuntime, "ensureConfiguredBindingRouteReady")
.mockResolvedValue({ ok: true });
try {
const result = await runGuildPreflight({
channelId,
guildId: "guild-1",
message: createDiscordMessage({
id: "m-binding-2",
channelId,
content: "hello <@openclaw-bot>",
author: { id: "user-1", bot: false, username: "alice" },
mentionedUsers: [{ id: "openclaw-bot" }],
}),
discordConfig: {} as DiscordConfig,
guildEntries: {
"guild-1": { channels: { [channelId]: { allow: true, requireMention: true } } },
},
});
expect(result).not.toBeNull();
} finally {
routeSpy.mockRestore();
ensureSpy.mockRestore();
}
});
});
describe("shouldIgnoreBoundThreadWebhookMessage", () => {

View File

@ -490,7 +490,7 @@ export async function preflightDiscordMessage(
});
const boundAgentId = boundSessionKey ? effectiveRoute.agentId : undefined;
const isBoundThreadSession = Boolean(threadBinding && earlyThreadChannel);
const bypassMentionRequirement = isBoundThreadSession || Boolean(configuredBinding);
const bypassMentionRequirement = isBoundThreadSession;
if (
isBoundThreadBotSystemMessage({
isBoundThreadSession,