@elizaos/plugin-discord 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/actions/chatWithAttachments.ts","../src/actions/downloadMedia.ts","../src/actions/summarizeConversation.ts","../src/actions/transcribeMedia.ts","../src/actions/voiceJoin.ts","../src/types.ts","../src/actions/voiceLeave.ts","../src/constants.ts","../src/messages.ts","../src/attachments.ts","../src/utils.ts","../src/providers/channelState.ts","../src/providers/voiceState.ts","../src/tests.ts","../src/voice.ts"],"sourcesContent":["import {\n\tChannelType,\n\ttype Character,\n\tcreateUniqueUuid,\n\ttype Entity,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\tlogger,\n\ttype Memory,\n\ttype Plugin,\n\tRole,\n\tService,\n\ttype UUID,\n\ttype World,\n} from \"@elizaos/core\";\nimport {\n\ttype Channel,\n\tChannelType as DiscordChannelType,\n\tClient as DiscordJsClient,\n\tEvents,\n\tGatewayIntentBits,\n\ttype Guild,\n\ttype GuildMember,\n\ttype MessageReaction,\n\ttype OAuth2Guild,\n\tPartials,\n\tPermissionsBitField,\n\ttype TextChannel,\n\ttype User,\n} from \"discord.js\";\nimport chatWithAttachments from \"./actions/chatWithAttachments.ts\";\nimport downloadMedia from \"./actions/downloadMedia.ts\";\nimport summarize from \"./actions/summarizeConversation.ts\";\nimport transcribe_media from \"./actions/transcribeMedia.ts\";\nimport joinVoice from \"./actions/voiceJoin.ts\";\nimport leaveVoice from \"./actions/voiceLeave.ts\";\nimport { DISCORD_SERVICE_NAME } from \"./constants.ts\";\nimport { MessageManager } from \"./messages.ts\";\nimport channelStateProvider from \"./providers/channelState.ts\";\nimport voiceStateProvider from \"./providers/voiceState.ts\";\nimport { DiscordTestSuite } from \"./tests.ts\";\nimport type { IDiscordService } from \"./types.ts\";\nimport { VoiceManager } from \"./voice.ts\";\n\nexport class DiscordService extends Service implements IDiscordService {\n\tstatic serviceType: string = DISCORD_SERVICE_NAME;\n\tcapabilityDescription =\n\t\t\"The agent is able to send and receive messages on discord\";\n\tclient: DiscordJsClient;\n\tcharacter: Character;\n\tmessageManager: MessageManager;\n\tvoiceManager: VoiceManager;\n\n\tconstructor(runtime: IAgentRuntime) {\n\t\tsuper(runtime);\n\n\t\tlogger.log(\"Discord client constructor was engaged\");\n\n\t\tthis.client = new DiscordJsClient({\n\t\t\tintents: [\n\t\t\t\tGatewayIntentBits.Guilds,\n\t\t\t\tGatewayIntentBits.GuildMembers,\n\t\t\t\tGatewayIntentBits.GuildPresences,\n\t\t\t\tGatewayIntentBits.DirectMessages,\n\t\t\t\tGatewayIntentBits.GuildVoiceStates,\n\t\t\t\tGatewayIntentBits.MessageContent,\n\t\t\t\tGatewayIntentBits.GuildMessages,\n\t\t\t\tGatewayIntentBits.DirectMessageTyping,\n\t\t\t\tGatewayIntentBits.GuildMessageTyping,\n\t\t\t\tGatewayIntentBits.GuildMessageReactions,\n\t\t\t],\n\t\t\tpartials: [\n\t\t\t\tPartials.Channel,\n\t\t\t\tPartials.Message,\n\t\t\t\tPartials.User,\n\t\t\t\tPartials.Reaction,\n\t\t\t],\n\t\t});\n\n\t\tthis.runtime = runtime;\n\t\tthis.voiceManager = new VoiceManager(this, runtime);\n\t\tthis.messageManager = new MessageManager(this);\n\n\t\tthis.client.once(Events.ClientReady, this.onClientReady.bind(this));\n\t\tthis.client.login(runtime.getSetting(\"DISCORD_API_TOKEN\") as string);\n\n\t\tthis.setupEventListeners();\n\n\t\t// give it to the\n\t\tconst ensureAllServersExist = async (runtime: IAgentRuntime) => {\n\t\t\tconst guilds = await this.client.guilds.fetch();\n\t\t\tfor (const [, guild] of guilds) {\n\t\t\t\tawait this.ensureAllChannelsExist(runtime, guild);\n\t\t\t}\n\t\t};\n\n\t\tensureAllServersExist(this.runtime);\n\t}\n\n\tasync ensureAllChannelsExist(runtime: IAgentRuntime, guild: OAuth2Guild) {\n\t\t// fetch the owning member from the OAuth2Guild object\n\t\tconst guildObj = await guild.fetch();\n\t\tconst guildChannels = await guild.fetch();\n\t\t// for channel in channels\n\t\tfor (const [, channel] of guildChannels.channels.cache) {\n\t\t\tconst roomId = createUniqueUuid(this.runtime, channel.id);\n\t\t\tconst room = await runtime.getDatabaseAdapter().getRoom(roomId);\n\t\t\t// if the room already exists, skip\n\t\t\tif (room) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst worldId = createUniqueUuid(runtime, guild.id);\n\t\t\tconst ownerId = createUniqueUuid(this.runtime, guildObj.ownerId);\n\t\t\tawait runtime.ensureWorldExists({\n\t\t\t\tid: worldId,\n\t\t\t\tname: guild.name,\n\t\t\t\tserverId: guild.id,\n\t\t\t\tagentId: runtime.agentId,\n\t\t\t\tmetadata: {\n\t\t\t\t\townership: guildObj.ownerId ? { ownerId } : undefined,\n\t\t\t\t\troles: {\n\t\t\t\t\t\t[ownerId]: Role.OWNER,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait runtime.ensureRoomExists({\n\t\t\t\tid: roomId,\n\t\t\t\tname: channel.name,\n\t\t\t\tsource: \"discord\",\n\t\t\t\ttype: ChannelType.GROUP,\n\t\t\t\tchannelId: channel.id,\n\t\t\t\tserverId: guild.id,\n\t\t\t\tworldId,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate setupEventListeners() {\n\t\t// When joining to a new server\n\t\tthis.client.on(\"guildCreate\", this.handleGuildCreate.bind(this));\n\n\t\tthis.client.on(\n\t\t\tEvents.MessageReactionAdd,\n\t\t\tthis.handleReactionAdd.bind(this),\n\t\t);\n\t\tthis.client.on(\n\t\t\tEvents.MessageReactionRemove,\n\t\t\tthis.handleReactionRemove.bind(this),\n\t\t);\n\n\t\tthis.client.on(Events.GuildMemberAdd, this.handleGuildMemberAdd.bind(this));\n\n\t\t// Handle voice events with the voice manager\n\t\tthis.client.on(\n\t\t\t\"voiceStateUpdate\",\n\t\t\tthis.voiceManager.handleVoiceStateUpdate.bind(this.voiceManager),\n\t\t);\n\t\tthis.client.on(\n\t\t\t\"userStream\",\n\t\t\tthis.voiceManager.handleUserStream.bind(this.voiceManager),\n\t\t);\n\n\t\t// Handle a new message with the message manager\n\t\tthis.client.on(\n\t\t\tEvents.MessageCreate,\n\t\t\tthis.messageManager.handleMessage.bind(this.messageManager),\n\t\t);\n\n\t\t// Handle a new interaction\n\t\tthis.client.on(\n\t\t\tEvents.InteractionCreate,\n\t\t\tthis.handleInteractionCreate.bind(this),\n\t\t);\n\t}\n\n\tprivate async handleGuildMemberAdd(member: GuildMember) {\n\t\tlogger.log(`New member joined: ${member.user.username}`);\n\n\t\tconst guild = member.guild;\n\n\t\tconst tag = member.user.bot\n\t\t\t? `${member.user.username}#${member.user.discriminator}`\n\t\t\t: member.user.username;\n\n\t\t// Emit standardized USER_JOINED event\n\t\tthis.runtime.emitEvent(\"USER_JOINED\", {\n\t\t\truntime: this.runtime,\n\t\t\tentityId: createUniqueUuid(this.runtime, member.id),\n\t\t\tuser: {\n\t\t\t\tid: member.id,\n\t\t\t\tusername: tag,\n\t\t\t\tdisplayName: member.displayName || member.user.username,\n\t\t\t},\n\t\t\tserverId: guild.id,\n\t\t\tchannelId: null, // No specific channel for server joins\n\t\t\tchannelType: ChannelType.WORLD,\n\t\t\tsource: \"discord\",\n\t\t});\n\n\t\tthis.runtime.emitEvent(\"DISCORD_USER_JOINED\", {\n\t\t\truntime: this.runtime,\n\t\t\tentityId: createUniqueUuid(this.runtime, member.id),\n\t\t\tmember,\n\t\t\tguild,\n\t\t});\n\t}\n\n\tstatic async start(runtime: IAgentRuntime): Promise<DiscordService> {\n\t\tconst client = new DiscordService(runtime);\n\t\treturn client;\n\t}\n\n\tstatic async stop(runtime: IAgentRuntime) {\n\t\tconst client = runtime.getService(DISCORD_SERVICE_NAME);\n\t\tif (!client) {\n\t\t\tlogger.error(\"DiscordService not found\");\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\t// disconnect websocket\n\t\t\t// this unbinds all the listeners\n\t\t\tawait client.stop();\n\t\t} catch (e) {\n\t\t\tlogger.error(\"client-discord instance stop err\", e);\n\t\t}\n\t}\n\n\tasync stop() {\n\t\tawait this.client.destroy();\n\t}\n\n\tprivate async onClientReady(readyClient: { user: { tag: any; id: any } }) {\n\t\tlogger.success(`Logged in as ${readyClient.user?.tag}`);\n\n\t\t// Register slash commands\n\t\tconst commands = [\n\t\t\t{\n\t\t\t\tname: \"joinchannel\",\n\t\t\t\tdescription: \"Join a voice channel\",\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"channel\",\n\t\t\t\t\t\ttype: 7, // CHANNEL type\n\t\t\t\t\t\tdescription: \"The voice channel to join\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tchannel_types: [2], // GuildVoice type\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"leavechannel\",\n\t\t\t\tdescription: \"Leave the current voice channel\",\n\t\t\t},\n\t\t];\n\n\t\ttry {\n\t\t\tawait this.client.application?.commands.set(commands);\n\t\t\tlogger.success(\"Slash commands registered\");\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error registering slash commands:\", error);\n\t\t}\n\n\t\t// Required permissions for the bot\n\t\tconst requiredPermissions = [\n\t\t\t// Text Permissions\n\t\t\tPermissionsBitField.Flags.ViewChannel,\n\t\t\tPermissionsBitField.Flags.SendMessages,\n\t\t\tPermissionsBitField.Flags.SendMessagesInThreads,\n\t\t\tPermissionsBitField.Flags.CreatePrivateThreads,\n\t\t\tPermissionsBitField.Flags.CreatePublicThreads,\n\t\t\tPermissionsBitField.Flags.EmbedLinks,\n\t\t\tPermissionsBitField.Flags.AttachFiles,\n\t\t\tPermissionsBitField.Flags.AddReactions,\n\t\t\tPermissionsBitField.Flags.UseExternalEmojis,\n\t\t\tPermissionsBitField.Flags.UseExternalStickers,\n\t\t\tPermissionsBitField.Flags.MentionEveryone,\n\t\t\tPermissionsBitField.Flags.ManageMessages,\n\t\t\tPermissionsBitField.Flags.ReadMessageHistory,\n\t\t\t// Voice Permissions\n\t\t\tPermissionsBitField.Flags.Connect,\n\t\t\tPermissionsBitField.Flags.Speak,\n\t\t\tPermissionsBitField.Flags.UseVAD,\n\t\t\tPermissionsBitField.Flags.PrioritySpeaker,\n\t\t].reduce((a, b) => a | b, 0n);\n\n\t\tlogger.success(\"Use this URL to add the bot to your server:\");\n\t\tlogger.success(\n\t\t\t`https://discord.com/api/oauth2/authorize?client_id=${readyClient.user?.id}&permissions=${requiredPermissions}&scope=bot%20applications.commands`,\n\t\t);\n\t\tawait this.onReady();\n\t}\n\n\tasync getChannelType(channel: Channel): Promise<ChannelType> {\n\t\tswitch (channel.type) {\n\t\t\tcase DiscordChannelType.DM:\n\t\t\t\treturn ChannelType.DM;\n\t\t\tcase DiscordChannelType.GuildText:\n\t\t\t\treturn ChannelType.GROUP;\n\t\t\tcase DiscordChannelType.GuildVoice:\n\t\t\t\treturn ChannelType.VOICE_GROUP;\n\t\t}\n\t}\n\n\tasync handleReactionAdd(reaction: MessageReaction, user: User) {\n\t\ttry {\n\t\t\tlogger.log(\"Reaction added\");\n\n\t\t\t// Early returns\n\t\t\tif (!reaction || !user) {\n\t\t\t\tlogger.warn(\"Invalid reaction or user\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get emoji info\n\t\t\tlet emoji = reaction.emoji.name;\n\t\t\tif (!emoji && reaction.emoji.id) {\n\t\t\t\temoji = `<:${reaction.emoji.name}:${reaction.emoji.id}>`;\n\t\t\t}\n\n\t\t\t// Fetch full message if partial\n\t\t\tif (reaction.partial) {\n\t\t\t\ttry {\n\t\t\t\t\tawait reaction.fetch();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to fetch partial reaction:\", error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Generate IDs with timestamp to ensure uniqueness\n\t\t\tconst timestamp = Date.now();\n\t\t\tconst roomId = createUniqueUuid(\n\t\t\t\tthis.runtime,\n\t\t\t\treaction.message.channel.id,\n\t\t\t);\n\t\t\tconst entityId = createUniqueUuid(this.runtime, user.id);\n\t\t\tconst reactionUUID = createUniqueUuid(\n\t\t\t\tthis.runtime,\n\t\t\t\t`${reaction.message.id}-${user.id}-${emoji}-${timestamp}`,\n\t\t\t);\n\n\t\t\t// Validate IDs\n\t\t\tif (!entityId || !roomId) {\n\t\t\t\tlogger.error(\"Invalid user ID or room ID\", {\n\t\t\t\t\tentityId,\n\t\t\t\t\troomId,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process message content\n\t\t\tconst messageContent = reaction.message.content || \"\";\n\t\t\tconst truncatedContent =\n\t\t\t\tmessageContent.length > 50\n\t\t\t\t\t? `${messageContent.substring(0, 50)}...`\n\t\t\t\t\t: messageContent;\n\t\t\tconst reactionMessage = `*Added <${emoji}> to: \"${truncatedContent}\"*`;\n\n\t\t\t// Get user info\n\t\t\tconst userName = reaction.message.author?.username || \"unknown\";\n\t\t\tconst name = reaction.message.author?.displayName || userName;\n\n\t\t\t// TODO: Get the type of the channel\n\n\t\t\tawait this.runtime.ensureConnection({\n\t\t\t\tentityId,\n\t\t\t\troomId,\n\t\t\t\tuserName,\n\t\t\t\tname: name,\n\t\t\t\tsource: \"discord\",\n\t\t\t\tchannelId: reaction.message.channel.id,\n\t\t\t\tserverId: reaction.message.guild?.id,\n\t\t\t\ttype: await this.getChannelType(reaction.message.channel as Channel),\n\t\t\t});\n\n\t\t\tconst inReplyTo = createUniqueUuid(this.runtime, reaction.message.id);\n\n\t\t\tconst memory: Memory = {\n\t\t\t\tid: reactionUUID,\n\t\t\t\tentityId,\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\tcontent: {\n\t\t\t\t\t// name,\n\t\t\t\t\t// userName,\n\t\t\t\t\ttext: reactionMessage,\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tinReplyTo,\n\t\t\t\t\tchannelType: await this.getChannelType(\n\t\t\t\t\t\treaction.message.channel as Channel,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\troomId,\n\t\t\t\tcreatedAt: timestamp,\n\t\t\t};\n\n\t\t\tconst callback: HandlerCallback = async (content) => {\n\t\t\t\tif (!reaction.message.channel) {\n\t\t\t\t\tlogger.error(\"No channel found for reaction message\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait (reaction.message.channel as TextChannel).send(content.text);\n\t\t\t\treturn [];\n\t\t\t};\n\n\t\t\tthis.runtime.emitEvent(\n\t\t\t\t[\"DISCORD_REACTION_RECEIVED\", \"REACTION_RECEIVED\"],\n\t\t\t\t{\n\t\t\t\t\truntime: this.runtime,\n\t\t\t\t\tmessage: memory,\n\t\t\t\t\tcallback,\n\t\t\t\t},\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlogger.error(\"Error handling reaction:\", error);\n\t\t}\n\t}\n\n\tasync handleReactionRemove(reaction: MessageReaction, user: User) {\n\t\ttry {\n\t\t\tlogger.log(\"Reaction removed\");\n\n\t\t\tlet emoji = reaction.emoji.name;\n\t\t\tif (!emoji && reaction.emoji.id) {\n\t\t\t\temoji = `<:${reaction.emoji.name}:${reaction.emoji.id}>`;\n\t\t\t}\n\n\t\t\t// Fetch the full message if it's a partial\n\t\t\tif (reaction.partial) {\n\t\t\t\ttry {\n\t\t\t\t\tawait reaction.fetch();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\"Something went wrong when fetching the message:\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst messageContent = reaction.message.content || \"\";\n\t\t\tconst truncatedContent =\n\t\t\t\tmessageContent.length > 50\n\t\t\t\t\t? `${messageContent.substring(0, 50)}...`\n\t\t\t\t\t: messageContent;\n\n\t\t\tconst reactionMessage = `*Removed <${emoji}> from: \"${truncatedContent}\"*`;\n\n\t\t\tconst roomId = createUniqueUuid(\n\t\t\t\tthis.runtime,\n\t\t\t\treaction.message.channel.id,\n\t\t\t);\n\n\t\t\tconst entityId = createUniqueUuid(this.runtime, user.id);\n\t\t\tconst timestamp = Date.now();\n\t\t\tconst reactionUUID = createUniqueUuid(\n\t\t\t\tthis.runtime,\n\t\t\t\t`${reaction.message.id}-${user.id}-${emoji}-${timestamp}`,\n\t\t\t);\n\n\t\t\tconst userName = reaction.message.author?.username || \"unknown\";\n\t\t\tconst name = reaction.message.author?.displayName || userName;\n\n\t\t\tawait this.runtime.ensureConnection({\n\t\t\t\tentityId,\n\t\t\t\troomId,\n\t\t\t\tuserName,\n\t\t\t\tname: name,\n\t\t\t\tsource: \"discord\",\n\t\t\t\tchannelId: reaction.message.channel.id,\n\t\t\t\tserverId: reaction.message.guild?.id,\n\t\t\t\ttype: await this.getChannelType(reaction.message.channel as Channel),\n\t\t\t});\n\n\t\t\tconst memory: Memory = {\n\t\t\t\tid: reactionUUID,\n\t\t\t\tentityId,\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\tcontent: {\n\t\t\t\t\t// name,\n\t\t\t\t\t// userName,\n\t\t\t\t\ttext: reactionMessage,\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tinReplyTo: createUniqueUuid(this.runtime, reaction.message.id),\n\t\t\t\t\tchannelType: await this.getChannelType(\n\t\t\t\t\t\treaction.message.channel as Channel,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\troomId,\n\t\t\t\tcreatedAt: Date.now(),\n\t\t\t};\n\n\t\t\tconst callback: HandlerCallback = async (content) => {\n\t\t\t\tif (!reaction.message.channel) {\n\t\t\t\t\tlogger.error(\"No channel found for reaction message\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait (reaction.message.channel as TextChannel).send(content.text);\n\t\t\t\treturn [];\n\t\t\t};\n\n\t\t\tthis.runtime.emitEvent([\"DISCORD_REACTION_EVENT\", \"REACTION_RECEIVED\"], {\n\t\t\t\truntime: this.runtime,\n\t\t\t\tmessage: memory,\n\t\t\t\tcallback,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlogger.error(\"Error handling reaction removal:\", error);\n\t\t}\n\t}\n\n\tprivate async handleGuildCreate(guild: Guild) {\n\t\tlogger.log(`Joined guild ${guild.name}`);\n\t\tconst fullGuild = await guild.fetch();\n\t\tthis.voiceManager.scanGuild(guild);\n\n\t\tconst ownerId = createUniqueUuid(this.runtime, fullGuild.ownerId);\n\n\t\t// Create standardized world data structure\n\t\tconst worldId = createUniqueUuid(this.runtime, fullGuild.id);\n\t\tconst standardizedData = {\n\t\t\truntime: this.runtime,\n\t\t\trooms: await this.buildStandardizedRooms(fullGuild, worldId),\n\t\t\tusers: await this.buildStandardizedUsers(fullGuild),\n\t\t\tworld: {\n\t\t\t\tid: worldId,\n\t\t\t\tname: fullGuild.name,\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\tserverId: fullGuild.id,\n\t\t\t\tmetadata: {\n\t\t\t\t\townership: fullGuild.ownerId ? { ownerId: ownerId } : undefined,\n\t\t\t\t\troles: {\n\t\t\t\t\t\t[ownerId]: Role.OWNER,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t} as World,\n\t\t\tsource: \"discord\",\n\t\t};\n\n\t\t// Emit both Discord-specific and standardized events with the same data structure\n\t\tthis.runtime.emitEvent([\"DISCORD_SERVER_JOINED\"], {\n\t\t\truntime: this.runtime,\n\t\t\tserver: fullGuild,\n\t\t\tsource: \"discord\",\n\t\t});\n\n\t\t// Emit standardized event with the same structure as SERVER_CONNECTED\n\t\tthis.runtime.emitEvent([\"SERVER_JOINED\"], standardizedData);\n\t}\n\n\tprivate async handleInteractionCreate(interaction: any) {\n\t\tif (!interaction.isCommand()) return;\n\n\t\tswitch (interaction.commandName) {\n\t\t\tcase \"joinchannel\":\n\t\t\t\tawait this.voiceManager.handleJoinChannelCommand(interaction);\n\t\t\t\tbreak;\n\t\t\tcase \"leavechannel\":\n\t\t\t\tawait this.voiceManager.handleLeaveChannelCommand(interaction);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Builds a standardized list of rooms from Discord guild channels\n\t */\n\tprivate async buildStandardizedRooms(\n\t\tguild: Guild,\n\t\t_worldId: UUID,\n\t): Promise<any[]> {\n\t\tconst rooms = [];\n\n\t\tfor (const [channelId, channel] of guild.channels.cache) {\n\t\t\t// Only process text and voice channels\n\t\t\tif (\n\t\t\t\tchannel.type === DiscordChannelType.GuildText ||\n\t\t\t\tchannel.type === DiscordChannelType.GuildVoice\n\t\t\t) {\n\t\t\t\tconst roomId = createUniqueUuid(this.runtime, channelId);\n\t\t\t\tlet channelType;\n\n\t\t\t\tswitch (channel.type) {\n\t\t\t\t\tcase DiscordChannelType.GuildText:\n\t\t\t\t\t\tchannelType = ChannelType.GROUP;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DiscordChannelType.GuildVoice:\n\t\t\t\t\t\tchannelType = ChannelType.VOICE_GROUP;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tchannelType = ChannelType.GROUP;\n\t\t\t\t}\n\n\t\t\t\t// For text channels, we could potentially get member permissions\n\t\t\t\t// But for performance reasons, keep this light for large guilds\n\t\t\t\tlet participants: UUID[] = [];\n\n\t\t\t\tif (\n\t\t\t\t\tguild.memberCount < 1000 &&\n\t\t\t\t\tchannel.type === DiscordChannelType.GuildText\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Only attempt this for smaller guilds\n\t\t\t\t\t\t// Get members with read permissions for this channel\n\t\t\t\t\t\tparticipants = Array.from(guild.members.cache.values())\n\t\t\t\t\t\t\t.filter((member) =>\n\t\t\t\t\t\t\t\tchannel\n\t\t\t\t\t\t\t\t\t.permissionsFor(member)\n\t\t\t\t\t\t\t\t\t?.has(PermissionsBitField.Flags.ViewChannel),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.map((member) => createUniqueUuid(this.runtime, member.id));\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\t`Failed to get participants for channel ${channel.name}:`,\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trooms.push({\n\t\t\t\t\tid: roomId,\n\t\t\t\t\tname: channel.name,\n\t\t\t\t\ttype: channelType,\n\t\t\t\t\tchannelId: channel.id,\n\t\t\t\t\tparticipants,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn rooms;\n\t}\n\n\t/**\n\t * Builds a standardized list of users from Discord guild members\n\t */\n\tprivate async buildStandardizedUsers(guild: Guild): Promise<Entity[]> {\n\t\tconst entities: Entity[] = [];\n\t\tconst botId = this.client.user?.id;\n\n\t\t// Strategy based on guild size\n\t\tif (guild.memberCount > 1000) {\n\t\t\tlogger.info(\n\t\t\t\t`Using optimized user sync for large guild ${guild.name} (${guild.memberCount} members)`,\n\t\t\t);\n\n\t\t\t// For large guilds, prioritize members already in cache + online members\n\t\t\ttry {\n\t\t\t\t// Use cache first\n\t\t\t\tfor (const [, member] of guild.members.cache) {\n\t\t\t\t\tconst tag = member.user.bot\n\t\t\t\t\t\t? `${member.user.username}#${member.user.discriminator}`\n\t\t\t\t\t\t: member.user.username;\n\n\t\t\t\t\tif (member.id !== botId) {\n\t\t\t\t\t\tentities.push({\n\t\t\t\t\t\t\tid: createUniqueUuid(this.runtime, member.id),\n\t\t\t\t\t\t\tnames: Array.from(\n\t\t\t\t\t\t\t\tnew Set([\n\t\t\t\t\t\t\t\t\tmember.user.username,\n\t\t\t\t\t\t\t\t\tmember.displayName,\n\t\t\t\t\t\t\t\t\tmember.user.globalName,\n\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdiscord: member.user.globalName\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t\tglobalName: member.user.globalName,\n\t\t\t\t\t\t\t\t\t\t\tuserId: member.id,\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t\tuserId: member.id,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If cache has very few members, try to get online members\n\t\t\t\tif (entities.length < 100) {\n\t\t\t\t\tlogger.info(`Adding online members for ${guild.name}`);\n\t\t\t\t\t// This is a more targeted fetch that is less likely to hit rate limits\n\t\t\t\t\tconst onlineMembers = await guild.members.fetch({ limit: 100 });\n\n\t\t\t\t\tfor (const [, member] of onlineMembers) {\n\t\t\t\t\t\tif (member.id !== botId) {\n\t\t\t\t\t\t\tconst entityId = createUniqueUuid(this.runtime, member.id);\n\t\t\t\t\t\t\t// Avoid duplicates\n\t\t\t\t\t\t\tif (!entities.some((u) => u.id === entityId)) {\n\t\t\t\t\t\t\t\tconst tag = member.user.bot\n\t\t\t\t\t\t\t\t\t? `${member.user.username}#${member.user.discriminator}`\n\t\t\t\t\t\t\t\t\t: member.user.username;\n\n\t\t\t\t\t\t\t\tentities.push({\n\t\t\t\t\t\t\t\t\tid: entityId,\n\t\t\t\t\t\t\t\t\tnames: Array.from(\n\t\t\t\t\t\t\t\t\t\tnew Set([\n\t\t\t\t\t\t\t\t\t\t\tmember.user.username,\n\t\t\t\t\t\t\t\t\t\t\tmember.displayName,\n\t\t\t\t\t\t\t\t\t\t\tmember.user.globalName,\n\t\t\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tdiscord: member.user.globalName\n\t\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t\t\t\tglobalName: member.user.globalName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuserId: member.id,\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuserId: member.id,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(`Error fetching members for ${guild.name}:`, error);\n\t\t\t}\n\t\t} else {\n\t\t\t// For smaller guilds, we can fetch all members\n\t\t\ttry {\n\t\t\t\tlet members = guild.members.cache;\n\t\t\t\tif (members.size === 0) {\n\t\t\t\t\tmembers = await guild.members.fetch();\n\t\t\t\t}\n\n\t\t\t\tfor (const [, member] of members) {\n\t\t\t\t\tif (member.id !== botId) {\n\t\t\t\t\t\tconst tag = member.user.bot\n\t\t\t\t\t\t\t? `${member.user.username}#${member.user.discriminator}`\n\t\t\t\t\t\t\t: member.user.username;\n\n\t\t\t\t\t\tentities.push({\n\t\t\t\t\t\t\tid: createUniqueUuid(this.runtime, member.id),\n\t\t\t\t\t\t\tnames: Array.from(\n\t\t\t\t\t\t\t\tnew Set([\n\t\t\t\t\t\t\t\t\tmember.user.username,\n\t\t\t\t\t\t\t\t\tmember.displayName,\n\t\t\t\t\t\t\t\t\tmember.user.globalName,\n\t\t\t\t\t\t\t\t]),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdiscord: member.user.globalName\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t\tglobalName: member.user.globalName,\n\t\t\t\t\t\t\t\t\t\t\tuserId: member.id,\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\tusername: tag,\n\t\t\t\t\t\t\t\t\t\t\tname: member.displayName || member.user.username,\n\t\t\t\t\t\t\t\t\t\t\tuserId: member.id,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(`Error fetching members for ${guild.name}:`, error);\n\t\t\t}\n\t\t}\n\n\t\treturn entities;\n\t}\n\n\tprivate async onReady() {\n\t\tlogger.log(\"DISCORD ON READY\");\n\t\tconst guilds = await this.client.guilds.fetch();\n\t\tfor (const [, guild] of guilds) {\n\t\t\tconst fullGuild = await guild.fetch();\n\t\t\tawait this.voiceManager.scanGuild(fullGuild);\n\n\t\t\t// Send after a brief delay\n\t\t\tsetTimeout(async () => {\n\t\t\t\t// For each server the client is in, fire a connected event\n\t\t\t\tconst fullGuild = await guild.fetch();\n\t\t\t\tlogger.log(\"DISCORD SERVER CONNECTED\", fullGuild.name);\n\n\t\t\t\t// Emit Discord-specific event with full guild object\n\t\t\t\tthis.runtime.emitEvent([\"DISCORD_SERVER_CONNECTED\"], {\n\t\t\t\t\truntime: this.runtime,\n\t\t\t\t\tserver: fullGuild,\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t});\n\n\t\t\t\t// Create platform-agnostic world data structure with simplified structure\n\t\t\t\tconst worldId = createUniqueUuid(this.runtime, fullGuild.id);\n\t\t\t\tconst ownerId = createUniqueUuid(this.runtime, fullGuild.ownerId);\n\n\t\t\t\tconst standardizedData = {\n\t\t\t\t\tname: fullGuild.name,\n\t\t\t\t\truntime: this.runtime,\n\t\t\t\t\trooms: await this.buildStandardizedRooms(fullGuild, worldId),\n\t\t\t\t\tusers: await this.buildStandardizedUsers(fullGuild),\n\t\t\t\t\tworld: {\n\t\t\t\t\t\tid: worldId,\n\t\t\t\t\t\tname: fullGuild.name,\n\t\t\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\t\t\tserverId: fullGuild.id,\n\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\townership: fullGuild.ownerId ? { ownerId } : undefined,\n\t\t\t\t\t\t\troles: {\n\t\t\t\t\t\t\t\t[ownerId]: Role.OWNER,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t} as World,\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t};\n\n\t\t\t\t// Emit standardized event\n\t\t\t\tthis.runtime.emitEvent([\"SERVER_CONNECTED\"], standardizedData);\n\t\t\t}, 1000);\n\t\t}\n\n\t\tthis.client.emit(\"voiceManagerReady\");\n\t}\n}\n\nconst discordPlugin: Plugin = {\n\tname: \"discord\",\n\tdescription: \"Discord client plugin\",\n\tservices: [DiscordService],\n\tactions: [\n\t\tchatWithAttachments,\n\t\tdownloadMedia,\n\t\tjoinVoice,\n\t\tleaveVoice,\n\t\tsummarize,\n\t\ttranscribe_media,\n\t],\n\tproviders: [channelStateProvider, voiceStateProvider],\n\ttests: [new DiscordTestSuite()],\n};\n\nexport default discordPlugin;\n","import {\n\ttype Action,\n\ttype ActionExample,\n\tChannelType,\n\tcomposePrompt,\n\ttype Content,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype Memory,\n\tModelTypes,\n\tparseJSONObjectFromText,\n\ttype State,\n\ttrimTokens,\n} from \"@elizaos/core\";\nimport * as fs from \"node:fs\";\n\nexport const summarizationTemplate = `# Summarized so far (we are adding to this)\n{{currentSummary}}\n\n# Current attachments we are summarizing\n{{attachmentsWithText}}\n\nSummarization objective: {{objective}}\n\n# Instructions: Summarize the attachments. Return the summary. Do not acknowledge this request, just summarize and continue the existing summary if there is one. Capture any important details based on the objective. Only respond with the new summary text.`;\n\nexport const attachmentIdsTemplate = `# Messages we are summarizing\n{{recentMessages}}\n\n# Instructions: {{senderName}} is requesting a summary of specific attachments. Your goal is to determine their objective, along with the list of attachment IDs to summarize.\nThe \"objective\" is a detailed description of what the user wants to summarize based on the conversation.\nThe \"attachmentIds\" is an array of attachment IDs that the user wants to summarize. If not specified, default to including all attachments from the conversation.\n\nYour response must be formatted as a JSON block with this structure:\n\\`\\`\\`json\n{\n \"objective\": \"<What the user wants to summarize>\",\n \"attachmentIds\": [\"<Attachment ID 1>\", \"<Attachment ID 2>\", ...]\n}\n\\`\\`\\`\n`;\n\nconst getAttachmentIds = async (\n\truntime: IAgentRuntime,\n\t_message: Memory,\n\tstate: State,\n): Promise<{ objective: string; attachmentIds: string[] } | null> => {\n\tconst prompt = composePrompt({\n\t\tstate,\n\t\ttemplate: attachmentIdsTemplate,\n\t});\n\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\tprompt,\n\t\t});\n\t\tconsole.log(\"response\", response);\n\t\t// try parsing to a json object\n\t\tconst parsedResponse = parseJSONObjectFromText(response) as {\n\t\t\tobjective: string;\n\t\t\tattachmentIds: string[];\n\t\t} | null;\n\t\t// see if it contains objective and attachmentIds\n\t\tif (parsedResponse?.objective && parsedResponse?.attachmentIds) {\n\t\t\treturn parsedResponse;\n\t\t}\n\t}\n\treturn null;\n};\n\nconst summarizeAction = {\n\tname: \"CHAT_WITH_ATTACHMENTS\",\n\tsimiles: [\n\t\t\"CHAT_WITH_ATTACHMENT\",\n\t\t\"SUMMARIZE_FILES\",\n\t\t\"SUMMARIZE_FILE\",\n\t\t\"SUMMARIZE_ATACHMENT\",\n\t\t\"CHAT_WITH_PDF\",\n\t\t\"ATTACHMENT_SUMMARY\",\n\t\t\"RECAP_ATTACHMENTS\",\n\t\t\"SUMMARIZE_FILE\",\n\t\t\"SUMMARIZE_VIDEO\",\n\t\t\"SUMMARIZE_AUDIO\",\n\t\t\"SUMMARIZE_IMAGE\",\n\t\t\"SUMMARIZE_DOCUMENT\",\n\t\t\"SUMMARIZE_LINK\",\n\t\t\"ATTACHMENT_SUMMARY\",\n\t\t\"FILE_SUMMARY\",\n\t],\n\tdescription:\n\t\t\"Answer a user request informed by specific attachments based on their IDs. If a user asks to chat with a PDF, or wants more specific information about a link or video or anything else they've attached, this is the action to use.\",\n\tvalidate: async (_runtime: IAgentRuntime, message: Memory, _state: State) => {\n\t\tconst room = await _runtime.getDatabaseAdapter().getRoom(message.roomId);\n\t\tif (room?.type !== ChannelType.GROUP) {\n\t\t\treturn false;\n\t\t}\n\t\t// only show if one of the keywords are in the message\n\t\tconst keywords: string[] = [\n\t\t\t\"attachment\",\n\t\t\t\"summary\",\n\t\t\t\"summarize\",\n\t\t\t\"research\",\n\t\t\t\"pdf\",\n\t\t\t\"video\",\n\t\t\t\"audio\",\n\t\t\t\"image\",\n\t\t\t\"document\",\n\t\t\t\"link\",\n\t\t\t\"file\",\n\t\t\t\"attachment\",\n\t\t\t\"summarize\",\n\t\t\t\"code\",\n\t\t\t\"report\",\n\t\t\t\"write\",\n\t\t\t\"details\",\n\t\t\t\"information\",\n\t\t\t\"talk\",\n\t\t\t\"chat\",\n\t\t\t\"read\",\n\t\t\t\"listen\",\n\t\t\t\"watch\",\n\t\t];\n\t\treturn keywords.some((keyword) =>\n\t\t\tmessage.content.text.toLowerCase().includes(keyword.toLowerCase()),\n\t\t);\n\t},\n\thandler: async (\n\t\truntime: IAgentRuntime,\n\t\tmessage: Memory,\n\t\tstate: State,\n\t\t_options: any,\n\t\tcallback: HandlerCallback,\n\t) => {\n\t\tconst callbackData: Content = {\n\t\t\ttext: \"\", // fill in later\n\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS_RESPONSE\"],\n\t\t\tsource: message.content.source,\n\t\t\tattachments: [],\n\t\t};\n\n\t\t// 1. extract attachment IDs from the message\n\t\tconst attachmentData = await getAttachmentIds(runtime, message, state);\n\t\tif (!attachmentData) {\n\t\t\tconsole.error(\"Couldn't get attachment IDs from message\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: message.content.source,\n\t\t\t\t\tthought:\n\t\t\t\t\t\t\"I tried to chat with attachments but I couldn't get attachment IDs\",\n\t\t\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"CHAT_WITH_ATTACHMENTS\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst { objective, attachmentIds } = attachmentData;\n\n\t\t// This is pretty gross but it can catch cases where the returned generated UUID is stupidly wrong for some reason\n\t\tconst attachments = state.data.recentMessages\n\t\t\t.filter(\n\t\t\t\t(msg) => msg.content.attachments && msg.content.attachments.length > 0,\n\t\t\t)\n\t\t\t.flatMap((msg) => msg.content.attachments)\n\t\t\t// check by first 5 characters of uuid\n\t\t\t.filter(\n\t\t\t\t(attachment) =>\n\t\t\t\t\tattachmentIds\n\t\t\t\t\t\t.map((attch) => attch.toLowerCase().slice(0, 5))\n\t\t\t\t\t\t.includes(attachment.id.toLowerCase().slice(0, 5)) ||\n\t\t\t\t\t// or check the other way\n\t\t\t\t\tattachmentIds.some((id) => {\n\t\t\t\t\t\tconst attachmentId = id.toLowerCase().slice(0, 5);\n\t\t\t\t\t\treturn attachment.id.toLowerCase().includes(attachmentId);\n\t\t\t\t\t}),\n\t\t\t);\n\n\t\tconst attachmentsWithText = attachments\n\t\t\t.map((attachment) => `# ${attachment.title}\\n${attachment.text}`)\n\t\t\t.join(\"\\n\\n\");\n\n\t\tlet currentSummary = \"\";\n\n\t\tconst chunkSize = 8192;\n\n\t\tstate.values.attachmentsWithText = attachmentsWithText;\n\t\tstate.values.objective = objective;\n\t\tconst template = await trimTokens(\n\t\t\tsummarizationTemplate,\n\t\t\tchunkSize,\n\t\t\truntime,\n\t\t);\n\t\tconst prompt = composePrompt({\n\t\t\tstate,\n\t\t\t// make sure it fits, we can pad the tokens a bit\n\t\t\t// Get the model's tokenizer based on the current model being used\n\t\t\ttemplate,\n\t\t});\n\n\t\tconst summary = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\tprompt,\n\t\t});\n\n\t\tcurrentSummary = `${currentSummary}\\n${summary}`;\n\n\t\tif (!currentSummary) {\n\t\t\tconsole.error(\"No summary found, that's not good!\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: message.content.source,\n\t\t\t\t\tthought:\n\t\t\t\t\t\t\"I tried to chat with attachments but I couldn't get a summary\",\n\t\t\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"CHAT_WITH_ATTACHMENTS\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tcallbackData.text = currentSummary.trim();\n\t\tif (\n\t\t\tcallbackData.text &&\n\t\t\t(currentSummary.trim()?.split(\"\\n\").length < 4 ||\n\t\t\t\tcurrentSummary.trim()?.split(\" \").length < 100)\n\t\t) {\n\t\t\tcallbackData.text = `Here is the summary:\n\\`\\`\\`md\n${currentSummary.trim()}\n\\`\\`\\`\n`;\n\t\t\tawait callback(callbackData);\n\t\t} else if (currentSummary.trim()) {\n\t\t\tconst summaryDir = \"cache\";\n\t\t\tconst summaryFilename = `${summaryDir}/summary_${Date.now()}.md`;\n\t\t\ttry {\n\t\t\t\tawait fs.promises.mkdir(summaryDir, { recursive: true });\n\t\t\t\t// Debug: Log before file operations\n\t\t\t\tconsole.log(\"Creating summary file:\", {\n\t\t\t\t\tfilename: summaryFilename,\n\t\t\t\t\tsummaryLength: currentSummary.length,\n\t\t\t\t});\n\n\t\t\t\t// Write file directly first\n\t\t\t\tawait fs.promises.writeFile(summaryFilename, currentSummary, \"utf8\");\n\t\t\t\tconsole.log(\"File written successfully\");\n\n\t\t\t\t// Then cache it\n\t\t\t\tawait runtime\n\t\t\t\t\t.getDatabaseAdapter()\n\t\t\t\t\t.setCache<string>(summaryFilename, currentSummary);\n\t\t\t\tconsole.log(\"Cache set operation completed\");\n\n\t\t\t\tawait callback(\n\t\t\t\t\t{\n\t\t\t\t\t\t...callbackData,\n\t\t\t\t\t\ttext: `I've attached the summary of the requested attachments as a text file.`,\n\t\t\t\t\t},\n\t\t\t\t\t[summaryFilename],\n\t\t\t\t);\n\t\t\t\tconsole.log(\"Callback completed with summary file\");\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error in file/cache process:\", error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} else {\n\t\t\tconsole.warn(\n\t\t\t\t\"Empty response from chat with attachments action, skipping\",\n\t\t\t);\n\t\t}\n\n\t\treturn callbackData;\n\t},\n\texamples: [\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Can you summarize the attachments b3e23, c4f67, and d5a89?\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sure thing! I'll pull up those specific attachments and provide a summary of their content.\",\n\t\t\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"I need a technical summary of the PDFs I sent earlier - a1b2c3.pdf, d4e5f6.pdf, and g7h8i9.pdf\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"I'll take a look at those specific PDF attachments and put together a technical summary for you. Give me a few minutes to review them.\",\n\t\t\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Can you watch this video for me and tell me which parts you think are most relevant to the report I'm writing? (the one I attached in my last message)\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"sure, no problem.\",\n\t\t\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"can you read my blog post and give me a detailed breakdown of the key points I made, and then suggest a handful of tweets to promote it?\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"great idea, give me a minute\",\n\t\t\t\t\tactions: [\"CHAT_WITH_ATTACHMENTS\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t] as ActionExample[][],\n} as Action;\n\nexport default summarizeAction;\n","import {\n\ttype Action,\n\ttype ActionExample,\n\tcomposePrompt,\n\ttype Content,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype IVideoService,\n\ttype Memory,\n\tModelTypes,\n\tparseJSONObjectFromText,\n\tServiceTypes,\n\ttype State,\n} from \"@elizaos/core\";\n\nexport const mediaUrlTemplate = `# Messages we are searching for a media URL\n{{recentMessages}}\n\n# Instructions: {{senderName}} is requesting to download a specific media file (video or audio). Your goal is to determine the URL of the media they want to download.\nThe \"mediaUrl\" is the URL of the media file that the user wants downloaded. If not specified, return null.\n\nYour response must be formatted as a JSON block with this structure:\n\\`\\`\\`json\n{\n \"mediaUrl\": \"<Media URL>\"\n}\n\\`\\`\\`\n`;\n\nconst getMediaUrl = async (\n\truntime: IAgentRuntime,\n\t_message: Memory,\n\tstate: State,\n): Promise<string | null> => {\n\tconst prompt = composePrompt({\n\t\tstate,\n\t\ttemplate: mediaUrlTemplate,\n\t});\n\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\tprompt,\n\t\t});\n\n\t\tconst parsedResponse = parseJSONObjectFromText(response) as {\n\t\t\tmediaUrl: string;\n\t\t} | null;\n\n\t\tif (parsedResponse?.mediaUrl) {\n\t\t\treturn parsedResponse.mediaUrl;\n\t\t}\n\t}\n\treturn null;\n};\n\nexport default {\n\tname: \"DOWNLOAD_MEDIA\",\n\tsimiles: [\n\t\t\"DOWNLOAD_VIDEO\",\n\t\t\"DOWNLOAD_AUDIO\",\n\t\t\"GET_MEDIA\",\n\t\t\"DOWNLOAD_PODCAST\",\n\t\t\"DOWNLOAD_YOUTUBE\",\n\t],\n\tdescription:\n\t\t\"Downloads a video or audio file from a URL and attaches it to the response message.\",\n\tvalidate: async (_runtime: IAgentRuntime, message: Memory, _state: State) => {\n\t\tif (message.content.source !== \"discord\") {\n\t\t\treturn false;\n\t\t}\n\t},\n\thandler: async (\n\t\truntime: IAgentRuntime,\n\t\tmessage: Memory,\n\t\tstate: State,\n\t\t_options: any,\n\t\tcallback: HandlerCallback,\n\t) => {\n\t\tconst videoService = runtime.getService<IVideoService>(ServiceTypes.VIDEO);\n\n\t\tconst mediaUrl = await getMediaUrl(runtime, message, state);\n\t\tif (!mediaUrl) {\n\t\t\tconsole.error(\"Couldn't get media URL from messages\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I couldn't find the media URL in the message`,\n\t\t\t\t\tactions: [\"DOWNLOAD_MEDIA_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"DOWNLOAD_MEDIA\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst videoInfo = await videoService.fetchVideoInfo(mediaUrl);\n\t\tconst mediaPath = await videoService.downloadVideo(videoInfo);\n\n\t\tconst response: Content = {\n\t\t\ttext: `I downloaded the video \"${videoInfo.title}\" and attached it below.`,\n\t\t\tactions: [\"DOWNLOAD_MEDIA_RESPONSE\"],\n\t\t\tsource: message.content.source,\n\t\t\tattachments: [],\n\t\t};\n\n\t\tconst maxRetries = 3;\n\t\tlet retries = 0;\n\n\t\twhile (retries < maxRetries) {\n\t\t\ttry {\n\t\t\t\tawait callback(\n\t\t\t\t\t{\n\t\t\t\t\t\t...response,\n\t\t\t\t\t},\n\t\t\t\t\t[mediaPath],\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t} catch (error) {\n\t\t\t\tretries++;\n\t\t\t\tconsole.error(`Error sending message (attempt ${retries}):`, error);\n\n\t\t\t\tif (retries === maxRetries) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\"Max retries reached. Failed to send message with attachment.\",\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Wait for a short delay before retrying\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 2000));\n\t\t\t}\n\t\t}\n\n\t\treturn response;\n\t},\n\texamples: [\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Downloading the YouTube video now, one sec\",\n\t\t\t\t\tactions: [\"DOWNLOAD_MEDIA\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Can you grab this video for me? https://vimeo.com/123456789\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sure thing, I'll download that Vimeo video for you\",\n\t\t\t\t\tactions: [\"DOWNLOAD_MEDIA\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"I need this video downloaded: https://www.youtube.com/watch?v=abcdefg\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"No problem, I'm on it. I'll have that YouTube video downloaded in a jiffy\",\n\t\t\t\t\tactions: [\"DOWNLOAD_MEDIA\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t] as ActionExample[][],\n} as Action;\n","import {\n\ttype Action,\n\ttype ActionExample,\n\tcomposePrompt,\n\ttype Content,\n\tgetEntityDetails,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype Media,\n\ttype Memory,\n\tModelTypes,\n\tparseJSONObjectFromText,\n\tsplitChunks,\n\ttype State,\n\ttrimTokens,\n} from \"@elizaos/core\";\nimport * as fs from \"node:fs\";\nexport const summarizationTemplate = `# Summarized so far (we are adding to this)\n{{currentSummary}}\n\n# Current conversation chunk we are summarizing (includes attachments)\n{{memoriesWithAttachments}}\n\nSummarization objective: {{objective}}\n\n# Instructions: Summarize the conversation so far. Return the summary. Do not acknowledge this request, just summarize and continue the existing summary if there is one. Capture any important details to the objective. Only respond with the new summary text.\nYour response should be extremely detailed and include any and all relevant information.`;\n\nexport const dateRangeTemplate = `# Messages we are summarizing (the conversation is continued after this)\n{{recentMessages}}\n\n# Instructions: {{senderName}} is requesting a summary of the conversation. Your goal is to determine their objective, along with the range of dates that their request covers.\nThe \"objective\" is a detailed description of what the user wants to summarize based on the conversation. If they just ask for a general summary, you can either base it off the conversation if the summary range is very recent, or set the object to be general, like \"a detailed summary of the conversation between all users\".\nThe \"start\" and \"end\" are the range of dates that the user wants to summarize, relative to the current time. The start and end should be relative to the current time, and measured in seconds, minutes, hours and days. The format is \"2 days ago\" or \"3 hours ago\" or \"4 minutes ago\" or \"5 seconds ago\", i.e. \"<integer> <unit> ago\".\nIf you aren't sure, you can use a default range of \"0 minutes ago\" to \"2 hours ago\" or more. Better to err on the side of including too much than too little.\n\nYour response must be formatted as a JSON block with this structure:\n\\`\\`\\`json\n{\n \"objective\": \"<What the user wants to summarize>\",\n \"start\": \"0 minutes ago\",\n \"end\": \"2 hours ago\"\n}\n\\`\\`\\`\n`;\n\nconst getDateRange = async (\n\truntime: IAgentRuntime,\n\t_message: Memory,\n\tstate: State,\n) => {\n\tconst prompt = composePrompt({\n\t\tstate,\n\t\ttemplate: dateRangeTemplate,\n\t});\n\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\tprompt,\n\t\t});\n\t\tconsole.log(\"response\", response);\n\t\t// try parsing to a json object\n\t\tconst parsedResponse = parseJSONObjectFromText(response) as {\n\t\t\tobjective: string;\n\t\t\tstart: string | number;\n\t\t\tend: string | number;\n\t\t} | null;\n\t\t// see if it contains objective, start and end\n\t\tif (parsedResponse) {\n\t\t\tif (\n\t\t\t\tparsedResponse.objective &&\n\t\t\t\tparsedResponse.start &&\n\t\t\t\tparsedResponse.end\n\t\t\t) {\n\t\t\t\t// TODO: parse start and end into timestamps\n\t\t\t\tconst startIntegerString = (parsedResponse.start as string).match(\n\t\t\t\t\t/\\d+/,\n\t\t\t\t)?.[0];\n\t\t\t\tconst endIntegerString = (parsedResponse.end as string).match(\n\t\t\t\t\t/\\d+/,\n\t\t\t\t)?.[0];\n\n\t\t\t\t// parse multiplier\n\t\t\t\tconst multipliers = {\n\t\t\t\t\tsecond: 1 * 1000,\n\t\t\t\t\tminute: 60 * 1000,\n\t\t\t\t\thour: 3600 * 1000,\n\t\t\t\t\tday: 86400 * 1000,\n\t\t\t\t};\n\n\t\t\t\tconst startMultiplier = (parsedResponse.start as string).match(\n\t\t\t\t\t/second|minute|hour|day/,\n\t\t\t\t)?.[0];\n\t\t\t\tconst endMultiplier = (parsedResponse.end as string).match(\n\t\t\t\t\t/second|minute|hour|day/,\n\t\t\t\t)?.[0];\n\n\t\t\t\tconst startInteger = startIntegerString\n\t\t\t\t\t? Number.parseInt(startIntegerString)\n\t\t\t\t\t: 0;\n\t\t\t\tconst endInteger = endIntegerString\n\t\t\t\t\t? Number.parseInt(endIntegerString)\n\t\t\t\t\t: 0;\n\n\t\t\t\t// multiply by multiplier\n\t\t\t\tconst startTime =\n\t\t\t\t\tstartInteger *\n\t\t\t\t\tmultipliers[startMultiplier as keyof typeof multipliers];\n\n\t\t\t\tconsole.log(\"startTime\", startTime);\n\n\t\t\t\tconst endTime =\n\t\t\t\t\tendInteger * multipliers[endMultiplier as keyof typeof multipliers];\n\n\t\t\t\tconsole.log(\"endTime\", endTime);\n\n\t\t\t\t// get the current time and subtract the start and end times\n\t\t\t\tparsedResponse.start = Date.now() - startTime;\n\t\t\t\tparsedResponse.end = Date.now() - endTime;\n\n\t\t\t\treturn parsedResponse;\n\t\t\t}\n\t\t}\n\t}\n};\n\nconst summarizeAction = {\n\tname: \"SUMMARIZE_CONVERSATION\",\n\tsimiles: [\n\t\t\"RECAP\",\n\t\t\"RECAP_CONVERSATION\",\n\t\t\"SUMMARIZE_CHAT\",\n\t\t\"SUMMARIZATION\",\n\t\t\"CHAT_SUMMARY\",\n\t\t\"CONVERSATION_SUMMARY\",\n\t],\n\tdescription: \"Summarizes the conversation and attachments.\",\n\tvalidate: async (_runtime: IAgentRuntime, message: Memory, _state: State) => {\n\t\tif (message.content.source !== \"discord\") {\n\t\t\treturn false;\n\t\t}\n\t\t// only show if one of the keywords are in the message\n\t\tconst keywords: string[] = [\n\t\t\t\"summarize\",\n\t\t\t\"summarization\",\n\t\t\t\"summary\",\n\t\t\t\"recap\",\n\t\t\t\"report\",\n\t\t\t\"overview\",\n\t\t\t\"review\",\n\t\t\t\"rundown\",\n\t\t\t\"wrap-up\",\n\t\t\t\"brief\",\n\t\t\t\"debrief\",\n\t\t\t\"abstract\",\n\t\t\t\"synopsis\",\n\t\t\t\"outline\",\n\t\t\t\"digest\",\n\t\t\t\"abridgment\",\n\t\t\t\"condensation\",\n\t\t\t\"encapsulation\",\n\t\t\t\"essence\",\n\t\t\t\"gist\",\n\t\t\t\"main points\",\n\t\t\t\"key points\",\n\t\t\t\"key takeaways\",\n\t\t\t\"bulletpoint\",\n\t\t\t\"highlights\",\n\t\t\t\"tldr\",\n\t\t\t\"tl;dr\",\n\t\t\t\"in a nutshell\",\n\t\t\t\"bottom line\",\n\t\t\t\"long story short\",\n\t\t\t\"sum up\",\n\t\t\t\"sum it up\",\n\t\t\t\"short version\",\n\t\t\t\"bring me up to speed\",\n\t\t\t\"catch me up\",\n\t\t];\n\t\treturn keywords.some((keyword) =>\n\t\t\tmessage.content.text.toLowerCase().includes(keyword.toLowerCase()),\n\t\t);\n\t},\n\thandler: async (\n\t\truntime: IAgentRuntime,\n\t\tmessage: Memory,\n\t\tstate: State,\n\t\t_options: any,\n\t\tcallback: HandlerCallback,\n\t) => {\n\t\tconst callbackData: Content = {\n\t\t\ttext: \"\", // fill in later\n\t\t\tactions: [\"SUMMARIZATION_RESPONSE\"],\n\t\t\tsource: message.content.source,\n\t\t\tattachments: [],\n\t\t};\n\t\tconst { roomId } = message;\n\n\t\t// 1. extract date range from the message\n\t\tconst dateRange = await getDateRange(runtime, message, state);\n\t\tif (!dateRange) {\n\t\t\tconsole.error(\"Couldn't get date range from message\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I couldn't get the date range from the message`,\n\t\t\t\t\tactions: [\"SUMMARIZE_CONVERSATION_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"SUMMARIZE_CONVERSATION\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst { objective, start, end } = dateRange;\n\n\t\t// 2. get these memories from the database\n\t\tconst memories = await runtime.getMemoryManager(\"messages\").getMemories({\n\t\t\troomId,\n\t\t\t// subtract start from current time\n\t\t\tstart: Number.parseInt(start as string),\n\t\t\tend: Number.parseInt(end as string),\n\t\t\tcount: 10000,\n\t\t\tunique: false,\n\t\t});\n\n\t\tconst entities = await getEntityDetails({\n\t\t\truntime: runtime as IAgentRuntime,\n\t\t\troomId,\n\t\t});\n\n\t\tconst actorMap = new Map(entities.map((entity) => [entity.id, entity]));\n\n\t\tconst formattedMemories = memories\n\t\t\t.map((memory) => {\n\t\t\t\tconst attachments = memory.content.attachments\n\t\t\t\t\t?.map((attachment: Media) => {\n\t\t\t\t\t\treturn `---\\nAttachment: ${attachment.id}\\n${attachment.description}\\n${attachment.text}\\n---`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\treturn `${actorMap.get(memory.entityId)?.name ?? \"Unknown User\"} (${actorMap.get(memory.entityId)?.username ?? \"\"}): ${memory.content.text}\\n${attachments}`;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tlet currentSummary = \"\";\n\n\t\tconst chunkSize = 8000;\n\n\t\tconst chunks = await splitChunks(formattedMemories, chunkSize, 0);\n\n\t\tconst _datestr = new Date().toUTCString().replace(/:/g, \"-\");\n\n\t\tstate.values.memoriesWithAttachments = formattedMemories;\n\t\tstate.values.objective = objective;\n\n\t\tfor (let i = 0; i < chunks.length; i++) {\n\t\t\tconst chunk = chunks[i];\n\t\t\tstate.values.currentSummary = currentSummary;\n\t\t\tstate.values.currentChunk = chunk;\n\t\t\tconst template = await trimTokens(\n\t\t\t\tsummarizationTemplate,\n\t\t\t\tchunkSize + 500,\n\t\t\t\truntime,\n\t\t\t);\n\t\t\tconst prompt = composePrompt({\n\t\t\t\tstate,\n\t\t\t\t// make sure it fits, we can pad the tokens a bit\n\t\t\t\ttemplate,\n\t\t\t});\n\n\t\t\tconst summary = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\t\tprompt,\n\t\t\t});\n\n\t\t\tcurrentSummary = `${currentSummary}\\n${summary}`;\n\t\t}\n\n\t\tif (!currentSummary) {\n\t\t\tconsole.error(\"No summary found, that's not good!\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I couldn't summarize the conversation`,\n\t\t\t\t\tactions: [\"SUMMARIZE_CONVERSATION_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"SUMMARIZE_CONVERSATION\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tcallbackData.text = currentSummary.trim();\n\t\tif (\n\t\t\tcallbackData.text &&\n\t\t\t(currentSummary.trim()?.split(\"\\n\").length < 4 ||\n\t\t\t\tcurrentSummary.trim()?.split(\" \").length < 100)\n\t\t) {\n\t\t\tcallbackData.text = `Here is the summary:\n\\`\\`\\`md\n${currentSummary.trim()}\n\\`\\`\\`\n`;\n\t\t\tawait callback(callbackData);\n\t\t} else if (currentSummary.trim()) {\n\t\t\tconst summaryDir = \"cache\";\n\t\t\tconst summaryFilename = `${summaryDir}/conversation_summary_${Date.now()}`;\n\t\t\tawait runtime\n\t\t\t\t.getDatabaseAdapter()\n\t\t\t\t.setCache<string>(summaryFilename, currentSummary);\n\t\t\tawait fs.promises.mkdir(summaryDir, { recursive: true });\n\n\t\t\tawait fs.promises.writeFile(summaryFilename, currentSummary, \"utf8\");\n\t\t\t// save the summary to a file\n\t\t\tawait callback(\n\t\t\t\t{\n\t\t\t\t\t...callbackData,\n\t\t\t\t\ttext: `I've attached the summary of the conversation from \\`${new Date(Number.parseInt(start as string)).toString()}\\` to \\`${new Date(Number.parseInt(end as string)).toString()}\\` as a text file.`,\n\t\t\t\t},\n\t\t\t\t[summaryFilename],\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.warn(\n\t\t\t\t\"Empty response from summarize conversation action, skipping\",\n\t\t\t);\n\t\t}\n\n\t\treturn callbackData;\n\t},\n\texamples: [\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"```js\\nconst x = 10\\n```\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"can you give me a detailed report on what we're talking about?\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"sure, no problem, give me a minute to get that together for you\",\n\t\t\t\t\tactions: [\"SUMMARIZE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"please summarize the conversation we just had and include this blogpost i'm linking (Attachment: b3e12)\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"sure, give me a sec\",\n\t\t\t\t\tactions: [\"SUMMARIZE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Can you summarize what moon and avf are talking about?\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Yeah, just hold on a second while I get that together for you...\",\n\t\t\t\t\tactions: [\"SUMMARIZE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"i need to write a blog post about farming, can you summarize the discussion from a few hours ago?\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"no problem, give me a few minutes to read through everything\",\n\t\t\t\t\tactions: [\"SUMMARIZE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t] as ActionExample[][],\n} as Action;\n\nexport default summarizeAction;\n","import {\n\ttype Action,\n\ttype ActionExample,\n\tcomposePrompt,\n\ttype Content,\n\tcreateUniqueUuid,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype Memory,\n\tModelTypes,\n\tparseJSONObjectFromText,\n\ttype State,\n} from \"@elizaos/core\";\n\nexport const transcriptionTemplate = `# Transcription of media file\n{{mediaTranscript}}\n\n# Instructions: Return only the full transcript of the media file without any additional prompt or commentary.`;\n\nexport const mediaAttachmentIdTemplate = `# Messages we are transcribing\n{{recentMessages}}\n\n# Instructions: {{senderName}} is requesting a transcription of a specific media file (audio or video). Your goal is to determine the ID of the attachment they want transcribed.\nThe \"attachmentId\" is the ID of the media file attachment that the user wants transcribed. If not specified, return null.\n\nYour response must be formatted as a JSON block with this structure:\n\\`\\`\\`json\n{\n \"attachmentId\": \"<Attachment ID>\"\n}\n\\`\\`\\`\n`;\n\nconst getMediaAttachmentId = async (\n\truntime: IAgentRuntime,\n\t_message: Memory,\n\tstate: State,\n): Promise<string | null> => {\n\tconst prompt = composePrompt({\n\t\tstate,\n\t\ttemplate: mediaAttachmentIdTemplate,\n\t});\n\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\tprompt,\n\t\t});\n\t\tconsole.log(\"response\", response);\n\n\t\tconst parsedResponse = parseJSONObjectFromText(response) as {\n\t\t\tattachmentId: string;\n\t\t} | null;\n\n\t\tif (parsedResponse?.attachmentId) {\n\t\t\treturn parsedResponse.attachmentId;\n\t\t}\n\t}\n\treturn null;\n};\n\nconst transcribeMediaAction = {\n\tname: \"TRANSCRIBE_MEDIA\",\n\tsimiles: [\n\t\t\"TRANSCRIBE_AUDIO\",\n\t\t\"TRANSCRIBE_VIDEO\",\n\t\t\"MEDIA_TRANSCRIPT\",\n\t\t\"VIDEO_TRANSCRIPT\",\n\t\t\"AUDIO_TRANSCRIPT\",\n\t],\n\tdescription:\n\t\t\"Transcribe the full text of an audio or video file that the user has attached.\",\n\tvalidate: async (_runtime: IAgentRuntime, message: Memory, _state: State) => {\n\t\tif (message.content.source !== \"discord\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst keywords: string[] = [\n\t\t\t\"transcribe\",\n\t\t\t\"transcript\",\n\t\t\t\"audio\",\n\t\t\t\"video\",\n\t\t\t\"media\",\n\t\t\t\"youtube\",\n\t\t\t\"meeting\",\n\t\t\t\"recording\",\n\t\t\t\"podcast\",\n\t\t\t\"call\",\n\t\t\t\"conference\",\n\t\t\t\"interview\",\n\t\t\t\"speech\",\n\t\t\t\"lecture\",\n\t\t\t\"presentation\",\n\t\t];\n\t\treturn keywords.some((keyword) =>\n\t\t\tmessage.content.text.toLowerCase().includes(keyword.toLowerCase()),\n\t\t);\n\t},\n\thandler: async (\n\t\truntime: IAgentRuntime,\n\t\tmessage: Memory,\n\t\tstate: State,\n\t\t_options: any,\n\t\tcallback: HandlerCallback,\n\t) => {\n\t\tconst callbackData: Content = {\n\t\t\ttext: \"\", // fill in later\n\t\t\tactions: [\"TRANSCRIBE_MEDIA_RESPONSE\"],\n\t\t\tsource: message.content.source,\n\t\t\tattachments: [],\n\t\t};\n\n\t\tconst attachmentId = await getMediaAttachmentId(runtime, message, state);\n\t\tif (!attachmentId) {\n\t\t\tconsole.error(\"Couldn't get media attachment ID from message\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I couldn't find the media attachment ID in the message`,\n\t\t\t\t\tactions: [\"TRANSCRIBE_MEDIA_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"TRANSCRIBE_MEDIA\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst attachment = state.data.recentMessages\n\t\t\t.filter(\n\t\t\t\t(msg) => msg.content.attachments && msg.content.attachments.length > 0,\n\t\t\t)\n\t\t\t.flatMap((msg) => msg.content.attachments)\n\t\t\t.find(\n\t\t\t\t(attachment) =>\n\t\t\t\t\tattachment.id.toLowerCase() === attachmentId.toLowerCase(),\n\t\t\t);\n\n\t\tif (!attachment) {\n\t\t\tconsole.error(`Couldn't find attachment with ID ${attachmentId}`);\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I couldn't find the media attachment with ID ${attachmentId}`,\n\t\t\t\t\tactions: [\"TRANSCRIBE_MEDIA_FAILED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"TRANSCRIBE_MEDIA\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst mediaTranscript = attachment.text;\n\n\t\tcallbackData.text = mediaTranscript.trim();\n\n\t\t// if callbackData.text is < 4 lines or < 100 words, then we we callback with normal message wrapped in markdown block\n\t\tif (\n\t\t\tcallbackData.text &&\n\t\t\t(callbackData.text?.split(\"\\n\").length < 4 ||\n\t\t\t\tcallbackData.text?.split(\" \").length < 100)\n\t\t) {\n\t\t\tcallbackData.text = `Here is the transcript:\n\\`\\`\\`md\n${mediaTranscript.trim()}\n\\`\\`\\`\n`;\n\t\t\tawait callback(callbackData);\n\t\t}\n\t\t// if text is big, let's send as an attachment\n\t\telse if (callbackData.text) {\n\t\t\tconst transcriptFilename = `content/transcript_${Date.now()}`;\n\n\t\t\t// save the transcript to a file\n\t\t\tawait runtime\n\t\t\t\t.getDatabaseAdapter()\n\t\t\t\t.setCache<string>(transcriptFilename, callbackData.text);\n\n\t\t\tawait callback(\n\t\t\t\t{\n\t\t\t\t\t...callbackData,\n\t\t\t\t\ttext: `I've attached the transcript as a text file.`,\n\t\t\t\t},\n\t\t\t\t[transcriptFilename],\n\t\t\t);\n\t\t} else {\n\t\t\tconsole.warn(\"Empty response from transcribe media action, skipping\");\n\t\t}\n\n\t\treturn callbackData;\n\t},\n\texamples: [\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Please transcribe the audio file I just sent.\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sure, I'll transcribe the full audio for you.\",\n\t\t\t\t\tactions: [\"TRANSCRIBE_MEDIA\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Can I get a transcript of that video recording?\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Absolutely, give me a moment to generate the full transcript of the video.\",\n\t\t\t\t\tactions: [\"TRANSCRIBE_MEDIA\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t] as ActionExample[][],\n} as Action;\n\nexport default transcribeMediaAction;\n","// src/actions/joinVoice\nimport {\n\ttype Action,\n\ttype ActionExample,\n\tChannelType,\n\tcomposePrompt,\n\tcreateUniqueUuid,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\tlogger,\n\ttype Memory,\n\tModelTypes,\n\ttype State,\n} from \"@elizaos/core\";\nimport {\n\ttype BaseGuildVoiceChannel,\n\ttype Channel,\n\tChannelType as DiscordChannelType,\n\ttype Guild,\n} from \"discord.js\";\nimport type { DiscordService } from \"../index.ts\";\nimport { ServiceTypes } from \"../types.ts\";\nimport type { VoiceManager } from \"../voice.ts\";\n\nexport default {\n\tname: \"JOIN_VOICE\",\n\tsimiles: [\n\t\t\"JOIN_VOICE\",\n\t\t\"JOIN_VC\",\n\t\t\"JOIN_VOICE_CHAT\",\n\t\t\"JOIN_VOICE_CHANNEL\",\n\t\t\"JOIN_MEETING\",\n\t\t\"JOIN_CALL\",\n\t],\n\tvalidate: async (runtime: IAgentRuntime, message: Memory, state: State) => {\n\t\tif (message.content.source !== \"discord\") {\n\t\t\t// not a discord message\n\t\t\treturn false;\n\t\t}\n\n\t\tconst room =\n\t\t\tstate.data.room ??\n\t\t\t(await runtime.getDatabaseAdapter().getRoom(message.roomId));\n\n\t\tif (room?.type !== ChannelType.GROUP) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst client = runtime.getService(ServiceTypes.DISCORD);\n\n\t\tif (!client) {\n\t\t\tlogger.error(\"Discord client not found\");\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t},\n\tdescription: \"Join a voice channel to participate in voice chat.\",\n\thandler: async (\n\t\truntime: IAgentRuntime,\n\t\tmessage: Memory,\n\t\tstate: State,\n\t\t_options: any,\n\t\tcallback: HandlerCallback,\n\t): Promise<boolean> => {\n\t\tconst room =\n\t\t\tstate.data.room ??\n\t\t\t(await runtime.getDatabaseAdapter().getRoom(message.roomId));\n\t\tif (!room) {\n\t\t\tthrow new Error(\"No room found\");\n\t\t}\n\n\t\tif (room.type !== ChannelType.GROUP) {\n\t\t\t// only handle in a group scenario for now\n\t\t\treturn false;\n\t\t}\n\n\t\tconsole.log(\"Running handler on provider\", room.name);\n\n\t\tconst serverId = room.serverId;\n\n\t\tif (!serverId) {\n\t\t\tthrow new Error(\"No server ID found\");\n\t\t}\n\n\t\tconst discordClient = runtime.getService(\n\t\t\tServiceTypes.DISCORD,\n\t\t) as DiscordService;\n\t\tconst client = discordClient.client;\n\t\tconst voiceManager = discordClient.voiceManager as VoiceManager;\n\n\t\tif (!client) {\n\t\t\tlogger.error(\"Discord client not found\");\n\t\t\treturn false;\n\t\t}\n\n\t\tconst voiceChannels = (\n\t\t\tclient.guilds.cache.get(serverId) as Guild\n\t\t).channels.cache.filter(\n\t\t\t(channel: Channel) => channel.type === DiscordChannelType.GuildVoice,\n\t\t);\n\n\t\tconst targetChannel = voiceChannels.find((channel) => {\n\t\t\tconst name = (channel as { name: string }).name.toLowerCase();\n\t\t\tconst messageContent = message?.content?.text;\n\t\t\t// remove all non-alphanumeric characters (keep spaces between words)\n\t\t\tconst replacedName = name.replace(/[^a-z0-9 ]/g, \"\");\n\n\t\t\treturn (\n\t\t\t\tname.includes(messageContent) ||\n\t\t\t\tmessageContent.includes(name) ||\n\t\t\t\treplacedName.includes(messageContent) ||\n\t\t\t\tmessageContent.includes(replacedName)\n\t\t\t);\n\t\t});\n\n\t\tif (targetChannel) {\n\t\t\tvoiceManager.joinChannel(targetChannel as BaseGuildVoiceChannel);\n\t\t\treturn true;\n\t\t}\n\t\tconst guild = client.guilds.cache.get(serverId);\n\t\tconst members = guild?.members.cache;\n\n\t\t// get the member who's stringTouuid(id) === message userId\n\t\tconst member = members?.find(\n\t\t\t(member) => createUniqueUuid(runtime, member.id) === message.entityId,\n\t\t);\n\n\t\tif (member?.voice?.channel) {\n\t\t\tvoiceManager.joinChannel(member?.voice?.channel as BaseGuildVoiceChannel);\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I joined the voice channel ${member?.voice?.channel?.name}`,\n\t\t\t\t\tactions: [\"JOIN_VOICE_STARTED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"JOIN_VOICE\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// save a memory for the new channel as well\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: createUniqueUuid(runtime, targetChannel.id),\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: `I joined the voice channel ${targetChannel.name}`,\n\t\t\t\t\tactions: [\"JOIN_VOICE_STARTED\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"JOIN_VOICE\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t}\n\n\t\tconst messageTemplate = `\nThe user has requested to join a voice channel.\nHere is the list of channels available in the server:\n{{voiceChannels}}\n\nHere is the user's request:\n{{userMessage}}\n\nPlease respond with the name of the voice channel which the bot should join. Try to infer what channel the user is talking about. If the user didn't specify a voice channel, respond with \"none\".\nYou should only respond with the name of the voice channel or none, no commentary or additional information should be included.\n`;\n\n\t\tconst guessState = {\n\t\t\tuserMessage: message.content.text,\n\t\t\tvoiceChannels: voiceChannels\n\t\t\t\t.map((channel) => (channel as { name: string }).name)\n\t\t\t\t.join(\"\\n\"),\n\t\t};\n\n\t\tconst prompt = composePrompt({\n\t\t\ttemplate: messageTemplate,\n\t\t\tstate: guessState as unknown as State,\n\t\t});\n\n\t\tconst responseContent = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\t\tprompt,\n\t\t});\n\n\t\tif (responseContent && responseContent.trim().length > 0) {\n\t\t\t// join the voice channel\n\t\t\tconst channelName = responseContent.toLowerCase();\n\n\t\t\tconst targetChannel = voiceChannels.find((channel) => {\n\t\t\t\tconst name = (channel as { name: string }).name.toLowerCase();\n\n\t\t\t\t// remove all non-alphanumeric characters (keep spaces between words)\n\t\t\t\tconst replacedName = name.replace(/[^a-z0-9 ]/g, \"\");\n\n\t\t\t\treturn (\n\t\t\t\t\tname.includes(channelName) ||\n\t\t\t\t\tchannelName.includes(name) ||\n\t\t\t\t\treplacedName.includes(channelName) ||\n\t\t\t\t\tchannelName.includes(replacedName)\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tif (targetChannel) {\n\t\t\t\tvoiceManager.joinChannel(targetChannel as BaseGuildVoiceChannel);\n\t\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\t\tentityId: message.entityId,\n\t\t\t\t\tagentId: message.agentId,\n\t\t\t\t\troomId: message.roomId,\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\t\tthought: `I joined the voice channel ${member?.voice?.channel?.name}`,\n\t\t\t\t\t\tactions: [\"JOIN_VOICE_STARTED\"],\n\t\t\t\t\t},\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\ttype: \"JOIN_VOICE\",\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\t// save a memory for the new channel as well\n\t\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\t\tentityId: message.entityId,\n\t\t\t\t\tagentId: message.agentId,\n\t\t\t\t\troomId: createUniqueUuid(runtime, targetChannel.id),\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\t\tthought: `I joined the voice channel ${targetChannel.name}`,\n\t\t\t\t\t\tactions: [\"JOIN_VOICE_STARTED\"],\n\t\t\t\t\t},\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\ttype: \"JOIN_VOICE\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tawait callback({\n\t\t\ttext: \"I couldn't figure out which channel you wanted me to join.\",\n\t\t\tsource: \"discord\",\n\t\t});\n\t\treturn false;\n\t},\n\texamples: [\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Hey, let's jump into the 'General' voice and chat\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sounds good\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"{{name2}}, can you join the vc, I want to discuss our strat\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sure I'll join right now\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"hey {{name2}}, we're having a team meeting in the 'conference' voice channel, plz join us\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"OK see you there\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"{{name2}}, let's have a quick voice chat in the 'Lounge' channel.\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"kk be there in a sec\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Hey {{name2}}, can you join me in the 'Music' voice channel\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sure\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"join voice chat with us {{name2}}\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"coming\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"hop in vc {{name2}}\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"joining now\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"get in vc with us {{name2}}\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"im in\",\n\t\t\t\t\tactions: [\"JOIN_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t] as ActionExample[][],\n} as Action;\n","import type { Character, IAgentRuntime } from \"@elizaos/core\";\nimport type { Client } from \"discord.js\";\n\nexport interface IDiscordService {\n\tclient: Client;\n\tcharacter: Character;\n}\n\nexport const ServiceTypes = {\n\tDISCORD: \"discord\",\n} as const;\n","// src/actions/leaveVoice\nimport {\n\tChannelType,\n\tcreateUniqueUuid,\n\tlogger,\n\ttype Action,\n\ttype ActionExample,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype Memory,\n\ttype State,\n} from \"@elizaos/core\";\nimport { BaseGuildVoiceChannel } from \"discord.js\";\n\nimport type { DiscordService } from \"../index.ts\";\nimport type { VoiceManager } from \"../voice.ts\";\nimport { ServiceTypes } from \"../types.ts\";\n\nexport default {\n\tname: \"LEAVE_VOICE\",\n\tsimiles: [\n\t\t\"LEAVE_VOICE\",\n\t\t\"LEAVE_VC\",\n\t\t\"LEAVE_VOICE_CHAT\",\n\t\t\"LEAVE_VOICE_CHANNEL\",\n\t\t\"LEAVE_MEETING\",\n\t\t\"LEAVE_CALL\",\n\t],\n\tvalidate: async (runtime: IAgentRuntime, message: Memory, state: State) => {\n\t\tif (message.content.source !== \"discord\") {\n\t\t\t// not a discord message\n\t\t\treturn false;\n\t\t}\n\n\t\tconst service = runtime.getService(ServiceTypes.DISCORD) as DiscordService;\n\n\t\tif (!service) {\n\t\t\tlogger.error(\"Discord client not found\");\n\t\t\treturn false;\n\t\t}\n\n\t\tconst room =\n\t\t\tstate.data.room ??\n\t\t\t(await runtime.getDatabaseAdapter().getRoom(message.roomId));\n\n\t\tif (room?.type !== ChannelType.GROUP) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if the client is connected to any voice channel\n\t\tconst isConnectedToVoice = service.client.voice.adapters.size > 0;\n\n\t\treturn isConnectedToVoice;\n\t},\n\tdescription: \"Leave the current voice channel.\",\n\thandler: async (\n\t\truntime: IAgentRuntime,\n\t\tmessage: Memory,\n\t\t_state: State,\n\t\t_options: any,\n\t): Promise<boolean> => {\n\t\tconst room = await runtime.getDatabaseAdapter().getRoom(message.roomId);\n\t\tif (!room) {\n\t\t\tthrow new Error(\"No room found\");\n\t\t}\n\n\t\tif (room.type !== ChannelType.GROUP) {\n\t\t\t// only handle in a group scenario for now\n\t\t\tthrow new Error(\"Not a group\");\n\t\t}\n\n\t\tconst serverId = room.serverId;\n\n\t\tif (!serverId) {\n\t\t\tthrow new Error(\"No server ID found 9\");\n\t\t}\n\t\tconst discordClient = runtime.getService(\n\t\t\tServiceTypes.DISCORD,\n\t\t) as DiscordService;\n\t\tconst voiceManager = discordClient.voiceManager as VoiceManager;\n\t\tconst client = discordClient.client;\n\n\t\tif (!client) {\n\t\t\tlogger.error(\"Discord client not found\");\n\t\t\tthrow new Error(\"Discord client not found\");\n\t\t}\n\n\t\tif (!voiceManager) {\n\t\t\tlogger.error(\"voiceManager is not available.\");\n\t\t\tthrow new Error(\"voiceManager is not available.\");\n\t\t}\n\n\t\tconst guild = client.guilds.cache.get(serverId);\n\n\t\tif (!guild) {\n\t\t\tconsole.warn(\"Bot is not in any voice channel.\");\n\t\t\t// create a memory with thought to self to self\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought:\n\t\t\t\t\t\t\"I tried to leave the voice channel but I'm not in any voice channel.\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"LEAVE_VOICE\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tconst voiceChannel = guild.members.me?.voice.channel;\n\n\t\tif (!voiceChannel || !(voiceChannel instanceof BaseGuildVoiceChannel)) {\n\t\t\tconsole.warn(\"Could not retrieve the voice channel.\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought: \"I tried to leave the voice channel but I couldn't find it.\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"LEAVE_VOICE\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tconst connection = voiceManager.getVoiceConnection(guild.id);\n\t\tif (!connection) {\n\t\t\tconsole.warn(\"No active voice connection found for the bot.\");\n\t\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\t\tentityId: message.entityId,\n\t\t\t\tagentId: message.agentId,\n\t\t\t\troomId: message.roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\tthought:\n\t\t\t\t\t\t\"I tried to leave the voice channel but I couldn't find the connection.\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t\tmetadata: {\n\t\t\t\t\ttype: \"LEAVE_VOICE\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tvoiceManager.leaveChannel(voiceChannel);\n\t\t// save a memory for the new channel as well\n\t\tawait runtime.getMemoryManager(\"messages\").createMemory({\n\t\t\tentityId: message.entityId,\n\t\t\tagentId: message.agentId,\n\t\t\troomId: createUniqueUuid(runtime, voiceChannel.id),\n\t\t\tcontent: {\n\t\t\t\tsource: \"discord\",\n\t\t\t\tthought: `I left the voice channel ${voiceChannel.name}`,\n\t\t\t\tactions: [\"LEAVE_VOICE_STARTED\"],\n\t\t\t},\n\t\t\tmetadata: {\n\t\t\t\ttype: \"LEAVE_VOICE\",\n\t\t\t},\n\t\t});\n\n\t\treturn true;\n\t},\n\texamples: [\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Hey {{name2}} please leave the voice channel\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sure\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"I have to go now but thanks for the chat\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"You too, talk to you later\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Great call everyone, hopping off now\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Agreed, I'll hop off too\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Hey {{name2}} I need you to step away from the voice chat for a bit\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"No worries, I'll leave the voice channel\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"{{name2}}, I think we covered everything, you can leave the voice chat now\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"Sounds good, see you both later\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"leave voice {{name2}}\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"ok leaving\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"plz leave the voice chat {{name2}}\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"aight im out\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[\n\t\t\t{\n\t\t\t\tname: \"{{name1}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"yo {{name2}} gtfo the vc\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"{{name2}}\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: \"sorry, talk to you later\",\n\t\t\t\t\tactions: [\"LEAVE_VOICE\"],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t] as ActionExample[][],\n} as Action;\n","export const MESSAGE_CONSTANTS = {\n\tMAX_MESSAGES: 10,\n\tRECENT_MESSAGE_COUNT: 3,\n\tCHAT_HISTORY_COUNT: 5,\n\tINTEREST_DECAY_TIME: 5 * 60 * 1000, // 5 minutes\n\tPARTIAL_INTEREST_DECAY: 3 * 60 * 1000, // 3 minutes\n\tDEFAULT_SIMILARITY_THRESHOLD: 0.3,\n\tDEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS: 0.2,\n} as const;\n\nexport const MESSAGE_LENGTH_THRESHOLDS = {\n\tLOSE_INTEREST: 100,\n\tSHORT_MESSAGE: 10,\n\tVERY_SHORT_MESSAGE: 2,\n\tIGNORE_RESPONSE: 4,\n} as const;\n\nexport const LOSE_INTEREST_WORDS = [\n\t\"shut up\",\n\t\"stop\",\n\t\"please shut up\",\n\t\"shut up please\",\n\t\"dont talk\",\n\t\"silence\",\n\t\"stop talking\",\n\t\"be quiet\",\n\t\"hush\",\n\t\"wtf\",\n\t\"chill\",\n\t\"stfu\",\n\t\"stupid bot\",\n\t\"dumb bot\",\n\t\"stop responding\",\n\t\"god damn it\",\n\t\"god damn\",\n\t\"goddamnit\",\n\t\"can you not\",\n\t\"can you stop\",\n\t\"be quiet\",\n\t\"hate you\",\n\t\"hate this\",\n\t\"fuck up\",\n] as const;\n\nexport const IGNORE_RESPONSE_WORDS = [\n\t\"lol\",\n\t\"nm\",\n\t\"uh\",\n\t\"wtf\",\n\t\"stfu\",\n\t\"dumb\",\n\t\"jfc\",\n\t\"omg\",\n] as const;\n\nexport const DISCORD_SERVICE_NAME = \"discord\";\n","import {\n\tChannelType,\n\ttype Content,\n\tcreateUniqueUuid,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype IBrowserService,\n\ttype IVideoService,\n\tlogger,\n\ttype Media,\n\ttype Memory,\n\tServiceTypes,\n} from \"@elizaos/core\";\nimport {\n\ttype Channel,\n\ttype Client,\n\tChannelType as DiscordChannelType,\n\ttype Message as DiscordMessage,\n\ttype TextChannel,\n} from \"discord.js\";\nimport { AttachmentManager } from \"./attachments\";\nimport { canSendMessage, sendMessageInChunks } from \"./utils\";\n\nexport class MessageManager {\n\tprivate client: Client;\n\tprivate runtime: IAgentRuntime;\n\tprivate attachmentManager: AttachmentManager;\n\tprivate getChannelType: (channel: Channel) => Promise<ChannelType>;\n\tconstructor(discordClient: any) {\n\t\tthis.client = discordClient.client;\n\t\tthis.runtime = discordClient.runtime;\n\t\tthis.attachmentManager = new AttachmentManager(this.runtime);\n\t\tthis.getChannelType = discordClient.getChannelType;\n\t}\n\n\tasync handleMessage(message: DiscordMessage) {\n\t\tif (\n\t\t\tthis.runtime.character.settings?.discord?.allowedChannelIds &&\n\t\t\t!this.runtime.character.settings.discord.allowedChannelIds.some(\n\t\t\t\t(id: string) => id === message.channel.id,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.interaction || message.author.id === this.client.user?.id) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tthis.runtime.character.settings?.discord?.shouldIgnoreBotMessages &&\n\t\t\tmessage.author?.bot\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tthis.runtime.character.settings?.discord?.shouldIgnoreDirectMessages &&\n\t\t\tmessage.channel.type === DiscordChannelType.DM\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst entityId = createUniqueUuid(this.runtime, message.author.id);\n\n\t\tconst userName = message.author.bot\n\t\t\t? `${message.author.username}#${message.author.discriminator}`\n\t\t\t: message.author.username;\n\t\tconst name = message.author.displayName;\n\t\tconst channelId = message.channel.id;\n\t\tconst roomId = createUniqueUuid(this.runtime, channelId);\n\n\t\tlet type: ChannelType;\n\t\tlet serverId: string | undefined;\n\n\t\tif (message.guild) {\n\t\t\tconst guild = await message.guild.fetch();\n\t\t\ttype = await this.getChannelType(message.channel as Channel);\n\t\t\tserverId = guild.id;\n\t\t} else {\n\t\t\ttype = ChannelType.DM;\n\t\t\tserverId = undefined;\n\t\t}\n\n\t\tawait this.runtime.ensureConnection({\n\t\t\tentityId: entityId,\n\t\t\troomId,\n\t\t\tuserName,\n\t\t\tname: name,\n\t\t\tsource: \"discord\",\n\t\t\tchannelId: message.channel.id,\n\t\t\tserverId,\n\t\t\ttype,\n\t\t});\n\n\t\ttry {\n\t\t\tconst canSendResult = canSendMessage(message.channel);\n\t\t\tif (!canSendResult.canSend) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`Cannot send message to channel ${message.channel}`,\n\t\t\t\t\tcanSendResult,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst { processedContent, attachments } =\n\t\t\t\tawait this.processMessage(message);\n\n\t\t\tconst audioAttachments = message.attachments.filter((attachment) =>\n\t\t\t\tattachment.contentType?.startsWith(\"audio/\"),\n\t\t\t);\n\n\t\t\tif (audioAttachments.size > 0) {\n\t\t\t\tconst processedAudioAttachments =\n\t\t\t\t\tawait this.attachmentManager.processAttachments(audioAttachments);\n\t\t\t\tattachments.push(...processedAudioAttachments);\n\t\t\t}\n\n\t\t\tif (!processedContent && !attachments?.length) {\n\t\t\t\t// Only process messages that are not empty\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst entityId = createUniqueUuid(this.runtime, message.author.id);\n\n\t\t\tconst messageId = createUniqueUuid(this.runtime, message.id);\n\n\t\t\tconst newMessage: Memory = {\n\t\t\t\tid: messageId,\n\t\t\t\tentityId: entityId,\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\troomId: roomId,\n\t\t\t\tcontent: {\n\t\t\t\t\t// name: name,\n\t\t\t\t\t// userName: userName,\n\t\t\t\t\ttext: processedContent || \" \",\n\t\t\t\t\tattachments: attachments,\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\turl: message.url,\n\t\t\t\t\tinReplyTo: message.reference?.messageId\n\t\t\t\t\t\t? createUniqueUuid(this.runtime, message.reference?.messageId)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t},\n\t\t\t\tcreatedAt: message.createdTimestamp,\n\t\t\t};\n\n\t\t\tconst callback: HandlerCallback = async (\n\t\t\t\tcontent: Content,\n\t\t\t\tfiles: any[],\n\t\t\t) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (message.id && !content.inReplyTo) {\n\t\t\t\t\t\tcontent.inReplyTo = createUniqueUuid(this.runtime, message.id);\n\t\t\t\t\t}\n\t\t\t\t\tconst messages = await sendMessageInChunks(\n\t\t\t\t\t\tmessage.channel as TextChannel,\n\t\t\t\t\t\tcontent.text,\n\t\t\t\t\t\tmessage.id,\n\t\t\t\t\t\tfiles,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst memories: Memory[] = [];\n\t\t\t\t\tfor (const m of messages) {\n\t\t\t\t\t\tconst actions = content.actions;\n\n\t\t\t\t\t\tconst memory: Memory = {\n\t\t\t\t\t\t\tid: createUniqueUuid(this.runtime, m.id),\n\t\t\t\t\t\t\tentityId: this.runtime.agentId,\n\t\t\t\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t...content,\n\t\t\t\t\t\t\t\tactions,\n\t\t\t\t\t\t\t\tinReplyTo: messageId,\n\t\t\t\t\t\t\t\turl: m.url,\n\t\t\t\t\t\t\t\tchannelType: type,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\troomId,\n\t\t\t\t\t\t\tcreatedAt: m.createdTimestamp,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tmemories.push(memory);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const m of memories) {\n\t\t\t\t\t\tawait this.runtime.getMemoryManager(\"messages\").createMemory(m);\n\t\t\t\t\t}\n\t\t\t\t\treturn memories;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(\"Error sending message:\", error);\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tthis.runtime.emitEvent([\"DISCORD_MESSAGE_RECEIVED\", \"MESSAGE_RECEIVED\"], {\n\t\t\t\truntime: this.runtime,\n\t\t\t\tmessage: newMessage,\n\t\t\t\tcallback,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error handling message:\", error);\n\t\t}\n\t}\n\n\tasync processMessage(\n\t\tmessage: DiscordMessage,\n\t): Promise<{ processedContent: string; attachments: Media[] }> {\n\t\tlet processedContent = message.content;\n\t\tlet attachments: Media[] = [];\n\n\t\tconst mentionRegex = /<@!?(\\d+)>/g;\n\t\tprocessedContent = processedContent.replace(\n\t\t\tmentionRegex,\n\t\t\t(match, entityId) => {\n\t\t\t\tconst user = message.mentions.users.get(entityId);\n\t\t\t\tif (user) {\n\t\t\t\t\treturn `${user.username} (@${entityId})`;\n\t\t\t\t}\n\t\t\t\treturn match;\n\t\t\t},\n\t\t);\n\n\t\tconst codeBlockRegex = /```([\\s\\S]*?)```/g;\n\t\tlet match;\n\t\twhile ((match = codeBlockRegex.exec(processedContent))) {\n\t\t\tconst codeBlock = match[1];\n\t\t\tconst lines = codeBlock.split(\"\\n\");\n\t\t\tconst title = lines[0];\n\t\t\tconst description = lines.slice(0, 3).join(\"\\n\");\n\t\t\tconst attachmentId = `code-${Date.now()}-${Math.floor(\n\t\t\t\tMath.random() * 1000,\n\t\t\t)}`.slice(-5);\n\t\t\tattachments.push({\n\t\t\t\tid: attachmentId,\n\t\t\t\turl: \"\",\n\t\t\t\ttitle: title || \"Code Block\",\n\t\t\t\tsource: \"Code\",\n\t\t\t\tdescription: description,\n\t\t\t\ttext: codeBlock,\n\t\t\t});\n\t\t\tprocessedContent = processedContent.replace(\n\t\t\t\tmatch[0],\n\t\t\t\t`Code Block (${attachmentId})`,\n\t\t\t);\n\t\t}\n\n\t\tif (message.attachments.size > 0) {\n\t\t\tattachments = await this.attachmentManager.processAttachments(\n\t\t\t\tmessage.attachments,\n\t\t\t);\n\t\t}\n\n\t\tconst urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n\t\tconst urls = processedContent.match(urlRegex) || [];\n\n\t\tfor (const url of urls) {\n\t\t\tif (\n\t\t\t\tthis.runtime\n\t\t\t\t\t.getService<IVideoService>(ServiceTypes.VIDEO)\n\t\t\t\t\t?.isVideoUrl(url)\n\t\t\t) {\n\t\t\t\tconst videoService = this.runtime.getService<IVideoService>(\n\t\t\t\t\tServiceTypes.VIDEO,\n\t\t\t\t);\n\t\t\t\tif (!videoService) {\n\t\t\t\t\tthrow new Error(\"Video service not found\");\n\t\t\t\t}\n\t\t\t\tconst videoInfo = await videoService.processVideo(url, this.runtime);\n\n\t\t\t\tattachments.push({\n\t\t\t\t\tid: `youtube-${Date.now()}`,\n\t\t\t\t\turl: url,\n\t\t\t\t\ttitle: videoInfo.title,\n\t\t\t\t\tsource: \"YouTube\",\n\t\t\t\t\tdescription: videoInfo.description,\n\t\t\t\t\ttext: videoInfo.text,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst browserService = this.runtime.getService<IBrowserService>(\n\t\t\t\t\tServiceTypes.BROWSER,\n\t\t\t\t);\n\t\t\t\tif (!browserService) {\n\t\t\t\t\tthrow new Error(\"Browser service not found\");\n\t\t\t\t}\n\n\t\t\t\tconst { title, description: summary } =\n\t\t\t\t\tawait browserService.getPageContent(url, this.runtime);\n\n\t\t\t\tattachments.push({\n\t\t\t\t\tid: `webpage-${Date.now()}`,\n\t\t\t\t\turl: url,\n\t\t\t\t\ttitle: title || \"Web Page\",\n\t\t\t\t\tsource: \"Web\",\n\t\t\t\t\tdescription: summary,\n\t\t\t\t\ttext: summary,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn { processedContent, attachments };\n\t}\n\n\tasync fetchBotName(botToken: string) {\n\t\tconst url = \"https://discord.com/api/v10/users/@me\";\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bot ${botToken}`,\n\t\t\t},\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Error fetching bot details: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = await response.json();\n\t\tconst discriminator = data.discriminator;\n\t\treturn (\n\t\t\t(data as { username: string }).username +\n\t\t\t(discriminator ? `#${discriminator}` : \"\")\n\t\t);\n\t}\n}\n","import { trimTokens } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n\ttype IAgentRuntime,\n\ttype IPdfService,\n\ttype IVideoService,\n\ttype Media,\n\tModelTypes,\n\tServiceTypes,\n} from \"@elizaos/core\";\nimport { type Attachment, Collection } from \"discord.js\";\nimport ffmpeg from \"fluent-ffmpeg\";\nimport fs from \"node:fs\";\n\nasync function generateSummary(\n\truntime: IAgentRuntime,\n\ttext: string,\n): Promise<{ title: string; description: string }> {\n\t// make sure text is under 128k characters\n\ttext = await trimTokens(text, 100000, runtime);\n\n\tconst prompt = `Please generate a concise summary for the following text:\n\n Text: \"\"\"\n ${text}\n \"\"\"\n\n Respond with a JSON object in the following format:\n \\`\\`\\`json\n {\n \"title\": \"Generated Title\",\n \"summary\": \"Generated summary and/or description of the text\"\n }\n \\`\\`\\``;\n\n\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\tprompt,\n\t});\n\n\tconst parsedResponse = parseJSONObjectFromText(response);\n\n\tif (parsedResponse?.title && parsedResponse?.summary) {\n\t\treturn {\n\t\t\ttitle: parsedResponse.title,\n\t\t\tdescription: parsedResponse.summary,\n\t\t};\n\t}\n\n\treturn {\n\t\ttitle: \"\",\n\t\tdescription: \"\",\n\t};\n}\n\nexport class AttachmentManager {\n\tprivate attachmentCache: Map<string, Media> = new Map();\n\tprivate runtime: IAgentRuntime;\n\n\tconstructor(runtime: IAgentRuntime) {\n\t\tthis.runtime = runtime;\n\t}\n\n\tasync processAttachments(\n\t\tattachments: Collection<string, Attachment> | Attachment[],\n\t): Promise<Media[]> {\n\t\tconst processedAttachments: Media[] = [];\n\t\tconst attachmentCollection =\n\t\t\tattachments instanceof Collection\n\t\t\t\t? attachments\n\t\t\t\t: new Collection(attachments.map((att) => [att.id, att]));\n\n\t\tfor (const [, attachment] of attachmentCollection) {\n\t\t\tconst media = await this.processAttachment(attachment);\n\t\t\tif (media) {\n\t\t\t\tprocessedAttachments.push(media);\n\t\t\t}\n\t\t}\n\n\t\treturn processedAttachments;\n\t}\n\n\tasync processAttachment(attachment: Attachment): Promise<Media | null> {\n\t\tif (this.attachmentCache.has(attachment.url)) {\n\t\t\treturn this.attachmentCache.get(attachment.url)!;\n\t\t}\n\n\t\tlet media: Media | null = null;\n\t\tif (attachment.contentType?.startsWith(\"application/pdf\")) {\n\t\t\tmedia = await this.processPdfAttachment(attachment);\n\t\t} else if (attachment.contentType?.startsWith(\"text/plain\")) {\n\t\t\tmedia = await this.processPlaintextAttachment(attachment);\n\t\t} else if (\n\t\t\tattachment.contentType?.startsWith(\"audio/\") ||\n\t\t\tattachment.contentType?.startsWith(\"video/mp4\")\n\t\t) {\n\t\t\tmedia = await this.processAudioVideoAttachment(attachment);\n\t\t} else if (attachment.contentType?.startsWith(\"image/\")) {\n\t\t\tmedia = await this.processImageAttachment(attachment);\n\t\t} else if (\n\t\t\tattachment.contentType?.startsWith(\"video/\") ||\n\t\t\tthis.runtime\n\t\t\t\t.getService<IVideoService>(ServiceTypes.VIDEO)\n\t\t\t\t.isVideoUrl(attachment.url)\n\t\t) {\n\t\t\tmedia = await this.processVideoAttachment(attachment);\n\t\t} else {\n\t\t\tmedia = await this.processGenericAttachment(attachment);\n\t\t}\n\n\t\tif (media) {\n\t\t\tthis.attachmentCache.set(attachment.url, media);\n\t\t}\n\t\treturn media;\n\t}\n\n\tprivate async processAudioVideoAttachment(\n\t\tattachment: Attachment,\n\t): Promise<Media> {\n\t\ttry {\n\t\t\tconst response = await fetch(attachment.url);\n\t\t\tconst audioVideoArrayBuffer = await response.arrayBuffer();\n\n\t\t\tlet audioBuffer: Buffer;\n\t\t\tif (attachment.contentType?.startsWith(\"audio/\")) {\n\t\t\t\taudioBuffer = Buffer.from(audioVideoArrayBuffer);\n\t\t\t} else if (attachment.contentType?.startsWith(\"video/mp4\")) {\n\t\t\t\taudioBuffer = await this.extractAudioFromMP4(audioVideoArrayBuffer);\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"Unsupported audio/video format\");\n\t\t\t}\n\n\t\t\tconst transcription = await this.runtime.useModel(\n\t\t\t\tModelTypes.TRANSCRIPTION,\n\t\t\t\taudioBuffer,\n\t\t\t);\n\t\t\tconst { title, description } = await generateSummary(\n\t\t\t\tthis.runtime,\n\t\t\t\ttranscription,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: title || \"Audio/Video Attachment\",\n\t\t\t\tsource: attachment.contentType?.startsWith(\"audio/\")\n\t\t\t\t\t? \"Audio\"\n\t\t\t\t\t: \"Video\",\n\t\t\t\tdescription:\n\t\t\t\t\tdescription ||\n\t\t\t\t\t\"User-uploaded audio/video attachment which has been transcribed\",\n\t\t\t\ttext: transcription || \"Audio/video content not available\",\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(\n\t\t\t\t`Error processing audio/video attachment: ${error.message}`,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: \"Audio/Video Attachment\",\n\t\t\t\tsource: attachment.contentType?.startsWith(\"audio/\")\n\t\t\t\t\t? \"Audio\"\n\t\t\t\t\t: \"Video\",\n\t\t\t\tdescription: \"An audio/video attachment (transcription failed)\",\n\t\t\t\ttext: `This is an audio/video attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}`,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate async extractAudioFromMP4(mp4Data: ArrayBuffer): Promise<Buffer> {\n\t\t// Use a library like 'fluent-ffmpeg' or 'ffmpeg-static' to extract the audio stream from the MP4 data\n\t\t// and convert it to MP3 or WAV format\n\t\t// Example using fluent-ffmpeg:\n\t\tconst tempMP4File = `temp_${Date.now()}.mp4`;\n\t\tconst tempAudioFile = `temp_${Date.now()}.mp3`;\n\n\t\ttry {\n\t\t\t// Write the MP4 data to a temporary file\n\t\t\tfs.writeFileSync(tempMP4File, Buffer.from(mp4Data));\n\n\t\t\t// Extract the audio stream and convert it to MP3\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tffmpeg(tempMP4File)\n\t\t\t\t\t.outputOptions(\"-vn\") // Disable video output\n\t\t\t\t\t.audioCodec(\"libmp3lame\") // Set audio codec to MP3\n\t\t\t\t\t.save(tempAudioFile) // Save the output to the specified file\n\t\t\t\t\t.on(\"end\", () => {\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t})\n\t\t\t\t\t.on(\"error\", (err) => {\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t})\n\t\t\t\t\t.run();\n\t\t\t});\n\n\t\t\t// Read the converted audio file and return it as a Buffer\n\t\t\tconst audioData = fs.readFileSync(tempAudioFile);\n\t\t\treturn audioData;\n\t\t} finally {\n\t\t\t// Clean up the temporary files\n\t\t\tif (fs.existsSync(tempMP4File)) {\n\t\t\t\tfs.unlinkSync(tempMP4File);\n\t\t\t}\n\t\t\tif (fs.existsSync(tempAudioFile)) {\n\t\t\t\tfs.unlinkSync(tempAudioFile);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async processPdfAttachment(attachment: Attachment): Promise<Media> {\n\t\ttry {\n\t\t\tconst response = await fetch(attachment.url);\n\t\t\tconst pdfBuffer = await response.arrayBuffer();\n\t\t\tconst text = await this.runtime\n\t\t\t\t.getService<IPdfService>(ServiceTypes.PDF)\n\t\t\t\t.convertPdfToText(Buffer.from(pdfBuffer));\n\t\t\tconst { title, description } = await generateSummary(this.runtime, text);\n\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: title || \"PDF Attachment\",\n\t\t\t\tsource: \"PDF\",\n\t\t\t\tdescription: description || \"A PDF document\",\n\t\t\t\ttext: text,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error processing PDF attachment: ${error.message}`);\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: \"PDF Attachment (conversion failed)\",\n\t\t\t\tsource: \"PDF\",\n\t\t\t\tdescription: \"A PDF document that could not be converted to text\",\n\t\t\t\ttext: `This is a PDF attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes`,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate async processPlaintextAttachment(\n\t\tattachment: Attachment,\n\t): Promise<Media> {\n\t\ttry {\n\t\t\tconst response = await fetch(attachment.url);\n\t\t\tconst text = await response.text();\n\t\t\tconst { title, description } = await generateSummary(this.runtime, text);\n\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: title || \"Plaintext Attachment\",\n\t\t\t\tsource: \"Plaintext\",\n\t\t\t\tdescription: description || \"A plaintext document\",\n\t\t\t\ttext: text,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error processing plaintext attachment: ${error.message}`);\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: \"Plaintext Attachment (retrieval failed)\",\n\t\t\t\tsource: \"Plaintext\",\n\t\t\t\tdescription: \"A plaintext document that could not be retrieved\",\n\t\t\t\ttext: `This is a plaintext attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes`,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate async processImageAttachment(attachment: Attachment): Promise<Media> {\n\t\ttry {\n\t\t\tconst { description, title } = await this.runtime.useModel(\n\t\t\t\tModelTypes.IMAGE_DESCRIPTION,\n\t\t\t\tattachment.url,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: title || \"Image Attachment\",\n\t\t\t\tsource: \"Image\",\n\t\t\t\tdescription: description || \"An image attachment\",\n\t\t\t\ttext: description || \"Image content not available\",\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error processing image attachment: ${error.message}`);\n\t\t\treturn this.createFallbackImageMedia(attachment);\n\t\t}\n\t}\n\n\tprivate createFallbackImageMedia(attachment: Attachment): Media {\n\t\treturn {\n\t\t\tid: attachment.id,\n\t\t\turl: attachment.url,\n\t\t\ttitle: \"Image Attachment\",\n\t\t\tsource: \"Image\",\n\t\t\tdescription: \"An image attachment (recognition failed)\",\n\t\t\ttext: `This is an image attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}`,\n\t\t};\n\t}\n\n\tprivate async processVideoAttachment(attachment: Attachment): Promise<Media> {\n\t\tconst videoService = this.runtime.getService<IVideoService>(\n\t\t\tServiceTypes.VIDEO,\n\t\t);\n\n\t\tif (!videoService) {\n\t\t\tthrow new Error(\"Video service not found\");\n\t\t}\n\n\t\tif (videoService.isVideoUrl(attachment.url)) {\n\t\t\tconst videoInfo = await videoService.processVideo(\n\t\t\t\tattachment.url,\n\t\t\t\tthis.runtime,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tid: attachment.id,\n\t\t\t\turl: attachment.url,\n\t\t\t\ttitle: videoInfo.title,\n\t\t\t\tsource: \"YouTube\",\n\t\t\t\tdescription: videoInfo.description,\n\t\t\t\ttext: videoInfo.text,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tid: attachment.id,\n\t\t\turl: attachment.url,\n\t\t\ttitle: \"Video Attachment\",\n\t\t\tsource: \"Video\",\n\t\t\tdescription: \"A video attachment\",\n\t\t\ttext: \"Video content not available\",\n\t\t};\n\t}\n\n\tprivate async processGenericAttachment(\n\t\tattachment: Attachment,\n\t): Promise<Media> {\n\t\treturn {\n\t\t\tid: attachment.id,\n\t\t\turl: attachment.url,\n\t\t\ttitle: \"Generic Attachment\",\n\t\t\tsource: \"Generic\",\n\t\t\tdescription: \"A generic attachment\",\n\t\t\ttext: \"Attachment content not available\",\n\t\t};\n\t}\n}\n","import {\n\ttype IAgentRuntime,\n\tModelTypes,\n\tlogger,\n\ttrimTokens,\n\tparseJSONObjectFromText,\n} from \"@elizaos/core\";\nimport {\n\tChannelType,\n\ttype Message as DiscordMessage,\n\tPermissionsBitField,\n\ttype TextChannel,\n\tThreadChannel,\n} from \"discord.js\";\n\nexport function getWavHeader(\n\taudioLength: number,\n\tsampleRate: number,\n\tchannelCount = 1,\n\tbitsPerSample = 16,\n): Buffer {\n\tconst wavHeader = Buffer.alloc(44);\n\twavHeader.write(\"RIFF\", 0);\n\twavHeader.writeUInt32LE(36 + audioLength, 4); // Length of entire file in bytes minus 8\n\twavHeader.write(\"WAVE\", 8);\n\twavHeader.write(\"fmt \", 12);\n\twavHeader.writeUInt32LE(16, 16); // Length of format data\n\twavHeader.writeUInt16LE(1, 20); // Type of format (1 is PCM)\n\twavHeader.writeUInt16LE(channelCount, 22); // Number of channels\n\twavHeader.writeUInt32LE(sampleRate, 24); // Sample rate\n\twavHeader.writeUInt32LE((sampleRate * bitsPerSample * channelCount) / 8, 28); // Byte rate\n\twavHeader.writeUInt16LE((bitsPerSample * channelCount) / 8, 32); // Block align ((BitsPerSample * Channels) / 8)\n\twavHeader.writeUInt16LE(bitsPerSample, 34); // Bits per sample\n\twavHeader.write(\"data\", 36); // Data chunk header\n\twavHeader.writeUInt32LE(audioLength, 40); // Data chunk size\n\treturn wavHeader;\n}\n\nconst MAX_MESSAGE_LENGTH = 1900;\n\nexport async function generateSummary(\n\truntime: IAgentRuntime,\n\ttext: string,\n): Promise<{ title: string; description: string }> {\n\t// make sure text is under 128k characters\n\ttext = await trimTokens(text, 100000, runtime);\n\n\tconst prompt = `Please generate a concise summary for the following text:\n\n Text: \"\"\"\n ${text}\n \"\"\"\n\n Respond with a JSON object in the following format:\n \\`\\`\\`json\n {\n \"title\": \"Generated Title\",\n \"summary\": \"Generated summary and/or description of the text\"\n }\n \\`\\`\\``;\n\n\tconst response = await runtime.useModel(ModelTypes.TEXT_SMALL, {\n\t\tprompt,\n\t});\n\n\tconst parsedResponse = parseJSONObjectFromText(response);\n\n\tif (parsedResponse?.title && parsedResponse?.summary) {\n\t\treturn {\n\t\t\ttitle: parsedResponse.title,\n\t\t\tdescription: parsedResponse.summary,\n\t\t};\n\t}\n\n\treturn {\n\t\ttitle: \"\",\n\t\tdescription: \"\",\n\t};\n}\n\nexport async function sendMessageInChunks(\n\tchannel: TextChannel,\n\tcontent: string,\n\t_inReplyTo: string,\n\tfiles: any[],\n): Promise<DiscordMessage[]> {\n\tconst sentMessages: DiscordMessage[] = [];\n\tconst messages = splitMessage(content);\n\ttry {\n\t\tfor (let i = 0; i < messages.length; i++) {\n\t\t\tconst message = messages[i];\n\t\t\tif (\n\t\t\t\tmessage.trim().length > 0 ||\n\t\t\t\t(i === messages.length - 1 && files && files.length > 0)\n\t\t\t) {\n\t\t\t\tconst options: any = {\n\t\t\t\t\tcontent: message.trim(),\n\t\t\t\t};\n\n\t\t\t\t// if (i === 0 && inReplyTo) {\n\t\t\t\t// // Reply to the specified message for the first chunk\n\t\t\t\t// options.reply = {\n\t\t\t\t// messageReference: inReplyTo,\n\t\t\t\t// };\n\t\t\t\t// }\n\n\t\t\t\tif (i === messages.length - 1 && files && files.length > 0) {\n\t\t\t\t\t// Attach files to the last message chunk\n\t\t\t\t\toptions.files = files;\n\t\t\t\t}\n\n\t\t\t\tconst m = await channel.send(options);\n\t\t\t\tsentMessages.push(m);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tlogger.error(\"Error sending message:\", error);\n\t}\n\n\treturn sentMessages;\n}\n\nfunction splitMessage(content: string): string[] {\n\tconst messages: string[] = [];\n\tlet currentMessage = \"\";\n\n\tconst rawLines = content?.split(\"\\n\") || [];\n\t// split all lines into MAX_MESSAGE_LENGTH chunks so any long lines are split\n\tconst lines = rawLines.flatMap((line) => {\n\t\tconst chunks = [];\n\t\twhile (line.length > MAX_MESSAGE_LENGTH) {\n\t\t\tchunks.push(line.slice(0, MAX_MESSAGE_LENGTH));\n\t\t\tline = line.slice(MAX_MESSAGE_LENGTH);\n\t\t}\n\t\tchunks.push(line);\n\t\treturn chunks;\n\t});\n\n\tfor (const line of lines) {\n\t\tif (currentMessage.length + line.length + 1 > MAX_MESSAGE_LENGTH) {\n\t\t\tmessages.push(currentMessage.trim());\n\t\t\tcurrentMessage = \"\";\n\t\t}\n\t\tcurrentMessage += `${line}\\n`;\n\t}\n\n\tif (currentMessage.trim().length > 0) {\n\t\tmessages.push(currentMessage.trim());\n\t}\n\n\treturn messages;\n}\n\nexport function canSendMessage(channel) {\n\t// validate input\n\tif (!channel) {\n\t\treturn {\n\t\t\tcanSend: false,\n\t\t\treason: \"No channel given\",\n\t\t};\n\t}\n\t// if it is a DM channel, we can always send messages\n\tif (channel.type === ChannelType.DM) {\n\t\treturn {\n\t\t\tcanSend: true,\n\t\t\treason: null,\n\t\t};\n\t}\n\tconst botMember = channel.guild?.members.cache.get(channel.client.user.id);\n\n\tif (!botMember) {\n\t\treturn {\n\t\t\tcanSend: false,\n\t\t\treason: \"Not a guild channel or bot member not found\",\n\t\t};\n\t}\n\n\t// Required permissions for sending messages\n\tconst requiredPermissions = [\n\t\tPermissionsBitField.Flags.ViewChannel,\n\t\tPermissionsBitField.Flags.SendMessages,\n\t\tPermissionsBitField.Flags.ReadMessageHistory,\n\t];\n\n\t// Add thread-specific permission if it's a thread\n\tif (channel instanceof ThreadChannel) {\n\t\trequiredPermissions.push(PermissionsBitField.Flags.SendMessagesInThreads);\n\t}\n\n\t// Check permissions\n\tconst permissions = channel.permissionsFor(botMember);\n\n\tif (!permissions) {\n\t\treturn {\n\t\t\tcanSend: false,\n\t\t\treason: \"Could not retrieve permissions\",\n\t\t};\n\t}\n\n\t// Check each required permission\n\tconst missingPermissions = requiredPermissions.filter(\n\t\t(perm) => !permissions.has(perm),\n\t);\n\n\treturn {\n\t\tcanSend: missingPermissions.length === 0,\n\t\tmissingPermissions: missingPermissions,\n\t\treason:\n\t\t\tmissingPermissions.length > 0\n\t\t\t\t? `Missing permissions: ${missingPermissions\n\t\t\t\t\t\t.map((p) => String(p))\n\t\t\t\t\t\t.join(\", \")}`\n\t\t\t\t: null,\n\t};\n}\n","import type { IAgentRuntime, Memory, Provider, State } from \"@elizaos/core\";\nimport { ChannelType } from \"@elizaos/core\";\nimport { ServiceTypes } from \"../types.ts\";\nimport type { DiscordService } from \"../index.ts\";\n\nconst channelStateProvider: Provider = {\n\tname: \"channelState\",\n\tget: async (runtime: IAgentRuntime, message: Memory, state?: State) => {\n\t\tconst room =\n\t\t\tstate.data?.room ??\n\t\t\t(await runtime.getDatabaseAdapter().getRoom(message.roomId));\n\t\tif (!room) {\n\t\t\tthrow new Error(\"No room found\");\n\t\t}\n\n\t\t// if message source is not discord, return\n\t\tif (message.content.source !== \"discord\") {\n\t\t\treturn {\n\t\t\t\tdata: null,\n\t\t\t\tvalues: {},\n\t\t\t\ttext: \"\",\n\t\t\t};\n\t\t}\n\n\t\tconst agentName = state?.agentName || \"The agent\";\n\t\tconst senderName = state?.senderName || \"someone\";\n\n\t\tlet responseText = \"\";\n\t\tlet channelType = \"\";\n\t\tlet serverName = \"\";\n\t\tlet channelId = \"\";\n\t\tconst serverId = room.serverId;\n\n\t\tif (room.type === ChannelType.DM) {\n\t\t\tchannelType = \"DM\";\n\t\t\tresponseText = `${agentName} is currently in a direct message conversation with ${senderName}. ${agentName} should engage in conversation, should respond to messages that are addressed to them and only ignore messages that seem to not require a response.`;\n\t\t} else {\n\t\t\tchannelType = \"GROUP\";\n\n\t\t\tif (!serverId) {\n\t\t\t\tconsole.error(\"No server ID found\");\n\t\t\t\treturn {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\troom,\n\t\t\t\t\t\tchannelType,\n\t\t\t\t\t},\n\t\t\t\t\tvalues: {\n\t\t\t\t\t\tchannelType,\n\t\t\t\t\t},\n\t\t\t\t\ttext: \"\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tchannelId = room.channelId;\n\n\t\t\tconst discordService = runtime.getService(\n\t\t\t\tServiceTypes.DISCORD,\n\t\t\t) as DiscordService;\n\t\t\tif (!discordService) {\n\t\t\t\tconsole.warn(\"No discord client found\");\n\t\t\t\treturn {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\troom,\n\t\t\t\t\t\tchannelType,\n\t\t\t\t\t\tserverId,\n\t\t\t\t\t},\n\t\t\t\t\tvalues: {\n\t\t\t\t\t\tchannelType,\n\t\t\t\t\t\tserverId,\n\t\t\t\t\t},\n\t\t\t\t\ttext: \"\",\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst guild = discordService.client.guilds.cache.get(serverId);\n\t\t\tserverName = guild.name;\n\n\t\t\tresponseText = `${agentName} is currently having a conversation in the channel \\`@${channelId} in the server \\`${serverName}\\` (@${serverId})`;\n\t\t\tresponseText += `\\n${agentName} is in a room with other users and should be self-conscious and only participate when directly addressed or when the conversation is relevant to them.`;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\troom,\n\t\t\t\tchannelType,\n\t\t\t\tserverId,\n\t\t\t\tserverName,\n\t\t\t\tchannelId,\n\t\t\t},\n\t\t\tvalues: {\n\t\t\t\tchannelType,\n\t\t\t\tserverName,\n\t\t\t\tchannelId,\n\t\t\t},\n\t\t\ttext: responseText,\n\t\t};\n\t},\n};\n\nexport default channelStateProvider;\n","import { getVoiceConnection } from \"@discordjs/voice\";\nimport type { IAgentRuntime, Memory, Provider, State } from \"@elizaos/core\";\nimport { ChannelType } from \"@elizaos/core\";\n\nconst voiceStateProvider: Provider = {\n\tname: \"voiceState\",\n\tget: async (runtime: IAgentRuntime, message: Memory, state?: State) => {\n\t\t// Voice doesn't get a discord message, so we need to use the channel for guild data\n\t\tconst room = await runtime.getDatabaseAdapter().getRoom(message.roomId);\n\t\tif (!room) {\n\t\t\tthrow new Error(\"No room found\");\n\t\t}\n\n\t\tif (room.type !== ChannelType.GROUP) {\n\t\t\t// only handle in a group scenario for now\n\t\t\treturn {\n\t\t\t\tdata: {\n\t\t\t\t\tisInVoiceChannel: false,\n\t\t\t\t\troom,\n\t\t\t\t},\n\t\t\t\tvalues: {\n\t\t\t\t\tisInVoiceChannel: \"false\",\n\t\t\t\t\troomType: room.type,\n\t\t\t\t},\n\t\t\t\ttext: \"\",\n\t\t\t};\n\t\t}\n\n\t\tconst serverId = room.serverId;\n\n\t\tif (!serverId) {\n\t\t\tthrow new Error(\"No server ID found 10\");\n\t\t}\n\n\t\tconst connection = getVoiceConnection(serverId);\n\t\tconst agentName = state?.agentName || \"The agent\";\n\n\t\tif (!connection) {\n\t\t\treturn {\n\t\t\t\tdata: {\n\t\t\t\t\tisInVoiceChannel: false,\n\t\t\t\t\troom,\n\t\t\t\t\tserverId,\n\t\t\t\t},\n\t\t\t\tvalues: {\n\t\t\t\t\tisInVoiceChannel: \"false\",\n\t\t\t\t\tserverId,\n\t\t\t\t},\n\t\t\t\ttext: `${agentName} is not currently in a voice channel`,\n\t\t\t};\n\t\t}\n\n\t\tconst worldId = room.worldId;\n\n\t\t// get the world from the runtime.getDatabaseAdapter().getWorld\n\t\tconst world = await runtime.getDatabaseAdapter().getWorld(worldId);\n\n\t\tif (!world) {\n\t\t\tthrow new Error(\"No world found\");\n\t\t}\n\n\t\tconst worldName = world.name;\n\t\tconst roomType = room.type;\n\t\tconst channelId = room.channelId;\n\t\tconst channelName = room.name;\n\n\t\tif (!channelId) {\n\t\t\treturn {\n\t\t\t\tdata: {\n\t\t\t\t\tisInVoiceChannel: true,\n\t\t\t\t\troom,\n\t\t\t\t\tserverId,\n\t\t\t\t\tworld,\n\t\t\t\t\tconnection,\n\t\t\t\t},\n\t\t\t\tvalues: {\n\t\t\t\t\tisInVoiceChannel: \"true\",\n\t\t\t\t\tserverId,\n\t\t\t\t\tworldName,\n\t\t\t\t\troomType,\n\t\t\t\t},\n\t\t\t\ttext: `${agentName} is in an invalid voice channel`,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\tisInVoiceChannel: true,\n\t\t\t\troom,\n\t\t\t\tserverId,\n\t\t\t\tworld,\n\t\t\t\tconnection,\n\t\t\t\tchannelId,\n\t\t\t\tchannelName,\n\t\t\t},\n\t\t\tvalues: {\n\t\t\t\tisInVoiceChannel: \"true\",\n\t\t\t\tserverId,\n\t\t\t\tworldName,\n\t\t\t\troomType,\n\t\t\t\tchannelId,\n\t\t\t\tchannelName,\n\t\t\t},\n\t\t\ttext: `${agentName} is currently in the voice channel: ${channelName} (ID: ${channelId})`,\n\t\t};\n\t},\n};\n\nexport default voiceStateProvider;\n","import {\n\tAudioPlayerStatus,\n\tNoSubscriberBehavior,\n\tVoiceConnectionStatus,\n\tcreateAudioPlayer,\n\tcreateAudioResource,\n\tentersState,\n\ttype VoiceConnection,\n} from \"@discordjs/voice\";\nimport {\n\tModelTypes,\n\tlogger,\n\ttype IAgentRuntime,\n\ttype TestSuite,\n} from \"@elizaos/core\";\nimport { ChannelType, Events, type TextChannel } from \"discord.js\";\nimport type { DiscordService } from \"./index.ts\";\nimport { ServiceTypes } from \"./types.ts\";\nimport { sendMessageInChunks } from \"./utils.ts\";\n\nconst TEST_IMAGE_URL =\n\t\"https://github.com/elizaOS/awesome-eliza/blob/main/assets/eliza-logo.jpg?raw=true\";\n\nexport class DiscordTestSuite implements TestSuite {\n\tname = \"discord\";\n\tprivate discordClient: DiscordService | null = null;\n\ttests: { name: string; fn: (runtime: IAgentRuntime) => Promise<void> }[];\n\n\tconstructor() {\n\t\tthis.tests = [\n\t\t\t{\n\t\t\t\tname: \"Initialize Discord Client\",\n\t\t\t\tfn: this.testCreatingDiscordClient.bind(this),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"Slash Commands - Join Voice\",\n\t\t\t\tfn: this.testJoinVoiceSlashCommand.bind(this),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"Voice Playback & TTS\",\n\t\t\t\tfn: this.testTextToSpeechPlayback.bind(this),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"Send Message with Attachments\",\n\t\t\t\tfn: this.testSendingTextMessage.bind(this),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"Handle Incoming Messages\",\n\t\t\t\tfn: this.testHandlingMessage.bind(this),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"Slash Commands - Leave Voice\",\n\t\t\t\tfn: this.testLeaveVoiceSlashCommand.bind(this),\n\t\t\t},\n\t\t];\n\t}\n\n\tasync testCreatingDiscordClient(runtime: IAgentRuntime) {\n\t\ttry {\n\t\t\tthis.discordClient = runtime.getService(\n\t\t\t\tServiceTypes.DISCORD,\n\t\t\t) as DiscordService;\n\n\t\t\t// Wait for the bot to be ready before proceeding\n\t\t\tif (this.discordClient.client.isReady()) {\n\t\t\t\tlogger.success(\"DiscordService is already ready.\");\n\t\t\t} else {\n\t\t\t\tlogger.info(\"Waiting for DiscordService to be ready...\");\n\t\t\t\tawait new Promise((resolve, reject) => {\n\t\t\t\t\tthis.discordClient.client.once(Events.ClientReady, resolve);\n\t\t\t\t\tthis.discordClient.client.once(Events.Error, reject);\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error in test creating Discord client: ${error}`);\n\t\t}\n\t}\n\n\tasync testJoinVoiceSlashCommand(runtime: IAgentRuntime) {\n\t\ttry {\n\t\t\tawait this.waitForVoiceManagerReady(this.discordClient);\n\n\t\t\tconst channel = await this.getTestChannel(runtime);\n\t\t\tif (!channel || !channel.isTextBased()) {\n\t\t\t\tthrow new Error(\"Invalid test channel for slash command test.\");\n\t\t\t}\n\n\t\t\t// Simulate a join channel slash command interaction\n\t\t\tconst fakeJoinInteraction = {\n\t\t\t\tisCommand: () => true,\n\t\t\t\tcommandName: \"joinchannel\",\n\t\t\t\toptions: {\n\t\t\t\t\tget: (name: string) =>\n\t\t\t\t\t\tname === \"channel\" ? { value: channel.id } : null,\n\t\t\t\t},\n\t\t\t\tguild: (channel as TextChannel).guild,\n\t\t\t\tdeferReply: async () => {},\n\t\t\t\teditReply: async (message: string) => {\n\t\t\t\t\tlogger.info(`JoinChannel Slash Command Response: ${message}`);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tawait this.discordClient.voiceManager.handleJoinChannelCommand(\n\t\t\t\tfakeJoinInteraction as any,\n\t\t\t);\n\n\t\t\tlogger.success(\"Slash command test completed successfully.\");\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error in slash commands test: ${error}`);\n\t\t}\n\t}\n\n\tasync testLeaveVoiceSlashCommand(runtime: IAgentRuntime) {\n\t\ttry {\n\t\t\tawait this.waitForVoiceManagerReady(this.discordClient);\n\n\t\t\tconst channel = await this.getTestChannel(runtime);\n\t\t\tif (!channel || !channel.isTextBased()) {\n\t\t\t\tthrow new Error(\"Invalid test channel for slash command test.\");\n\t\t\t}\n\n\t\t\t// Simulate a leave channel slash command interaction\n\t\t\tconst fakeLeaveInteraction = {\n\t\t\t\tisCommand: () => true,\n\t\t\t\tcommandName: \"leavechannel\",\n\t\t\t\tguildId: (channel as TextChannel).guildId,\n\t\t\t\treply: async (message: string) => {\n\t\t\t\t\tlogger.info(`LeaveChannel Slash Command Response: ${message}`);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tawait this.discordClient.voiceManager.handleLeaveChannelCommand(\n\t\t\t\tfakeLeaveInteraction as any,\n\t\t\t);\n\n\t\t\tlogger.success(\"Slash command test completed successfully.\");\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error in slash commands test: ${error}`);\n\t\t}\n\t}\n\n\tasync testTextToSpeechPlayback(runtime: IAgentRuntime) {\n\t\ttry {\n\t\t\tawait this.waitForVoiceManagerReady(this.discordClient);\n\n\t\t\tconst channel = await this.getTestChannel(runtime);\n\t\t\tif (!channel || channel.type !== ChannelType.GuildVoice) {\n\t\t\t\tthrow new Error(\"Invalid voice channel.\");\n\t\t\t}\n\n\t\t\tawait this.discordClient.voiceManager.joinChannel(channel);\n\n\t\t\tconst guild = await this.getActiveGuild(this.discordClient);\n\t\t\tconst guildId = guild.id;\n\t\t\tconst connection =\n\t\t\t\tthis.discordClient.voiceManager.getVoiceConnection(guildId);\n\n\t\t\ttry {\n\t\t\t\tawait entersState(connection, VoiceConnectionStatus.Ready, 10_000);\n\t\t\t\tlogger.success(`Voice connection is ready in guild: ${guildId}`);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(`Voice connection failed to become ready: ${error}`);\n\t\t\t}\n\n\t\t\tlet responseStream = null;\n\n\t\t\ttry {\n\t\t\t\tresponseStream = await runtime.useModel(\n\t\t\t\t\tModelTypes.TEXT_TO_SPEECH,\n\t\t\t\t\t`Hi! I'm ${runtime.character.name}! How are you doing today?`,\n\t\t\t\t);\n\t\t\t} catch (_error) {\n\t\t\t\tthrow new Error(\"No text to speech service found\");\n\t\t\t}\n\n\t\t\tif (!responseStream) {\n\t\t\t\tthrow new Error(\"TTS response stream is null or undefined.\");\n\t\t\t}\n\n\t\t\tawait this.playAudioStream(responseStream, connection);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error in TTS playback test: ${error}`);\n\t\t}\n\t}\n\n\tasync testSendingTextMessage(runtime: IAgentRuntime) {\n\t\ttry {\n\t\t\tconst channel = await this.getTestChannel(runtime);\n\n\t\t\tawait this.sendMessageToChannel(\n\t\t\t\tchannel as TextChannel,\n\t\t\t\t\"Testing Message\",\n\t\t\t\t[TEST_IMAGE_URL],\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error in sending text message: ${error}`);\n\t\t}\n\t}\n\n\tasync testHandlingMessage(runtime: IAgentRuntime) {\n\t\ttry {\n\t\t\tconst channel = await this.getTestChannel(runtime);\n\n\t\t\tconst fakeMessage = {\n\t\t\t\tcontent: `Hello, ${runtime.character.name}! How are you?`,\n\t\t\t\tauthor: {\n\t\t\t\t\tid: \"mock-user-id\",\n\t\t\t\t\tusername: \"MockUser\",\n\t\t\t\t\tbot: false,\n\t\t\t\t},\n\t\t\t\tchannel,\n\t\t\t\tid: \"mock-message-id\",\n\t\t\t\tcreatedTimestamp: Date.now(),\n\t\t\t\tmentions: {\n\t\t\t\t\thas: () => false,\n\t\t\t\t},\n\t\t\t\treference: null,\n\t\t\t\tattachments: [],\n\t\t\t};\n\t\t\tawait this.discordClient.messageManager.handleMessage(fakeMessage as any);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error in sending text message: ${error}`);\n\t\t}\n\t}\n\n\t// #############################\n\t// Utility Functions\n\t// #############################\n\n\tasync getTestChannel(runtime: IAgentRuntime) {\n\t\tconst channelId = this.validateChannelId(runtime);\n\t\tconst channel = await this.discordClient.client.channels.fetch(channelId);\n\n\t\tif (!channel) throw new Error(\"no test channel found!\");\n\n\t\treturn channel;\n\t}\n\n\tasync sendMessageToChannel(\n\t\tchannel: TextChannel,\n\t\tmessageContent: string,\n\t\tfiles: any[],\n\t) {\n\t\ttry {\n\t\t\tif (!channel || !channel.isTextBased()) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Channel is not a text-based channel or does not exist.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait sendMessageInChunks(\n\t\t\t\tchannel as TextChannel,\n\t\t\t\tmessageContent,\n\t\t\t\tnull,\n\t\t\t\tfiles,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Error sending message: ${error}`);\n\t\t}\n\t}\n\n\tasync playAudioStream(responseStream: any, connection: VoiceConnection) {\n\t\tconst audioPlayer = createAudioPlayer({\n\t\t\tbehaviors: {\n\t\t\t\tnoSubscriber: NoSubscriberBehavior.Pause,\n\t\t\t},\n\t\t});\n\n\t\tconst audioResource = createAudioResource(responseStream);\n\n\t\taudioPlayer.play(audioResource);\n\t\tconnection.subscribe(audioPlayer);\n\n\t\tlogger.success(\"TTS playback started successfully.\");\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\taudioPlayer.once(AudioPlayerStatus.Idle, () => {\n\t\t\t\tlogger.info(\"TTS playback finished.\");\n\t\t\t\tresolve();\n\t\t\t});\n\n\t\t\taudioPlayer.once(\"error\", (error) => {\n\t\t\t\treject(error);\n\t\t\t\tthrow new Error(`TTS playback error: ${error}`);\n\t\t\t});\n\t\t});\n\t}\n\n\tasync getActiveGuild(discordClient: DiscordService) {\n\t\tconst guilds = await discordClient.client.guilds.fetch();\n\t\tconst fullGuilds = await Promise.all(guilds.map((guild) => guild.fetch())); // Fetch full guild data\n\n\t\tconst activeGuild = fullGuilds.find((g) => g.members.me?.voice.channelId);\n\t\tif (!activeGuild) {\n\t\t\tthrow new Error(\"No active voice connection found for the bot.\");\n\t\t}\n\t\treturn activeGuild;\n\t}\n\n\tprivate async waitForVoiceManagerReady(discordClient: DiscordService) {\n\t\tif (!discordClient) {\n\t\t\tthrow new Error(\"Discord client is not initialized.\");\n\t\t}\n\n\t\tif (!discordClient.voiceManager.isReady()) {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tdiscordClient.voiceManager.once(\"ready\", resolve);\n\t\t\t\tdiscordClient.voiceManager.once(\"error\", reject);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate validateChannelId(runtime: IAgentRuntime) {\n\t\tconst testChannelId =\n\t\t\truntime.getSetting(\"DISCORD_TEST_CHANNEL_ID\") ||\n\t\t\tprocess.env.DISCORD_TEST_CHANNEL_ID;\n\t\tif (!testChannelId) {\n\t\t\tthrow new Error(\n\t\t\t\t\"DISCORD_TEST_CHANNEL_ID is not set. Please provide a valid channel ID in the environment variables.\",\n\t\t\t);\n\t\t}\n\t\treturn testChannelId;\n\t}\n}\n","import {\n\ttype AudioPlayer,\n\ttype AudioReceiveStream,\n\tNoSubscriberBehavior,\n\tStreamType,\n\ttype VoiceConnection,\n\tVoiceConnectionStatus,\n\tcreateAudioPlayer,\n\tcreateAudioResource,\n\tentersState,\n\tgetVoiceConnections,\n\tjoinVoiceChannel,\n} from \"@discordjs/voice\";\nimport {\n\tChannelType,\n\ttype Content,\n\ttype HandlerCallback,\n\ttype IAgentRuntime,\n\ttype Memory,\n\tModelTypes,\n\ttype UUID,\n\tcreateUniqueUuid,\n\tlogger,\n} from \"@elizaos/core\";\nimport {\n\ttype BaseGuildVoiceChannel,\n\ttype Channel,\n\ttype Client,\n\tChannelType as DiscordChannelType,\n\ttype Guild,\n\ttype GuildMember,\n\ttype VoiceChannel,\n\ttype VoiceState,\n} from \"discord.js\";\nimport { EventEmitter } from \"node:events\";\nimport { type Readable, pipeline } from \"node:stream\";\nimport prism from \"prism-media\";\nimport type { DiscordService } from \"./index.ts\";\nimport { getWavHeader } from \"./utils.ts\";\n\n// These values are chosen for compatibility with picovoice components\nconst DECODE_FRAME_SIZE = 1024;\nconst DECODE_SAMPLE_RATE = 16000;\n\nexport class AudioMonitor {\n\tprivate readable: Readable;\n\tprivate buffers: Buffer[] = [];\n\tprivate maxSize: number;\n\tprivate lastFlagged = -1;\n\tprivate ended = false;\n\n\tconstructor(\n\t\treadable: Readable,\n\t\tmaxSize: number,\n\t\tonStart: () => void,\n\t\tcallback: (buffer: Buffer) => void,\n\t) {\n\t\tthis.readable = readable;\n\t\tthis.maxSize = maxSize;\n\t\tthis.readable.on(\"data\", (chunk: Buffer) => {\n\t\t\t//console.log('AudioMonitor got data');\n\t\t\tif (this.lastFlagged < 0) {\n\t\t\t\tthis.lastFlagged = this.buffers.length;\n\t\t\t}\n\t\t\tthis.buffers.push(chunk);\n\t\t\tconst currentSize = this.buffers.reduce(\n\t\t\t\t(acc, cur) => acc + cur.length,\n\t\t\t\t0,\n\t\t\t);\n\t\t\twhile (currentSize > this.maxSize) {\n\t\t\t\tthis.buffers.shift();\n\t\t\t\tthis.lastFlagged--;\n\t\t\t}\n\t\t});\n\t\tthis.readable.on(\"end\", () => {\n\t\t\tlogger.log(\"AudioMonitor ended\");\n\t\t\tthis.ended = true;\n\t\t\tif (this.lastFlagged < 0) return;\n\t\t\tcallback(this.getBufferFromStart());\n\t\t\tthis.lastFlagged = -1;\n\t\t});\n\t\tthis.readable.on(\"speakingStopped\", () => {\n\t\t\tif (this.ended) return;\n\t\t\tlogger.log(\"Speaking stopped\");\n\t\t\tif (this.lastFlagged < 0) return;\n\t\t\tcallback(this.getBufferFromStart());\n\t\t});\n\t\tthis.readable.on(\"speakingStarted\", () => {\n\t\t\tif (this.ended) return;\n\t\t\tonStart();\n\t\t\tlogger.log(\"Speaking started\");\n\t\t\tthis.reset();\n\t\t});\n\t}\n\n\tstop() {\n\t\tthis.readable.removeAllListeners(\"data\");\n\t\tthis.readable.removeAllListeners(\"end\");\n\t\tthis.readable.removeAllListeners(\"speakingStopped\");\n\t\tthis.readable.removeAllListeners(\"speakingStarted\");\n\t}\n\n\tisFlagged() {\n\t\treturn this.lastFlagged >= 0;\n\t}\n\n\tgetBufferFromFlag() {\n\t\tif (this.lastFlagged < 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst buffer = Buffer.concat(this.buffers.slice(this.lastFlagged));\n\t\treturn buffer;\n\t}\n\n\tgetBufferFromStart() {\n\t\tconst buffer = Buffer.concat(this.buffers);\n\t\treturn buffer;\n\t}\n\n\treset() {\n\t\tthis.buffers = [];\n\t\tthis.lastFlagged = -1;\n\t}\n\n\tisEnded() {\n\t\treturn this.ended;\n\t}\n}\n\nexport class VoiceManager extends EventEmitter {\n\tprivate processingVoice = false;\n\tprivate transcriptionTimeout: NodeJS.Timeout | null = null;\n\tprivate userStates: Map<\n\t\tstring,\n\t\t{\n\t\t\tbuffers: Buffer[];\n\t\t\ttotalLength: number;\n\t\t\tlastActive: number;\n\t\t\ttranscriptionText: string;\n\t\t}\n\t> = new Map();\n\tprivate activeAudioPlayer: AudioPlayer | null = null;\n\tprivate client: Client;\n\tprivate runtime: IAgentRuntime;\n\tprivate streams: Map<string, Readable> = new Map();\n\tprivate connections: Map<string, VoiceConnection> = new Map();\n\tprivate activeMonitors: Map<\n\t\tstring,\n\t\t{ channel: BaseGuildVoiceChannel; monitor: AudioMonitor }\n\t> = new Map();\n\tprivate ready: boolean;\n\n\tconstructor(service: DiscordService, runtime: IAgentRuntime) {\n\t\tsuper();\n\t\tthis.client = service.client;\n\t\tthis.runtime = runtime;\n\n\t\tthis.client.on(\"voiceManagerReady\", () => {\n\t\t\tthis.setReady(true);\n\t\t});\n\t}\n\n\tasync getChannelType(channel: Channel): Promise<ChannelType> {\n\t\tswitch (channel.type) {\n\t\t\tcase DiscordChannelType.GuildVoice:\n\t\t\tcase DiscordChannelType.GuildStageVoice:\n\t\t\t\treturn ChannelType.VOICE_GROUP;\n\t\t}\n\t}\n\n\tprivate setReady(status: boolean) {\n\t\tthis.ready = status;\n\t\tthis.emit(\"ready\");\n\t\tlogger.success(`VoiceManager is now ready: ${this.ready}`);\n\t}\n\n\tisReady() {\n\t\treturn this.ready;\n\t}\n\n\tasync handleVoiceStateUpdate(oldState: VoiceState, newState: VoiceState) {\n\t\tconst oldChannelId = oldState.channelId;\n\t\tconst newChannelId = newState.channelId;\n\t\tconst member = newState.member;\n\t\tif (!member) return;\n\t\tif (member.id === this.client.user?.id) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ignore mute/unmute events\n\t\tif (oldChannelId === newChannelId) {\n\t\t\treturn;\n\t\t}\n\n\t\t// User leaving a channel where the bot is present\n\t\tif (oldChannelId && this.connections.has(oldChannelId)) {\n\t\t\tthis.stopMonitoringMember(member.id);\n\t\t}\n\n\t\t// User joining a channel where the bot is present\n\t\tif (newChannelId && this.connections.has(newChannelId)) {\n\t\t\tawait this.monitorMember(\n\t\t\t\tmember,\n\t\t\t\tnewState.channel as BaseGuildVoiceChannel,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync joinChannel(channel: BaseGuildVoiceChannel) {\n\t\tconst oldConnection = this.getVoiceConnection(channel.guildId as string);\n\t\tif (oldConnection) {\n\t\t\ttry {\n\t\t\t\toldConnection.destroy();\n\t\t\t\t// Remove all associated streams and monitors\n\t\t\t\tthis.streams.clear();\n\t\t\t\tthis.activeMonitors.clear();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error leaving voice channel:\", error);\n\t\t\t}\n\t\t}\n\n\t\tconst connection = joinVoiceChannel({\n\t\t\tchannelId: channel.id,\n\t\t\tguildId: channel.guild.id,\n\t\t\tadapterCreator: channel.guild.voiceAdapterCreator as any,\n\t\t\tselfDeaf: false,\n\t\t\tselfMute: false,\n\t\t\tgroup: this.client.user.id,\n\t\t});\n\n\t\ttry {\n\t\t\t// Wait for either Ready or Signalling state\n\t\t\tawait Promise.race([\n\t\t\t\tentersState(connection, VoiceConnectionStatus.Ready, 20_000),\n\t\t\t\tentersState(connection, VoiceConnectionStatus.Signalling, 20_000),\n\t\t\t]);\n\n\t\t\t// Log connection success\n\t\t\tlogger.log(\n\t\t\t\t`Voice connection established in state: ${connection.state.status}`,\n\t\t\t);\n\n\t\t\t// Set up ongoing state change monitoring\n\t\t\tconnection.on(\"stateChange\", async (oldState, newState) => {\n\t\t\t\tlogger.log(\n\t\t\t\t\t`Voice connection state changed from ${oldState.status} to ${newState.status}`,\n\t\t\t\t);\n\n\t\t\t\tif (newState.status === VoiceConnectionStatus.Disconnected) {\n\t\t\t\t\tlogger.log(\"Handling disconnection...\");\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try to reconnect if disconnected\n\t\t\t\t\t\tawait Promise.race([\n\t\t\t\t\t\t\tentersState(connection, VoiceConnectionStatus.Signalling, 5_000),\n\t\t\t\t\t\t\tentersState(connection, VoiceConnectionStatus.Connecting, 5_000),\n\t\t\t\t\t\t]);\n\t\t\t\t\t\t// Seems to be reconnecting to a new channel\n\t\t\t\t\t\tlogger.log(\"Reconnecting to channel...\");\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// Seems to be a real disconnect, destroy and cleanup\n\t\t\t\t\t\tlogger.log(`Disconnection confirmed - cleaning up...${e}`);\n\t\t\t\t\t\tconnection.destroy();\n\t\t\t\t\t\tthis.connections.delete(channel.id);\n\t\t\t\t\t}\n\t\t\t\t} else if (newState.status === VoiceConnectionStatus.Destroyed) {\n\t\t\t\t\tthis.connections.delete(channel.id);\n\t\t\t\t} else if (\n\t\t\t\t\t!this.connections.has(channel.id) &&\n\t\t\t\t\t(newState.status === VoiceConnectionStatus.Ready ||\n\t\t\t\t\t\tnewState.status === VoiceConnectionStatus.Signalling)\n\t\t\t\t) {\n\t\t\t\t\tthis.connections.set(channel.id, connection);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconnection.on(\"error\", (error) => {\n\t\t\t\tlogger.log(\"Voice connection error:\", error);\n\t\t\t\t// Don't immediately destroy - let the state change handler deal with it\n\t\t\t\tlogger.log(\"Connection error - will attempt to recover...\");\n\t\t\t});\n\n\t\t\t// Store the connection\n\t\t\tthis.connections.set(channel.id, connection);\n\n\t\t\t// Continue with voice state modifications\n\t\t\tconst me = channel.guild.members.me;\n\t\t\tif (me?.voice && me.permissions.has(\"DeafenMembers\")) {\n\t\t\t\ttry {\n\t\t\t\t\tawait me.voice.setDeaf(false);\n\t\t\t\t\tawait me.voice.setMute(false);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.log(\"Failed to modify voice state:\", error);\n\t\t\t\t\t// Continue even if this fails\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconnection.receiver.speaking.on(\"start\", async (entityId: string) => {\n\t\t\t\tlet user = channel.members.get(entityId);\n\t\t\t\tif (!user) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tuser = await channel.guild.members.fetch(entityId);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconsole.error(\"Failed to fetch user:\", error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (user && !user?.user.bot) {\n\t\t\t\t\tthis.monitorMember(user as GuildMember, channel);\n\t\t\t\t\tthis.streams.get(entityId)?.emit(\"speakingStarted\");\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconnection.receiver.speaking.on(\"end\", async (entityId: string) => {\n\t\t\t\tconst user = channel.members.get(entityId);\n\t\t\t\tif (!user?.user.bot) {\n\t\t\t\t\tthis.streams.get(entityId)?.emit(\"speakingStopped\");\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlogger.log(\"Failed to establish voice connection:\", error);\n\t\t\tconnection.destroy();\n\t\t\tthis.connections.delete(channel.id);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tgetVoiceConnection(guildId: string) {\n\t\tconst connections = getVoiceConnections(this.client.user.id);\n\t\tif (!connections) {\n\t\t\treturn;\n\t\t}\n\t\tconst connection = [...connections.values()].find(\n\t\t\t(connection) => connection.joinConfig.guildId === guildId,\n\t\t);\n\t\treturn connection;\n\t}\n\n\tprivate async monitorMember(\n\t\tmember: GuildMember,\n\t\tchannel: BaseGuildVoiceChannel,\n\t) {\n\t\tconst entityId = member?.id;\n\t\tconst userName = member?.user?.username;\n\t\tconst name = member?.user?.displayName;\n\t\tconst connection = this.getVoiceConnection(member?.guild?.id);\n\t\tconst receiveStream = connection?.receiver.subscribe(entityId, {\n\t\t\tautoDestroy: true,\n\t\t\temitClose: true,\n\t\t});\n\t\tif (!receiveStream || receiveStream.readableLength === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst opusDecoder = new prism.opus.Decoder({\n\t\t\tchannels: 1,\n\t\t\trate: DECODE_SAMPLE_RATE,\n\t\t\tframeSize: DECODE_FRAME_SIZE,\n\t\t});\n\t\tconst volumeBuffer: number[] = [];\n\t\tconst VOLUME_WINDOW_SIZE = 30;\n\t\tconst SPEAKING_THRESHOLD = 0.05;\n\t\topusDecoder.on(\"data\", (pcmData: Buffer) => {\n\t\t\t// Monitor the audio volume while the agent is speaking.\n\t\t\t// If the average volume of the user's audio exceeds the defined threshold, it indicates active speaking.\n\t\t\t// When active speaking is detected, stop the agent's current audio playback to avoid overlap.\n\n\t\t\tif (this.activeAudioPlayer) {\n\t\t\t\tconst samples = new Int16Array(\n\t\t\t\t\tpcmData.buffer,\n\t\t\t\t\tpcmData.byteOffset,\n\t\t\t\t\tpcmData.length / 2,\n\t\t\t\t);\n\t\t\t\tconst maxAmplitude = Math.max(...samples.map(Math.abs)) / 32768;\n\t\t\t\tvolumeBuffer.push(maxAmplitude);\n\n\t\t\t\tif (volumeBuffer.length > VOLUME_WINDOW_SIZE) {\n\t\t\t\t\tvolumeBuffer.shift();\n\t\t\t\t}\n\t\t\t\tconst avgVolume =\n\t\t\t\t\tvolumeBuffer.reduce((sum, v) => sum + v, 0) / VOLUME_WINDOW_SIZE;\n\n\t\t\t\tif (avgVolume > SPEAKING_THRESHOLD) {\n\t\t\t\t\tvolumeBuffer.length = 0;\n\t\t\t\t\tthis.cleanupAudioPlayer(this.activeAudioPlayer);\n\t\t\t\t\tthis.processingVoice = false;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tpipeline(\n\t\t\treceiveStream as AudioReceiveStream,\n\t\t\topusDecoder as any,\n\t\t\t(err: Error | null) => {\n\t\t\t\tif (err) {\n\t\t\t\t\tconsole.log(`Opus decoding pipeline error: ${err}`);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t\tthis.streams.set(entityId, opusDecoder);\n\t\tthis.connections.set(entityId, connection as VoiceConnection);\n\t\topusDecoder.on(\"error\", (err: any) => {\n\t\t\tconsole.log(`Opus decoding error: ${err}`);\n\t\t});\n\t\tconst errorHandler = (err: any) => {\n\t\t\tconsole.log(`Opus decoding error: ${err}`);\n\t\t};\n\t\tconst streamCloseHandler = () => {\n\t\t\tconsole.log(`voice stream from ${member?.displayName} closed`);\n\t\t\tthis.streams.delete(entityId);\n\t\t\tthis.connections.delete(entityId);\n\t\t};\n\t\tconst closeHandler = () => {\n\t\t\tconsole.log(`Opus decoder for ${member?.displayName} closed`);\n\t\t\topusDecoder.removeListener(\"error\", errorHandler);\n\t\t\topusDecoder.removeListener(\"close\", closeHandler);\n\t\t\treceiveStream?.removeListener(\"close\", streamCloseHandler);\n\t\t};\n\t\topusDecoder.on(\"error\", errorHandler);\n\t\topusDecoder.on(\"close\", closeHandler);\n\t\treceiveStream?.on(\"close\", streamCloseHandler);\n\n\t\tthis.client.emit(\n\t\t\t\"userStream\",\n\t\t\tentityId,\n\t\t\tname,\n\t\t\tuserName,\n\t\t\tchannel,\n\t\t\topusDecoder,\n\t\t);\n\t}\n\n\tleaveChannel(channel: BaseGuildVoiceChannel) {\n\t\tconst connection = this.connections.get(channel.id);\n\t\tif (connection) {\n\t\t\tconnection.destroy();\n\t\t\tthis.connections.delete(channel.id);\n\t\t}\n\n\t\t// Stop monitoring all members in this channel\n\t\tfor (const [memberId, monitorInfo] of this.activeMonitors) {\n\t\t\tif (\n\t\t\t\tmonitorInfo.channel.id === channel.id &&\n\t\t\t\tmemberId !== this.client.user?.id\n\t\t\t) {\n\t\t\t\tthis.stopMonitoringMember(memberId);\n\t\t\t}\n\t\t}\n\n\t\tconsole.log(`Left voice channel: ${channel.name} (${channel.id})`);\n\t}\n\n\tstopMonitoringMember(memberId: string) {\n\t\tconst monitorInfo = this.activeMonitors.get(memberId);\n\t\tif (monitorInfo) {\n\t\t\tmonitorInfo.monitor.stop();\n\t\t\tthis.activeMonitors.delete(memberId);\n\t\t\tthis.streams.delete(memberId);\n\t\t\tconsole.log(`Stopped monitoring user ${memberId}`);\n\t\t}\n\t}\n\n\tasync debouncedProcessTranscription(\n\t\tentityId: UUID,\n\t\tname: string,\n\t\tuserName: string,\n\t\tchannel: BaseGuildVoiceChannel,\n\t) {\n\t\tconst DEBOUNCE_TRANSCRIPTION_THRESHOLD = 1500; // wait for 1.5 seconds of silence\n\n\t\tif (this.activeAudioPlayer?.state?.status === \"idle\") {\n\t\t\tlogger.log(\"Cleaning up idle audio player.\");\n\t\t\tthis.cleanupAudioPlayer(this.activeAudioPlayer);\n\t\t}\n\n\t\tif (this.activeAudioPlayer || this.processingVoice) {\n\t\t\tconst state = this.userStates.get(entityId);\n\t\t\tstate.buffers.length = 0;\n\t\t\tstate.totalLength = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.transcriptionTimeout) {\n\t\t\tclearTimeout(this.transcriptionTimeout);\n\t\t}\n\n\t\tthis.transcriptionTimeout = setTimeout(async () => {\n\t\t\tthis.processingVoice = true;\n\t\t\ttry {\n\t\t\t\tawait this.processTranscription(\n\t\t\t\t\tentityId,\n\t\t\t\t\tchannel.id,\n\t\t\t\t\tchannel,\n\t\t\t\t\tname,\n\t\t\t\t\tuserName,\n\t\t\t\t);\n\n\t\t\t\t// Clean all users' previous buffers\n\t\t\t\tthis.userStates.forEach((state, _) => {\n\t\t\t\t\tstate.buffers.length = 0;\n\t\t\t\t\tstate.totalLength = 0;\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tthis.processingVoice = false;\n\t\t\t}\n\t\t}, DEBOUNCE_TRANSCRIPTION_THRESHOLD) as unknown as NodeJS.Timeout;\n\t}\n\n\tasync handleUserStream(\n\t\tuserId: UUID,\n\t\tname: string,\n\t\tuserName: string,\n\t\tchannel: BaseGuildVoiceChannel,\n\t\taudioStream: Readable,\n\t) {\n\t\tconst entityId = createUniqueUuid(this.runtime, userId);\n\t\tconsole.log(`Starting audio monitor for user: ${entityId}`);\n\t\tif (!this.userStates.has(entityId)) {\n\t\t\tthis.userStates.set(entityId, {\n\t\t\t\tbuffers: [],\n\t\t\t\ttotalLength: 0,\n\t\t\t\tlastActive: Date.now(),\n\t\t\t\ttranscriptionText: \"\",\n\t\t\t});\n\t\t}\n\n\t\tconst state = this.userStates.get(entityId);\n\n\t\tconst processBuffer = async (buffer: Buffer) => {\n\t\t\ttry {\n\t\t\t\tstate?.buffers.push(buffer);\n\t\t\t\tstate!.totalLength += buffer.length;\n\t\t\t\tstate!.lastActive = Date.now();\n\t\t\t\tthis.debouncedProcessTranscription(entityId, name, userName, channel);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`Error processing buffer for user ${entityId}:`, error);\n\t\t\t}\n\t\t};\n\n\t\tnew AudioMonitor(\n\t\t\taudioStream,\n\t\t\t10000000,\n\t\t\t() => {\n\t\t\t\tif (this.transcriptionTimeout) {\n\t\t\t\t\tclearTimeout(this.transcriptionTimeout);\n\t\t\t\t}\n\t\t\t},\n\t\t\tasync (buffer) => {\n\t\t\t\tif (!buffer) {\n\t\t\t\t\tconsole.error(\"Received empty buffer\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait processBuffer(buffer);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate async processTranscription(\n\t\tentityId: UUID,\n\t\tchannelId: string,\n\t\tchannel: BaseGuildVoiceChannel,\n\t\tname: string,\n\t\tuserName: string,\n\t) {\n\t\tconst state = this.userStates.get(entityId);\n\t\tif (!state || state.buffers.length === 0) return;\n\t\ttry {\n\t\t\tconst inputBuffer = Buffer.concat(state.buffers, state.totalLength);\n\n\t\t\tstate.buffers.length = 0; // Clear the buffers\n\t\t\tstate.totalLength = 0;\n\t\t\t// Convert Opus to WAV\n\t\t\tconst wavBuffer = await this.convertOpusToWav(inputBuffer);\n\t\t\tconsole.log(\"Starting transcription...\");\n\n\t\t\tconst transcriptionText = await this.runtime.useModel(\n\t\t\t\tModelTypes.TRANSCRIPTION,\n\t\t\t\twavBuffer,\n\t\t\t);\n\t\t\tfunction isValidTranscription(text: string): boolean {\n\t\t\t\tif (!text || text.includes(\"[BLANK_AUDIO]\")) return false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (transcriptionText && isValidTranscription(transcriptionText)) {\n\t\t\t\tstate.transcriptionText += transcriptionText;\n\t\t\t}\n\n\t\t\tif (state.transcriptionText.length) {\n\t\t\t\tthis.cleanupAudioPlayer(this.activeAudioPlayer);\n\t\t\t\tconst finalText = state.transcriptionText;\n\t\t\t\tstate.transcriptionText = \"\";\n\t\t\t\tawait this.handleMessage(\n\t\t\t\t\tfinalText,\n\t\t\t\t\tentityId,\n\t\t\t\t\tchannelId,\n\t\t\t\t\tchannel,\n\t\t\t\t\tname,\n\t\t\t\t\tuserName,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(`Error transcribing audio for user ${entityId}:`, error);\n\t\t}\n\t}\n\n\tprivate async handleMessage(\n\t\tmessage: string,\n\t\tentityId: UUID,\n\t\tchannelId: string,\n\t\tchannel: BaseGuildVoiceChannel,\n\t\tname: string,\n\t\tuserName: string,\n\t) {\n\t\ttry {\n\t\t\tif (!message || message.trim() === \"\" || message.length < 3) {\n\t\t\t\treturn { text: \"\", actions: [\"IGNORE\"] };\n\t\t\t}\n\n\t\t\tconst roomId = createUniqueUuid(this.runtime, channelId);\n\t\t\tconst type = await this.getChannelType(channel as Channel);\n\n\t\t\tawait this.runtime.ensureConnection({\n\t\t\t\tentityId,\n\t\t\t\troomId,\n\t\t\t\tuserName,\n\t\t\t\tname: name,\n\t\t\t\tsource: \"discord\",\n\t\t\t\tchannelId,\n\t\t\t\tserverId: channel.guild.id,\n\t\t\t\ttype,\n\t\t\t});\n\n\t\t\tconst memory: Memory = {\n\t\t\t\tid: createUniqueUuid(\n\t\t\t\t\tthis.runtime,\n\t\t\t\t\t`${channelId}-voice-message-${Date.now()}`,\n\t\t\t\t),\n\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\tentityId,\n\t\t\t\troomId,\n\t\t\t\tcontent: {\n\t\t\t\t\ttext: message,\n\t\t\t\t\tsource: \"discord\",\n\t\t\t\t\turl: channel.url,\n\t\t\t\t\tname: name,\n\t\t\t\t\tuserName: userName,\n\t\t\t\t\tisVoiceMessage: true,\n\t\t\t\t\tchannelType: type,\n\t\t\t\t},\n\t\t\t\tcreatedAt: Date.now(),\n\t\t\t};\n\n\t\t\tconst callback: HandlerCallback = async (\n\t\t\t\tcontent: Content,\n\t\t\t\t_files: any[] = [],\n\t\t\t) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst responseMemory: Memory = {\n\t\t\t\t\t\tid: createUniqueUuid(\n\t\t\t\t\t\t\tthis.runtime,\n\t\t\t\t\t\t\t`${memory.id}-voice-response-${Date.now()}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tentityId: this.runtime.agentId,\n\t\t\t\t\t\tagentId: this.runtime.agentId,\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t...content,\n\t\t\t\t\t\t\tname: this.runtime.character.name,\n\t\t\t\t\t\t\tinReplyTo: memory.id,\n\t\t\t\t\t\t\tisVoiceMessage: true,\n\t\t\t\t\t\t\tchannelType: type,\n\t\t\t\t\t\t},\n\t\t\t\t\t\troomId,\n\t\t\t\t\t\tcreatedAt: Date.now(),\n\t\t\t\t\t};\n\n\t\t\t\t\tif (responseMemory.content.text?.trim()) {\n\t\t\t\t\t\tawait this.runtime\n\t\t\t\t\t\t\t.getMemoryManager(\"messages\")\n\t\t\t\t\t\t\t.createMemory(responseMemory);\n\n\t\t\t\t\t\tconst responseStream = await this.runtime.useModel(\n\t\t\t\t\t\t\tModelTypes.TEXT_TO_SPEECH,\n\t\t\t\t\t\t\tcontent.text,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (responseStream) {\n\t\t\t\t\t\t\tawait this.playAudioStream(entityId, responseStream as Readable);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [responseMemory];\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(\"Error in voice message callback:\", error);\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Emit voice-specific events\n\t\t\tthis.runtime.emitEvent(\n\t\t\t\t[\"DISCORD_VOICE_MESSAGE_RECEIVED\", \"VOICE_MESSAGE_RECEIVED\"],\n\t\t\t\t{\n\t\t\t\t\truntime: this.runtime,\n\t\t\t\t\tmessage: memory,\n\t\t\t\t\tcallback,\n\t\t\t\t},\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error processing voice message:\", error);\n\t\t}\n\t}\n\n\tprivate async convertOpusToWav(pcmBuffer: Buffer): Promise<Buffer> {\n\t\ttry {\n\t\t\t// Generate the WAV header\n\t\t\tconst wavHeader = getWavHeader(pcmBuffer.length, DECODE_SAMPLE_RATE);\n\n\t\t\t// Concatenate the WAV header and PCM data\n\t\t\tconst wavBuffer = Buffer.concat([wavHeader, pcmBuffer]);\n\n\t\t\treturn wavBuffer;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error converting PCM to WAV:\", error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync scanGuild(guild: Guild) {\n\t\tlet chosenChannel: BaseGuildVoiceChannel | null = null;\n\n\t\ttry {\n\t\t\tconst channelId = this.runtime.getSetting(\n\t\t\t\t\"DISCORD_VOICE_CHANNEL_ID\",\n\t\t\t) as string;\n\t\t\tif (channelId) {\n\t\t\t\tconst channel = await guild.channels.fetch(channelId);\n\t\t\t\tif (channel?.isVoiceBased()) {\n\t\t\t\t\tchosenChannel = channel as BaseGuildVoiceChannel;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!chosenChannel) {\n\t\t\t\tconst channels = (await guild.channels.fetch()).filter(\n\t\t\t\t\t(channel) => channel?.type === DiscordChannelType.GuildVoice,\n\t\t\t\t);\n\t\t\t\tfor (const [, channel] of channels) {\n\t\t\t\t\tconst voiceChannel = channel as BaseGuildVoiceChannel;\n\t\t\t\t\tif (\n\t\t\t\t\t\tvoiceChannel.members.size > 0 &&\n\t\t\t\t\t\t(chosenChannel === null ||\n\t\t\t\t\t\t\tvoiceChannel.members.size > chosenChannel.members.size)\n\t\t\t\t\t) {\n\t\t\t\t\t\tchosenChannel = voiceChannel;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (chosenChannel) {\n\t\t\t\tconsole.log(`Joining channel: ${chosenChannel.name}`);\n\t\t\t\tawait this.joinChannel(chosenChannel);\n\t\t\t} else {\n\t\t\t\tconsole.warn(\"No suitable voice channel found to join.\");\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error selecting or joining a voice channel:\", error);\n\t\t}\n\t}\n\n\tasync playAudioStream(entityId: UUID, audioStream: Readable) {\n\t\tconst connection = this.connections.get(entityId);\n\t\tif (connection == null) {\n\t\t\tconsole.log(`No connection for user ${entityId}`);\n\t\t\treturn;\n\t\t}\n\t\tthis.cleanupAudioPlayer(this.activeAudioPlayer);\n\t\tconst audioPlayer = createAudioPlayer({\n\t\t\tbehaviors: {\n\t\t\t\tnoSubscriber: NoSubscriberBehavior.Pause,\n\t\t\t},\n\t\t});\n\t\tthis.activeAudioPlayer = audioPlayer;\n\t\tconnection.subscribe(audioPlayer);\n\n\t\tconst audioStartTime = Date.now();\n\n\t\tconst resource = createAudioResource(audioStream, {\n\t\t\tinputType: StreamType.Arbitrary,\n\t\t});\n\t\taudioPlayer.play(resource);\n\n\t\taudioPlayer.on(\"error\", (err: any) => {\n\t\t\tconsole.log(`Audio player error: ${err}`);\n\t\t});\n\n\t\taudioPlayer.on(\n\t\t\t\"stateChange\",\n\t\t\t(_oldState: any, newState: { status: string }) => {\n\t\t\t\tif (newState.status === \"idle\") {\n\t\t\t\t\tconst idleTime = Date.now();\n\t\t\t\t\tconsole.log(`Audio playback took: ${idleTime - audioStartTime}ms`);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t}\n\n\tcleanupAudioPlayer(audioPlayer: AudioPlayer) {\n\t\tif (!audioPlayer) return;\n\n\t\taudioPlayer.stop();\n\t\taudioPlayer.removeAllListeners();\n\t\tif (audioPlayer === this.activeAudioPlayer) {\n\t\t\tthis.activeAudioPlayer = null;\n\t\t}\n\t}\n\n\tasync handleJoinChannelCommand(interaction: any) {\n\t\ttry {\n\t\t\t// Defer the reply immediately to prevent interaction timeout\n\t\t\tawait interaction.deferReply();\n\n\t\t\tconst channelId = interaction.options.get(\"channel\")?.value as string;\n\t\t\tif (!channelId) {\n\t\t\t\tawait interaction.editReply(\"Please provide a voice channel to join.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst guild = interaction.guild;\n\t\t\tif (!guild) {\n\t\t\t\tawait interaction.editReply(\"Could not find guild.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst voiceChannel = interaction.guild.channels.cache.find(\n\t\t\t\t(channel: VoiceChannel) =>\n\t\t\t\t\tchannel.id === channelId &&\n\t\t\t\t\tchannel.type === DiscordChannelType.GuildVoice,\n\t\t\t);\n\n\t\t\tif (!voiceChannel) {\n\t\t\t\tawait interaction.editReply(\"Voice channel not found!\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait this.joinChannel(voiceChannel as BaseGuildVoiceChannel);\n\t\t\tawait interaction.editReply(`Joined voice channel: ${voiceChannel.name}`);\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error joining voice channel:\", error);\n\t\t\t// Use editReply instead of reply for the error case\n\t\t\tawait interaction\n\t\t\t\t.editReply(\"Failed to join the voice channel.\")\n\t\t\t\t.catch(console.error);\n\t\t}\n\t}\n\n\tasync handleLeaveChannelCommand(interaction: any) {\n\t\tconst connection = this.getVoiceConnection(interaction.guildId as any);\n\n\t\tif (!connection) {\n\t\t\tawait interaction.reply(\"Not currently in a voice channel.\");\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconnection.destroy();\n\t\t\tawait interaction.reply(\"Left the voice channel.\");\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error leaving voice channel:\", error);\n\t\t\tawait interaction.reply(\"Failed to leave the voice channel.\");\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["ChannelType","createUniqueUuid","logger","DiscordChannelType","Events","PermissionsBitField","composePrompt","ModelTypes","parseJSONObjectFromText","composePrompt","ModelTypes","parseJSONObjectFromText","trimTokens","fs","summarizationTemplate","summarizeAction","composePrompt","ModelTypes","parseJSONObjectFromText","composePrompt","ModelTypes","parseJSONObjectFromText","attachment","ChannelType","composePrompt","createUniqueUuid","ModelTypes","ServiceTypes","ChannelType","ServiceTypes","member","createUniqueUuid","composePrompt","ModelTypes","targetChannel","ChannelType","createUniqueUuid","logger","ServiceTypes","logger","ChannelType","createUniqueUuid","ChannelType","createUniqueUuid","logger","ServiceTypes","DiscordChannelType","trimTokens","parseJSONObjectFromText","ModelTypes","ServiceTypes","fs","ModelTypes","logger","trimTokens","parseJSONObjectFromText","ChannelType","logger","ChannelType","DiscordChannelType","createUniqueUuid","ChannelType","logger","entityId","match","ServiceTypes","ChannelType","ChannelType","ServiceTypes","ChannelType","ModelTypes","logger","ChannelType","ServiceTypes","logger","ChannelType","ModelTypes","NoSubscriberBehavior","VoiceConnectionStatus","createAudioPlayer","createAudioResource","entersState","ChannelType","ModelTypes","createUniqueUuid","logger","DiscordChannelType","logger","DiscordChannelType","ChannelType","entersState","VoiceConnectionStatus","connection","createUniqueUuid","ModelTypes","createAudioPlayer","NoSubscriberBehavior","createAudioResource","logger","Events","runtime","createUniqueUuid","ChannelType","PermissionsBitField","DiscordChannelType","fullGuild"]}