diff --git a/packages/client-discord/src/messages.ts b/packages/client-discord/src/messages.ts index 5487e6eb57..cb4371bf8b 100644 --- a/packages/client-discord/src/messages.ts +++ b/packages/client-discord/src/messages.ts @@ -507,6 +507,27 @@ export class MessageManager { } } + private _isMessageForMe(message: DiscordMessage): boolean { + const isMentioned = message.mentions.users?.has(this.client.user?.id as string); + const guild = message.guild; + const member = guild?.members.cache.get(this.client.user?.id as string); + const nickname = member?.nickname; + const memberId = member?.id; + + // Don't consider role mentions as direct mentions + const hasRoleMentionOnly = message.mentions.roles.size > 0 && !isMentioned; + + // If it's only a role mention and we're in team mode, let team logic handle it + if (hasRoleMentionOnly && this.runtime.character.clientConfig?.discord?.isPartOfTeam) { + return false; + } + + return isMentioned || (!this.runtime.character.clientConfig?.discord?.shouldRespondOnlyToMentions && ( + message.content.toLowerCase().includes(this.client.user?.username.toLowerCase() as string) || + message.content.toLowerCase().includes(this.client.user?.tag.toLowerCase() as string) || + (nickname && message.content.toLowerCase().includes(nickname.toLowerCase())))); + } + async processMessageMedia( message: DiscordMessage ): Promise<{ processedContent: string; attachments: Media[] }> { @@ -1197,7 +1218,7 @@ export class MessageManager { return false; } } - + if (message.mentions.has(this.client.user?.id as string)) return true; const guild = message.guild; @@ -1307,4 +1328,4 @@ export class MessageManager { const data = await response.json(); return data.username; } -} +} \ No newline at end of file diff --git a/packages/client-discord/src/utils.ts b/packages/client-discord/src/utils.ts index 6ee1e98871..859e4db275 100644 --- a/packages/client-discord/src/utils.ts +++ b/packages/client-discord/src/utils.ts @@ -297,4 +297,4 @@ export function cosineSimilarity(text1: string, text2: string, text3?: string): ); return dotProduct / maxMagnitude; -} \ No newline at end of file +} diff --git a/packages/client-telegram/src/messageManager.ts b/packages/client-telegram/src/messageManager.ts index de2894859f..8ee3937fa1 100644 --- a/packages/client-telegram/src/messageManager.ts +++ b/packages/client-telegram/src/messageManager.ts @@ -360,6 +360,22 @@ export class MessageManager { return true; } + private _isMessageForMe(message: Message): boolean { + const botUsername = this.bot.botInfo?.username; + if (!botUsername) return false; + + const messageText = 'text' in message ? message.text : + 'caption' in message ? (message as any).caption : ''; + if (!messageText) return false; + + const isReplyToBot = (message as any).reply_to_message?.from?.is_bot === true && + (message as any).reply_to_message?.from?.username === botUsername; + const isMentioned = messageText.includes(`@${botUsername}`); + const hasUsername = messageText.toLowerCase().includes(botUsername.toLowerCase()); + + return isReplyToBot || isMentioned || (!this.runtime.character.clientConfig?.telegram?.shouldRespondOnlyToMentions && hasUsername); + } + // Process image messages and generate descriptions private async processImage( message: Message @@ -406,7 +422,7 @@ export class MessageManager { message: Message, state: State ): Promise { - + if (this.runtime.character.clientConfig?.telegram?.shouldRespondOnlyToMentions) { return this._isMessageForMe(message); } diff --git a/packages/client-telegram/src/telegramClient.ts b/packages/client-telegram/src/telegramClient.ts index 2900a1f648..37aabbb64d 100644 --- a/packages/client-telegram/src/telegramClient.ts +++ b/packages/client-telegram/src/telegramClient.ts @@ -1,4 +1,5 @@ import { Context, Telegraf } from "telegraf"; +import { message } from 'telegraf/filters'; import { IAgentRuntime, elizaLogger } from "@ai16z/eliza"; import { MessageManager } from "./messageManager.ts"; import { getOrCreateRecommenderInBe } from "./getOrCreateRecommenderInBe.ts"; @@ -47,11 +48,56 @@ export class TelegramClient { this.messageManager.bot = this.bot; } + private async isGroupAuthorized(ctx: Context): Promise { + const config = this.runtime.character.clientConfig?.telegram; + if (ctx.from?.id === ctx.botInfo?.id) { + return false; + } + + if (!config?.shouldOnlyJoinInAllowedGroups) { + return true; + } + + const allowedGroups = config.allowedGroupIds || []; + const currentGroupId = ctx.chat.id.toString(); + + if (!allowedGroups.includes(currentGroupId)) { + elizaLogger.info(`Unauthorized group detected: ${currentGroupId}`); + try { + await ctx.reply("Not authorized. Leaving."); + await ctx.leaveChat(); + } catch (error) { + elizaLogger.error(`Error leaving unauthorized group ${currentGroupId}:`, error); + } + return false; + } + + return true; + } + private setupMessageHandlers(): void { elizaLogger.log("Setting up message handler..."); + this.bot.on(message('new_chat_members'), async (ctx) => { + try { + const newMembers = ctx.message.new_chat_members; + const isBotAdded = newMembers.some(member => member.id === ctx.botInfo.id); + + if (isBotAdded && !(await this.isGroupAuthorized(ctx))) { + return; + } + } catch (error) { + elizaLogger.error("Error handling new chat members:", error); + } + }); + this.bot.on("message", async (ctx) => { try { + // Check group authorization first + if (!(await this.isGroupAuthorized(ctx))) { + return; + } + if (this.tgTrader) { const userId = ctx.from?.id.toString(); const username = @@ -76,12 +122,18 @@ export class TelegramClient { ); } } + await this.messageManager.handleMessage(ctx); } catch (error) { elizaLogger.error("❌ Error handling message:", error); - await ctx.reply( - "An error occurred while processing your message." - ); + // Don't try to reply if we've left the group or been kicked + if (error?.response?.error_code !== 403) { + try { + await ctx.reply("An error occurred while processing your message."); + } catch (replyError) { + elizaLogger.error("Failed to send error message:", replyError); + } + } } }); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index b5baa2ec01..e207c42262 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -724,6 +724,7 @@ export type Character = { discord?: { shouldIgnoreBotMessages?: boolean; shouldIgnoreDirectMessages?: boolean; + shouldRespondOnlyToMentions?: boolean; messageSimilarityThreshold?: number; isPartOfTeam?: boolean; teamAgentIds?: string[]; @@ -733,6 +734,9 @@ export type Character = { telegram?: { shouldIgnoreBotMessages?: boolean; shouldIgnoreDirectMessages?: boolean; + shouldRespondOnlyToMentions?: boolean; + shouldOnlyJoinInAllowedGroups?: boolean; + allowedGroupIds?: string[]; messageSimilarityThreshold?: number; isPartOfTeam?: boolean; teamAgentIds?: string[]; @@ -742,6 +746,7 @@ export type Character = { slack?: { shouldIgnoreBotMessages?: boolean; shouldIgnoreDirectMessages?: boolean; + }; };