mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 01:31:08 +00:00
fix(discord): short-circuit bound thread self-loop drops
This commit is contained in:
@@ -122,6 +122,56 @@ function isBoundThreadBotSystemMessage(params: {
|
||||
return DISCORD_BOUND_THREAD_SYSTEM_PREFIXES.some((prefix) => text.startsWith(prefix));
|
||||
}
|
||||
|
||||
type BoundThreadLookupRecordLike = {
|
||||
webhookId?: string | null;
|
||||
metadata?: {
|
||||
webhookId?: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
function isDiscordThreadChannelType(type: ChannelType | undefined): boolean {
|
||||
return (
|
||||
type === ChannelType.PublicThread ||
|
||||
type === ChannelType.PrivateThread ||
|
||||
type === ChannelType.AnnouncementThread
|
||||
);
|
||||
}
|
||||
|
||||
function isDiscordThreadChannelMessage(params: {
|
||||
isGuildMessage: boolean;
|
||||
message: Message;
|
||||
channelInfo: import("./message-utils.js").DiscordChannelInfo | null;
|
||||
}): boolean {
|
||||
if (!params.isGuildMessage) {
|
||||
return false;
|
||||
}
|
||||
const channel =
|
||||
"channel" in params.message ? (params.message as { channel?: unknown }).channel : undefined;
|
||||
return Boolean(
|
||||
(channel &&
|
||||
typeof channel === "object" &&
|
||||
"isThread" in channel &&
|
||||
typeof (channel as { isThread?: unknown }).isThread === "function" &&
|
||||
(channel as { isThread: () => boolean }).isThread()) ||
|
||||
isDiscordThreadChannelType(params.channelInfo?.type),
|
||||
);
|
||||
}
|
||||
|
||||
function resolveInjectedBoundThreadLookupRecord(params: {
|
||||
threadBindings: DiscordMessagePreflightParams["threadBindings"];
|
||||
threadId: string;
|
||||
}): BoundThreadLookupRecordLike | undefined {
|
||||
const getByThreadId = (params.threadBindings as { getByThreadId?: (threadId: string) => unknown })
|
||||
.getByThreadId;
|
||||
if (typeof getByThreadId !== "function") {
|
||||
return undefined;
|
||||
}
|
||||
const binding = getByThreadId(params.threadId);
|
||||
return binding && typeof binding === "object"
|
||||
? (binding as BoundThreadLookupRecordLike)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function resolveDiscordMentionState(params: {
|
||||
authorIsBot: boolean;
|
||||
botId?: string;
|
||||
@@ -180,16 +230,18 @@ export function shouldIgnoreBoundThreadWebhookMessage(params: {
|
||||
accountId?: string;
|
||||
threadId?: string;
|
||||
webhookId?: string | null;
|
||||
threadBinding?: SessionBindingRecord;
|
||||
threadBinding?: BoundThreadLookupRecordLike;
|
||||
}): boolean {
|
||||
const webhookId = params.webhookId?.trim() || "";
|
||||
if (!webhookId) {
|
||||
return false;
|
||||
}
|
||||
const boundWebhookId =
|
||||
typeof params.threadBinding?.metadata?.webhookId === "string"
|
||||
? params.threadBinding.metadata.webhookId.trim()
|
||||
: "";
|
||||
typeof params.threadBinding?.webhookId === "string"
|
||||
? params.threadBinding.webhookId.trim()
|
||||
: typeof params.threadBinding?.metadata?.webhookId === "string"
|
||||
? params.threadBinding.metadata.webhookId.trim()
|
||||
: "";
|
||||
if (!boundWebhookId) {
|
||||
const threadId = params.threadId?.trim() || "";
|
||||
if (!threadId) {
|
||||
@@ -371,6 +423,43 @@ export async function preflightDiscordMessage(
|
||||
}
|
||||
const isDirectMessage = channelInfo?.type === ChannelType.DM;
|
||||
const isGroupDm = channelInfo?.type === ChannelType.GroupDM;
|
||||
const messageText = resolveDiscordMessageText(message, {
|
||||
includeForwarded: true,
|
||||
});
|
||||
const injectedBoundThreadBinding =
|
||||
!isDirectMessage && !isGroupDm
|
||||
? resolveInjectedBoundThreadLookupRecord({
|
||||
threadBindings: params.threadBindings,
|
||||
threadId: messageChannelId,
|
||||
})
|
||||
: undefined;
|
||||
if (
|
||||
shouldIgnoreBoundThreadWebhookMessage({
|
||||
accountId: params.accountId,
|
||||
threadId: messageChannelId,
|
||||
webhookId,
|
||||
threadBinding: injectedBoundThreadBinding,
|
||||
})
|
||||
) {
|
||||
logVerbose(`discord: drop bound-thread webhook echo message ${message.id}`);
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
isBoundThreadBotSystemMessage({
|
||||
isBoundThreadSession:
|
||||
Boolean(injectedBoundThreadBinding) &&
|
||||
isDiscordThreadChannelMessage({
|
||||
isGuildMessage,
|
||||
message,
|
||||
channelInfo,
|
||||
}),
|
||||
isBotAuthor: Boolean(author.bot),
|
||||
text: messageText,
|
||||
})
|
||||
) {
|
||||
logVerbose(`discord: drop bound-thread bot system message ${message.id}`);
|
||||
return null;
|
||||
}
|
||||
const data = message === params.data.message ? params.data : { ...params.data, message };
|
||||
logDebug(
|
||||
`[discord-preflight] channelId=${messageChannelId} guild_id=${params.data.guild_id} channelType=${channelInfo?.type} isGuild=${isGuildMessage} isDM=${isDirectMessage} isGroupDm=${isGroupDm}`,
|
||||
@@ -461,9 +550,6 @@ export async function preflightDiscordMessage(
|
||||
const baseText = resolveDiscordMessageText(message, {
|
||||
includeForwarded: false,
|
||||
});
|
||||
const messageText = resolveDiscordMessageText(message, {
|
||||
includeForwarded: true,
|
||||
});
|
||||
|
||||
// Intercept text-only slash commands (e.g. user typing "/reset" instead of using Discord's slash command picker)
|
||||
// These should not be forwarded to the agent; proper slash command interactions are handled elsewhere
|
||||
|
||||
Reference in New Issue
Block a user