mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:50:43 +00:00
fix(discord): suppress bound thread webhook copies
This commit is contained in:
@@ -23,6 +23,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Gateway/logging: keep deferred channel startup logs on the subsystem logger, so Slack, Discord, Telegram, and voice-call startup messages keep timestamped prefixes. Thanks @vincentkoc.
|
||||
- Discord/threads: ignore webhook-authored copies in already-bound Discord session threads even when the webhook id differs, preventing PluralKit proxy copies from creating duplicate turn pressure. Fixes #52005. Thanks @acgh213.
|
||||
- Discord/threads: return the created thread as partial success when the follow-up initial message fails, so agents do not retry thread creation and create empty duplicate threads. Fixes #48450. Thanks @dahifi.
|
||||
- Discord/components: consume every button or select in a non-reusable component message after the first authorized click, so single-use panels cannot fire sibling callbacks. Fixes #54227. Thanks @fujiwarakasei.
|
||||
- Discord/reactions: skip reaction listener registration when DMs and group DMs are disabled and every configured guild has `reactionNotifications: "off"`, avoiding needless reaction-event queue work. Fixes #47516. Thanks @x4v13r1120.
|
||||
|
||||
@@ -146,16 +146,19 @@ export function shouldIgnoreBoundThreadWebhookMessage(params: {
|
||||
normalizeOptionalString(params.threadBinding?.webhookId) ??
|
||||
normalizeOptionalString(params.threadBinding?.metadata?.webhookId) ??
|
||||
"";
|
||||
if (!boundWebhookId) {
|
||||
const threadId = normalizeOptionalString(params.threadId) ?? "";
|
||||
if (!threadId) {
|
||||
return false;
|
||||
}
|
||||
return isRecentlyUnboundThreadWebhookMessage({
|
||||
accountId: params.accountId,
|
||||
threadId,
|
||||
webhookId,
|
||||
});
|
||||
if (boundWebhookId && webhookId === boundWebhookId) {
|
||||
return true;
|
||||
}
|
||||
return webhookId === boundWebhookId;
|
||||
const threadId = normalizeOptionalString(params.threadId) ?? "";
|
||||
if (!threadId) {
|
||||
return false;
|
||||
}
|
||||
if (params.threadBinding) {
|
||||
return true;
|
||||
}
|
||||
return isRecentlyUnboundThreadWebhookMessage({
|
||||
accountId: params.accountId,
|
||||
threadId,
|
||||
webhookId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -624,7 +624,7 @@ describe("preflightDiscordMessage", () => {
|
||||
expect(result?.boundSessionKey).toBe(threadBinding.targetSessionKey);
|
||||
});
|
||||
|
||||
it("drops hydrated bound-thread webhook echoes after fetching an empty payload", async () => {
|
||||
it("drops hydrated bound-thread webhook copies after fetching an empty payload", async () => {
|
||||
const threadBinding = createThreadBinding({
|
||||
targetKind: "session",
|
||||
targetSessionKey: "agent:main:acp:discord-thread-1",
|
||||
@@ -685,6 +685,38 @@ describe("preflightDiscordMessage", () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("drops bound-thread webhook copies from other webhook ids", async () => {
|
||||
const threadBinding = createThreadBinding({
|
||||
targetKind: "session",
|
||||
targetSessionKey: "agent:main:acp:discord-thread-1",
|
||||
});
|
||||
const threadId = "thread-webhook-proxy-1";
|
||||
const parentId = "channel-parent-webhook-proxy-1";
|
||||
const message = createDiscordMessage({
|
||||
id: "m-webhook-proxy-1",
|
||||
channelId: threadId,
|
||||
content: "proxied user message",
|
||||
webhook_id: "pluralkit-webhook-1",
|
||||
author: {
|
||||
id: "relay-bot-1",
|
||||
bot: true,
|
||||
username: "Proxy",
|
||||
},
|
||||
});
|
||||
|
||||
const result = await runThreadBoundPreflight({
|
||||
threadId,
|
||||
parentId,
|
||||
message,
|
||||
threadBinding,
|
||||
discordConfig: {
|
||||
allowBots: true,
|
||||
} as DiscordConfig,
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("bypasses mention gating in bound threads for allowed bot senders", async () => {
|
||||
const threadBinding = createThreadBinding();
|
||||
const threadId = "thread-bot-focus";
|
||||
@@ -1445,18 +1477,20 @@ describe("shouldIgnoreBoundThreadWebhookMessage", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when webhook ids differ", () => {
|
||||
it("returns true when a bound thread receives a different webhook id", () => {
|
||||
expect(
|
||||
shouldIgnoreBoundThreadWebhookMessage({
|
||||
threadId: "thread-1",
|
||||
webhookId: "wh-other",
|
||||
threadBinding: createThreadBinding(),
|
||||
}),
|
||||
).toBe(false);
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when there is no bound thread webhook", () => {
|
||||
it("returns true when a bound thread receives a webhook without a recorded bound webhook id", () => {
|
||||
expect(
|
||||
shouldIgnoreBoundThreadWebhookMessage({
|
||||
threadId: "thread-1",
|
||||
webhookId: "wh-1",
|
||||
threadBinding: createThreadBinding({
|
||||
metadata: {
|
||||
@@ -1464,6 +1498,15 @@ describe("shouldIgnoreBoundThreadWebhookMessage", () => {
|
||||
},
|
||||
}),
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for differing webhook ids without a known thread id", () => {
|
||||
expect(
|
||||
shouldIgnoreBoundThreadWebhookMessage({
|
||||
webhookId: "wh-other",
|
||||
threadBinding: createThreadBinding(),
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user