diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24d74c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/* +dist/* +.turbo/turbo-build.log +dist/index.js +dist/index.js.map diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index ad823e8..0000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare const discordPlugin: { - name: string; - description: string; - clients: ElizaClient[]; -}; - -export { discordPlugin as default }; diff --git a/dist/index.js b/dist/index.js index 9c31960..ecd5f1b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -58,7 +58,7 @@ var getAttachmentIds = async (runtime, message, state) => { }); console.log("response", response); const parsedResponse = parseJSONObjectFromText(response); - if ((parsedResponse == null ? void 0 : parsedResponse.objective) && (parsedResponse == null ? void 0 : parsedResponse.attachmentIds)) { + if (parsedResponse?.objective && parsedResponse?.attachmentIds) { return parsedResponse; } } @@ -118,7 +118,6 @@ var summarizeAction = { ); }, handler: async (runtime, message, state, options, callback) => { - var _a, _b; state = await runtime.composeState(message); const callbackData = { text: "", @@ -174,7 +173,7 @@ ${attachment.text}`).join("\n\n"); return; } callbackData.text = currentSummary.trim(); - if (callbackData.text && (((_a = currentSummary.trim()) == null ? void 0 : _a.split("\n").length) < 4 || ((_b = currentSummary.trim()) == null ? void 0 : _b.split(" ").length) < 100)) { + if (callbackData.text && (currentSummary.trim()?.split("\n").length < 4 || currentSummary.trim()?.split(" ").length < 100)) { callbackData.text = `Here is the summary: \`\`\`md ${currentSummary.trim()} @@ -317,7 +316,7 @@ var getMediaUrl = async (runtime, message, state) => { modelClass: ModelClass2.SMALL }); const parsedResponse = parseJSONObjectFromText2(response); - if (parsedResponse == null ? void 0 : parsedResponse.mediaUrl) { + if (parsedResponse?.mediaUrl) { return parsedResponse.mediaUrl; } } @@ -485,7 +484,6 @@ var joinvoice_default = { }, description: "Join a voice channel to participate in voice chat.", handler: async (runtime, message, state) => { - var _a, _b, _c, _d, _e; if (!state) { console.error("State is not available."); } @@ -493,7 +491,7 @@ var joinvoice_default = { if (!discordMessage.content) { discordMessage.content = message.content.text; } - const id = (_a = discordMessage.guild) == null ? void 0 : _a.id; + const id = discordMessage.guild?.id; const client = state.discordClient; const voiceChannels = client.guilds.cache.get(id).channels.cache.filter( (channel) => channel.type === ChannelType.GuildVoice @@ -507,7 +505,7 @@ var joinvoice_default = { if (targetChannel) { joinVoiceChannel({ channelId: targetChannel.id, - guildId: (_b = discordMessage.guild) == null ? void 0 : _b.id, + guildId: discordMessage.guild?.id, adapterCreator: client.guilds.cache.get(id).voiceAdapterCreator, selfDeaf: false, selfMute: false, @@ -516,10 +514,10 @@ var joinvoice_default = { return true; } else { const member = discordMessage.member; - if ((_c = member == null ? void 0 : member.voice) == null ? void 0 : _c.channel) { + if (member?.voice?.channel) { joinVoiceChannel({ channelId: member.voice.channel.id, - guildId: (_d = discordMessage.guild) == null ? void 0 : _d.id, + guildId: discordMessage.guild?.id, adapterCreator: client.guilds.cache.get(id).voiceAdapterCreator, selfDeaf: false, selfMute: false, @@ -568,7 +566,7 @@ You should only respond with the name of the voice channel or none, no commentar if (targetChannel2) { joinVoiceChannel({ channelId: targetChannel2.id, - guildId: (_e = discordMessage.guild) == null ? void 0 : _e.id, + guildId: discordMessage.guild?.id, adapterCreator: client.guilds.cache.get(id).voiceAdapterCreator, selfDeaf: false, selfMute: false, @@ -759,7 +757,6 @@ var leavevoice_default = { }, description: "Leave the current voice channel.", handler: async (runtime, message, state) => { - var _a, _b, _c; if (!state.discordClient) { return; } @@ -767,13 +764,12 @@ var leavevoice_default = { if (!discordMessage) { throw new Error("Discord message is not available in the state."); } - const voiceChannels = (_c = (_b = state.discordClient) == null ? void 0 : _b.guilds.cache.get((_a = discordMessage.guild) == null ? void 0 : _a.id)) == null ? void 0 : _c.channels.cache.filter( + const voiceChannels = state.discordClient?.guilds.cache.get(discordMessage.guild?.id)?.channels.cache.filter( (channel) => channel.type === ChannelType2.GuildVoice ); - voiceChannels == null ? void 0 : voiceChannels.forEach((_channel) => { - var _a2; + voiceChannels?.forEach((_channel) => { const connection = getVoiceConnection( - (_a2 = discordMessage.guild) == null ? void 0 : _a2.id + discordMessage.guild?.id ); if (connection) { connection.destroy(); @@ -942,7 +938,6 @@ Your response must be formatted as a JSON block with this structure: \`\`\` `; var getDateRange = async (runtime, message, state) => { - var _a, _b, _c, _d; state = await runtime.composeState(message); const context = composeContext4({ state, @@ -958,22 +953,22 @@ var getDateRange = async (runtime, message, state) => { const parsedResponse = parseJSONObjectFromText3(response); if (parsedResponse) { if (parsedResponse.objective && parsedResponse.start && parsedResponse.end) { - const startIntegerString = (_a = parsedResponse.start.match(/\d+/)) == null ? void 0 : _a[0]; - const endIntegerString = (_b = parsedResponse.end.match( + const startIntegerString = parsedResponse.start.match(/\d+/)?.[0]; + const endIntegerString = parsedResponse.end.match( /\d+/ - )) == null ? void 0 : _b[0]; + )?.[0]; const multipliers = { second: 1 * 1e3, minute: 60 * 1e3, hour: 3600 * 1e3, day: 86400 * 1e3 }; - const startMultiplier = (_c = parsedResponse.start.match( + const startMultiplier = parsedResponse.start.match( /second|minute|hour|day/ - )) == null ? void 0 : _c[0]; - const endMultiplier = (_d = parsedResponse.end.match( + )?.[0]; + const endMultiplier = parsedResponse.end.match( /second|minute|hour|day/ - )) == null ? void 0 : _d[0]; + )?.[0]; const startInteger = startIntegerString ? Number.parseInt(startIntegerString) : 0; const endInteger = endIntegerString ? Number.parseInt(endIntegerString) : 0; const startTime = startInteger * multipliers[startMultiplier]; @@ -1044,7 +1039,6 @@ var summarizeAction2 = { ); }, handler: async (runtime, message, state, options, callback) => { - var _a, _b; state = await runtime.composeState(message); const callbackData = { text: "", @@ -1075,15 +1069,14 @@ var summarizeAction2 = { }); const actorMap = new Map(actors.map((actor) => [actor.id, actor])); const formattedMemories = memories.map((memory) => { - var _a2, _b2, _c; - const attachments = (_a2 = memory.content.attachments) == null ? void 0 : _a2.map((attachment) => { + const attachments = memory.content.attachments?.map((attachment) => { return `--- Attachment: ${attachment.id} ${attachment.description} ${attachment.text} ---`; }).join("\n"); - return `${((_b2 = actorMap.get(memory.userId)) == null ? void 0 : _b2.name) ?? "Unknown User"} (${((_c = actorMap.get(memory.userId)) == null ? void 0 : _c.username) ?? ""}): ${memory.content.text} + return `${actorMap.get(memory.userId)?.name ?? "Unknown User"} (${actorMap.get(memory.userId)?.username ?? ""}): ${memory.content.text} ${attachments}`; }).join("\n"); let currentSummary = ""; @@ -1122,7 +1115,7 @@ ${attachments}`; return; } callbackData.text = currentSummary.trim(); - if (callbackData.text && (((_a = currentSummary.trim()) == null ? void 0 : _a.split("\n").length) < 4 || ((_b = currentSummary.trim()) == null ? void 0 : _b.split(" ").length) < 100)) { + if (callbackData.text && (currentSummary.trim()?.split("\n").length < 4 || currentSummary.trim()?.split(" ").length < 100)) { callbackData.text = `Here is the summary: \`\`\`md ${currentSummary.trim()} @@ -1251,7 +1244,7 @@ var getMediaAttachmentId = async (runtime, message, state) => { }); console.log("response", response); const parsedResponse = parseJSONObjectFromText4(response); - if (parsedResponse == null ? void 0 : parsedResponse.attachmentId) { + if (parsedResponse?.attachmentId) { return parsedResponse.attachmentId; } } @@ -1293,7 +1286,6 @@ var transcribeMediaAction = { ); }, handler: async (runtime, message, state, options, callback) => { - var _a, _b; state = await runtime.composeState(message); const callbackData = { text: "", @@ -1322,7 +1314,7 @@ var transcribeMediaAction = { } const mediaTranscript = attachment.text; callbackData.text = mediaTranscript.trim(); - if (callbackData.text && (((_a = callbackData.text) == null ? void 0 : _a.split("\n").length) < 4 || ((_b = callbackData.text) == null ? void 0 : _b.split(" ").length) < 100)) { + if (callbackData.text && (callbackData.text?.split("\n").length < 4 || callbackData.text?.split(" ").length < 100)) { callbackData.text = `Here is the transcript: \`\`\`md ${mediaTranscript.trim()} @@ -1428,7 +1420,7 @@ async function generateSummary(runtime, text) { modelClass: ModelClass6.SMALL }); const parsedResponse = parseJSONObjectFromText5(response); - if ((parsedResponse == null ? void 0 : parsedResponse.title) && (parsedResponse == null ? void 0 : parsedResponse.summary)) { + if (parsedResponse?.title && parsedResponse?.summary) { return { title: parsedResponse.title, description: parsedResponse.summary @@ -1457,20 +1449,19 @@ var AttachmentManager = class { return processedAttachments; } async processAttachment(attachment) { - var _a, _b, _c, _d, _e, _f; if (this.attachmentCache.has(attachment.url)) { return this.attachmentCache.get(attachment.url); } let media = null; - if ((_a = attachment.contentType) == null ? void 0 : _a.startsWith("application/pdf")) { + if (attachment.contentType?.startsWith("application/pdf")) { media = await this.processPdfAttachment(attachment); - } else if ((_b = attachment.contentType) == null ? void 0 : _b.startsWith("text/plain")) { + } else if (attachment.contentType?.startsWith("text/plain")) { media = await this.processPlaintextAttachment(attachment); - } else if (((_c = attachment.contentType) == null ? void 0 : _c.startsWith("audio/")) || ((_d = attachment.contentType) == null ? void 0 : _d.startsWith("video/mp4"))) { + } else if (attachment.contentType?.startsWith("audio/") || attachment.contentType?.startsWith("video/mp4")) { media = await this.processAudioVideoAttachment(attachment); - } else if ((_e = attachment.contentType) == null ? void 0 : _e.startsWith("image/")) { + } else if (attachment.contentType?.startsWith("image/")) { media = await this.processImageAttachment(attachment); - } else if (((_f = attachment.contentType) == null ? void 0 : _f.startsWith("video/")) || this.runtime.getService(ServiceType2.VIDEO).isVideoUrl(attachment.url)) { + } else if (attachment.contentType?.startsWith("video/") || this.runtime.getService(ServiceType2.VIDEO).isVideoUrl(attachment.url)) { media = await this.processVideoAttachment(attachment); } else { media = await this.processGenericAttachment(attachment); @@ -1481,14 +1472,13 @@ var AttachmentManager = class { return media; } async processAudioVideoAttachment(attachment) { - var _a, _b, _c, _d; try { const response = await fetch(attachment.url); const audioVideoArrayBuffer = await response.arrayBuffer(); let audioBuffer; - if ((_a = attachment.contentType) == null ? void 0 : _a.startsWith("audio/")) { + if (attachment.contentType?.startsWith("audio/")) { audioBuffer = Buffer.from(audioVideoArrayBuffer); - } else if ((_b = attachment.contentType) == null ? void 0 : _b.startsWith("video/mp4")) { + } else if (attachment.contentType?.startsWith("video/mp4")) { audioBuffer = await this.extractAudioFromMP4( audioVideoArrayBuffer ); @@ -1510,7 +1500,7 @@ var AttachmentManager = class { id: attachment.id, url: attachment.url, title: title || "Audio/Video Attachment", - source: ((_c = attachment.contentType) == null ? void 0 : _c.startsWith("audio/")) ? "Audio" : "Video", + source: attachment.contentType?.startsWith("audio/") ? "Audio" : "Video", description: description || "User-uploaded audio/video attachment which has been transcribed", text: transcription || "Audio/video content not available" }; @@ -1522,7 +1512,7 @@ var AttachmentManager = class { id: attachment.id, url: attachment.url, title: "Audio/Video Attachment", - source: ((_d = attachment.contentType) == null ? void 0 : _d.startsWith("audio/")) ? "Audio" : "Video", + source: attachment.contentType?.startsWith("audio/") ? "Audio" : "Video", description: "An audio/video attachment (transcription failed)", text: `This is an audio/video attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}` }; @@ -2015,7 +2005,7 @@ async function sendMessageInChunks(channel, content, inReplyTo, files) { function splitMessage(content) { const messages = []; let currentMessage = ""; - const rawLines = (content == null ? void 0 : content.split("\n")) || []; + const rawLines = content?.split("\n") || []; const lines = rawLines.flatMap((line) => { const chunks = []; while (line.length > MAX_MESSAGE_LENGTH) { @@ -2038,7 +2028,6 @@ function splitMessage(content) { return messages; } function canSendMessage(channel) { - var _a; if (!channel) { return { canSend: false, @@ -2051,7 +2040,7 @@ function canSendMessage(channel) { reason: null }; } - const botMember = (_a = channel.guild) == null ? void 0 : _a.members.cache.get(channel.client.user.id); + const botMember = channel.guild?.members.cache.get(channel.client.user.id); if (!botMember) { return { canSend: false, @@ -2156,20 +2145,19 @@ var MessageManager = class { lastChannelActivity = {}; autoPostInterval; constructor(discordClient, voiceManager) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r; this.client = discordClient.client; this.voiceManager = voiceManager; this.discordClient = discordClient; this.runtime = discordClient.runtime; this.attachmentManager = new AttachmentManager(this.runtime); this.autoPostConfig = { - enabled: ((_c = (_b = (_a = this.runtime.character.clientConfig) == null ? void 0 : _a.discord) == null ? void 0 : _b.autoPost) == null ? void 0 : _c.enabled) || false, - monitorTime: ((_f = (_e = (_d = this.runtime.character.clientConfig) == null ? void 0 : _d.discord) == null ? void 0 : _e.autoPost) == null ? void 0 : _f.monitorTime) || 3e5, - inactivityThreshold: ((_i = (_h = (_g = this.runtime.character.clientConfig) == null ? void 0 : _g.discord) == null ? void 0 : _h.autoPost) == null ? void 0 : _i.inactivityThreshold) || 36e5, + enabled: this.runtime.character.clientConfig?.discord?.autoPost?.enabled || false, + monitorTime: this.runtime.character.clientConfig?.discord?.autoPost?.monitorTime || 3e5, + inactivityThreshold: this.runtime.character.clientConfig?.discord?.autoPost?.inactivityThreshold || 36e5, // 1 hour default - mainChannelId: (_l = (_k = (_j = this.runtime.character.clientConfig) == null ? void 0 : _j.discord) == null ? void 0 : _k.autoPost) == null ? void 0 : _l.mainChannelId, - announcementChannelIds: ((_o = (_n = (_m = this.runtime.character.clientConfig) == null ? void 0 : _m.discord) == null ? void 0 : _n.autoPost) == null ? void 0 : _o.announcementChannelIds) || [], - minTimeBetweenPosts: ((_r = (_q = (_p = this.runtime.character.clientConfig) == null ? void 0 : _p.discord) == null ? void 0 : _q.autoPost) == null ? void 0 : _r.minTimeBetweenPosts) || 72e5 + mainChannelId: this.runtime.character.clientConfig?.discord?.autoPost?.mainChannelId, + announcementChannelIds: this.runtime.character.clientConfig?.discord?.autoPost?.announcementChannelIds || [], + minTimeBetweenPosts: this.runtime.character.clientConfig?.discord?.autoPost?.minTimeBetweenPosts || 72e5 // 2 hours default }; if (this.autoPostConfig.enabled) { @@ -2177,23 +2165,22 @@ var MessageManager = class { } } async handleMessage(message) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x; - if (((_b = (_a = this.runtime.character.clientConfig) == null ? void 0 : _a.discord) == null ? void 0 : _b.allowedChannelIds) && !this.runtime.character.clientConfig.discord.allowedChannelIds.includes(message.channelId)) { + if (this.runtime.character.clientConfig?.discord?.allowedChannelIds && !this.runtime.character.clientConfig.discord.allowedChannelIds.includes(message.channelId)) { return; } this.lastChannelActivity[message.channelId] = Date.now(); - if (message.interaction || message.author.id === ((_c = this.client.user) == null ? void 0 : _c.id)) { + if (message.interaction || message.author.id === this.client.user?.id) { return; } - if (((_e = (_d = this.runtime.character.clientConfig) == null ? void 0 : _d.discord) == null ? void 0 : _e.shouldIgnoreBotMessages) && ((_f = message.author) == null ? void 0 : _f.bot)) { + if (this.runtime.character.clientConfig?.discord?.shouldIgnoreBotMessages && message.author?.bot) { return; } - if ((_h = (_g = this.runtime.character.clientConfig) == null ? void 0 : _g.discord) == null ? void 0 : _h.shouldRespondOnlyToMentions) { + if (this.runtime.character.clientConfig?.discord?.shouldRespondOnlyToMentions) { if (!this._isMessageForMe(message)) { return; } } - if (((_j = (_i = this.runtime.character.clientConfig) == null ? void 0 : _i.discord) == null ? void 0 : _j.shouldIgnoreDirectMessages) && message.channel.type === ChannelType4.DM) { + if (this.runtime.character.clientConfig?.discord?.shouldIgnoreDirectMessages && message.channel.type === ChannelType4.DM) { return; } const userId = message.author.id; @@ -2202,11 +2189,11 @@ var MessageManager = class { const channelId = message.channel.id; const isDirectlyMentioned = this._isMessageForMe(message); const hasInterest = this._checkInterest(message.channelId); - if (((_l = (_k = this.runtime.character.clientConfig) == null ? void 0 : _k.discord) == null ? void 0 : _l.isPartOfTeam) && !((_n = (_m = this.runtime.character.clientConfig) == null ? void 0 : _m.discord) == null ? void 0 : _n.shouldRespondOnlyToMentions)) { + if (this.runtime.character.clientConfig?.discord?.isPartOfTeam && !this.runtime.character.clientConfig?.discord?.shouldRespondOnlyToMentions) { const authorId = this._getNormalizedUserId(message.author.id); if (!this._isTeamLeader() && this._isRelevantToTeamMember(message.content, channelId)) { this.interestChannels[message.channelId] = { - currentHandler: (_o = this.client.user) == null ? void 0 : _o.id, + currentHandler: this.client.user?.id, lastMessageSent: Date.now(), messages: [] }; @@ -2223,11 +2210,11 @@ var MessageManager = class { unique: false, count: 5 }); - const lastSelfSortedMemories = lastSelfMemories == null ? void 0 : lastSelfMemories.filter((m) => m.userId === this.runtime.agentId).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0)); + const lastSelfSortedMemories = lastSelfMemories?.filter((m) => m.userId === this.runtime.agentId).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0)); const isRelevant = this._isRelevantToTeamMember( message.content, channelId, - lastSelfSortedMemories == null ? void 0 : lastSelfSortedMemories[0] + lastSelfSortedMemories?.[0] ); if (!isRelevant) { delete this.interestChannels[message.channelId]; @@ -2237,13 +2224,13 @@ var MessageManager = class { if (isTeamRequest) { if (isLeader) { this.interestChannels[message.channelId] = { - currentHandler: (_p = this.client.user) == null ? void 0 : _p.id, + currentHandler: this.client.user?.id, lastMessageSent: Date.now(), messages: [] }; } else { this.interestChannels[message.channelId] = { - currentHandler: (_q = this.client.user) == null ? void 0 : _q.id, + currentHandler: this.client.user?.id, lastMessageSent: Date.now(), messages: [] }; @@ -2253,16 +2240,13 @@ var MessageManager = class { } } const otherTeamMembers = this.runtime.character.clientConfig.discord.teamAgentIds.filter( - (id) => { - var _a2; - return id !== ((_a2 = this.client.user) == null ? void 0 : _a2.id); - } + (id) => id !== this.client.user?.id ); const mentionedTeamMember = otherTeamMembers.find( (id) => message.content.includes(`<@${id}>`) ); if (mentionedTeamMember) { - if (hasInterest || ((_r = this.interestChannels[message.channelId]) == null ? void 0 : _r.currentHandler) === ((_s = this.client.user) == null ? void 0 : _s.id)) { + if (hasInterest || this.interestChannels[message.channelId]?.currentHandler === this.client.user?.id) { delete this.interestChannels[message.channelId]; if (!isDirectlyMentioned) { return; @@ -2271,7 +2255,7 @@ var MessageManager = class { } if (isDirectlyMentioned) { this.interestChannels[message.channelId] = { - currentHandler: (_t = this.client.user) == null ? void 0 : _t.id, + currentHandler: this.client.user?.id, lastMessageSent: Date.now(), messages: [] }; @@ -2289,10 +2273,7 @@ var MessageManager = class { try { const { processedContent, attachments } = await this.processMessageMedia(message); const audioAttachments = message.attachments.filter( - (attachment) => { - var _a2; - return (_a2 = attachment.contentType) == null ? void 0 : _a2.startsWith("audio/"); - } + (attachment) => attachment.contentType?.startsWith("audio/") ); if (audioAttachments.size > 0) { const processedAudioAttachments = await this.attachmentManager.processAttachments( @@ -2319,7 +2300,7 @@ var MessageManager = class { attachments, source: "discord", url: message.url, - inReplyTo: ((_u = message.reference) == null ? void 0 : _u.messageId) ? stringToUuid( + inReplyTo: message.reference?.messageId ? stringToUuid( message.reference.messageId + "-" + this.runtime.agentId ) : void 0 }; @@ -2355,7 +2336,7 @@ var MessageManager = class { let state = await this.runtime.composeState(userMessage, { discordClient: this.client, discordMessage: message, - agentName: this.runtime.character.name || ((_v = this.client.user) == null ? void 0 : _v.displayName) + agentName: this.runtime.character.name || this.client.user?.displayName }); const canSendResult = canSendMessage(message.channel); if (!canSendResult.canSend) { @@ -2386,7 +2367,7 @@ var MessageManager = class { if (shouldRespond) { const context = composeContext6({ state, - template: ((_w = this.runtime.character.templates) == null ? void 0 : _w.discordMessageHandlerTemplate) || discordMessageHandlerTemplate + template: this.runtime.character.templates?.discordMessageHandlerTemplate || discordMessageHandlerTemplate }); const stopTyping = this.simulateTyping(message); const responseContent = await this._generateResponse( @@ -2396,7 +2377,7 @@ var MessageManager = class { ).finally(() => { stopTyping(); }); - responseContent.text = (_x = responseContent.text) == null ? void 0 : _x.trim(); + responseContent.text = responseContent.text?.trim(); responseContent.inReplyTo = stringToUuid( message.id + "-" + this.runtime.agentId ); @@ -2450,7 +2431,7 @@ var MessageManager = class { } }; const action = this.runtime.actions.find((a) => a.name === responseContent.action); - const shouldSuppressInitialMessage = action == null ? void 0 : action.suppressInitialMessage; + const shouldSuppressInitialMessage = action?.suppressInitialMessage; let responseMessages = []; if (!shouldSuppressInitialMessage) { responseMessages = await callback(responseContent); @@ -2523,7 +2504,6 @@ var MessageManager = class { }, 5e3); } async _checkChannelActivity() { - var _a, _b; if (!this.autoPostConfig.enabled || !this.autoPostConfig.mainChannelId) return; const channel = this.client.channels.cache.get(this.autoPostConfig.mainChannelId); if (!channel) return; @@ -2550,14 +2530,14 @@ var MessageManager = class { let state = await this.runtime.composeState(memory, { discordClient: this.client, discordMessage: null, - agentName: this.runtime.character.name || ((_a = this.client.user) == null ? void 0 : _a.displayName) + agentName: this.runtime.character.name || this.client.user?.displayName }); const context = composeContext6({ state, - template: ((_b = this.runtime.character.templates) == null ? void 0 : _b.discordAutoPostTemplate) || discordAutoPostTemplate + template: this.runtime.character.templates?.discordAutoPostTemplate || discordAutoPostTemplate }); const responseContent = await this._generateResponse(memory, state, context); - if (!(responseContent == null ? void 0 : responseContent.text)) return; + if (!responseContent?.text) return; const messages2 = await sendMessageInChunks(channel, responseContent.text.trim(), null, []); const memories = messages2.map((m) => ({ id: stringToUuid(m.id + "-" + this.runtime.agentId), @@ -2599,7 +2579,6 @@ var MessageManager = class { const newsChannel = channel; try { newsChannel.createMessageCollector().on("collect", async (message) => { - var _a, _b; if (message.author.bot || Date.now() - message.createdTimestamp > 3e5) return; const mainChannel = this.client.channels.cache.get(this.autoPostConfig.mainChannelId); if (!mainChannel) return; @@ -2621,16 +2600,16 @@ var MessageManager = class { let state = await this.runtime.composeState(memory, { discordClient: this.client, discordMessage: message, - announcementContent: message == null ? void 0 : message.content, + announcementContent: message?.content, announcementChannelId: channel.id, - agentName: this.runtime.character.name || ((_a = this.client.user) == null ? void 0 : _a.displayName) + agentName: this.runtime.character.name || this.client.user?.displayName }); const context = composeContext6({ state, - template: ((_b = this.runtime.character.templates) == null ? void 0 : _b.discordAnnouncementHypeTemplate) || discordAnnouncementHypeTemplate + template: this.runtime.character.templates?.discordAnnouncementHypeTemplate || discordAnnouncementHypeTemplate }); const responseContent = await this._generateResponse(memory, state, context); - if (!(responseContent == null ? void 0 : responseContent.text)) return; + if (!responseContent?.text) return; const messages = await sendMessageInChunks(mainChannel, responseContent.text.trim(), null, []); const memories = messages.map((m) => ({ id: stringToUuid(m.id + "-" + this.runtime.agentId), @@ -2666,25 +2645,23 @@ var MessageManager = class { } } _isMessageForMe(message) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i; - const isMentioned = (_b = message.mentions.users) == null ? void 0 : _b.has( - (_a = this.client.user) == null ? void 0 : _a.id + const isMentioned = message.mentions.users?.has( + this.client.user?.id ); const guild = message.guild; - const member = guild == null ? void 0 : guild.members.cache.get((_c = this.client.user) == null ? void 0 : _c.id); - const nickname = member == null ? void 0 : member.nickname; + const member = guild?.members.cache.get(this.client.user?.id); + const nickname = member?.nickname; const hasRoleMentionOnly = message.mentions.roles.size > 0 && !isMentioned; - if (hasRoleMentionOnly && ((_e = (_d = this.runtime.character.clientConfig) == null ? void 0 : _d.discord) == null ? void 0 : _e.isPartOfTeam)) { + if (hasRoleMentionOnly && this.runtime.character.clientConfig?.discord?.isPartOfTeam) { return false; } - return isMentioned || !((_g = (_f = this.runtime.character.clientConfig) == null ? void 0 : _f.discord) == null ? void 0 : _g.shouldRespondOnlyToMentions) && (message.content.toLowerCase().includes( - (_h = this.client.user) == null ? void 0 : _h.username.toLowerCase() + return isMentioned || !this.runtime.character.clientConfig?.discord?.shouldRespondOnlyToMentions && (message.content.toLowerCase().includes( + this.client.user?.username.toLowerCase() ) || message.content.toLowerCase().includes( - (_i = this.client.user) == null ? void 0 : _i.tag.toLowerCase() + this.client.user?.tag.toLowerCase() ) || nickname && message.content.toLowerCase().includes(nickname.toLowerCase())); } async processMessageMedia(message) { - var _a; let processedContent = message.content; let attachments = []; const codeBlockRegex = /```([\s\S]*?)```/g; @@ -2718,7 +2695,7 @@ var MessageManager = class { const urlRegex = /(https?:\/\/[^\s]+)/g; const urls = processedContent.match(urlRegex) || []; for (const url of urls) { - if ((_a = this.runtime.getService(ServiceType3.VIDEO)) == null ? void 0 : _a.isVideoUrl(url)) { + if (this.runtime.getService(ServiceType3.VIDEO)?.isVideoUrl(url)) { const videoService = this.runtime.getService( ServiceType3.VIDEO ); @@ -2761,9 +2738,8 @@ var MessageManager = class { return id.toString().replace(/[^0-9]/g, ""); } _isTeamMember(userId) { - var _a; - const teamConfig = (_a = this.runtime.character.clientConfig) == null ? void 0 : _a.discord; - if (!(teamConfig == null ? void 0 : teamConfig.isPartOfTeam) || !teamConfig.teamAgentIds) return false; + const teamConfig = this.runtime.character.clientConfig?.discord; + if (!teamConfig?.isPartOfTeam || !teamConfig.teamAgentIds) return false; const normalizedUserId = this._getNormalizedUserId(userId); const isTeamMember = teamConfig.teamAgentIds.some( (teamId) => this._getNormalizedUserId(teamId) === normalizedUserId @@ -2771,20 +2747,17 @@ var MessageManager = class { return isTeamMember; } _isTeamLeader() { - var _a, _b, _c; - return ((_a = this.client.user) == null ? void 0 : _a.id) === ((_c = (_b = this.runtime.character.clientConfig) == null ? void 0 : _b.discord) == null ? void 0 : _c.teamLeaderId); + return this.client.user?.id === this.runtime.character.clientConfig?.discord?.teamLeaderId; } _isTeamCoordinationRequest(content) { - var _a; const contentLower = content.toLowerCase(); - return (_a = TEAM_COORDINATION.KEYWORDS) == null ? void 0 : _a.some( + return TEAM_COORDINATION.KEYWORDS?.some( (keyword) => contentLower.includes(keyword.toLowerCase()) ); } _isRelevantToTeamMember(content, channelId, lastAgentMemory = null) { - var _a; - const teamConfig = (_a = this.runtime.character.clientConfig) == null ? void 0 : _a.discord; - if (this._isTeamLeader() && (lastAgentMemory == null ? void 0 : lastAgentMemory.content.text)) { + const teamConfig = this.runtime.character.clientConfig?.discord; + if (this._isTeamLeader() && lastAgentMemory?.content.text) { const timeSinceLastMessage = Date.now() - lastAgentMemory.createdAt; if (timeSinceLastMessage > MESSAGE_CONSTANTS.INTEREST_DECAY_TIME) { return false; @@ -2795,7 +2768,7 @@ var MessageManager = class { ); return similarity >= MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS; } - if (!(teamConfig == null ? void 0 : teamConfig.teamMemberInterestKeywords)) { + if (!teamConfig?.teamMemberInterestKeywords) { return false; } return teamConfig.teamMemberInterestKeywords.some( @@ -2809,16 +2782,15 @@ var MessageManager = class { const similarity = cosineSimilarity( currentMessage.toLowerCase(), previousContext.content.toLowerCase(), - agentLastMessage == null ? void 0 : agentLastMessage.toLowerCase() + agentLastMessage?.toLowerCase() ); const weightedSimilarity = similarity * timeWeight; return weightedSimilarity; } async _shouldRespondBasedOnContext(message, channelState) { - var _a, _b, _c, _d, _e, _f; if (this._isMessageForMe(message)) return true; - if ((channelState == null ? void 0 : channelState.currentHandler) !== ((_a = this.client.user) == null ? void 0 : _a.id)) return false; - if (!((_b = channelState.messages) == null ? void 0 : _b.length)) return false; + if (channelState?.currentHandler !== this.client.user?.id) return false; + if (!channelState.messages?.length) return false; const lastUserMessage = [...channelState.messages].reverse().find( (m, index) => index > 0 && // Skip first message (current) m.userId !== this.runtime.agentId @@ -2831,16 +2803,16 @@ var MessageManager = class { unique: false, count: 5 }); - const lastSelfSortedMemories = lastSelfMemories == null ? void 0 : lastSelfMemories.filter((m) => m.userId === this.runtime.agentId).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0)); + const lastSelfSortedMemories = lastSelfMemories?.filter((m) => m.userId === this.runtime.agentId).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0)); const contextSimilarity = await this._analyzeContextSimilarity( message.content, { content: lastUserMessage.content.text || "", timestamp: Date.now() }, - (_d = (_c = lastSelfSortedMemories == null ? void 0 : lastSelfSortedMemories[0]) == null ? void 0 : _c.content) == null ? void 0 : _d.text + lastSelfSortedMemories?.[0]?.content?.text ); - const similarityThreshold = ((_f = (_e = this.runtime.character.clientConfig) == null ? void 0 : _e.discord) == null ? void 0 : _f.messageSimilarityThreshold) || channelState.contextSimilarityThreshold || MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD; + const similarityThreshold = this.runtime.character.clientConfig?.discord?.messageSimilarityThreshold || channelState.contextSimilarityThreshold || MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD; return contextSimilarity >= similarityThreshold; } _checkInterest(channelId) { @@ -2863,10 +2835,7 @@ var MessageManager = class { channelId )) { const recentTeamResponses = channelState.messages.slice(-3).some( - (m) => { - var _a; - return m.userId !== ((_a = this.client.user) == null ? void 0 : _a.id) && this._isTeamMember(m.userId); - } + (m) => m.userId !== this.client.user?.id && this._isTeamMember(m.userId) ); if (recentTeamResponses) { delete this.interestChannels[channelId]; @@ -2879,10 +2848,7 @@ var MessageManager = class { -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT ); const differentUsers = new Set(recentMessages.map((m) => m.userId)).size; - if (differentUsers > 1 && !recentMessages.some((m) => { - var _a; - return m.userId === ((_a = this.client.user) == null ? void 0 : _a.id); - })) { + if (differentUsers > 1 && !recentMessages.some((m) => m.userId === this.client.user?.id)) { delete this.interestChannels[channelId]; return false; } @@ -2890,19 +2856,18 @@ var MessageManager = class { return true; } async _shouldIgnore(message) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; - if (message.author.id === ((_a = this.client.user) == null ? void 0 : _a.id)) return true; - if ((_c = (_b = this.runtime.character.clientConfig) == null ? void 0 : _b.discord) == null ? void 0 : _c.shouldRespondOnlyToMentions) { + if (message.author.id === this.client.user?.id) return true; + if (this.runtime.character.clientConfig?.discord?.shouldRespondOnlyToMentions) { return !this._isMessageForMe(message); } - if ((_e = (_d = this.runtime.character.clientConfig) == null ? void 0 : _d.discord) == null ? void 0 : _e.isPartOfTeam) { + if (this.runtime.character.clientConfig?.discord?.isPartOfTeam) { const authorId = this._getNormalizedUserId(message.author.id); if (this._isTeamLeader()) { if (this._isTeamCoordinationRequest(message.content)) { return false; } if (!this._isMessageForMe(message)) { - const otherMemberInterests = ((_g = (_f = this.runtime.character.clientConfig) == null ? void 0 : _f.discord) == null ? void 0 : _g.teamMemberInterestKeywords) || []; + const otherMemberInterests = this.runtime.character.clientConfig?.discord?.teamMemberInterestKeywords || []; const hasOtherInterests = otherMemberInterests.some( (keyword) => message.content.toLowerCase().includes(keyword.toLowerCase()) ); @@ -2931,8 +2896,8 @@ var MessageManager = class { } } const channelState = this.interestChannels[message.channelId]; - if (channelState == null ? void 0 : channelState.currentHandler) { - if (channelState.currentHandler === ((_h = this.client.user) == null ? void 0 : _h.id)) { + if (channelState?.currentHandler) { + if (channelState.currentHandler === this.client.user?.id) { if (this._isRelevantToTeamMember( message.content, message.channelId @@ -2950,12 +2915,12 @@ var MessageManager = class { } } let messageContent = message.content.toLowerCase(); - const botMention = `<@!?${(_i = this.client.user) == null ? void 0 : _i.id}>`; + const botMention = `<@!?${this.client.user?.id}>`; messageContent = messageContent.replace( new RegExp(botMention, "gi"), this.runtime.character.name.toLowerCase() ); - const botUsername = (_j = this.client.user) == null ? void 0 : _j.username.toLowerCase(); + const botUsername = this.client.user?.username.toLowerCase(); messageContent = messageContent.replace( new RegExp(`\\b${botUsername}\\b`, "g"), this.runtime.character.name.toLowerCase() @@ -2997,17 +2962,16 @@ var MessageManager = class { return false; } async _shouldRespond(message, state) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q; - if (message.author.id === ((_a = this.client.user) == null ? void 0 : _a.id)) return false; - if ((_c = (_b = this.runtime.character.clientConfig) == null ? void 0 : _b.discord) == null ? void 0 : _c.shouldRespondOnlyToMentions) { + if (message.author.id === this.client.user?.id) return false; + if (this.runtime.character.clientConfig?.discord?.shouldRespondOnlyToMentions) { return this._isMessageForMe(message); } const channelState = this.interestChannels[message.channelId]; - if (((_e = (_d = this.runtime.character.clientConfig) == null ? void 0 : _d.discord) == null ? void 0 : _e.isPartOfTeam) && !this._isTeamLeader() && this._isRelevantToTeamMember(message.content, message.channelId)) { + if (this.runtime.character.clientConfig?.discord?.isPartOfTeam && !this._isTeamLeader() && this._isRelevantToTeamMember(message.content, message.channelId)) { return true; } try { - if ((_g = (_f = this.runtime.character.clientConfig) == null ? void 0 : _f.discord) == null ? void 0 : _g.isPartOfTeam) { + if (this.runtime.character.clientConfig?.discord?.isPartOfTeam) { if (this._isTeamLeader() && this._isTeamCoordinationRequest(message.content)) { return true; } @@ -3018,15 +2982,12 @@ var MessageManager = class { await new Promise( (resolve) => setTimeout(resolve, TIMING_CONSTANTS.TEAM_MEMBER_DELAY) ); - if ((_h = channelState == null ? void 0 : channelState.messages) == null ? void 0 : _h.length) { + if (channelState?.messages?.length) { const recentMessages = channelState.messages.slice( -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT ); const leaderResponded = recentMessages.some( - (m) => { - var _a2, _b2; - return m.userId === ((_b2 = (_a2 = this.runtime.character.clientConfig) == null ? void 0 : _a2.discord) == null ? void 0 : _b2.teamLeaderId) && Date.now() - channelState.lastMessageSent < 3e3; - } + (m) => m.userId === this.runtime.character.clientConfig?.discord?.teamLeaderId && Date.now() - channelState.lastMessageSent < 3e3 ); if (leaderResponded) { return Math.random() > RESPONSE_CHANCES.AFTER_LEADER; @@ -3044,15 +3005,12 @@ var MessageManager = class { await new Promise( (resolve) => setTimeout(resolve, randomDelay) ); - if ((_i = channelState == null ? void 0 : channelState.messages) == null ? void 0 : _i.length) { + if (channelState?.messages?.length) { const recentResponses = channelState.messages.slice( -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT ); const otherTeamMemberResponded = recentResponses.some( - (m) => { - var _a2; - return m.userId !== ((_a2 = this.client.user) == null ? void 0 : _a2.id) && this._isTeamMember(m.userId); - } + (m) => m.userId !== this.client.user?.id && this._isTeamMember(m.userId) ); if (otherTeamMemberResponded) { return false; @@ -3062,13 +3020,13 @@ var MessageManager = class { if (this._isMessageForMe(message)) { const channelState2 = this.interestChannels[message.channelId]; if (channelState2) { - channelState2.currentHandler = (_j = this.client.user) == null ? void 0 : _j.id; + channelState2.currentHandler = this.client.user?.id; channelState2.lastMessageSent = Date.now(); } return true; } - if (channelState == null ? void 0 : channelState.currentHandler) { - if (channelState.currentHandler !== ((_k = this.client.user) == null ? void 0 : _k.id) && this._isTeamMember(channelState.currentHandler)) { + if (channelState?.currentHandler) { + if (channelState.currentHandler !== this.client.user?.id && this._isTeamMember(channelState.currentHandler)) { return false; } } @@ -3077,10 +3035,7 @@ var MessageManager = class { -MESSAGE_CONSTANTS.CHAT_HISTORY_COUNT ); const ourMessageCount = recentMessages.filter( - (m) => { - var _a2; - return m.userId === ((_a2 = this.client.user) == null ? void 0 : _a2.id); - } + (m) => m.userId === this.client.user?.id ).length; if (ourMessageCount > 2) { const responseChance = Math.pow( @@ -3100,18 +3055,18 @@ var MessageManager = class { channelId: message.channelId }); } - if (channelState == null ? void 0 : channelState.previousContext) { + if (channelState?.previousContext) { const shouldRespondContext2 = await this._shouldRespondBasedOnContext(message, channelState); if (!shouldRespondContext2) { delete this.interestChannels[message.channelId]; return false; } } - if (message.mentions.has((_l = this.client.user) == null ? void 0 : _l.id)) return true; + if (message.mentions.has(this.client.user?.id)) return true; const guild = message.guild; - const member = guild == null ? void 0 : guild.members.cache.get((_m = this.client.user) == null ? void 0 : _m.id); - const nickname = member == null ? void 0 : member.nickname; - if (message.content.toLowerCase().includes((_n = this.client.user) == null ? void 0 : _n.username.toLowerCase()) || message.content.toLowerCase().includes((_o = this.client.user) == null ? void 0 : _o.tag.toLowerCase()) || nickname && message.content.toLowerCase().includes(nickname.toLowerCase())) { + const member = guild?.members.cache.get(this.client.user?.id); + const nickname = member?.nickname; + if (message.content.toLowerCase().includes(this.client.user?.username.toLowerCase()) || message.content.toLowerCase().includes(this.client.user?.tag.toLowerCase()) || nickname && message.content.toLowerCase().includes(nickname.toLowerCase())) { return true; } if (!message.guild) { @@ -3119,7 +3074,7 @@ var MessageManager = class { } const shouldRespondContext = composeContext6({ state, - template: ((_p = this.runtime.character.templates) == null ? void 0 : _p.discordShouldRespondTemplate) || ((_q = this.runtime.character.templates) == null ? void 0 : _q.shouldRespondTemplate) || composeRandomUser(discordShouldRespondTemplate, 2) + template: this.runtime.character.templates?.discordShouldRespondTemplate || this.runtime.character.templates?.shouldRespondTemplate || composeRandomUser(discordShouldRespondTemplate, 2) }); const response = await generateShouldRespond({ runtime: this.runtime, @@ -3209,13 +3164,13 @@ import { } from "discord.js"; var channelStateProvider = { get: async (runtime, message, state) => { - const discordMessage = (state == null ? void 0 : state.discordMessage) || (state == null ? void 0 : state.discordChannel); + const discordMessage = state?.discordMessage || state?.discordChannel; if (!discordMessage) { return ""; } - const guild = discordMessage == null ? void 0 : discordMessage.guild; - const agentName = (state == null ? void 0 : state.agentName) || "The agent"; - const senderName = (state == null ? void 0 : state.senderName) || "someone"; + const guild = discordMessage?.guild; + const agentName = state?.agentName || "The agent"; + const senderName = state?.senderName || "someone"; if (!guild) { return agentName + " is currently in a direct message conversation with " + senderName; } @@ -3240,16 +3195,15 @@ import { getVoiceConnection as getVoiceConnection2 } from "@discordjs/voice"; import { ChannelType as ChannelType6 } from "discord.js"; var voiceStateProvider = { get: async (runtime, message, state) => { - var _a, _b, _c, _d, _e; - const discordMessage = (state == null ? void 0 : state.discordMessage) || state.discordChannel; + const discordMessage = state?.discordMessage || state.discordChannel; const connection = getVoiceConnection2( - (_a = discordMessage == null ? void 0 : discordMessage.guild) == null ? void 0 : _a.id + discordMessage?.guild?.id ); - const agentName = (state == null ? void 0 : state.agentName) || "The agent"; + const agentName = state?.agentName || "The agent"; if (!connection) { return agentName + " is not currently in a voice channel"; } - const channel = (_e = (_d = (_c = (_b = (state == null ? void 0 : state.discordMessage) || state.discordChannel) == null ? void 0 : _b.guild) == null ? void 0 : _c.channels) == null ? void 0 : _d.cache) == null ? void 0 : _e.get( + const channel = (state?.discordMessage || state.discordChannel)?.guild?.channels?.cache?.get( connection.joinConfig.channelId ); if (!channel || channel.type !== ChannelType6.GuildVoice) { @@ -3288,6 +3242,9 @@ import { import EventEmitter from "events"; import prism from "prism-media"; import { pipeline } from "stream"; +import fs3 from "fs"; +import path2 from "path"; +var record_files = false; var DECODE_FRAME_SIZE = 1024; var DECODE_SAMPLE_RATE = 16e3; var AudioMonitor = class { @@ -3377,12 +3334,11 @@ var VoiceManager = class extends EventEmitter { this.runtime = client.runtime; } async handleVoiceStateUpdate(oldState, newState) { - var _a; const oldChannelId = oldState.channelId; const newChannelId = newState.channelId; const member = newState.member; if (!member) return; - if (member.id === ((_a = this.client.user) == null ? void 0 : _a.id)) { + if (member.id === this.client.user?.id) { return; } if (oldChannelId === newChannelId) { @@ -3472,7 +3428,7 @@ var VoiceManager = class extends EventEmitter { }); this.connections.set(channel.id, connection); const me = channel.guild.members.me; - if ((me == null ? void 0 : me.voice) && me.permissions.has("DeafenMembers")) { + if (me?.voice && me.permissions.has("DeafenMembers")) { try { await me.voice.setDeaf(false); await me.voice.setMute(false); @@ -3481,7 +3437,6 @@ var VoiceManager = class extends EventEmitter { } } connection.receiver.speaking.on("start", async (userId) => { - var _a; let user = channel.members.get(userId); if (!user) { try { @@ -3490,16 +3445,15 @@ var VoiceManager = class extends EventEmitter { console.error("Failed to fetch user:", error); } } - if (user && !(user == null ? void 0 : user.user.bot)) { + if (user && !user?.user.bot) { this.monitorMember(user, channel); - (_a = this.streams.get(userId)) == null ? void 0 : _a.emit("speakingStarted"); + this.streams.get(userId)?.emit("speakingStarted"); } }); connection.receiver.speaking.on("end", async (userId) => { - var _a; const user = channel.members.get(userId); - if (!(user == null ? void 0 : user.user.bot)) { - (_a = this.streams.get(userId)) == null ? void 0 : _a.emit("speakingStopped"); + if (!user?.user.bot) { + this.streams.get(userId)?.emit("speakingStopped"); } }); } catch (error) { @@ -3520,12 +3474,11 @@ var VoiceManager = class extends EventEmitter { return connection; } async monitorMember(member, channel) { - var _a, _b, _c; - const userId = member == null ? void 0 : member.id; - const userName = (_a = member == null ? void 0 : member.user) == null ? void 0 : _a.username; - const name = (_b = member == null ? void 0 : member.user) == null ? void 0 : _b.displayName; - const connection = this.getVoiceConnection((_c = member == null ? void 0 : member.guild) == null ? void 0 : _c.id); - const receiveStream = connection == null ? void 0 : connection.receiver.subscribe(userId, { + const userId = member?.id; + const userName = member?.user?.username; + const name = member?.user?.displayName; + const connection = this.getVoiceConnection(member?.guild?.id); + const receiveStream = connection?.receiver.subscribe(userId, { autoDestroy: true, emitClose: true }); @@ -3578,19 +3531,19 @@ var VoiceManager = class extends EventEmitter { console.log(`Opus decoding error: ${err}`); }; const streamCloseHandler = () => { - console.log(`voice stream from ${member == null ? void 0 : member.displayName} closed`); + console.log(`voice stream from ${member?.displayName} closed`); this.streams.delete(userId); this.connections.delete(userId); }; const closeHandler = () => { - console.log(`Opus decoder for ${member == null ? void 0 : member.displayName} closed`); + console.log(`Opus decoder for ${member?.displayName} closed`); opusDecoder.removeListener("error", errorHandler); opusDecoder.removeListener("close", closeHandler); - receiveStream == null ? void 0 : receiveStream.removeListener("close", streamCloseHandler); + receiveStream?.removeListener("close", streamCloseHandler); }; opusDecoder.on("error", errorHandler); opusDecoder.on("close", closeHandler); - receiveStream == null ? void 0 : receiveStream.on("close", streamCloseHandler); + receiveStream?.on("close", streamCloseHandler); this.client.emit( "userStream", userId, @@ -3601,14 +3554,13 @@ var VoiceManager = class extends EventEmitter { ); } leaveChannel(channel) { - var _a; const connection = this.connections.get(channel.id); if (connection) { connection.destroy(); this.connections.delete(channel.id); } for (const [memberId, monitorInfo] of this.activeMonitors) { - if (monitorInfo.channel.id === channel.id && memberId !== ((_a = this.client.user) == null ? void 0 : _a.id)) { + if (monitorInfo.channel.id === channel.id && memberId !== this.client.user?.id) { this.stopMonitoringMember(memberId); } } @@ -3627,9 +3579,8 @@ var VoiceManager = class extends EventEmitter { console.log(`Joined guild ${guild.name}`); } async debouncedProcessTranscription(userId, name, userName, channel) { - var _a, _b; const DEBOUNCE_TRANSCRIPTION_THRESHOLD = 1500; - if (((_b = (_a = this.activeAudioPlayer) == null ? void 0 : _a.state) == null ? void 0 : _b.status) === "idle") { + if (this.activeAudioPlayer?.state?.status === "idle") { elizaLogger3.log("Cleaning up idle audio player."); this.cleanupAudioPlayer(this.activeAudioPlayer); } @@ -3720,7 +3671,25 @@ var VoiceManager = class extends EventEmitter { state.totalLength = 0; const wavBuffer = await this.convertOpusToWav(inputBuffer); console.log("Starting transcription..."); - const transcriptionText = await this.runtime.getService(ServiceType4.TRANSCRIPTION).transcribe(wavBuffer); + let arrayBuffer = wavBuffer.buffer.slice( + wavBuffer.byteOffset, + wavBuffer.byteOffset + wavBuffer.byteLength + ); + if (arrayBuffer instanceof SharedArrayBuffer) { + const tempArrayBuffer = new ArrayBuffer(arrayBuffer.byteLength); + new Uint8Array(tempArrayBuffer).set(new Uint8Array(arrayBuffer)); + arrayBuffer = tempArrayBuffer; + } + if (record_files) { + const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"); + const userName2 = name.replace(/\s+/g, "_"); + const fileName = `${userName2}_${timestamp}.wav`; + const filePath = path2.join(".", "recordings", fileName); + fs3.mkdirSync(path2.dirname(filePath), { recursive: true }); + fs3.writeFileSync(filePath, wavBuffer); + console.log(`WAV file saved as ${filePath}`); + } + const transcriptionText = await this.runtime.getService(ServiceType4.TRANSCRIPTION).transcribe(arrayBuffer); if (transcriptionText && isValidTranscription(transcriptionText)) { state.transcriptionText += transcriptionText; } @@ -3745,7 +3714,6 @@ var VoiceManager = class extends EventEmitter { } } async handleUserMessage(message, userId, channelId, channel, name, userName) { - var _a, _b; try { const roomId = stringToUuid2(channelId + "-" + this.runtime.agentId); const userIdUUID = stringToUuid2(userId); @@ -3805,7 +3773,7 @@ var VoiceManager = class extends EventEmitter { } const context = composeContext7({ state, - template: ((_a = this.runtime.character.templates) == null ? void 0 : _a.discordVoiceHandlerTemplate) || ((_b = this.runtime.character.templates) == null ? void 0 : _b.messageHandlerTemplate) || discordVoiceHandlerTemplate + template: this.runtime.character.templates?.discordVoiceHandlerTemplate || this.runtime.character.templates?.messageHandlerTemplate || discordVoiceHandlerTemplate }); const responseContent = await this._generateResponse( memory, @@ -3813,7 +3781,6 @@ var VoiceManager = class extends EventEmitter { context ); const callback = async (content2) => { - var _a2; console.log("callback content: ", content2); const { roomId: roomId2 } = memory; const responseMemory = { @@ -3830,7 +3797,7 @@ var VoiceManager = class extends EventEmitter { roomId: roomId2, embedding: getEmbeddingZeroVector2() }; - if ((_a2 = responseMemory.content.text) == null ? void 0 : _a2.trim()) { + if (responseMemory.content.text?.trim()) { await this.runtime.messageManager.createMemory( responseMemory ); @@ -3881,16 +3848,15 @@ var VoiceManager = class extends EventEmitter { } } async _shouldRespond(message, userId, channel, state) { - var _a, _b, _c, _d, _e; - if (userId === ((_a = this.client.user) == null ? void 0 : _a.id)) return false; + if (userId === this.client.user?.id) return false; const lowerMessage = message.toLowerCase(); const botName = this.client.user.username.toLowerCase(); const characterName = this.runtime.character.name.toLowerCase(); const guild = channel.guild; - const member = guild == null ? void 0 : guild.members.cache.get((_b = this.client.user) == null ? void 0 : _b.id); - const nickname = member == null ? void 0 : member.nickname; + const member = guild?.members.cache.get(this.client.user?.id); + const nickname = member?.nickname; if (lowerMessage.includes(botName) || lowerMessage.includes(characterName) || lowerMessage.includes( - (_c = this.client.user) == null ? void 0 : _c.tag.toLowerCase() + this.client.user?.tag.toLowerCase() ) || nickname && lowerMessage.includes(nickname.toLowerCase())) { return true; } @@ -3899,7 +3865,7 @@ var VoiceManager = class extends EventEmitter { } const shouldRespondContext = composeContext7({ state, - template: ((_d = this.runtime.character.templates) == null ? void 0 : _d.discordShouldRespondTemplate) || ((_e = this.runtime.character.templates) == null ? void 0 : _e.shouldRespondTemplate) || composeRandomUser2(discordShouldRespondTemplate, 2) + template: this.runtime.character.templates?.discordShouldRespondTemplate || this.runtime.character.templates?.shouldRespondTemplate || composeRandomUser2(discordShouldRespondTemplate, 2) }); const response = await generateShouldRespond2({ runtime: this.runtime, @@ -3941,7 +3907,6 @@ var VoiceManager = class extends EventEmitter { return response; } async _shouldIgnore(message) { - var _a; elizaLogger3.debug("message.content: ", message.content); if (message.content.text.length < 3) { return true; @@ -3969,19 +3934,13 @@ var VoiceManager = class extends EventEmitter { "sexy" ]; if (message.content.text.length < 50 && loseInterestWords.some( - (word) => { - var _a2; - return (_a2 = message.content.text) == null ? void 0 : _a2.toLowerCase().includes(word); - } + (word) => message.content.text?.toLowerCase().includes(word) )) { return true; } const ignoreWords = ["k", "ok", "bye", "lol", "nm", "uh"]; - if (((_a = message.content.text) == null ? void 0 : _a.length) < 8 && ignoreWords.some( - (word) => { - var _a2; - return (_a2 = message.content.text) == null ? void 0 : _a2.toLowerCase().includes(word); - } + if (message.content.text?.length < 8 && ignoreWords.some( + (word) => message.content.text?.toLowerCase().includes(word) )) { return true; } @@ -3995,13 +3954,13 @@ var VoiceManager = class extends EventEmitter { ); if (channelId) { const channel = await guild.channels.fetch(channelId); - if (channel == null ? void 0 : channel.isVoiceBased()) { + if (channel?.isVoiceBased()) { chosenChannel = channel; } } if (!chosenChannel) { const channels = (await guild.channels.fetch()).filter( - (channel) => (channel == null ? void 0 : channel.type) == ChannelType7.GuildVoice + (channel) => channel?.type == ChannelType7.GuildVoice ); for (const [, channel] of channels) { const voiceChannel = channel; @@ -4063,10 +4022,9 @@ var VoiceManager = class extends EventEmitter { } } async handleJoinChannelCommand(interaction) { - var _a; try { await interaction.deferReply(); - const channelId = (_a = interaction.options.get("channel")) == null ? void 0 : _a.value; + const channelId = interaction.options.get("channel")?.value; if (!channelId) { await interaction.editReply( "Please provide a voice channel to join." @@ -4190,8 +4148,7 @@ var DiscordClient = class extends EventEmitter2 { } } async onClientReady(readyClient) { - var _a, _b, _c; - elizaLogger4.success(`Logged in as ${(_a = readyClient.user) == null ? void 0 : _a.tag}`); + elizaLogger4.success(`Logged in as ${readyClient.user?.tag}`); const commands = [ { name: "joinchannel", @@ -4214,7 +4171,7 @@ var DiscordClient = class extends EventEmitter2 { } ]; try { - await ((_b = this.client.application) == null ? void 0 : _b.commands.set(commands)); + await this.client.application?.commands.set(commands); elizaLogger4.success("Slash commands registered"); } catch (error) { console.error("Error registering slash commands:", error); @@ -4242,12 +4199,11 @@ var DiscordClient = class extends EventEmitter2 { ].reduce((a, b) => a | b, 0n); elizaLogger4.success("Use this URL to add the bot to your server:"); elizaLogger4.success( - `https://discord.com/api/oauth2/authorize?client_id=${(_c = readyClient.user) == null ? void 0 : _c.id}&permissions=${requiredPermissions}&scope=bot%20applications.commands` + `https://discord.com/api/oauth2/authorize?client_id=${readyClient.user?.id}&permissions=${requiredPermissions}&scope=bot%20applications.commands` ); await this.onReady(); } async handleReactionAdd(reaction, user) { - var _a, _b; try { elizaLogger4.log("Reaction added"); if (!reaction || !user) { @@ -4289,8 +4245,8 @@ var DiscordClient = class extends EventEmitter2 { const messageContent = reaction.message.content || ""; const truncatedContent = messageContent.length > 100 ? `${messageContent.substring(0, 100)}...` : messageContent; const reactionMessage = `*<${emoji}>: "${truncatedContent}"*`; - const userName = ((_a = reaction.message.author) == null ? void 0 : _a.username) || "unknown"; - const name = ((_b = reaction.message.author) == null ? void 0 : _b.displayName) || userName; + const userName = reaction.message.author?.username || "unknown"; + const name = reaction.message.author?.displayName || userName; await this.runtime.ensureConnection( userIdUUID, roomId, diff --git a/dist/index.js.map b/dist/index.js.map index 25f292d..0a69b34 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/client.ts","../src/actions/chat_with_attachments.ts","../src/actions/download_media.ts","../src/actions/joinvoice.ts","../src/actions/leavevoice.ts","../src/actions/summarize_conversation.ts","../src/actions/transcribe_media.ts","../src/messages.ts","../src/attachments.ts","../src/templates.ts","../src/constants.ts","../src/utils.ts","../src/providers/channelState.ts","../src/providers/voiceState.ts","../src/voice.ts","../src/index.ts"],"sourcesContent":["import {\n getEmbeddingZeroVector,\n stringToUuid,\n elizaLogger,\n type Character,\n type Client as ElizaClient,\n type IAgentRuntime,\n type Plugin,\n} from \"@elizaos/core\";\nimport {\n Client,\n Events,\n GatewayIntentBits,\n type Guild,\n type MessageReaction,\n Partials,\n type User,\n} from \"discord.js\";\nimport { EventEmitter } from \"events\";\nimport chat_with_attachments from \"./actions/chat_with_attachments.ts\";\nimport download_media from \"./actions/download_media.ts\";\nimport joinvoice from \"./actions/joinvoice.ts\";\nimport leavevoice from \"./actions/leavevoice.ts\";\nimport summarize from \"./actions/summarize_conversation.ts\";\nimport transcribe_media from \"./actions/transcribe_media.ts\";\nimport { MessageManager } from \"./messages.ts\";\nimport channelStateProvider from \"./providers/channelState.ts\";\nimport voiceStateProvider from \"./providers/voiceState.ts\";\nimport { VoiceManager } from \"./voice.ts\";\nimport { PermissionsBitField } from \"discord.js\";\n\nclass DiscordClient extends EventEmitter {\n apiToken: string;\n client: Client;\n runtime: IAgentRuntime;\n character: Character;\n private messageManager: MessageManager;\n private voiceManager: VoiceManager;\n\n constructor(runtime: IAgentRuntime) {\n super();\n\n this.apiToken = runtime.getSetting(\"DISCORD_API_TOKEN\") as string;\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.GuildVoiceStates,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.DirectMessageTyping,\n GatewayIntentBits.GuildMessageTyping,\n GatewayIntentBits.GuildMessageReactions,\n ],\n partials: [\n Partials.Channel,\n Partials.Message,\n Partials.User,\n Partials.Reaction,\n ],\n });\n\n this.runtime = runtime;\n this.voiceManager = new VoiceManager(this);\n this.messageManager = new MessageManager(this, this.voiceManager);\n\n this.client.once(Events.ClientReady, this.onClientReady.bind(this));\n this.client.login(this.apiToken);\n\n this.setupEventListeners();\n\n this.runtime.registerAction(joinvoice);\n this.runtime.registerAction(leavevoice);\n this.runtime.registerAction(summarize);\n this.runtime.registerAction(chat_with_attachments);\n this.runtime.registerAction(transcribe_media);\n this.runtime.registerAction(download_media);\n\n this.runtime.providers.push(channelStateProvider);\n this.runtime.providers.push(voiceStateProvider);\n }\n\n private setupEventListeners() {\n // When joining to a new server\n this.client.on(\"guildCreate\", this.handleGuildCreate.bind(this));\n\n this.client.on(\n Events.MessageReactionAdd,\n this.handleReactionAdd.bind(this)\n );\n this.client.on(\n Events.MessageReactionRemove,\n this.handleReactionRemove.bind(this)\n );\n\n // Handle voice events with the voice manager\n this.client.on(\n \"voiceStateUpdate\",\n this.voiceManager.handleVoiceStateUpdate.bind(this.voiceManager)\n );\n this.client.on(\n \"userStream\",\n this.voiceManager.handleUserStream.bind(this.voiceManager)\n );\n\n // Handle a new message with the message manager\n this.client.on(\n Events.MessageCreate,\n this.messageManager.handleMessage.bind(this.messageManager)\n );\n\n // Handle a new interaction\n this.client.on(\n Events.InteractionCreate,\n this.handleInteractionCreate.bind(this)\n );\n }\n\n async stop() {\n try {\n // disconnect websocket\n // this unbinds all the listeners\n await this.client.destroy();\n } catch (e) {\n elizaLogger.error(\"client-discord instance stop err\", e);\n }\n }\n\n private async onClientReady(readyClient: { user: { tag: any; id: any } }) {\n elizaLogger.success(`Logged in as ${readyClient.user?.tag}`);\n\n // Register slash commands\n const commands = [\n {\n name: \"joinchannel\",\n description: \"Join a voice channel\",\n options: [\n {\n name: \"channel\",\n type: 7, // CHANNEL type\n description: \"The voice channel to join\",\n required: true,\n channel_types: [2], // GuildVoice type\n },\n ],\n },\n {\n name: \"leavechannel\",\n description: \"Leave the current voice channel\",\n },\n ];\n\n try {\n await this.client.application?.commands.set(commands);\n elizaLogger.success(\"Slash commands registered\");\n } catch (error) {\n console.error(\"Error registering slash commands:\", error);\n }\n\n // Required permissions for the bot\n const requiredPermissions = [\n // Text Permissions\n PermissionsBitField.Flags.ViewChannel,\n PermissionsBitField.Flags.SendMessages,\n PermissionsBitField.Flags.SendMessagesInThreads,\n PermissionsBitField.Flags.CreatePrivateThreads,\n PermissionsBitField.Flags.CreatePublicThreads,\n PermissionsBitField.Flags.EmbedLinks,\n PermissionsBitField.Flags.AttachFiles,\n PermissionsBitField.Flags.AddReactions,\n PermissionsBitField.Flags.UseExternalEmojis,\n PermissionsBitField.Flags.UseExternalStickers,\n PermissionsBitField.Flags.MentionEveryone,\n PermissionsBitField.Flags.ManageMessages,\n PermissionsBitField.Flags.ReadMessageHistory,\n // Voice Permissions\n PermissionsBitField.Flags.Connect,\n PermissionsBitField.Flags.Speak,\n PermissionsBitField.Flags.UseVAD,\n PermissionsBitField.Flags.PrioritySpeaker,\n ].reduce((a, b) => a | b, 0n);\n\n elizaLogger.success(\"Use this URL to add the bot to your server:\");\n elizaLogger.success(\n `https://discord.com/api/oauth2/authorize?client_id=${readyClient.user?.id}&permissions=${requiredPermissions}&scope=bot%20applications.commands`\n );\n await this.onReady();\n }\n\n async handleReactionAdd(reaction: MessageReaction, user: User) {\n try {\n elizaLogger.log(\"Reaction added\");\n\n // Early returns\n if (!reaction || !user) {\n elizaLogger.warn(\"Invalid reaction or user\");\n return;\n }\n\n // Get emoji info\n let emoji = reaction.emoji.name;\n if (!emoji && reaction.emoji.id) {\n emoji = `<:${reaction.emoji.name}:${reaction.emoji.id}>`;\n }\n\n // Fetch full message if partial\n if (reaction.partial) {\n try {\n await reaction.fetch();\n } catch (error) {\n elizaLogger.error(\n \"Failed to fetch partial reaction:\",\n error\n );\n return;\n }\n }\n\n // Generate IDs with timestamp to ensure uniqueness\n const timestamp = Date.now();\n const roomId = stringToUuid(\n `${reaction.message.channel.id}-${this.runtime.agentId}`\n );\n const userIdUUID = stringToUuid(\n `${user.id}-${this.runtime.agentId}`\n );\n const reactionUUID = stringToUuid(\n `${reaction.message.id}-${user.id}-${emoji}-${timestamp}-${this.runtime.agentId}`\n );\n\n // Validate IDs\n if (!userIdUUID || !roomId) {\n elizaLogger.error(\"Invalid user ID or room ID\", {\n userIdUUID,\n roomId,\n });\n return;\n }\n\n // Process message content\n const messageContent = reaction.message.content || \"\";\n const truncatedContent =\n messageContent.length > 100\n ? `${messageContent.substring(0, 100)}...`\n : messageContent;\n const reactionMessage = `*<${emoji}>: \"${truncatedContent}\"*`;\n\n // Get user info\n const userName = reaction.message.author?.username || \"unknown\";\n const name = reaction.message.author?.displayName || userName;\n\n // Ensure connection\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n // Create memory with retry logic\n const memory = {\n id: reactionUUID,\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n content: {\n text: reactionMessage,\n source: \"discord\",\n inReplyTo: stringToUuid(\n `${reaction.message.id}-${this.runtime.agentId}`\n ),\n },\n roomId,\n createdAt: timestamp,\n embedding: getEmbeddingZeroVector(),\n };\n\n try {\n await this.runtime.messageManager.createMemory(memory);\n elizaLogger.debug(\"Reaction memory created\", {\n reactionId: reactionUUID,\n emoji,\n userId: user.id,\n });\n } catch (error) {\n if (error.code === \"23505\") {\n // Duplicate key error\n elizaLogger.warn(\"Duplicate reaction memory, skipping\", {\n reactionId: reactionUUID,\n });\n return;\n }\n throw error; // Re-throw other errors\n }\n } catch (error) {\n elizaLogger.error(\"Error handling reaction:\", error);\n }\n }\n\n async handleReactionRemove(reaction: MessageReaction, user: User) {\n elizaLogger.log(\"Reaction removed\");\n // if (user.bot) return;\n\n let emoji = reaction.emoji.name;\n if (!emoji && reaction.emoji.id) {\n emoji = `<:${reaction.emoji.name}:${reaction.emoji.id}>`;\n }\n\n // Fetch the full message if it's a partial\n if (reaction.partial) {\n try {\n await reaction.fetch();\n } catch (error) {\n console.error(\n \"Something went wrong when fetching the message:\",\n error\n );\n return;\n }\n }\n\n const messageContent = reaction.message.content;\n const truncatedContent =\n messageContent.length > 50\n ? messageContent.substring(0, 50) + \"...\"\n : messageContent;\n\n const reactionMessage = `*Removed <${emoji} emoji> from: \"${truncatedContent}\"*`;\n\n const roomId = stringToUuid(\n reaction.message.channel.id + \"-\" + this.runtime.agentId\n );\n const userIdUUID = stringToUuid(user.id);\n\n // Generate a unique UUID for the reaction removal\n const reactionUUID = stringToUuid(\n `${reaction.message.id}-${user.id}-${emoji}-removed-${this.runtime.agentId}`\n );\n\n const userName = reaction.message.author.username;\n const name = reaction.message.author.displayName;\n\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n try {\n // Save the reaction removal as a message\n await this.runtime.messageManager.createMemory({\n id: reactionUUID, // This is the ID of the reaction removal message\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n content: {\n text: reactionMessage,\n source: \"discord\",\n inReplyTo: stringToUuid(\n reaction.message.id + \"-\" + this.runtime.agentId\n ), // This is the ID of the original message\n },\n roomId,\n createdAt: Date.now(),\n embedding: getEmbeddingZeroVector(),\n });\n } catch (error) {\n console.error(\"Error creating reaction removal message:\", error);\n }\n }\n\n private handleGuildCreate(guild: Guild) {\n console.log(`Joined guild ${guild.name}`);\n this.voiceManager.scanGuild(guild);\n }\n\n private async handleInteractionCreate(interaction: any) {\n if (!interaction.isCommand()) return;\n\n switch (interaction.commandName) {\n case \"joinchannel\":\n await this.voiceManager.handleJoinChannelCommand(interaction);\n break;\n case \"leavechannel\":\n await this.voiceManager.handleLeaveChannelCommand(interaction);\n break;\n }\n }\n\n private async onReady() {\n const guilds = await this.client.guilds.fetch();\n for (const [, guild] of guilds) {\n const fullGuild = await guild.fetch();\n this.voiceManager.scanGuild(fullGuild);\n }\n }\n}\n\n// function startDiscord(runtime: IAgentRuntime) {\n// return new DiscordClient(runtime);\n// }\n\nexport const DiscordClientInterface: ElizaClient = {\n name: 'discord',\n start: async (runtime: IAgentRuntime) => new DiscordClient(runtime),\n};","import { composeContext, getModelSettings } from \"@elizaos/core\";\nimport { generateText, trimTokens } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Memory,\n ModelClass,\n type State,\n} from \"@elizaos/core\";\nimport * as fs from \"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\": \"\",\n \"attachmentIds\": [\"\", \"\", ...]\n}\n\\`\\`\\`\n`;\n\nconst getAttachmentIds = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n): Promise<{ objective: string; attachmentIds: string[] } | null> => {\n state = (await runtime.composeState(message)) as State;\n\n const context = composeContext({\n state,\n template: attachmentIdsTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n console.log(\"response\", response);\n // try parsing to a json object\n const parsedResponse = parseJSONObjectFromText(response) as {\n objective: string;\n attachmentIds: string[];\n } | null;\n // see if it contains objective and attachmentIds\n if (parsedResponse?.objective && parsedResponse?.attachmentIds) {\n return parsedResponse;\n }\n }\n return null;\n};\n\nconst summarizeAction = {\n name: \"CHAT_WITH_ATTACHMENTS\",\n similes: [\n \"CHAT_WITH_ATTACHMENT\",\n \"SUMMARIZE_FILES\",\n \"SUMMARIZE_FILE\",\n \"SUMMARIZE_ATACHMENT\",\n \"CHAT_WITH_PDF\",\n \"ATTACHMENT_SUMMARY\",\n \"RECAP_ATTACHMENTS\",\n \"SUMMARIZE_FILE\",\n \"SUMMARIZE_VIDEO\",\n \"SUMMARIZE_AUDIO\",\n \"SUMMARIZE_IMAGE\",\n \"SUMMARIZE_DOCUMENT\",\n \"SUMMARIZE_LINK\",\n \"ATTACHMENT_SUMMARY\",\n \"FILE_SUMMARY\",\n ],\n description:\n \"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 validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n // only show if one of the keywords are in the message\n const keywords: string[] = [\n \"attachment\",\n \"summary\",\n \"summarize\",\n \"research\",\n \"pdf\",\n \"video\",\n \"audio\",\n \"image\",\n \"document\",\n \"link\",\n \"file\",\n \"attachment\",\n \"summarize\",\n \"code\",\n \"report\",\n \"write\",\n \"details\",\n \"information\",\n \"talk\",\n \"chat\",\n \"read\",\n \"listen\",\n \"watch\",\n ];\n return keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword.toLowerCase())\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n state = (await runtime.composeState(message)) as State;\n\n const callbackData: Content = {\n text: \"\", // fill in later\n action: \"CHAT_WITH_ATTACHMENTS_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n\n // 1. extract attachment IDs from the message\n const attachmentData = await getAttachmentIds(runtime, message, state);\n if (!attachmentData) {\n console.error(\"Couldn't get attachment IDs from message\");\n return;\n }\n\n const { objective, attachmentIds } = attachmentData;\n\n // This is pretty gross but it can catch cases where the returned generated UUID is stupidly wrong for some reason\n const attachments = state.recentMessagesData\n .filter(\n (msg) =>\n msg.content.attachments &&\n msg.content.attachments.length > 0\n )\n .flatMap((msg) => msg.content.attachments)\n // check by first 5 characters of uuid\n .filter(\n (attachment) =>\n attachmentIds\n .map((attch) => attch.toLowerCase().slice(0, 5))\n .includes(attachment.id.toLowerCase().slice(0, 5)) ||\n // or check the other way\n attachmentIds.some((id) => {\n const attachmentId = id.toLowerCase().slice(0, 5);\n return attachment.id\n .toLowerCase()\n .includes(attachmentId);\n })\n );\n\n const attachmentsWithText = attachments\n .map((attachment) => `# ${attachment.title}\\n${attachment.text}`)\n .join(\"\\n\\n\");\n\n let currentSummary = \"\";\n\n const modelSettings = getModelSettings(\n runtime.character.modelProvider,\n ModelClass.SMALL\n );\n const chunkSize = modelSettings.maxOutputTokens;\n\n state.attachmentsWithText = attachmentsWithText;\n state.objective = objective;\n const template = await trimTokens(\n summarizationTemplate,\n chunkSize + 500,\n runtime\n );\n const context = composeContext({\n state,\n // make sure it fits, we can pad the tokens a bit\n // Get the model's tokenizer based on the current model being used\n template,\n });\n\n const summary = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n currentSummary = currentSummary + \"\\n\" + summary;\n\n if (!currentSummary) {\n console.error(\"No summary found, that's not good!\");\n return;\n }\n\n callbackData.text = currentSummary.trim();\n if (\n callbackData.text &&\n (currentSummary.trim()?.split(\"\\n\").length < 4 ||\n currentSummary.trim()?.split(\" \").length < 100)\n ) {\n callbackData.text = `Here is the summary:\n\\`\\`\\`md\n${currentSummary.trim()}\n\\`\\`\\`\n`;\n await callback(callbackData);\n } else if (currentSummary.trim()) {\n const summaryFilename = `content/summary_${Date.now()}.md`;\n\n try {\n // Debug: Log before file operations\n console.log(\"Creating summary file:\", {\n filename: summaryFilename,\n summaryLength: currentSummary.length,\n });\n\n // Write file directly first\n await fs.promises.writeFile(\n summaryFilename,\n currentSummary,\n \"utf8\"\n );\n console.log(\"File written successfully\");\n\n // Then cache it\n await runtime.cacheManager.set(summaryFilename, currentSummary);\n console.log(\"Cache set operation completed\");\n\n await callback(\n {\n ...callbackData,\n text: `I've attached the summary of the requested attachments as a text file.`,\n },\n [summaryFilename]\n );\n console.log(\"Callback completed with summary file\");\n } catch (error) {\n console.error(\"Error in file/cache process:\", error);\n throw error;\n }\n } else {\n console.warn(\n \"Empty response from chat with attachments action, skipping\"\n );\n }\n\n return callbackData;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can you summarize the attachments b3e23, c4f67, and d5a89?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure thing! I'll pull up those specific attachments and provide a summary of their content.\",\n action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"I need a technical summary of the PDFs I sent earlier - a1b2c3.pdf, d4e5f6.pdf, and g7h8i9.pdf\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"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 action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"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 },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sure, no problem.\",\n action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"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 },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"great idea, give me a minute\",\n action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n\nexport default summarizeAction;\n","import path from \"path\";\nimport { composeContext } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type IVideoService,\n type Memory,\n ModelClass,\n ServiceType,\n type State,\n} from \"@elizaos/core\";\nimport { generateText } 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\": \"\"\n}\n\\`\\`\\`\n`;\n\nconst getMediaUrl = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n): Promise => {\n if (!state) {\n state = (await runtime.composeState(message)) as State;\n }\n\n const context = composeContext({\n state,\n template: mediaUrlTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n const parsedResponse = parseJSONObjectFromText(response) as {\n mediaUrl: string;\n } | null;\n\n if (parsedResponse?.mediaUrl) {\n return parsedResponse.mediaUrl;\n }\n }\n return null;\n};\n\nexport default {\n name: \"DOWNLOAD_MEDIA\",\n similes: [\n \"DOWNLOAD_VIDEO\",\n \"DOWNLOAD_AUDIO\",\n \"GET_MEDIA\",\n \"DOWNLOAD_PODCAST\",\n \"DOWNLOAD_YOUTUBE\",\n ],\n description:\n \"Downloads a video or audio file from a URL and attaches it to the response message.\",\n validate: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n const videoService = runtime\n .getService(ServiceType.VIDEO)\n .getInstance();\n if (!state) {\n state = (await runtime.composeState(message)) as State;\n }\n\n const mediaUrl = await getMediaUrl(runtime, message, state);\n if (!mediaUrl) {\n console.error(\"Couldn't get media URL from messages\");\n return;\n }\n\n const videoInfo = await videoService.fetchVideoInfo(mediaUrl);\n const mediaPath = await videoService.downloadVideo(videoInfo);\n\n const response: Content = {\n text: `I downloaded the video \"${videoInfo.title}\" and attached it below.`,\n action: \"DOWNLOAD_MEDIA_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n\n const filename = path.basename(mediaPath);\n\n const maxRetries = 3;\n let retries = 0;\n\n while (retries < maxRetries) {\n try {\n await callback(\n {\n ...response,\n },\n [\"content_cache/\" + filename]\n );\n break;\n } catch (error) {\n retries++;\n console.error(\n `Error sending message (attempt ${retries}):`,\n error\n );\n\n if (retries === maxRetries) {\n console.error(\n \"Max retries reached. Failed to send message with attachment.\"\n );\n break;\n }\n\n // Wait for a short delay before retrying\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n }\n\n return response;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Downloading the YouTube video now, one sec\",\n action: \"DOWNLOAD_MEDIA\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can you grab this video for me? https://vimeo.com/123456789\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure thing, I'll download that Vimeo video for you\",\n action: \"DOWNLOAD_MEDIA\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"I need this video downloaded: https://www.youtube.com/watch?v=abcdefg\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"No problem, I'm on it. I'll have that YouTube video downloaded in a jiffy\",\n action: \"DOWNLOAD_MEDIA\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n","// eslint-disable-next-line\n// @ts-nocheck\n// src/actions/joinVoice\nimport {\n type Action,\n type ActionExample,\n composeContext,\n type IAgentRuntime,\n type Memory,\n type State,\n generateText,\n ModelClass,\n} from \"@elizaos/core\";\nimport {\n type Channel,\n ChannelType,\n type Client,\n type Message as DiscordMessage,\n type Guild,\n type GuildMember,\n} from \"discord.js\";\nimport { joinVoiceChannel } from \"@discordjs/voice\";\n\nexport default {\n name: \"JOIN_VOICE\",\n similes: [\n \"JOIN_VOICE\",\n \"JOIN_VC\",\n \"JOIN_VOICE_CHAT\",\n \"JOIN_VOICE_CHANNEL\",\n \"JOIN_MEETING\",\n \"JOIN_CALL\",\n ],\n validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n state: State\n ) => {\n if (message.content.source !== \"discord\") {\n // not a discord message\n return false;\n }\n\n if (!state.discordClient) {\n return;\n }\n\n // did they say something about joining a voice channel? if not, don't validate\n const keywords = [\n \"join\",\n \"come to\",\n \"come on\",\n \"enter\",\n \"voice\",\n \"chat\",\n \"talk\",\n \"call\",\n \"hop on\",\n \"get on\",\n \"vc\",\n \"meeting\",\n \"discussion\",\n ];\n if (\n !keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword)\n )\n ) {\n return false;\n }\n\n return true;\n },\n description: \"Join a voice channel to participate in voice chat.\",\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n ): Promise => {\n if (!state) {\n console.error(\"State is not available.\");\n }\n\n // We normalize data in from voice channels\n const discordMessage = (state.discordChannel ||\n state.discordMessage) as DiscordMessage;\n\n if (!discordMessage.content) {\n discordMessage.content = message.content.text;\n }\n\n const id = (discordMessage as DiscordMessage).guild?.id as string;\n const client = state.discordClient as Client;\n const voiceChannels = (\n client.guilds.cache.get(id) as Guild\n ).channels.cache.filter(\n (channel: Channel) => channel.type === ChannelType.GuildVoice\n );\n\n const messageContent = discordMessage.content;\n\n const targetChannel = voiceChannels.find((channel) => {\n const name = (channel as { name: string }).name.toLowerCase();\n\n // remove all non-alphanumeric characters (keep spaces between words)\n const replacedName = name.replace(/[^a-z0-9 ]/g, \"\");\n\n return (\n name.includes(messageContent) ||\n messageContent.includes(name) ||\n replacedName.includes(messageContent) ||\n messageContent.includes(replacedName)\n );\n });\n\n if (targetChannel) {\n joinVoiceChannel({\n channelId: targetChannel.id,\n guildId: (discordMessage as DiscordMessage).guild?.id as string,\n adapterCreator: (client.guilds.cache.get(id) as Guild)\n .voiceAdapterCreator,\n selfDeaf: false,\n selfMute: false,\n group: client.user.id,\n });\n return true;\n } else {\n const member = (discordMessage as DiscordMessage)\n .member as GuildMember;\n if (member?.voice?.channel) {\n joinVoiceChannel({\n channelId: member.voice.channel.id,\n guildId: (discordMessage as DiscordMessage).guild\n ?.id as string,\n adapterCreator: (client.guilds.cache.get(id) as Guild)\n .voiceAdapterCreator,\n selfDeaf: false,\n selfMute: false,\n group: client.user.id,\n });\n return true;\n }\n\n const 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 const guessState = {\n userMessage: message.content.text,\n voiceChannels: voiceChannels\n .map((channel) => (channel as { name: string }).name)\n .join(\"\\n\"),\n };\n\n const context = composeContext({\n template: messageTemplate,\n state: guessState as unknown as State,\n });\n\n const _datestr = new Date().toUTCString().replace(/:/g, \"-\");\n\n const responseContent = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n runtime.databaseAdapter.log({\n body: { message, context, response: responseContent },\n userId: message.userId,\n roomId: message.roomId,\n type: \"joinvoice\",\n });\n\n if (responseContent && responseContent.trim().length > 0) {\n // join the voice channel\n const channelName = responseContent.toLowerCase();\n\n const targetChannel = voiceChannels.find((channel) => {\n const name = (\n channel as { name: string }\n ).name.toLowerCase();\n\n // remove all non-alphanumeric characters (keep spaces between words)\n const replacedName = name.replace(/[^a-z0-9 ]/g, \"\");\n\n return (\n name.includes(channelName) ||\n channelName.includes(name) ||\n replacedName.includes(channelName) ||\n channelName.includes(replacedName)\n );\n });\n\n if (targetChannel) {\n joinVoiceChannel({\n channelId: targetChannel.id,\n guildId: (discordMessage as DiscordMessage).guild\n ?.id as string,\n adapterCreator: (client.guilds.cache.get(id) as Guild)\n .voiceAdapterCreator,\n selfDeaf: false,\n selfMute: false,\n group: client.user.id,\n });\n return true;\n }\n }\n\n await (discordMessage as DiscordMessage).reply(\n \"I couldn't figure out which channel you wanted me to join.\"\n );\n return false;\n }\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey, let's jump into the 'General' voice and chat\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sounds good\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"{{user2}}, can you join the vc, I want to discuss our strat\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure I'll join right now\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"hey {{user2}}, we're having a team meeting in the 'conference' voice channel, plz join us\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"OK see you there\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"{{user2}}, let's have a quick voice chat in the 'Lounge' channel.\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"kk be there in a sec\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey {{user2}}, can you join me in the 'Music' voice channel\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"join voice chat with us {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"coming\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"hop in vc {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"joining now\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"get in vc with us {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"im in\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n","// src/actions/leaveVoice\nimport { getVoiceConnection } from \"@discordjs/voice\";\nimport {\n type Channel,\n ChannelType,\n type Client,\n type Message as DiscordMessage,\n} from \"discord.js\";\nimport type {\n Action,\n ActionExample,\n IAgentRuntime,\n Memory,\n State,\n} from \"@elizaos/core\";\n\nexport default {\n name: \"LEAVE_VOICE\",\n similes: [\n \"LEAVE_VOICE\",\n \"LEAVE_VC\",\n \"LEAVE_VOICE_CHAT\",\n \"LEAVE_VOICE_CHANNEL\",\n \"LEAVE_MEETING\",\n \"LEAVE_CALL\",\n ],\n validate: async (runtime: IAgentRuntime, message: Memory, state: State) => {\n if (message.content.source !== \"discord\") {\n // not a discord message\n return false;\n }\n\n if (!state.discordClient) {\n return false;\n }\n\n const keywords = [\n \"leave\",\n \"exit\",\n \"stop\",\n \"quit\",\n \"get off\",\n \"get out\",\n \"bye\",\n \"cya\",\n \"see you\",\n \"hop off\",\n \"get off\",\n \"voice\",\n \"vc\",\n \"chat\",\n \"call\",\n \"meeting\",\n \"discussion\",\n ];\n if (\n !keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword)\n )\n ) {\n return false;\n }\n\n const client = state.discordClient as Client;\n\n // Check if the client is connected to any voice channel\n const isConnectedToVoice = client.voice.adapters.size > 0;\n\n return isConnectedToVoice;\n },\n description: \"Leave the current voice channel.\",\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n ): Promise => {\n if (!state.discordClient) {\n return;\n }\n\n const discordMessage = (state.discordMessage ||\n state.discordChannel) as DiscordMessage;\n\n if (!discordMessage) {\n throw new Error(\"Discord message is not available in the state.\");\n }\n const voiceChannels = (state.discordClient as Client)?.guilds.cache\n .get((discordMessage as DiscordMessage).guild?.id as string)\n ?.channels.cache.filter(\n (channel: Channel) => channel.type === ChannelType.GuildVoice\n );\n\n voiceChannels?.forEach((_channel: Channel) => {\n const connection = getVoiceConnection(\n (discordMessage as DiscordMessage).guild?.id as string\n );\n if (connection) {\n connection.destroy();\n }\n });\n return true;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey {{user2}} please leave the voice channel\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"I have to go now but thanks for the chat\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"You too, talk to you later\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Great call everyone, hopping off now\",\n action: \"LEAVE_VOICE\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Agreed, I'll hop off too\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey {{user2}} I need you to step away from the voice chat for a bit\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"No worries, I'll leave the voice channel\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"{{user2}}, I think we covered everything, you can leave the voice chat now\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sounds good, see you both later\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"leave voice {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"ok leaving\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"plz leave the voice chat {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"aight im out\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"yo {{user2}} gtfo the vc\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sorry, talk to you later\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n","import { composeContext, getModelSettings } from \"@elizaos/core\";\nimport { generateText, splitChunks, trimTokens } from \"@elizaos/core\";\nimport { getActorDetails } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Media,\n type Memory,\n ModelClass,\n type State,\n} from \"@elizaos/core\";\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. \" 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\": \"\",\n \"start\": \"0 minutes ago\",\n \"end\": \"2 hours ago\"\n}\n\\`\\`\\`\n`;\n\nconst getDateRange = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n) => {\n state = (await runtime.composeState(message)) as State;\n\n const context = composeContext({\n state,\n template: dateRangeTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n console.log(\"response\", response);\n // try parsing to a json object\n const parsedResponse = parseJSONObjectFromText(response) as {\n objective: string;\n start: string | number;\n end: string | number;\n } | null;\n // see if it contains objective, start and end\n if (parsedResponse) {\n if (\n parsedResponse.objective &&\n parsedResponse.start &&\n parsedResponse.end\n ) {\n // TODO: parse start and end into timestamps\n const startIntegerString = (\n parsedResponse.start as string\n ).match(/\\d+/)?.[0];\n const endIntegerString = (parsedResponse.end as string).match(\n /\\d+/\n )?.[0];\n\n // parse multiplier\n const multipliers = {\n second: 1 * 1000,\n minute: 60 * 1000,\n hour: 3600 * 1000,\n day: 86400 * 1000,\n };\n\n const startMultiplier = (parsedResponse.start as string).match(\n /second|minute|hour|day/\n )?.[0];\n const endMultiplier = (parsedResponse.end as string).match(\n /second|minute|hour|day/\n )?.[0];\n\n const startInteger = startIntegerString\n ? Number.parseInt(startIntegerString)\n : 0;\n const endInteger = endIntegerString\n ? Number.parseInt(endIntegerString)\n : 0;\n\n // multiply by multiplier\n const startTime =\n startInteger *\n multipliers[startMultiplier as keyof typeof multipliers];\n\n console.log(\"startTime\", startTime);\n\n const endTime =\n endInteger *\n multipliers[endMultiplier as keyof typeof multipliers];\n\n console.log(\"endTime\", endTime);\n\n // get the current time and subtract the start and end times\n parsedResponse.start = Date.now() - startTime;\n parsedResponse.end = Date.now() - endTime;\n\n return parsedResponse;\n }\n }\n }\n};\n\nconst summarizeAction = {\n name: \"SUMMARIZE_CONVERSATION\",\n similes: [\n \"RECAP\",\n \"RECAP_CONVERSATION\",\n \"SUMMARIZE_CHAT\",\n \"SUMMARIZATION\",\n \"CHAT_SUMMARY\",\n \"CONVERSATION_SUMMARY\",\n ],\n description: \"Summarizes the conversation and attachments.\",\n validate: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n // only show if one of the keywords are in the message\n const keywords: string[] = [\n \"summarize\",\n \"summarization\",\n \"summary\",\n \"recap\",\n \"report\",\n \"overview\",\n \"review\",\n \"rundown\",\n \"wrap-up\",\n \"brief\",\n \"debrief\",\n \"abstract\",\n \"synopsis\",\n \"outline\",\n \"digest\",\n \"abridgment\",\n \"condensation\",\n \"encapsulation\",\n \"essence\",\n \"gist\",\n \"main points\",\n \"key points\",\n \"key takeaways\",\n \"bulletpoint\",\n \"highlights\",\n \"tldr\",\n \"tl;dr\",\n \"in a nutshell\",\n \"bottom line\",\n \"long story short\",\n \"sum up\",\n \"sum it up\",\n \"short version\",\n \"bring me up to speed\",\n \"catch me up\",\n ];\n return keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword.toLowerCase())\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n state = (await runtime.composeState(message)) as State;\n\n const callbackData: Content = {\n text: \"\", // fill in later\n action: \"SUMMARIZATION_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n const { roomId } = message;\n\n // 1. extract date range from the message\n const dateRange = await getDateRange(runtime, message, state);\n if (!dateRange) {\n console.error(\"Couldn't get date range from message\");\n return;\n }\n\n console.log(\"dateRange\", dateRange);\n\n const { objective, start, end } = dateRange;\n\n // 2. get these memories from the database\n const memories = await runtime.messageManager.getMemories({\n roomId,\n // subtract start from current time\n start: Number.parseInt(start as string),\n end: Number.parseInt(end as string),\n count: 10000,\n unique: false,\n });\n\n const actors = await getActorDetails({\n runtime: runtime as IAgentRuntime,\n roomId,\n });\n\n const actorMap = new Map(actors.map((actor) => [actor.id, actor]));\n\n const formattedMemories = memories\n .map((memory) => {\n const attachments = memory.content.attachments\n ?.map((attachment: Media) => {\n return `---\\nAttachment: ${attachment.id}\\n${attachment.description}\\n${attachment.text}\\n---`;\n })\n .join(\"\\n\");\n return `${actorMap.get(memory.userId)?.name ?? \"Unknown User\"} (${actorMap.get(memory.userId)?.username ?? \"\"}): ${memory.content.text}\\n${attachments}`;\n })\n .join(\"\\n\");\n\n let currentSummary = \"\";\n\n const modelSettings = getModelSettings(\n runtime.character.modelProvider,\n ModelClass.SMALL\n );\n const chunkSize = modelSettings.maxOutputTokens - 1000;\n\n const chunks = await splitChunks(formattedMemories, chunkSize, 0);\n\n const _datestr = new Date().toUTCString().replace(/:/g, \"-\");\n\n state.memoriesWithAttachments = formattedMemories;\n state.objective = objective;\n\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n state.currentSummary = currentSummary;\n state.currentChunk = chunk;\n const template = await trimTokens(\n summarizationTemplate,\n chunkSize + 500,\n runtime\n );\n const context = composeContext({\n state,\n // make sure it fits, we can pad the tokens a bit\n template,\n });\n\n const summary = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n currentSummary = currentSummary + \"\\n\" + summary;\n }\n\n if (!currentSummary) {\n console.error(\"No summary found, that's not good!\");\n return;\n }\n\n callbackData.text = currentSummary.trim();\n if (\n callbackData.text &&\n (currentSummary.trim()?.split(\"\\n\").length < 4 ||\n currentSummary.trim()?.split(\" \").length < 100)\n ) {\n callbackData.text = `Here is the summary:\n\\`\\`\\`md\n${currentSummary.trim()}\n\\`\\`\\`\n`;\n await callback(callbackData);\n } else if (currentSummary.trim()) {\n const summaryFilename = `content/conversation_summary_${Date.now()}`;\n await runtime.cacheManager.set(summaryFilename, currentSummary);\n // save the summary to a file\n await callback(\n {\n ...callbackData,\n text: `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 },\n [summaryFilename]\n );\n } else {\n console.warn(\n \"Empty response from summarize conversation action, skipping\"\n );\n }\n\n return callbackData;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"```js\\nconst x = 10\\n```\",\n },\n },\n {\n user: \"{{user1}}\",\n content: {\n text: \"can you give me a detailed report on what we're talking about?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sure, no problem, give me a minute to get that together for you\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"please summarize the conversation we just had and include this blogpost i'm linking (Attachment: b3e12)\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sure, give me a sec\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can you summarize what moon and avf are talking about?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Yeah, just hold on a second while I get that together for you...\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"i need to write a blog post about farming, can you summarize the discussion from a few hours ago?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"no problem, give me a few minutes to read through everything\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n\nexport default summarizeAction;\n","import { composeContext } from \"@elizaos/core\";\nimport { generateText } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Memory,\n ModelClass,\n type 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 context 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\": \"\"\n}\n\\`\\`\\`\n`;\n\nconst getMediaAttachmentId = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n): Promise => {\n state = (await runtime.composeState(message)) as State;\n\n const context = composeContext({\n state,\n template: mediaAttachmentIdTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n console.log(\"response\", response);\n\n const parsedResponse = parseJSONObjectFromText(response) as {\n attachmentId: string;\n } | null;\n\n if (parsedResponse?.attachmentId) {\n return parsedResponse.attachmentId;\n }\n }\n return null;\n};\n\nconst transcribeMediaAction = {\n name: \"TRANSCRIBE_MEDIA\",\n similes: [\n \"TRANSCRIBE_AUDIO\",\n \"TRANSCRIBE_VIDEO\",\n \"MEDIA_TRANSCRIPT\",\n \"VIDEO_TRANSCRIPT\",\n \"AUDIO_TRANSCRIPT\",\n ],\n description:\n \"Transcribe the full text of an audio or video file that the user has attached.\",\n validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n\n const keywords: string[] = [\n \"transcribe\",\n \"transcript\",\n \"audio\",\n \"video\",\n \"media\",\n \"youtube\",\n \"meeting\",\n \"recording\",\n \"podcast\",\n \"call\",\n \"conference\",\n \"interview\",\n \"speech\",\n \"lecture\",\n \"presentation\",\n ];\n return keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword.toLowerCase())\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n state = (await runtime.composeState(message)) as State;\n\n const callbackData: Content = {\n text: \"\", // fill in later\n action: \"TRANSCRIBE_MEDIA_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n\n const attachmentId = await getMediaAttachmentId(\n runtime,\n message,\n state\n );\n if (!attachmentId) {\n console.error(\"Couldn't get media attachment ID from message\");\n return;\n }\n\n const attachment = state.recentMessagesData\n .filter(\n (msg) =>\n msg.content.attachments &&\n msg.content.attachments.length > 0\n )\n .flatMap((msg) => msg.content.attachments)\n .find(\n (attachment) =>\n attachment.id.toLowerCase() === attachmentId.toLowerCase()\n );\n\n if (!attachment) {\n console.error(`Couldn't find attachment with ID ${attachmentId}`);\n return;\n }\n\n const mediaTranscript = attachment.text;\n\n callbackData.text = mediaTranscript.trim();\n\n // if callbackData.text is < 4 lines or < 100 words, then we we callback with normal message wrapped in markdown block\n if (\n callbackData.text &&\n (callbackData.text?.split(\"\\n\").length < 4 ||\n callbackData.text?.split(\" \").length < 100)\n ) {\n callbackData.text = `Here is the transcript:\n\\`\\`\\`md\n${mediaTranscript.trim()}\n\\`\\`\\`\n`;\n await callback(callbackData);\n }\n // if text is big, let's send as an attachment\n else if (callbackData.text) {\n const transcriptFilename = `content/transcript_${Date.now()}`;\n\n // save the transcript to a file\n await runtime.cacheManager.set(\n transcriptFilename,\n callbackData.text\n );\n\n await callback(\n {\n ...callbackData,\n text: `I've attached the transcript as a text file.`,\n },\n [transcriptFilename]\n );\n } else {\n console.warn(\n \"Empty response from transcribe media action, skipping\"\n );\n }\n\n return callbackData;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Please transcribe the audio file I just sent.\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure, I'll transcribe the full audio for you.\",\n action: \"TRANSCRIBE_MEDIA\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can I get a transcript of that video recording?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Absolutely, give me a moment to generate the full transcript of the video.\",\n action: \"TRANSCRIBE_MEDIA\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n\nexport default transcribeMediaAction;\n","import { composeContext, composeRandomUser } from \"@elizaos/core\";\nimport { generateMessageResponse, generateShouldRespond } from \"@elizaos/core\";\nimport {\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type IBrowserService,\n type ISpeechService,\n type IVideoService,\n type Media,\n type Memory,\n ModelClass,\n ServiceType,\n type State,\n type UUID,\n} from \"@elizaos/core\";\nimport { stringToUuid, getEmbeddingZeroVector } from \"@elizaos/core\";\nimport {\n ChannelType,\n type Client,\n type Message as DiscordMessage,\n type TextChannel,\n} from \"discord.js\";\nimport { elizaLogger } from \"@elizaos/core\";\nimport { AttachmentManager } from \"./attachments.ts\";\nimport type { VoiceManager } from \"./voice.ts\";\nimport {\n discordShouldRespondTemplate,\n discordMessageHandlerTemplate,\n discordAutoPostTemplate,\n discordAnnouncementHypeTemplate\n} from \"./templates.ts\";\nimport {\n IGNORE_RESPONSE_WORDS,\n LOSE_INTEREST_WORDS,\n MESSAGE_CONSTANTS,\n MESSAGE_LENGTH_THRESHOLDS,\n RESPONSE_CHANCES,\n TEAM_COORDINATION,\n TIMING_CONSTANTS,\n} from \"./constants\";\nimport {\n sendMessageInChunks,\n canSendMessage,\n cosineSimilarity,\n} from \"./utils.ts\";\n\ninterface MessageContext {\n content: string;\n timestamp: number;\n}\n\ninterface AutoPostConfig {\n enabled: boolean;\n monitorTime: number;\n inactivityThreshold: number; // milliseconds\n mainChannelId: string;\n announcementChannelIds: string[];\n lastAutoPost?: number;\n minTimeBetweenPosts?: number; // minimum time between auto posts\n}\n\nexport type InterestChannels = {\n [key: string]: {\n currentHandler: string | undefined;\n lastMessageSent: number;\n messages: { userId: UUID; userName: string; content: Content }[];\n previousContext?: MessageContext;\n contextSimilarityThreshold?: number;\n };\n};\n\nexport class MessageManager {\n private client: Client;\n private runtime: IAgentRuntime;\n private attachmentManager: AttachmentManager;\n private interestChannels: InterestChannels = {};\n private discordClient: any;\n private voiceManager: VoiceManager;\n //Auto post\n private autoPostConfig: AutoPostConfig;\n private lastChannelActivity: { [channelId: string]: number } = {};\n private autoPostInterval: NodeJS.Timeout;\n\n constructor(discordClient: any, voiceManager: VoiceManager) {\n this.client = discordClient.client;\n this.voiceManager = voiceManager;\n this.discordClient = discordClient;\n this.runtime = discordClient.runtime;\n this.attachmentManager = new AttachmentManager(this.runtime);\n\n this.autoPostConfig = {\n enabled: this.runtime.character.clientConfig?.discord?.autoPost?.enabled || false,\n monitorTime: this.runtime.character.clientConfig?.discord?.autoPost?.monitorTime || 300000,\n inactivityThreshold: this.runtime.character.clientConfig?.discord?.autoPost?.inactivityThreshold || 3600000, // 1 hour default\n mainChannelId: this.runtime.character.clientConfig?.discord?.autoPost?.mainChannelId,\n announcementChannelIds: this.runtime.character.clientConfig?.discord?.autoPost?.announcementChannelIds || [],\n minTimeBetweenPosts: this.runtime.character.clientConfig?.discord?.autoPost?.minTimeBetweenPosts || 7200000, // 2 hours default\n };\n\n if (this.autoPostConfig.enabled) {\n this._startAutoPostMonitoring();\n }\n }\n\n async handleMessage(message: DiscordMessage) {\n\n if (this.runtime.character.clientConfig?.discord?.allowedChannelIds &&\n !this.runtime.character.clientConfig.discord.allowedChannelIds.includes(message.channelId)) {\n return;\n }\n\n // Update last activity time for the channel\n this.lastChannelActivity[message.channelId] = Date.now();\n\n if (\n message.interaction ||\n message.author.id ===\n this.client.user?.id /* || message.author?.bot*/\n ) {\n return;\n }\n\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldIgnoreBotMessages &&\n message.author?.bot\n ) {\n return;\n }\n\n // Check for mentions-only mode setting\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n if (!this._isMessageForMe(message)) {\n return;\n }\n }\n\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldIgnoreDirectMessages &&\n message.channel.type === ChannelType.DM\n ) {\n return;\n }\n\n const userId = message.author.id as UUID;\n const userName = message.author.username;\n const name = message.author.displayName;\n const channelId = message.channel.id;\n const isDirectlyMentioned = this._isMessageForMe(message);\n const hasInterest = this._checkInterest(message.channelId);\n\n // Team handling\n if (\n this.runtime.character.clientConfig?.discord?.isPartOfTeam &&\n !this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n const authorId = this._getNormalizedUserId(message.author.id);\n\n if (\n !this._isTeamLeader() &&\n this._isRelevantToTeamMember(message.content, channelId)\n ) {\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n }\n\n const isTeamRequest = this._isTeamCoordinationRequest(\n message.content\n );\n const isLeader = this._isTeamLeader();\n\n // After team-wide responses, check if we should maintain interest\n if (hasInterest && !isDirectlyMentioned) {\n const lastSelfMemories =\n await this.runtime.messageManager.getMemories({\n roomId: stringToUuid(\n channelId + \"-\" + this.runtime.agentId\n ),\n unique: false,\n count: 5,\n });\n\n const lastSelfSortedMemories = lastSelfMemories\n ?.filter((m) => m.userId === this.runtime.agentId)\n .sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n\n const isRelevant = this._isRelevantToTeamMember(\n message.content,\n channelId,\n lastSelfSortedMemories?.[0]\n );\n\n if (!isRelevant) {\n // Clearing interest - conversation not relevant to team member\n delete this.interestChannels[message.channelId];\n return;\n }\n }\n\n if (isTeamRequest) {\n if (isLeader) {\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n } else {\n // Set temporary interest for this response\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n\n // Clear interest after this cycle unless directly mentioned\n if (!isDirectlyMentioned) {\n // Use existing message cycle to clear interest\n this.interestChannels[\n message.channelId\n ].lastMessageSent = 0;\n }\n }\n }\n\n // Check for other team member mentions\n const otherTeamMembers =\n this.runtime.character.clientConfig.discord.teamAgentIds.filter(\n (id) => id !== this.client.user?.id\n );\n const mentionedTeamMember = otherTeamMembers.find((id) =>\n message.content.includes(`<@${id}>`)\n );\n\n // If another team member is mentioned, clear our interest\n if (mentionedTeamMember) {\n if (\n hasInterest ||\n this.interestChannels[message.channelId]?.currentHandler ===\n this.client.user?.id\n ) {\n delete this.interestChannels[message.channelId];\n\n // Only return if we're not the mentioned member\n if (!isDirectlyMentioned) {\n return;\n }\n }\n }\n\n // Set/maintain interest only if we're mentioned or already have interest\n if (isDirectlyMentioned) {\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n } else if (!isTeamRequest && !hasInterest) {\n return;\n }\n\n // Bot-specific checks\n if (message.author.bot) {\n if (this._isTeamMember(authorId) && !isDirectlyMentioned) {\n return;\n } else if (\n this.runtime.character.clientConfig.discord\n .shouldIgnoreBotMessages\n ) {\n return;\n }\n }\n }\n\n try {\n const { processedContent, attachments } =\n await this.processMessageMedia(message);\n\n const audioAttachments = message.attachments.filter((attachment) =>\n attachment.contentType?.startsWith(\"audio/\")\n );\n if (audioAttachments.size > 0) {\n const processedAudioAttachments =\n await this.attachmentManager.processAttachments(\n audioAttachments\n );\n attachments.push(...processedAudioAttachments);\n }\n\n const roomId = stringToUuid(channelId + \"-\" + this.runtime.agentId);\n const userIdUUID = stringToUuid(userId);\n\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n const messageId = stringToUuid(\n message.id + \"-\" + this.runtime.agentId\n );\n\n let shouldIgnore = false;\n let shouldRespond = true;\n\n const content: Content = {\n text: processedContent,\n attachments: attachments,\n source: \"discord\",\n url: message.url,\n inReplyTo: message.reference?.messageId\n ? stringToUuid(\n message.reference.messageId +\n \"-\" +\n this.runtime.agentId\n )\n : undefined,\n };\n\n const userMessage = {\n content,\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n roomId,\n };\n\n const memory: Memory = {\n id: stringToUuid(message.id + \"-\" + this.runtime.agentId),\n ...userMessage,\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n roomId,\n content,\n createdAt: message.createdTimestamp,\n };\n\n if (content.text) {\n await this.runtime.messageManager.addEmbeddingToMemory(memory);\n await this.runtime.messageManager.createMemory(memory);\n\n if (this.interestChannels[message.channelId]) {\n // Add new message\n this.interestChannels[message.channelId].messages.push({\n userId: userIdUUID,\n userName: userName,\n content: content,\n });\n\n // Trim to keep only recent messages\n if (\n this.interestChannels[message.channelId].messages\n .length > MESSAGE_CONSTANTS.MAX_MESSAGES\n ) {\n this.interestChannels[message.channelId].messages =\n this.interestChannels[\n message.channelId\n ].messages.slice(-MESSAGE_CONSTANTS.MAX_MESSAGES);\n }\n }\n }\n\n let state = await this.runtime.composeState(userMessage, {\n discordClient: this.client,\n discordMessage: message,\n agentName:\n this.runtime.character.name ||\n this.client.user?.displayName,\n });\n\n const canSendResult = canSendMessage(message.channel);\n if (!canSendResult.canSend) {\n return elizaLogger.warn(\n `Cannot send message to channel ${message.channel}`,\n canSendResult\n );\n }\n\n if (!shouldIgnore) {\n shouldIgnore = await this._shouldIgnore(message);\n }\n\n if (shouldIgnore) {\n return;\n }\n\n const agentUserState =\n await this.runtime.databaseAdapter.getParticipantUserState(\n roomId,\n this.runtime.agentId\n );\n\n if (\n agentUserState === \"MUTED\" &&\n !message.mentions.has(this.client.user.id) &&\n !hasInterest\n ) {\n console.log(\"Ignoring muted room\");\n // Ignore muted rooms unless explicitly mentioned\n return;\n }\n\n if (agentUserState === \"FOLLOWED\") {\n shouldRespond = true; // Always respond in followed rooms\n } else if (\n (!shouldRespond && hasInterest) ||\n (shouldRespond && !hasInterest)\n ) {\n shouldRespond = await this._shouldRespond(message, state);\n }\n\n if (shouldRespond) {\n const context = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordMessageHandlerTemplate ||\n discordMessageHandlerTemplate,\n });\n\n // simulate discord typing while generating a response\n const stopTyping = this.simulateTyping(message);\n\n const responseContent = await this._generateResponse(\n memory,\n state,\n context\n ).finally(() => {\n stopTyping();\n });\n\n responseContent.text = responseContent.text?.trim();\n responseContent.inReplyTo = stringToUuid(\n message.id + \"-\" + this.runtime.agentId\n );\n\n if (!responseContent.text) {\n return;\n }\n\n const callback: HandlerCallback = async (\n content: Content,\n files: any[]\n ) => {\n try {\n if (message.id && !content.inReplyTo) {\n content.inReplyTo = stringToUuid(\n message.id + \"-\" + this.runtime.agentId\n );\n }\n const messages = await sendMessageInChunks(\n message.channel as TextChannel,\n content.text,\n message.id,\n files\n );\n\n const memories: Memory[] = [];\n for (const m of messages) {\n let action = content.action;\n // If there's only one message or it's the last message, keep the original action\n // For multiple messages, set all but the last to 'CONTINUE'\n if (\n messages.length > 1 &&\n m !== messages[messages.length - 1]\n ) {\n action = \"CONTINUE\";\n }\n\n const memory: Memory = {\n id: stringToUuid(\n m.id + \"-\" + this.runtime.agentId\n ),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: {\n ...content,\n action,\n inReplyTo: messageId,\n url: m.url,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: m.createdTimestamp,\n };\n memories.push(memory);\n }\n for (const m of memories) {\n await this.runtime.messageManager.createMemory(m);\n }\n return memories;\n } catch (error) {\n console.error(\"Error sending message:\", error);\n return [];\n }\n };\n\n const action = this.runtime.actions.find((a) => a.name === responseContent.action);\n const shouldSuppressInitialMessage = action?.suppressInitialMessage;\n\n let responseMessages = [];\n\n if (!shouldSuppressInitialMessage) {\n responseMessages = await callback(responseContent);\n } else {\n responseMessages = [\n {\n id: stringToUuid(messageId + \"-\" + this.runtime.agentId),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: responseContent,\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now(),\n }\n ]\n }\n\n state = await this.runtime.updateRecentMessageState(state);\n\n await this.runtime.processActions(\n memory,\n responseMessages,\n state,\n callback\n );\n }\n await this.runtime.evaluate(memory, state, shouldRespond);\n } catch (error) {\n console.error(\"Error handling message:\", error);\n if (message.channel.type === ChannelType.GuildVoice) {\n // For voice channels, use text-to-speech for the error message\n const errorMessage = \"Sorry, I had a glitch. What was that?\";\n\n const speechService = this.runtime.getService(\n ServiceType.SPEECH_GENERATION\n );\n if (!speechService) {\n throw new Error(\"Speech generation service not found\");\n }\n\n const audioStream = await speechService.generate(\n this.runtime,\n errorMessage\n );\n await this.voiceManager.playAudioStream(userId, audioStream);\n } else {\n // For text channels, send the error message\n console.error(\"Error sending message:\", error);\n }\n }\n }\n\n async cacheMessages(channel: TextChannel, count = 20) {\n const messages = await channel.messages.fetch({ limit: count });\n\n // TODO: This is throwing an error but seems to work?\n for (const [_, message] of messages) {\n await this.handleMessage(message);\n }\n }\n\n private _startAutoPostMonitoring(): void {\n // Wait for client to be ready\n if (!this.client.isReady()) {\n elizaLogger.info('[AutoPost Discord] Client not ready, waiting for ready event')\n this.client.once('ready', () => {\n elizaLogger.info('[AutoPost Discord] Client ready, starting monitoring')\n this._initializeAutoPost();\n });\n } else {\n elizaLogger.info('[AutoPost Discord] Client already ready, starting monitoring')\n this._initializeAutoPost();\n }\n }\n\n private _initializeAutoPost(): void {\n // Give the client a moment to fully load its cache\n setTimeout(() => {\n // Monitor with random intervals between 2-6 hours\n this.autoPostInterval = setInterval(() => {\n this._checkChannelActivity();\n }, Math.floor(Math.random() * (4 * 60 * 60 * 1000) + 2 * 60 * 60 * 1000));\n\n // Start monitoring announcement channels\n this._monitorAnnouncementChannels();\n }, 5000); // 5 second delay to ensure everything is loaded\n }\n\n private async _checkChannelActivity(): Promise {\n if (!this.autoPostConfig.enabled || !this.autoPostConfig.mainChannelId) return;\n\n const channel = this.client.channels.cache.get(this.autoPostConfig.mainChannelId) as TextChannel;\n if (!channel) return;\n\n try {\n // Get last message time\n const messages = await channel.messages.fetch({ limit: 1 });\n const lastMessage = messages.first();\n const lastMessageTime = lastMessage ? lastMessage.createdTimestamp : 0;\n\n const now = Date.now();\n const timeSinceLastMessage = now - lastMessageTime;\n const timeSinceLastAutoPost = now - (this.autoPostConfig.lastAutoPost || 0);\n\n // Add some randomness to the inactivity threshold (±30 minutes)\n const randomThreshold = this.autoPostConfig.inactivityThreshold +\n (Math.random() * 1800000 - 900000);\n\n // Check if we should post\n if ((timeSinceLastMessage > randomThreshold) &&\n timeSinceLastAutoPost > (this.autoPostConfig.minTimeBetweenPosts || 0)) {\n\n try {\n // Create memory and generate response\n const roomId = stringToUuid(channel.id + \"-\" + this.runtime.agentId);\n\n const memory = {\n id: stringToUuid(`autopost-${Date.now()}`),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n roomId,\n content: { text: \"AUTO_POST_ENGAGEMENT\", source: \"discord\" },\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now()\n };\n\n let state = await this.runtime.composeState(memory, {\n discordClient: this.client,\n discordMessage: null,\n agentName: this.runtime.character.name || this.client.user?.displayName\n });\n\n // Generate response using template\n const context = composeContext({\n state,\n template: this.runtime.character.templates?.discordAutoPostTemplate || discordAutoPostTemplate\n });\n\n const responseContent = await this._generateResponse(memory, state, context);\n if (!responseContent?.text) return;\n\n // Send message and update memory\n const messages = await sendMessageInChunks(channel, responseContent.text.trim(), null, []);\n\n // Create and store memories\n const memories = messages.map(m => ({\n id: stringToUuid(m.id + \"-\" + this.runtime.agentId),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: {\n ...responseContent,\n url: m.url,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: m.createdTimestamp,\n }));\n\n for (const m of memories) {\n await this.runtime.messageManager.createMemory(m);\n }\n\n // Update state and last post time\n this.autoPostConfig.lastAutoPost = Date.now();\n state = await this.runtime.updateRecentMessageState(state);\n await this.runtime.evaluate(memory, state, true);\n } catch (error) {\n elizaLogger.warn(\"[AutoPost Discord] Error:\", error);\n }\n } else {\n elizaLogger.warn(\"[AutoPost Discord] Activity within threshold. Not posting.\");\n }\n } catch (error) {\n elizaLogger.warn(\"[AutoPost Discord] Error checking last message:\", error);\n }\n }\n\n private async _monitorAnnouncementChannels(): Promise {\n if (!this.autoPostConfig.enabled || !this.autoPostConfig.announcementChannelIds.length) {\n elizaLogger.warn('[AutoPost Discord] Auto post config disabled or no announcement channels')\n return;\n }\n\n for (const announcementChannelId of this.autoPostConfig.announcementChannelIds) {\n const channel = this.client.channels.cache.get(announcementChannelId);\n\n if (channel) {\n // Check if it's either a text channel or announcement channel\n // ChannelType.GuildAnnouncement is 5\n // ChannelType.GuildText is 0\n if (channel instanceof TextChannel || channel.type === ChannelType.GuildAnnouncement) {\n const newsChannel = channel as TextChannel;\n try {\n newsChannel.createMessageCollector().on('collect', async (message: DiscordMessage) => {\n if (message.author.bot || Date.now() - message.createdTimestamp > 300000) return;\n\n const mainChannel = this.client.channels.cache.get(this.autoPostConfig.mainChannelId) as TextChannel;\n if (!mainChannel) return;\n\n try {\n // Create memory and generate response\n const roomId = stringToUuid(mainChannel.id + \"-\" + this.runtime.agentId);\n const memory = {\n id: stringToUuid(`announcement-${Date.now()}`),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n roomId,\n content: {\n text: message.content,\n source: \"discord\",\n metadata: { announcementUrl: message.url }\n },\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now()\n };\n\n let state = await this.runtime.composeState(memory, {\n discordClient: this.client,\n discordMessage: message,\n announcementContent: message?.content,\n announcementChannelId: channel.id,\n agentName: this.runtime.character.name || this.client.user?.displayName\n });\n\n // Generate response using template\n const context = composeContext({\n state,\n template: this.runtime.character.templates?.discordAnnouncementHypeTemplate || discordAnnouncementHypeTemplate\n\n });\n\n const responseContent = await this._generateResponse(memory, state, context);\n if (!responseContent?.text) return;\n\n // Send message and update memory\n const messages = await sendMessageInChunks(mainChannel, responseContent.text.trim(), null, []);\n\n // Create and store memories\n const memories = messages.map(m => ({\n id: stringToUuid(m.id + \"-\" + this.runtime.agentId),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: {\n ...responseContent,\n url: m.url,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: m.createdTimestamp,\n }));\n\n for (const m of memories) {\n await this.runtime.messageManager.createMemory(m);\n }\n\n // Update state\n state = await this.runtime.updateRecentMessageState(state);\n await this.runtime.evaluate(memory, state, true);\n } catch (error) {\n elizaLogger.warn(\"[AutoPost Discord] Announcement Error:\", error);\n }\n });\n elizaLogger.info(`[AutoPost Discord] Successfully set up collector for announcement channel: ${newsChannel.name}`);\n } catch (error) {\n elizaLogger.warn(`[AutoPost Discord] Error setting up announcement channel collector:`, error);\n }\n } else {\n elizaLogger.warn(`[AutoPost Discord] Channel ${announcementChannelId} is not a valid announcement or text channel, type:`, channel.type);\n }\n } else {\n elizaLogger.warn(`[AutoPost Discord] Could not find channel ${announcementChannelId} directly`);\n }\n }\n }\n\n private _isMessageForMe(message: DiscordMessage): boolean {\n const isMentioned = message.mentions.users?.has(\n this.client.user?.id as string\n );\n const guild = message.guild;\n const member = guild?.members.cache.get(this.client.user?.id as string);\n const nickname = member?.nickname;\n\n // Don't consider role mentions as direct mentions\n const hasRoleMentionOnly =\n message.mentions.roles.size > 0 && !isMentioned;\n\n // If it's only a role mention and we're in team mode, let team logic handle it\n if (\n hasRoleMentionOnly &&\n this.runtime.character.clientConfig?.discord?.isPartOfTeam\n ) {\n return false;\n }\n\n return (\n isMentioned ||\n (!this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions &&\n (message.content\n .toLowerCase()\n .includes(\n this.client.user?.username.toLowerCase() as string\n ) ||\n message.content\n .toLowerCase()\n .includes(\n this.client.user?.tag.toLowerCase() as string\n ) ||\n (nickname &&\n message.content\n .toLowerCase()\n .includes(nickname.toLowerCase()))))\n );\n }\n\n async processMessageMedia(\n message: DiscordMessage\n ): Promise<{ processedContent: string; attachments: Media[] }> {\n let processedContent = message.content;\n\n let attachments: Media[] = [];\n\n // Process code blocks in the message content\n const codeBlockRegex = /```([\\s\\S]*?)```/g;\n let match;\n while ((match = codeBlockRegex.exec(processedContent))) {\n const codeBlock = match[1];\n const lines = codeBlock.split(\"\\n\");\n const title = lines[0];\n const description = lines.slice(0, 3).join(\"\\n\");\n const attachmentId =\n `code-${Date.now()}-${Math.floor(Math.random() * 1000)}`.slice(\n -5\n );\n attachments.push({\n id: attachmentId,\n url: \"\",\n title: title || \"Code Block\",\n source: \"Code\",\n description: description,\n text: codeBlock,\n });\n processedContent = processedContent.replace(\n match[0],\n `Code Block (${attachmentId})`\n );\n }\n\n // Process message attachments\n if (message.attachments.size > 0) {\n attachments = await this.attachmentManager.processAttachments(\n message.attachments\n );\n }\n\n // TODO: Move to attachments manager\n const urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n const urls = processedContent.match(urlRegex) || [];\n\n for (const url of urls) {\n if (\n this.runtime\n .getService(ServiceType.VIDEO)\n ?.isVideoUrl(url)\n ) {\n const videoService = this.runtime.getService(\n ServiceType.VIDEO\n );\n if (!videoService) {\n throw new Error(\"Video service not found\");\n }\n const videoInfo = await videoService.processVideo(\n url,\n this.runtime\n );\n\n attachments.push({\n id: `youtube-${Date.now()}`,\n url: url,\n title: videoInfo.title,\n source: \"YouTube\",\n description: videoInfo.description,\n text: videoInfo.text,\n });\n } else {\n const browserService = this.runtime.getService(\n ServiceType.BROWSER\n );\n if (!browserService) {\n throw new Error(\"Browser service not found\");\n }\n\n const { title, description: summary } =\n await browserService.getPageContent(url, this.runtime);\n\n attachments.push({\n id: `webpage-${Date.now()}`,\n url: url,\n title: title || \"Web Page\",\n source: \"Web\",\n description: summary,\n text: summary,\n });\n }\n }\n\n return { processedContent, attachments };\n }\n\n private _getNormalizedUserId(id: string): string {\n return id.toString().replace(/[^0-9]/g, \"\");\n }\n\n private _isTeamMember(userId: string): boolean {\n const teamConfig = this.runtime.character.clientConfig?.discord;\n if (!teamConfig?.isPartOfTeam || !teamConfig.teamAgentIds) return false;\n\n const normalizedUserId = this._getNormalizedUserId(userId);\n\n const isTeamMember = teamConfig.teamAgentIds.some(\n (teamId) => this._getNormalizedUserId(teamId) === normalizedUserId\n );\n\n return isTeamMember;\n }\n\n private _isTeamLeader(): boolean {\n return (\n this.client.user?.id ===\n this.runtime.character.clientConfig?.discord?.teamLeaderId\n );\n }\n\n private _isTeamCoordinationRequest(content: string): boolean {\n const contentLower = content.toLowerCase();\n return TEAM_COORDINATION.KEYWORDS?.some((keyword) =>\n contentLower.includes(keyword.toLowerCase())\n );\n }\n\n private _isRelevantToTeamMember(\n content: string,\n channelId: string,\n lastAgentMemory: Memory | null = null\n ): boolean {\n const teamConfig = this.runtime.character.clientConfig?.discord;\n\n if (this._isTeamLeader() && lastAgentMemory?.content.text) {\n const timeSinceLastMessage = Date.now() - lastAgentMemory.createdAt;\n if (timeSinceLastMessage > MESSAGE_CONSTANTS.INTEREST_DECAY_TIME) {\n return false; // Memory too old, not relevant\n }\n\n const similarity = cosineSimilarity(\n content.toLowerCase(),\n lastAgentMemory.content.text.toLowerCase()\n );\n\n return (\n similarity >=\n MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS\n );\n }\n\n // If no keywords defined, only leader maintains conversation\n if (!teamConfig?.teamMemberInterestKeywords) {\n return false;\n }\n\n return teamConfig.teamMemberInterestKeywords.some((keyword) =>\n content.toLowerCase().includes(keyword.toLowerCase())\n );\n }\n\n private async _analyzeContextSimilarity(\n currentMessage: string,\n previousContext?: MessageContext,\n agentLastMessage?: string\n ): Promise {\n if (!previousContext) return 1; // No previous context to compare against\n\n // If more than 5 minutes have passed, reduce similarity weight\n const timeDiff = Date.now() - previousContext.timestamp;\n const timeWeight = Math.max(0, 1 - timeDiff / (5 * 60 * 1000)); // 5 minutes threshold\n\n // Calculate content similarity\n const similarity = cosineSimilarity(\n currentMessage.toLowerCase(),\n previousContext.content.toLowerCase(),\n agentLastMessage?.toLowerCase()\n );\n\n // Weight the similarity by time factor\n const weightedSimilarity = similarity * timeWeight;\n\n return weightedSimilarity;\n }\n\n private async _shouldRespondBasedOnContext(\n message: DiscordMessage,\n channelState: InterestChannels[string]\n ): Promise {\n // Always respond if directly mentioned\n if (this._isMessageForMe(message)) return true;\n\n // If we're not the current handler, don't respond\n if (channelState?.currentHandler !== this.client.user?.id) return false;\n\n // Check if we have messages to compare\n if (!channelState.messages?.length) return false;\n\n // Get last user message (not from the bot)\n const lastUserMessage = [...channelState.messages].reverse().find(\n (m, index) =>\n index > 0 && // Skip first message (current)\n m.userId !== this.runtime.agentId\n );\n\n if (!lastUserMessage) return false;\n\n const lastSelfMemories = await this.runtime.messageManager.getMemories({\n roomId: stringToUuid(\n message.channel.id + \"-\" + this.runtime.agentId\n ),\n unique: false,\n count: 5,\n });\n\n const lastSelfSortedMemories = lastSelfMemories\n ?.filter((m) => m.userId === this.runtime.agentId)\n .sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n\n // Calculate context similarity\n const contextSimilarity = await this._analyzeContextSimilarity(\n message.content,\n {\n content: lastUserMessage.content.text || \"\",\n timestamp: Date.now(),\n },\n lastSelfSortedMemories?.[0]?.content?.text\n );\n\n const similarityThreshold =\n this.runtime.character.clientConfig?.discord\n ?.messageSimilarityThreshold ||\n channelState.contextSimilarityThreshold ||\n MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD;\n\n return contextSimilarity >= similarityThreshold;\n }\n\n private _checkInterest(channelId: string): boolean {\n const channelState = this.interestChannels[channelId];\n if (!channelState) return false;\n\n const lastMessage =\n channelState.messages[channelState.messages.length - 1];\n // If it's been more than 5 minutes since last message, reduce interest\n const timeSinceLastMessage = Date.now() - channelState.lastMessageSent;\n\n if (timeSinceLastMessage > MESSAGE_CONSTANTS.INTEREST_DECAY_TIME) {\n delete this.interestChannels[channelId];\n return false;\n } else if (\n timeSinceLastMessage > MESSAGE_CONSTANTS.PARTIAL_INTEREST_DECAY\n ) {\n // Require stronger relevance for continued interest\n return this._isRelevantToTeamMember(\n lastMessage.content.text || \"\",\n channelId\n );\n }\n\n // If team leader and messages exist, check for topic changes and team member responses\n if (this._isTeamLeader() && channelState.messages.length > 0) {\n // If leader's keywords don't match and another team member has responded, drop interest\n if (\n !this._isRelevantToTeamMember(\n lastMessage.content.text || \"\",\n channelId\n )\n ) {\n const recentTeamResponses = channelState.messages\n .slice(-3)\n .some(\n (m) =>\n m.userId !== this.client.user?.id &&\n this._isTeamMember(m.userId)\n );\n\n if (recentTeamResponses) {\n delete this.interestChannels[channelId];\n return false;\n }\n }\n }\n\n // Check if conversation has shifted to a new topic\n if (channelState.messages.length > 0) {\n const recentMessages = channelState.messages.slice(\n -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT\n );\n const differentUsers = new Set(recentMessages.map((m) => m.userId))\n .size;\n\n // If multiple users are talking and we're not involved, reduce interest\n if (\n differentUsers > 1 &&\n !recentMessages.some((m) => m.userId === this.client.user?.id)\n ) {\n delete this.interestChannels[channelId];\n return false;\n }\n }\n\n return true;\n }\n\n private async _shouldIgnore(message: DiscordMessage): Promise {\n // if the message is from us, ignore\n if (message.author.id === this.client.user?.id) return true;\n\n // Honor mentions-only mode\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n return !this._isMessageForMe(message);\n }\n\n // Team-based ignore logic\n if (this.runtime.character.clientConfig?.discord?.isPartOfTeam) {\n const authorId = this._getNormalizedUserId(message.author.id);\n\n if (this._isTeamLeader()) {\n if (this._isTeamCoordinationRequest(message.content)) {\n return false;\n }\n // Ignore if message is only about team member interests and not directed to leader\n if (!this._isMessageForMe(message)) {\n const otherMemberInterests =\n this.runtime.character.clientConfig?.discord\n ?.teamMemberInterestKeywords || [];\n const hasOtherInterests = otherMemberInterests.some(\n (keyword) =>\n message.content\n .toLowerCase()\n .includes(keyword.toLowerCase())\n );\n if (hasOtherInterests) {\n return true;\n }\n }\n } else if (this._isTeamCoordinationRequest(message.content)) {\n const randomDelay =\n Math.floor(\n Math.random() *\n (TIMING_CONSTANTS.TEAM_MEMBER_DELAY_MAX -\n TIMING_CONSTANTS.TEAM_MEMBER_DELAY_MIN)\n ) + TIMING_CONSTANTS.TEAM_MEMBER_DELAY_MIN; // 1-3 second random delay\n await new Promise((resolve) =>\n setTimeout(resolve, randomDelay)\n );\n return false;\n }\n\n if (this._isTeamMember(authorId)) {\n if (!this._isMessageForMe(message)) {\n // If message contains our interests, don't ignore\n if (\n this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n return false;\n }\n return true;\n }\n }\n\n // Check if we're in an active conversation based on context\n const channelState = this.interestChannels[message.channelId];\n\n if (channelState?.currentHandler) {\n // If we're the current handler, check context\n if (channelState.currentHandler === this.client.user?.id) {\n //If it's our keywords, bypass context check\n if (\n this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n return false;\n }\n\n const shouldRespondContext =\n await this._shouldRespondBasedOnContext(\n message,\n channelState\n );\n\n // If context is different, ignore. If similar, don't ignore\n return !shouldRespondContext;\n }\n\n // If another team member is handling and we're not mentioned or coordinating\n else if (\n !this._isMessageForMe(message) &&\n !this._isTeamCoordinationRequest(message.content)\n ) {\n return true;\n }\n }\n }\n\n let messageContent = message.content.toLowerCase();\n\n // Replace the bot's @ping with the character name\n const botMention = `<@!?${this.client.user?.id}>`;\n messageContent = messageContent.replace(\n new RegExp(botMention, \"gi\"),\n this.runtime.character.name.toLowerCase()\n );\n\n // Replace the bot's username with the character name\n const botUsername = this.client.user?.username.toLowerCase();\n messageContent = messageContent.replace(\n new RegExp(`\\\\b${botUsername}\\\\b`, \"g\"),\n this.runtime.character.name.toLowerCase()\n );\n\n // strip all special characters\n messageContent = messageContent.replace(/[^a-zA-Z0-9\\s]/g, \"\");\n\n // short responses where eliza should stop talking and disengage unless mentioned again\n if (\n messageContent.length < MESSAGE_LENGTH_THRESHOLDS.LOSE_INTEREST &&\n LOSE_INTEREST_WORDS.some((word) => messageContent.includes(word))\n ) {\n delete this.interestChannels[message.channelId];\n return true;\n }\n\n // If we're not interested in the channel and it's a short message, ignore it\n if (\n messageContent.length < MESSAGE_LENGTH_THRESHOLDS.SHORT_MESSAGE &&\n !this.interestChannels[message.channelId]\n ) {\n return true;\n }\n\n const targetedPhrases = [\n this.runtime.character.name + \" stop responding\",\n this.runtime.character.name + \" stop talking\",\n this.runtime.character.name + \" shut up\",\n this.runtime.character.name + \" stfu\",\n \"stop talking\" + this.runtime.character.name,\n this.runtime.character.name + \" stop talking\",\n \"shut up \" + this.runtime.character.name,\n this.runtime.character.name + \" shut up\",\n \"stfu \" + this.runtime.character.name,\n this.runtime.character.name + \" stfu\",\n \"chill\" + this.runtime.character.name,\n this.runtime.character.name + \" chill\",\n ];\n\n // lose interest if pinged and told to stop responding\n if (targetedPhrases.some((phrase) => messageContent.includes(phrase))) {\n delete this.interestChannels[message.channelId];\n return true;\n }\n\n // if the message is short, ignore but maintain interest\n if (\n !this.interestChannels[message.channelId] &&\n messageContent.length < MESSAGE_LENGTH_THRESHOLDS.VERY_SHORT_MESSAGE\n ) {\n return true;\n }\n\n if (\n message.content.length <\n MESSAGE_LENGTH_THRESHOLDS.IGNORE_RESPONSE &&\n IGNORE_RESPONSE_WORDS.some((word) =>\n message.content.toLowerCase().includes(word)\n )\n ) {\n return true;\n }\n return false;\n }\n\n private async _shouldRespond(\n message: DiscordMessage,\n state: State\n ): Promise {\n if (message.author.id === this.client.user?.id) return false;\n // if (message.author.bot) return false;\n\n // Honor mentions-only mode\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n return this._isMessageForMe(message);\n }\n\n const channelState = this.interestChannels[message.channelId];\n\n // Check if team member has direct interest first\n if (\n this.runtime.character.clientConfig?.discord?.isPartOfTeam &&\n !this._isTeamLeader() &&\n this._isRelevantToTeamMember(message.content, message.channelId)\n ) {\n return true;\n }\n\n try {\n // Team-based response logic\n if (this.runtime.character.clientConfig?.discord?.isPartOfTeam) {\n // Team leader coordination\n if (\n this._isTeamLeader() &&\n this._isTeamCoordinationRequest(message.content)\n ) {\n return true;\n }\n\n if (\n !this._isTeamLeader() &&\n this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n // Add small delay for non-leader responses\n await new Promise((resolve) =>\n setTimeout(resolve, TIMING_CONSTANTS.TEAM_MEMBER_DELAY)\n ); //1.5 second delay\n\n // If leader has responded in last few seconds, reduce chance of responding\n\n if (channelState?.messages?.length) {\n const recentMessages = channelState.messages.slice(\n -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT\n );\n const leaderResponded = recentMessages.some(\n (m) =>\n m.userId ===\n this.runtime.character.clientConfig?.discord\n ?.teamLeaderId &&\n Date.now() - channelState.lastMessageSent < 3000\n );\n\n if (leaderResponded) {\n // 50% chance to respond if leader just did\n return (\n Math.random() > RESPONSE_CHANCES.AFTER_LEADER\n );\n }\n }\n\n return true;\n }\n\n // If I'm the leader but message doesn't match my keywords, add delay and check for team responses\n if (\n this._isTeamLeader() &&\n !this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n const randomDelay =\n Math.floor(\n Math.random() *\n (TIMING_CONSTANTS.LEADER_DELAY_MAX -\n TIMING_CONSTANTS.LEADER_DELAY_MIN)\n ) + TIMING_CONSTANTS.LEADER_DELAY_MIN; // 2-4 second random delay\n await new Promise((resolve) =>\n setTimeout(resolve, randomDelay)\n );\n\n // After delay, check if another team member has already responded\n if (channelState?.messages?.length) {\n const recentResponses = channelState.messages.slice(\n -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT\n );\n const otherTeamMemberResponded = recentResponses.some(\n (m) =>\n m.userId !== this.client.user?.id &&\n this._isTeamMember(m.userId)\n );\n\n if (otherTeamMemberResponded) {\n return false;\n }\n }\n }\n\n // Update current handler if we're mentioned\n if (this._isMessageForMe(message)) {\n const channelState =\n this.interestChannels[message.channelId];\n if (channelState) {\n channelState.currentHandler = this.client.user?.id;\n channelState.lastMessageSent = Date.now();\n }\n return true;\n }\n\n // Don't respond if another teammate is handling the conversation\n if (channelState?.currentHandler) {\n if (\n channelState.currentHandler !== this.client.user?.id &&\n this._isTeamMember(channelState.currentHandler)\n ) {\n return false;\n }\n }\n\n // Natural conversation cadence\n if (!this._isMessageForMe(message) && channelState) {\n // Count our recent messages\n const recentMessages = channelState.messages.slice(\n -MESSAGE_CONSTANTS.CHAT_HISTORY_COUNT\n );\n const ourMessageCount = recentMessages.filter(\n (m) => m.userId === this.client.user?.id\n ).length;\n\n // Reduce responses if we've been talking a lot\n if (ourMessageCount > 2) {\n // Exponentially decrease chance to respond\n const responseChance = Math.pow(\n 0.5,\n ourMessageCount - 2\n );\n if (Math.random() > responseChance) {\n return false;\n }\n }\n }\n }\n } catch (error) {\n elizaLogger.error(\"Error in _shouldRespond team processing:\", {\n error,\n agentId: this.runtime.agentId,\n channelId: message.channelId,\n });\n }\n\n // Otherwise do context check\n if (channelState?.previousContext) {\n const shouldRespondContext =\n await this._shouldRespondBasedOnContext(message, channelState);\n if (!shouldRespondContext) {\n delete this.interestChannels[message.channelId];\n return false;\n }\n }\n\n if (message.mentions.has(this.client.user?.id as string)) return true;\n\n const guild = message.guild;\n const member = guild?.members.cache.get(this.client.user?.id as string);\n const nickname = member?.nickname;\n\n if (\n message.content\n .toLowerCase()\n .includes(this.client.user?.username.toLowerCase() as string) ||\n message.content\n .toLowerCase()\n .includes(this.client.user?.tag.toLowerCase() as string) ||\n (nickname &&\n message.content.toLowerCase().includes(nickname.toLowerCase()))\n ) {\n return true;\n }\n\n if (!message.guild) {\n return true;\n }\n\n // If none of the above conditions are met, use the generateText to decide\n const shouldRespondContext = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordShouldRespondTemplate ||\n this.runtime.character.templates?.shouldRespondTemplate ||\n composeRandomUser(discordShouldRespondTemplate, 2),\n });\n\n const response = await generateShouldRespond({\n runtime: this.runtime,\n context: shouldRespondContext,\n modelClass: ModelClass.SMALL,\n });\n\n if (response === \"RESPOND\") {\n if (channelState) {\n channelState.previousContext = {\n content: message.content,\n timestamp: Date.now(),\n };\n }\n\n return true;\n } else if (response === \"IGNORE\") {\n return false;\n } else if (response === \"STOP\") {\n delete this.interestChannels[message.channelId];\n return false;\n } else {\n console.error(\n \"Invalid response from response generateText:\",\n response\n );\n return false;\n }\n }\n\n private async _generateResponse(\n message: Memory,\n state: State,\n context: string\n ): Promise {\n const { userId, roomId } = message;\n\n const response = await generateMessageResponse({\n runtime: this.runtime,\n context,\n modelClass: ModelClass.LARGE,\n });\n\n if (!response) {\n console.error(\"No response from generateMessageResponse\");\n return;\n }\n\n await this.runtime.databaseAdapter.log({\n body: { message, context, response },\n userId: userId,\n roomId,\n type: \"response\",\n });\n\n return response;\n }\n\n async fetchBotName(botToken: string) {\n const url = \"https://discord.com/api/v10/users/@me\";\n\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bot ${botToken}`,\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Error fetching bot details: ${response.statusText}`\n );\n }\n\n const data = await response.json();\n return data.username;\n }\n\n /**\n * Simulate discord typing while generating a response;\n * returns a function to interrupt the typing loop\n *\n * @param message\n */\n private simulateTyping(message: DiscordMessage) {\n let typing = true;\n\n const typingLoop = async () => {\n while (typing) {\n await message.channel.sendTyping();\n await new Promise((resolve) => setTimeout(resolve, 3000));\n }\n };\n\n typingLoop();\n\n return function stopTyping() {\n typing = false;\n };\n }\n}\n","import { generateText, trimTokens } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type IAgentRuntime,\n type IImageDescriptionService,\n type IPdfService,\n type ITranscriptionService,\n type IVideoService,\n type Media,\n ModelClass,\n ServiceType,\n} from \"@elizaos/core\";\nimport { type Attachment, Collection } from \"discord.js\";\nimport ffmpeg from \"fluent-ffmpeg\";\nimport fs from \"fs\";\n\nasync function generateSummary(\n runtime: IAgentRuntime,\n text: string\n): Promise<{ title: string; description: string }> {\n // make sure text is under 128k characters\n text = await trimTokens(text, 100000, runtime);\n\n const 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 const response = await generateText({\n runtime,\n context: prompt,\n modelClass: ModelClass.SMALL,\n });\n\n const parsedResponse = parseJSONObjectFromText(response);\n\n if (parsedResponse?.title && parsedResponse?.summary) {\n return {\n title: parsedResponse.title,\n description: parsedResponse.summary,\n };\n }\n\n return {\n title: \"\",\n description: \"\",\n };\n}\n\nexport class AttachmentManager {\n private attachmentCache: Map = new Map();\n private runtime: IAgentRuntime;\n\n constructor(runtime: IAgentRuntime) {\n this.runtime = runtime;\n }\n\n async processAttachments(\n attachments: Collection | Attachment[]\n ): Promise {\n const processedAttachments: Media[] = [];\n const attachmentCollection =\n attachments instanceof Collection\n ? attachments\n : new Collection(attachments.map((att) => [att.id, att]));\n\n for (const [, attachment] of attachmentCollection) {\n const media = await this.processAttachment(attachment);\n if (media) {\n processedAttachments.push(media);\n }\n }\n\n return processedAttachments;\n }\n\n async processAttachment(attachment: Attachment): Promise {\n if (this.attachmentCache.has(attachment.url)) {\n return this.attachmentCache.get(attachment.url)!;\n }\n\n let media: Media | null = null;\n if (attachment.contentType?.startsWith(\"application/pdf\")) {\n media = await this.processPdfAttachment(attachment);\n } else if (attachment.contentType?.startsWith(\"text/plain\")) {\n media = await this.processPlaintextAttachment(attachment);\n } else if (\n attachment.contentType?.startsWith(\"audio/\") ||\n attachment.contentType?.startsWith(\"video/mp4\")\n ) {\n media = await this.processAudioVideoAttachment(attachment);\n } else if (attachment.contentType?.startsWith(\"image/\")) {\n media = await this.processImageAttachment(attachment);\n } else if (\n attachment.contentType?.startsWith(\"video/\") ||\n this.runtime\n .getService(ServiceType.VIDEO)\n .isVideoUrl(attachment.url)\n ) {\n media = await this.processVideoAttachment(attachment);\n } else {\n media = await this.processGenericAttachment(attachment);\n }\n\n if (media) {\n this.attachmentCache.set(attachment.url, media);\n }\n return media;\n }\n\n private async processAudioVideoAttachment(\n attachment: Attachment\n ): Promise {\n try {\n const response = await fetch(attachment.url);\n const audioVideoArrayBuffer = await response.arrayBuffer();\n\n let audioBuffer: Buffer;\n if (attachment.contentType?.startsWith(\"audio/\")) {\n audioBuffer = Buffer.from(audioVideoArrayBuffer);\n } else if (attachment.contentType?.startsWith(\"video/mp4\")) {\n audioBuffer = await this.extractAudioFromMP4(\n audioVideoArrayBuffer\n );\n } else {\n throw new Error(\"Unsupported audio/video format\");\n }\n\n const transcriptionService =\n this.runtime.getService(\n ServiceType.TRANSCRIPTION\n );\n if (!transcriptionService) {\n throw new Error(\"Transcription service not found\");\n }\n\n const transcription =\n await transcriptionService.transcribeAttachment(audioBuffer);\n const { title, description } = await generateSummary(\n this.runtime,\n transcription\n );\n\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"Audio/Video Attachment\",\n source: attachment.contentType?.startsWith(\"audio/\")\n ? \"Audio\"\n : \"Video\",\n description:\n description ||\n \"User-uploaded audio/video attachment which has been transcribed\",\n text: transcription || \"Audio/video content not available\",\n };\n } catch (error) {\n console.error(\n `Error processing audio/video attachment: ${error.message}`\n );\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Audio/Video Attachment\",\n source: attachment.contentType?.startsWith(\"audio/\")\n ? \"Audio\"\n : \"Video\",\n description: \"An audio/video attachment (transcription failed)\",\n text: `This is an audio/video attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}`,\n };\n }\n }\n\n private async extractAudioFromMP4(mp4Data: ArrayBuffer): Promise {\n // Use a library like 'fluent-ffmpeg' or 'ffmpeg-static' to extract the audio stream from the MP4 data\n // and convert it to MP3 or WAV format\n // Example using fluent-ffmpeg:\n const tempMP4File = `temp_${Date.now()}.mp4`;\n const tempAudioFile = `temp_${Date.now()}.mp3`;\n\n try {\n // Write the MP4 data to a temporary file\n fs.writeFileSync(tempMP4File, Buffer.from(mp4Data));\n\n // Extract the audio stream and convert it to MP3\n await new Promise((resolve, reject) => {\n ffmpeg(tempMP4File)\n .outputOptions(\"-vn\") // Disable video output\n .audioCodec(\"libmp3lame\") // Set audio codec to MP3\n .save(tempAudioFile) // Save the output to the specified file\n .on(\"end\", () => {\n resolve();\n })\n .on(\"error\", (err) => {\n reject(err);\n })\n .run();\n });\n\n // Read the converted audio file and return it as a Buffer\n const audioData = fs.readFileSync(tempAudioFile);\n return audioData;\n } finally {\n // Clean up the temporary files\n if (fs.existsSync(tempMP4File)) {\n fs.unlinkSync(tempMP4File);\n }\n if (fs.existsSync(tempAudioFile)) {\n fs.unlinkSync(tempAudioFile);\n }\n }\n }\n\n private async processPdfAttachment(attachment: Attachment): Promise {\n try {\n const response = await fetch(attachment.url);\n const pdfBuffer = await response.arrayBuffer();\n const text = await this.runtime\n .getService(ServiceType.PDF)\n .convertPdfToText(Buffer.from(pdfBuffer));\n const { title, description } = await generateSummary(\n this.runtime,\n text\n );\n\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"PDF Attachment\",\n source: \"PDF\",\n description: description || \"A PDF document\",\n text: text,\n };\n } catch (error) {\n console.error(`Error processing PDF attachment: ${error.message}`);\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"PDF Attachment (conversion failed)\",\n source: \"PDF\",\n description:\n \"A PDF document that could not be converted to text\",\n text: `This is a PDF attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes`,\n };\n }\n }\n\n private async processPlaintextAttachment(\n attachment: Attachment\n ): Promise {\n try {\n const response = await fetch(attachment.url);\n const text = await response.text();\n const { title, description } = await generateSummary(\n this.runtime,\n text\n );\n\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"Plaintext Attachment\",\n source: \"Plaintext\",\n description: description || \"A plaintext document\",\n text: text,\n };\n } catch (error) {\n console.error(\n `Error processing plaintext attachment: ${error.message}`\n );\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Plaintext Attachment (retrieval failed)\",\n source: \"Plaintext\",\n description: \"A plaintext document that could not be retrieved\",\n text: `This is a plaintext attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes`,\n };\n }\n }\n\n private async processImageAttachment(\n attachment: Attachment\n ): Promise {\n try {\n const { description, title } = await this.runtime\n .getService(\n ServiceType.IMAGE_DESCRIPTION\n )\n .describeImage(attachment.url);\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"Image Attachment\",\n source: \"Image\",\n description: description || \"An image attachment\",\n text: description || \"Image content not available\",\n };\n } catch (error) {\n console.error(\n `Error processing image attachment: ${error.message}`\n );\n return this.createFallbackImageMedia(attachment);\n }\n }\n\n private createFallbackImageMedia(attachment: Attachment): Media {\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Image Attachment\",\n source: \"Image\",\n description: \"An image attachment (recognition failed)\",\n text: `This is an image attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}`,\n };\n }\n\n private async processVideoAttachment(\n attachment: Attachment\n ): Promise {\n const videoService = this.runtime.getService(\n ServiceType.VIDEO\n );\n\n if (!videoService) {\n throw new Error(\"Video service not found\");\n }\n\n if (videoService.isVideoUrl(attachment.url)) {\n const videoInfo = await videoService.processVideo(\n attachment.url,\n this.runtime\n );\n return {\n id: attachment.id,\n url: attachment.url,\n title: videoInfo.title,\n source: \"YouTube\",\n description: videoInfo.description,\n text: videoInfo.text,\n };\n } else {\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Video Attachment\",\n source: \"Video\",\n description: \"A video attachment\",\n text: \"Video content not available\",\n };\n }\n }\n\n private async processGenericAttachment(\n attachment: Attachment\n ): Promise {\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Generic Attachment\",\n source: \"Generic\",\n description: \"A generic attachment\",\n text: \"Attachment content not available\",\n };\n }\n}\n","import { messageCompletionFooter, shouldRespondFooter } from \"@elizaos/core\";\n\nexport const discordShouldRespondTemplate =\n `# Task: Decide if {{agentName}} should respond.\nAbout {{agentName}}:\n{{bio}}\n\n# INSTRUCTIONS: Determine if {{agentName}} should respond to the message and participate in the conversation. Do not comment. Just respond with \"RESPOND\" or \"IGNORE\" or \"STOP\".\n\n# RESPONSE EXAMPLES\n{{user1}}: I just saw a really great movie\n{{user2}}: Oh? Which movie?\nResult: [IGNORE]\n\n{{agentName}}: Oh, this is my favorite scene\n{{user1}}: sick\n{{user2}}: wait, why is it your favorite scene\nResult: [RESPOND]\n\n{{user1}}: stfu bot\nResult: [STOP]\n\n{{user1}}: Hey {{agent}}, can you help me with something\nResult: [RESPOND]\n\n{{user1}}: {{agentName}} stfu plz\nResult: [STOP]\n\n{{user1}}: i need help\n{{agentName}}: how can I help you?\n{{user1}}: no. i need help from someone else\nResult: [IGNORE]\n\n{{user1}}: Hey {{agent}}, can I ask you a question\n{{agentName}}: Sure, what is it\n{{user1}}: can you ask claude to create a basic react module that demonstrates a counter\nResult: [RESPOND]\n\n{{user1}}: {{agentName}} can you tell me a story\n{{user1}}: about a girl named elara\n{{agentName}}: Sure.\n{{agentName}}: Once upon a time, in a quaint little village, there was a curious girl named Elara.\n{{agentName}}: Elara was known for her adventurous spirit and her knack for finding beauty in the mundane.\n{{user1}}: I'm loving it, keep going\nResult: [RESPOND]\n\n{{user1}}: {{agentName}} stop responding plz\nResult: [STOP]\n\n{{user1}}: okay, i want to test something. can you say marco?\n{{agentName}}: marco\n{{user1}}: great. okay, now do it again\nResult: [RESPOND]\n\nResponse options are [RESPOND], [IGNORE] and [STOP].\n\n{{agentName}} is in a room with other users and is very worried about being annoying and saying too much.\nRespond with [RESPOND] to messages that are directed at {{agentName}}, or participate in conversations that are interesting or relevant to their background.\nIf a message is not interesting or relevant, respond with [IGNORE]\nUnless directly responding to a user, respond with [IGNORE] to messages that are very short or do not contain much information.\nIf a user asks {{agentName}} to be quiet, respond with [STOP]\nIf {{agentName}} concludes a conversation and isn't part of the conversation anymore, respond with [STOP]\n\nIMPORTANT: {{agentName}} is particularly sensitive about being annoying, so if there is any doubt, it is better to respond with [IGNORE].\nIf {{agentName}} is conversing with a user and they have not asked to stop, it is better to respond with [RESPOND].\n\n{{recentMessages}}\n\n# INSTRUCTIONS: Choose the option that best describes {{agentName}}'s response to the last message. Ignore messages if they are addressed to someone else.\n` + shouldRespondFooter;\n\nexport const discordVoiceHandlerTemplate =\n `# Task: Generate conversational voice dialog for {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n\n# Attachments\n{{attachments}}\n\n# Capabilities\nNote that {{agentName}} is capable of reading/seeing/hearing various forms of media, including images, videos, audio, plaintext and PDFs. Recent attachments have been included above under the \"Attachments\" section.\n\n{{actions}}\n\n{{messageDirections}}\n\n{{recentMessages}}\n\n# Instructions: Write the next message for {{agentName}}. Include an optional action if appropriate. {{actionNames}}\n` + messageCompletionFooter;\n\nexport const discordMessageHandlerTemplate =\n // {{goals}}\n `# Action Examples\n{{actionExamples}}\n(Action examples are for reference only. Do not use the information from them in your response.)\n\n# Knowledge\n{{knowledge}}\n\n# Task: Generate dialog and actions for the character {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n{{lore}}\n\nExamples of {{agentName}}'s dialog and actions:\n{{characterMessageExamples}}\n\n{{providers}}\n\n{{attachments}}\n\n{{actions}}\n\n# Capabilities\nNote that {{agentName}} is capable of reading/seeing/hearing various forms of media, including images, videos, audio, plaintext and PDFs. Recent attachments have been included above under the \"Attachments\" section.\n\n{{messageDirections}}\n\n{{recentMessages}}\n\n# Instructions: Write the next message for {{agentName}}. Include an action, if appropriate. {{actionNames}}\n` + messageCompletionFooter;\n\nexport const discordAutoPostTemplate =\n `# Action Examples\nNONE: Respond but perform no additional action. This is the default if the agent is speaking and not doing anything additional.\n\n# Task: Generate an engaging community message as {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n{{lore}}\n\nExamples of {{agentName}}'s dialog and actions:\n{{characterMessageExamples}}\n\n{{messageDirections}}\n\n# Recent Chat History:\n{{recentMessages}}\n\n# Instructions: Write a natural, engaging message to restart community conversation. Focus on:\n- Community engagement\n- Educational topics\n- General discusions\n- Support queries\n- Keep message warm and inviting\n- Maximum 3 lines\n- Use 1-2 emojis maximum\n- Avoid financial advice\n- Stay within known facts\n- No team member mentions\n- Be hyped, not repetitive\n- Be natural, act like a human, connect with the community\n- Don't sound so robotic like\n- Randomly grab the most recent 5 messages for some context. Validate the context randomly and use that as a reference point for your next message, but not always, only when relevant.\n- If the recent messages are mostly from {{agentName}}, make sure to create conversation starters, given there is no messages from others to reference.\n- DO NOT REPEAT THE SAME thing that you just said from your recent chat history, start the message different each time, and be organic, non reptitive.\n\n# Instructions: Write the next message for {{agentName}}. Include the \"NONE\" action only, as the only valid action for auto-posts is \"NONE\".\n` + messageCompletionFooter;\n\nexport const discordAnnouncementHypeTemplate =\n `# Action Examples\nNONE: Respond but perform no additional action. This is the default if the agent is speaking and not doing anything additional.\n\n# Task: Generate announcement hype message as {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n{{lore}}\n\nExamples of {{agentName}}'s dialog and actions:\n{{characterMessageExamples}}\n\n{{messageDirections}}\n\n# Announcement Content:\n{{announcementContent}}\n\n# Instructions: Write an exciting message to bring attention to the announcement. Requirements:\n- Reference the announcement channel using <#{{announcementChannelId}}>\n- Reference the announcement content to get information about the announcement to use where appropriate to make the message dynamic vs a static post\n- Create genuine excitement\n- Encourage community participation\n- If there are links like Twitter/X posts, encourage users to like/retweet/comment to spread awarenress, but directly say that, wrap that into the post so its natural.\n- Stay within announced facts only\n- No additional promises or assumptions\n- No team member mentions\n- Start the message differently each time. Don't start with the same word like \"hey\", \"hey hey\", etc. be dynamic\n- Address everyone, not as a direct reply to whoever made the announcement or wrote it, but you can reference them\n- Maximum 3-7 lines formatted nicely if needed, based on the context of the announcement\n- Use 1-2 emojis maximum\n\n# Instructions: Write the next message for {{agentName}}. Include the \"NONE\" action only, as no other actions are appropriate for announcement hype.\n` + messageCompletionFooter;","export const TEAM_COORDINATION = {\n KEYWORDS: [\n \"team\",\n \"all agents\",\n \"team update\",\n \"gm team\",\n \"hello team\",\n \"hey team\",\n \"hi team\",\n \"morning team\",\n \"evening team\",\n \"night team\",\n \"update team\",\n ],\n} as const;\n\nexport const MESSAGE_CONSTANTS = {\n MAX_MESSAGES: 10,\n RECENT_MESSAGE_COUNT: 3,\n CHAT_HISTORY_COUNT: 5,\n INTEREST_DECAY_TIME: 5 * 60 * 1000, // 5 minutes\n PARTIAL_INTEREST_DECAY: 3 * 60 * 1000, // 3 minutes\n DEFAULT_SIMILARITY_THRESHOLD: 0.3,\n DEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS: 0.2,\n} as const;\n\nexport const MESSAGE_LENGTH_THRESHOLDS = {\n LOSE_INTEREST: 100,\n SHORT_MESSAGE: 10,\n VERY_SHORT_MESSAGE: 2,\n IGNORE_RESPONSE: 4,\n} as const;\n\nexport const TIMING_CONSTANTS = {\n LEADER_RESPONSE_TIMEOUT: 3000,\n TEAM_MEMBER_DELAY: 1500,\n LEADER_DELAY_MIN: 3000,\n LEADER_DELAY_MAX: 4000,\n TEAM_MEMBER_DELAY_MIN: 1000,\n TEAM_MEMBER_DELAY_MAX: 3000,\n} as const;\n\nexport const RESPONSE_CHANCES = {\n AFTER_LEADER: 0.5, // 50% chance\n FREQUENT_CHATTER: 0.5, // Base chance for frequent responders\n} as const;\n\nexport const LOSE_INTEREST_WORDS = [\n \"shut up\",\n \"stop\",\n \"please shut up\",\n \"shut up please\",\n \"dont talk\",\n \"silence\",\n \"stop talking\",\n \"be quiet\",\n \"hush\",\n \"wtf\",\n \"chill\",\n \"stfu\",\n \"stupid bot\",\n \"dumb bot\",\n \"stop responding\",\n \"god damn it\",\n \"god damn\",\n \"goddamnit\",\n \"can you not\",\n \"can you stop\",\n \"be quiet\",\n \"hate you\",\n \"hate this\",\n \"fuck up\",\n] as const;\n\nexport const IGNORE_RESPONSE_WORDS = [\n \"lol\",\n \"nm\",\n \"uh\",\n \"wtf\",\n \"stfu\",\n \"dumb\",\n \"jfc\",\n \"omg\",\n] as const;\n","import {\n type IAgentRuntime,\n ModelClass,\n elizaLogger,\n generateText,\n trimTokens,\n parseJSONObjectFromText,\n} from \"@elizaos/core\";\nimport {\n ChannelType,\n type Message as DiscordMessage,\n PermissionsBitField,\n type TextChannel,\n ThreadChannel,\n} from \"discord.js\";\n\nexport function getWavHeader(\n audioLength: number,\n sampleRate: number,\n channelCount = 1,\n bitsPerSample = 16\n): Buffer {\n const wavHeader = Buffer.alloc(44);\n wavHeader.write(\"RIFF\", 0);\n wavHeader.writeUInt32LE(36 + audioLength, 4); // Length of entire file in bytes minus 8\n wavHeader.write(\"WAVE\", 8);\n wavHeader.write(\"fmt \", 12);\n wavHeader.writeUInt32LE(16, 16); // Length of format data\n wavHeader.writeUInt16LE(1, 20); // Type of format (1 is PCM)\n wavHeader.writeUInt16LE(channelCount, 22); // Number of channels\n wavHeader.writeUInt32LE(sampleRate, 24); // Sample rate\n wavHeader.writeUInt32LE(\n (sampleRate * bitsPerSample * channelCount) / 8,\n 28\n ); // Byte rate\n wavHeader.writeUInt16LE((bitsPerSample * channelCount) / 8, 32); // Block align ((BitsPerSample * Channels) / 8)\n wavHeader.writeUInt16LE(bitsPerSample, 34); // Bits per sample\n wavHeader.write(\"data\", 36); // Data chunk header\n wavHeader.writeUInt32LE(audioLength, 40); // Data chunk size\n return wavHeader;\n}\n\nconst MAX_MESSAGE_LENGTH = 1900;\n\nexport async function generateSummary(\n runtime: IAgentRuntime,\n text: string\n): Promise<{ title: string; description: string }> {\n // make sure text is under 128k characters\n text = await trimTokens(text, 100000, runtime);\n\n const 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 const response = await generateText({\n runtime,\n context: prompt,\n modelClass: ModelClass.SMALL,\n });\n\n const parsedResponse = parseJSONObjectFromText(response);\n\n if (parsedResponse?.title && parsedResponse?.summary) {\n return {\n title: parsedResponse.title,\n description: parsedResponse.summary,\n };\n }\n\n return {\n title: \"\",\n description: \"\",\n };\n}\n\nexport async function sendMessageInChunks(\n channel: TextChannel,\n content: string,\n inReplyTo: string,\n files: any[]\n): Promise {\n const sentMessages: DiscordMessage[] = [];\n const messages = splitMessage(content);\n try {\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i];\n if (\n message.trim().length > 0 ||\n (i === messages.length - 1 && files && files.length > 0)\n ) {\n const options: any = {\n content: message.trim(),\n };\n\n // if (i === 0 && inReplyTo) {\n // // Reply to the specified message for the first chunk\n // options.reply = {\n // messageReference: inReplyTo,\n // };\n // }\n\n if (i === messages.length - 1 && files && files.length > 0) {\n // Attach files to the last message chunk\n options.files = files;\n }\n\n const m = await channel.send(options);\n sentMessages.push(m);\n }\n }\n } catch (error) {\n elizaLogger.error(\"Error sending message:\", error);\n }\n\n return sentMessages;\n}\n\nfunction splitMessage(content: string): string[] {\n const messages: string[] = [];\n let currentMessage = \"\";\n\n const rawLines = content?.split(\"\\n\") || [];\n // split all lines into MAX_MESSAGE_LENGTH chunks so any long lines are split\n const lines = rawLines.flatMap((line) => {\n const chunks = [];\n while (line.length > MAX_MESSAGE_LENGTH) {\n chunks.push(line.slice(0, MAX_MESSAGE_LENGTH));\n line = line.slice(MAX_MESSAGE_LENGTH);\n }\n chunks.push(line);\n return chunks;\n });\n\n for (const line of lines) {\n if (currentMessage.length + line.length + 1 > MAX_MESSAGE_LENGTH) {\n messages.push(currentMessage.trim());\n currentMessage = \"\";\n }\n currentMessage += line + \"\\n\";\n }\n\n if (currentMessage.trim().length > 0) {\n messages.push(currentMessage.trim());\n }\n\n return messages;\n}\n\nexport function canSendMessage(channel) {\n // validate input\n if (!channel) {\n return {\n canSend: false,\n reason: \"No channel given\",\n };\n }\n // if it is a DM channel, we can always send messages\n if (channel.type === ChannelType.DM) {\n return {\n canSend: true,\n reason: null,\n };\n }\n const botMember = channel.guild?.members.cache.get(channel.client.user.id);\n\n if (!botMember) {\n return {\n canSend: false,\n reason: \"Not a guild channel or bot member not found\",\n };\n }\n\n // Required permissions for sending messages\n const requiredPermissions = [\n PermissionsBitField.Flags.ViewChannel,\n PermissionsBitField.Flags.SendMessages,\n PermissionsBitField.Flags.ReadMessageHistory,\n ];\n\n // Add thread-specific permission if it's a thread\n if (channel instanceof ThreadChannel) {\n requiredPermissions.push(\n PermissionsBitField.Flags.SendMessagesInThreads\n );\n }\n\n // Check permissions\n const permissions = channel.permissionsFor(botMember);\n\n if (!permissions) {\n return {\n canSend: false,\n reason: \"Could not retrieve permissions\",\n };\n }\n\n // Check each required permission\n const missingPermissions = requiredPermissions.filter(\n (perm) => !permissions.has(perm)\n );\n\n return {\n canSend: missingPermissions.length === 0,\n missingPermissions: missingPermissions,\n reason:\n missingPermissions.length > 0\n ? `Missing permissions: ${missingPermissions\n .map((p) => String(p))\n .join(\", \")}`\n : null,\n };\n}\n\nexport function cosineSimilarity(\n text1: string,\n text2: string,\n text3?: string\n): number {\n const preprocessText = (text: string) =>\n text\n .toLowerCase()\n .replace(/[^\\w\\s'_-]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n\n const getWords = (text: string) => {\n return text.split(\" \").filter((word) => word.length > 1);\n };\n\n const words1 = getWords(preprocessText(text1));\n const words2 = getWords(preprocessText(text2));\n const words3 = text3 ? getWords(preprocessText(text3)) : [];\n\n const freq1: { [key: string]: number } = {};\n const freq2: { [key: string]: number } = {};\n const freq3: { [key: string]: number } = {};\n\n words1.forEach((word) => (freq1[word] = (freq1[word] || 0) + 1));\n words2.forEach((word) => (freq2[word] = (freq2[word] || 0) + 1));\n if (words3.length) {\n words3.forEach((word) => (freq3[word] = (freq3[word] || 0) + 1));\n }\n\n const uniqueWords = new Set([\n ...Object.keys(freq1),\n ...Object.keys(freq2),\n ...(words3.length ? Object.keys(freq3) : []),\n ]);\n\n let dotProduct = 0;\n let magnitude1 = 0;\n let magnitude2 = 0;\n let magnitude3 = 0;\n\n uniqueWords.forEach((word) => {\n const val1 = freq1[word] || 0;\n const val2 = freq2[word] || 0;\n const val3 = freq3[word] || 0;\n\n if (words3.length) {\n // For three-way, calculate pairwise similarities\n const sim12 = val1 * val2;\n const sim23 = val2 * val3;\n const sim13 = val1 * val3;\n\n // Take maximum similarity between any pair\n dotProduct += Math.max(sim12, sim23, sim13);\n } else {\n dotProduct += val1 * val2;\n }\n\n magnitude1 += val1 * val1;\n magnitude2 += val2 * val2;\n if (words3.length) {\n magnitude3 += val3 * val3;\n }\n });\n\n magnitude1 = Math.sqrt(magnitude1);\n magnitude2 = Math.sqrt(magnitude2);\n magnitude3 = words3.length ? Math.sqrt(magnitude3) : 1;\n\n if (\n magnitude1 === 0 ||\n magnitude2 === 0 ||\n (words3.length && magnitude3 === 0)\n )\n return 0;\n\n // For two texts, use original calculation\n if (!words3.length) {\n return dotProduct / (magnitude1 * magnitude2);\n }\n\n // For three texts, use max magnitude pair to maintain scale\n const maxMagnitude = Math.max(\n magnitude1 * magnitude2,\n magnitude2 * magnitude3,\n magnitude1 * magnitude3\n );\n\n return dotProduct / maxMagnitude;\n}\n","import {\n ChannelType,\n type Message as DiscordMessage,\n type TextChannel,\n} from \"discord.js\";\nimport type { IAgentRuntime, Memory, Provider, State } from \"@elizaos/core\";\n\nconst channelStateProvider: Provider = {\n get: async (runtime: IAgentRuntime, message: Memory, state?: State) => {\n const discordMessage =\n (state?.discordMessage as DiscordMessage) ||\n (state?.discordChannel as DiscordMessage);\n if (!discordMessage) {\n return \"\";\n }\n\n const guild = discordMessage?.guild;\n const agentName = state?.agentName || \"The agent\";\n const senderName = state?.senderName || \"someone\";\n\n if (!guild) {\n return (\n agentName +\n \" is currently in a direct message conversation with \" +\n senderName\n );\n }\n\n const serverName = guild.name; // The name of the server\n const guildId = guild.id; // The ID of the guild\n const channel = discordMessage.channel;\n\n if (!channel) {\n console.log(\"channel is null\");\n return \"\";\n }\n\n let response =\n agentName +\n \" is currently having a conversation in the channel `@\" +\n channel.id +\n \" in the server `\" +\n serverName +\n \"` (@\" +\n guildId +\n \")\";\n if (\n channel.type === ChannelType.GuildText &&\n (channel as TextChannel).topic\n ) {\n // Check if the channel is a text channel\n response +=\n \"\\nThe topic of the channel is: \" +\n (channel as TextChannel).topic;\n }\n return response;\n },\n};\n\nexport default channelStateProvider;\n","import { getVoiceConnection } from \"@discordjs/voice\";\nimport { ChannelType, type Message as DiscordMessage } from \"discord.js\";\nimport type { IAgentRuntime, Memory, Provider, State } from \"@elizaos/core\";\n\nconst voiceStateProvider: Provider = {\n get: async (runtime: IAgentRuntime, message: Memory, state?: State) => {\n // Voice doesn't get a discord message, so we need to use the channel for guild data\n const discordMessage = (state?.discordMessage ||\n state.discordChannel) as DiscordMessage;\n const connection = getVoiceConnection(\n (discordMessage as DiscordMessage)?.guild?.id as string\n );\n const agentName = state?.agentName || \"The agent\";\n if (!connection) {\n return agentName + \" is not currently in a voice channel\";\n }\n\n const channel = (\n (state?.discordMessage as DiscordMessage) ||\n (state.discordChannel as DiscordMessage)\n )?.guild?.channels?.cache?.get(\n connection.joinConfig.channelId as string\n );\n\n if (!channel || channel.type !== ChannelType.GuildVoice) {\n return agentName + \" is in an invalid voice channel\";\n }\n\n return `${agentName} is currently in the voice channel: ${channel.name} (ID: ${channel.id})`;\n },\n};\n\nexport default voiceStateProvider;\n","import {\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Memory,\n ModelClass,\n ServiceType,\n type State,\n type UUID,\n composeContext,\n composeRandomUser,\n elizaLogger,\n getEmbeddingZeroVector,\n generateMessageResponse,\n stringToUuid,\n generateShouldRespond,\n type ITranscriptionService,\n type ISpeechService,\n} from \"@elizaos/core\";\nimport {\n type AudioPlayer,\n type AudioReceiveStream,\n NoSubscriberBehavior,\n StreamType,\n type VoiceConnection,\n VoiceConnectionStatus,\n createAudioPlayer,\n createAudioResource,\n getVoiceConnections,\n joinVoiceChannel,\n entersState,\n} from \"@discordjs/voice\";\nimport {\n type BaseGuildVoiceChannel,\n ChannelType,\n type Client,\n type Guild,\n type GuildMember,\n type VoiceChannel,\n type VoiceState,\n} from \"discord.js\";\nimport EventEmitter from \"events\";\nimport prism from \"prism-media\";\nimport { type Readable, pipeline } from \"stream\";\nimport type { DiscordClient } from \"./index.ts\";\nimport {\n discordShouldRespondTemplate,\n discordVoiceHandlerTemplate,\n} from \"./templates.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 private readable: Readable;\n private buffers: Buffer[] = [];\n private maxSize: number;\n private lastFlagged = -1;\n private ended = false;\n\n constructor(\n readable: Readable,\n maxSize: number,\n onStart: () => void,\n callback: (buffer: Buffer) => void\n ) {\n this.readable = readable;\n this.maxSize = maxSize;\n this.readable.on(\"data\", (chunk: Buffer) => {\n //console.log('AudioMonitor got data');\n if (this.lastFlagged < 0) {\n this.lastFlagged = this.buffers.length;\n }\n this.buffers.push(chunk);\n const currentSize = this.buffers.reduce(\n (acc, cur) => acc + cur.length,\n 0\n );\n while (currentSize > this.maxSize) {\n this.buffers.shift();\n this.lastFlagged--;\n }\n });\n this.readable.on(\"end\", () => {\n elizaLogger.log(\"AudioMonitor ended\");\n this.ended = true;\n if (this.lastFlagged < 0) return;\n callback(this.getBufferFromStart());\n this.lastFlagged = -1;\n });\n this.readable.on(\"speakingStopped\", () => {\n if (this.ended) return;\n elizaLogger.log(\"Speaking stopped\");\n if (this.lastFlagged < 0) return;\n callback(this.getBufferFromStart());\n });\n this.readable.on(\"speakingStarted\", () => {\n if (this.ended) return;\n onStart();\n elizaLogger.log(\"Speaking started\");\n this.reset();\n });\n }\n\n stop() {\n this.readable.removeAllListeners(\"data\");\n this.readable.removeAllListeners(\"end\");\n this.readable.removeAllListeners(\"speakingStopped\");\n this.readable.removeAllListeners(\"speakingStarted\");\n }\n\n isFlagged() {\n return this.lastFlagged >= 0;\n }\n\n getBufferFromFlag() {\n if (this.lastFlagged < 0) {\n return null;\n }\n const buffer = Buffer.concat(this.buffers.slice(this.lastFlagged));\n return buffer;\n }\n\n getBufferFromStart() {\n const buffer = Buffer.concat(this.buffers);\n return buffer;\n }\n\n reset() {\n this.buffers = [];\n this.lastFlagged = -1;\n }\n\n isEnded() {\n return this.ended;\n }\n}\n\nexport class VoiceManager extends EventEmitter {\n private processingVoice = false;\n private transcriptionTimeout: NodeJS.Timeout | null = null;\n private userStates: Map<\n string,\n {\n buffers: Buffer[];\n totalLength: number;\n lastActive: number;\n transcriptionText: string;\n }\n > = new Map();\n private activeAudioPlayer: AudioPlayer | null = null;\n private client: Client;\n private runtime: IAgentRuntime;\n private streams: Map = new Map();\n private connections: Map = new Map();\n private activeMonitors: Map<\n string,\n { channel: BaseGuildVoiceChannel; monitor: AudioMonitor }\n > = new Map();\n\n constructor(client: DiscordClient) {\n super();\n this.client = client.client;\n this.runtime = client.runtime;\n }\n\n async handleVoiceStateUpdate(oldState: VoiceState, newState: VoiceState) {\n const oldChannelId = oldState.channelId;\n const newChannelId = newState.channelId;\n const member = newState.member;\n if (!member) return;\n if (member.id === this.client.user?.id) {\n return;\n }\n\n // Ignore mute/unmute events\n if (oldChannelId === newChannelId) {\n return;\n }\n\n // User leaving a channel where the bot is present\n if (oldChannelId && this.connections.has(oldChannelId)) {\n this.stopMonitoringMember(member.id);\n }\n\n // User joining a channel where the bot is present\n if (newChannelId && this.connections.has(newChannelId)) {\n await this.monitorMember(\n member,\n newState.channel as BaseGuildVoiceChannel\n );\n }\n }\n\n async joinChannel(channel: BaseGuildVoiceChannel) {\n const oldConnection = this.getVoiceConnection(\n channel.guildId as string\n );\n if (oldConnection) {\n try {\n oldConnection.destroy();\n // Remove all associated streams and monitors\n this.streams.clear();\n this.activeMonitors.clear();\n } catch (error) {\n console.error(\"Error leaving voice channel:\", error);\n }\n }\n\n const connection = joinVoiceChannel({\n channelId: channel.id,\n guildId: channel.guild.id,\n adapterCreator: channel.guild.voiceAdapterCreator as any,\n selfDeaf: false,\n selfMute: false,\n group: this.client.user.id,\n });\n\n try {\n // Wait for either Ready or Signalling state\n await Promise.race([\n entersState(connection, VoiceConnectionStatus.Ready, 20_000),\n entersState(\n connection,\n VoiceConnectionStatus.Signalling,\n 20_000\n ),\n ]);\n\n // Log connection success\n elizaLogger.log(\n `Voice connection established in state: ${connection.state.status}`\n );\n\n // Set up ongoing state change monitoring\n connection.on(\"stateChange\", async (oldState, newState) => {\n elizaLogger.log(\n `Voice connection state changed from ${oldState.status} to ${newState.status}`\n );\n\n if (newState.status === VoiceConnectionStatus.Disconnected) {\n elizaLogger.log(\"Handling disconnection...\");\n\n try {\n // Try to reconnect if disconnected\n await Promise.race([\n entersState(\n connection,\n VoiceConnectionStatus.Signalling,\n 5_000\n ),\n entersState(\n connection,\n VoiceConnectionStatus.Connecting,\n 5_000\n ),\n ]);\n // Seems to be reconnecting to a new channel\n elizaLogger.log(\"Reconnecting to channel...\");\n } catch (e) {\n // Seems to be a real disconnect, destroy and cleanup\n elizaLogger.log(\n \"Disconnection confirmed - cleaning up...\" + e\n );\n connection.destroy();\n this.connections.delete(channel.id);\n }\n } else if (\n newState.status === VoiceConnectionStatus.Destroyed\n ) {\n this.connections.delete(channel.id);\n } else if (\n !this.connections.has(channel.id) &&\n (newState.status === VoiceConnectionStatus.Ready ||\n newState.status === VoiceConnectionStatus.Signalling)\n ) {\n this.connections.set(channel.id, connection);\n }\n });\n\n connection.on(\"error\", (error) => {\n elizaLogger.log(\"Voice connection error:\", error);\n // Don't immediately destroy - let the state change handler deal with it\n elizaLogger.log(\n \"Connection error - will attempt to recover...\"\n );\n });\n\n // Store the connection\n this.connections.set(channel.id, connection);\n\n // Continue with voice state modifications\n const me = channel.guild.members.me;\n if (me?.voice && me.permissions.has(\"DeafenMembers\")) {\n try {\n await me.voice.setDeaf(false);\n await me.voice.setMute(false);\n } catch (error) {\n elizaLogger.log(\"Failed to modify voice state:\", error);\n // Continue even if this fails\n }\n }\n\n connection.receiver.speaking.on(\"start\", async (userId: string) => {\n let user = channel.members.get(userId);\n if (!user) {\n try {\n user = await channel.guild.members.fetch(userId);\n } catch (error) {\n console.error(\"Failed to fetch user:\", error);\n }\n }\n if (user && !user?.user.bot) {\n this.monitorMember(user as GuildMember, channel);\n this.streams.get(userId)?.emit(\"speakingStarted\");\n }\n });\n\n connection.receiver.speaking.on(\"end\", async (userId: string) => {\n const user = channel.members.get(userId);\n if (!user?.user.bot) {\n this.streams.get(userId)?.emit(\"speakingStopped\");\n }\n });\n } catch (error) {\n elizaLogger.log(\"Failed to establish voice connection:\", error);\n connection.destroy();\n this.connections.delete(channel.id);\n throw error;\n }\n }\n\n private getVoiceConnection(guildId: string) {\n const connections = getVoiceConnections(this.client.user.id);\n if (!connections) {\n return;\n }\n const connection = [...connections.values()].find(\n (connection) => connection.joinConfig.guildId === guildId\n );\n return connection;\n }\n\n private async monitorMember(\n member: GuildMember,\n channel: BaseGuildVoiceChannel\n ) {\n const userId = member?.id;\n const userName = member?.user?.username;\n const name = member?.user?.displayName;\n const connection = this.getVoiceConnection(member?.guild?.id);\n const receiveStream = connection?.receiver.subscribe(userId, {\n autoDestroy: true,\n emitClose: true,\n });\n if (!receiveStream || receiveStream.readableLength === 0) {\n return;\n }\n const opusDecoder = new prism.opus.Decoder({\n channels: 1,\n rate: DECODE_SAMPLE_RATE,\n frameSize: DECODE_FRAME_SIZE,\n });\n const volumeBuffer: number[] = [];\n const VOLUME_WINDOW_SIZE = 30;\n const SPEAKING_THRESHOLD = 0.05;\n opusDecoder.on(\"data\", (pcmData: Buffer) => {\n // Monitor the audio volume while the agent is speaking.\n // If the average volume of the user's audio exceeds the defined threshold, it indicates active speaking.\n // When active speaking is detected, stop the agent's current audio playback to avoid overlap.\n\n if (this.activeAudioPlayer) {\n const samples = new Int16Array(\n pcmData.buffer,\n pcmData.byteOffset,\n pcmData.length / 2\n );\n const maxAmplitude = Math.max(...samples.map(Math.abs)) / 32768;\n volumeBuffer.push(maxAmplitude);\n\n if (volumeBuffer.length > VOLUME_WINDOW_SIZE) {\n volumeBuffer.shift();\n }\n const avgVolume =\n volumeBuffer.reduce((sum, v) => sum + v, 0) /\n VOLUME_WINDOW_SIZE;\n\n if (avgVolume > SPEAKING_THRESHOLD) {\n volumeBuffer.length = 0;\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n this.processingVoice = false;\n }\n }\n });\n pipeline(\n receiveStream as AudioReceiveStream,\n opusDecoder as any,\n (err: Error | null) => {\n if (err) {\n console.log(`Opus decoding pipeline error: ${err}`);\n }\n }\n );\n this.streams.set(userId, opusDecoder);\n this.connections.set(userId, connection as VoiceConnection);\n opusDecoder.on(\"error\", (err: any) => {\n console.log(`Opus decoding error: ${err}`);\n });\n const errorHandler = (err: any) => {\n console.log(`Opus decoding error: ${err}`);\n };\n const streamCloseHandler = () => {\n console.log(`voice stream from ${member?.displayName} closed`);\n this.streams.delete(userId);\n this.connections.delete(userId);\n };\n const closeHandler = () => {\n console.log(`Opus decoder for ${member?.displayName} closed`);\n opusDecoder.removeListener(\"error\", errorHandler);\n opusDecoder.removeListener(\"close\", closeHandler);\n receiveStream?.removeListener(\"close\", streamCloseHandler);\n };\n opusDecoder.on(\"error\", errorHandler);\n opusDecoder.on(\"close\", closeHandler);\n receiveStream?.on(\"close\", streamCloseHandler);\n\n this.client.emit(\n \"userStream\",\n userId,\n name,\n userName,\n channel,\n opusDecoder\n );\n }\n\n leaveChannel(channel: BaseGuildVoiceChannel) {\n const connection = this.connections.get(channel.id);\n if (connection) {\n connection.destroy();\n this.connections.delete(channel.id);\n }\n\n // Stop monitoring all members in this channel\n for (const [memberId, monitorInfo] of this.activeMonitors) {\n if (\n monitorInfo.channel.id === channel.id &&\n memberId !== this.client.user?.id\n ) {\n this.stopMonitoringMember(memberId);\n }\n }\n\n console.log(`Left voice channel: ${channel.name} (${channel.id})`);\n }\n\n stopMonitoringMember(memberId: string) {\n const monitorInfo = this.activeMonitors.get(memberId);\n if (monitorInfo) {\n monitorInfo.monitor.stop();\n this.activeMonitors.delete(memberId);\n this.streams.delete(memberId);\n console.log(`Stopped monitoring user ${memberId}`);\n }\n }\n\n async handleGuildCreate(guild: Guild) {\n console.log(`Joined guild ${guild.name}`);\n // this.scanGuild(guild);\n }\n\n async debouncedProcessTranscription(\n userId: UUID,\n name: string,\n userName: string,\n channel: BaseGuildVoiceChannel\n ) {\n const DEBOUNCE_TRANSCRIPTION_THRESHOLD = 1500; // wait for 1.5 seconds of silence\n\n if (this.activeAudioPlayer?.state?.status === \"idle\") {\n elizaLogger.log(\"Cleaning up idle audio player.\");\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n }\n\n if (this.activeAudioPlayer || this.processingVoice) {\n const state = this.userStates.get(userId);\n state.buffers.length = 0;\n state.totalLength = 0;\n return;\n }\n\n if (this.transcriptionTimeout) {\n clearTimeout(this.transcriptionTimeout);\n }\n\n this.transcriptionTimeout = setTimeout(async () => {\n this.processingVoice = true;\n try {\n await this.processTranscription(\n userId,\n channel.id,\n channel,\n name,\n userName\n );\n\n // Clean all users' previous buffers\n this.userStates.forEach((state, _) => {\n state.buffers.length = 0;\n state.totalLength = 0;\n });\n } finally {\n this.processingVoice = false;\n }\n }, DEBOUNCE_TRANSCRIPTION_THRESHOLD);\n }\n\n async handleUserStream(\n userId: UUID,\n name: string,\n userName: string,\n channel: BaseGuildVoiceChannel,\n audioStream: Readable\n ) {\n console.log(`Starting audio monitor for user: ${userId}`);\n if (!this.userStates.has(userId)) {\n this.userStates.set(userId, {\n buffers: [],\n totalLength: 0,\n lastActive: Date.now(),\n transcriptionText: \"\",\n });\n }\n\n const state = this.userStates.get(userId);\n\n const processBuffer = async (buffer: Buffer) => {\n try {\n state!.buffers.push(buffer);\n state!.totalLength += buffer.length;\n state!.lastActive = Date.now();\n this.debouncedProcessTranscription(\n userId,\n name,\n userName,\n channel\n );\n } catch (error) {\n console.error(\n `Error processing buffer for user ${userId}:`,\n error\n );\n }\n };\n\n new AudioMonitor(\n audioStream,\n 10000000,\n () => {\n if (this.transcriptionTimeout) {\n clearTimeout(this.transcriptionTimeout);\n }\n },\n async (buffer) => {\n if (!buffer) {\n console.error(\"Received empty buffer\");\n return;\n }\n await processBuffer(buffer);\n }\n );\n }\n\n private async processTranscription(\n userId: UUID,\n channelId: string,\n channel: BaseGuildVoiceChannel,\n name: string,\n userName: string\n ) {\n const state = this.userStates.get(userId);\n if (!state || state.buffers.length === 0) return;\n try {\n const inputBuffer = Buffer.concat(state.buffers, state.totalLength);\n\n state.buffers.length = 0; // Clear the buffers\n state.totalLength = 0;\n // Convert Opus to WAV\n const wavBuffer = await this.convertOpusToWav(inputBuffer);\n console.log(\"Starting transcription...\");\n\n const transcriptionText = await this.runtime\n .getService(ServiceType.TRANSCRIPTION)\n .transcribe(wavBuffer);\n\n function isValidTranscription(text: string): boolean {\n if (!text || text.includes(\"[BLANK_AUDIO]\")) return false;\n return true;\n }\n\n if (transcriptionText && isValidTranscription(transcriptionText)) {\n state.transcriptionText += transcriptionText;\n }\n\n if (state.transcriptionText.length) {\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n const finalText = state.transcriptionText;\n state.transcriptionText = \"\";\n await this.handleUserMessage(\n finalText,\n userId,\n channelId,\n channel,\n name,\n userName\n );\n }\n } catch (error) {\n console.error(\n `Error transcribing audio for user ${userId}:`,\n error\n );\n }\n }\n\n private async handleUserMessage(\n message: string,\n userId: UUID,\n channelId: string,\n channel: BaseGuildVoiceChannel,\n name: string,\n userName: string\n ) {\n try {\n const roomId = stringToUuid(channelId + \"-\" + this.runtime.agentId);\n const userIdUUID = stringToUuid(userId);\n\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n let state = await this.runtime.composeState(\n {\n agentId: this.runtime.agentId,\n content: { text: message, source: \"Discord\" },\n userId: userIdUUID,\n roomId,\n },\n {\n discordChannel: channel,\n discordClient: this.client,\n agentName: this.runtime.character.name,\n }\n );\n\n if (message && message.startsWith(\"/\")) {\n return null;\n }\n\n const memory = {\n id: stringToUuid(channelId + \"-voice-message-\" + Date.now()),\n agentId: this.runtime.agentId,\n content: {\n text: message,\n source: \"discord\",\n url: channel.url,\n },\n userId: userIdUUID,\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now(),\n };\n\n if (!memory.content.text) {\n return { text: \"\", action: \"IGNORE\" };\n }\n\n await this.runtime.messageManager.createMemory(memory);\n\n state = await this.runtime.updateRecentMessageState(state);\n\n const shouldIgnore = await this._shouldIgnore(memory);\n\n if (shouldIgnore) {\n return { text: \"\", action: \"IGNORE\" };\n }\n\n const shouldRespond = await this._shouldRespond(\n message,\n userId,\n channel,\n state\n );\n\n if (!shouldRespond) {\n return;\n }\n\n const context = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordVoiceHandlerTemplate ||\n this.runtime.character.templates?.messageHandlerTemplate ||\n discordVoiceHandlerTemplate,\n });\n\n const responseContent = await this._generateResponse(\n memory,\n state,\n context\n );\n\n const callback: HandlerCallback = async (content: Content) => {\n console.log(\"callback content: \", content);\n const { roomId } = memory;\n\n const responseMemory: Memory = {\n id: stringToUuid(\n memory.id + \"-voice-response-\" + Date.now()\n ),\n agentId: this.runtime.agentId,\n userId: this.runtime.agentId,\n content: {\n ...content,\n user: this.runtime.character.name,\n inReplyTo: memory.id,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n };\n\n if (responseMemory.content.text?.trim()) {\n await this.runtime.messageManager.createMemory(\n responseMemory\n );\n state = await this.runtime.updateRecentMessageState(state);\n\n const responseStream = await this.runtime\n .getService(\n ServiceType.SPEECH_GENERATION\n )\n .generate(this.runtime, content.text);\n\n if (responseStream) {\n await this.playAudioStream(\n userId,\n responseStream as Readable\n );\n }\n\n await this.runtime.evaluate(memory, state);\n } else {\n console.warn(\"Empty response, skipping\");\n }\n return [responseMemory];\n };\n\n const responseMemories = await callback(responseContent);\n\n const response = responseContent;\n\n const content = (response.responseMessage ||\n response.content ||\n response.message) as string;\n\n if (!content) {\n return null;\n }\n\n console.log(\"responseMemories: \", responseMemories);\n\n await this.runtime.processActions(\n memory,\n responseMemories,\n state,\n callback\n );\n } catch (error) {\n console.error(\"Error processing transcribed text:\", error);\n }\n }\n\n private async convertOpusToWav(pcmBuffer: Buffer): Promise {\n try {\n // Generate the WAV header\n const wavHeader = getWavHeader(\n pcmBuffer.length,\n DECODE_SAMPLE_RATE\n );\n\n // Concatenate the WAV header and PCM data\n const wavBuffer = Buffer.concat([wavHeader, pcmBuffer]);\n\n return wavBuffer;\n } catch (error) {\n console.error(\"Error converting PCM to WAV:\", error);\n throw error;\n }\n }\n\n private async _shouldRespond(\n message: string,\n userId: UUID,\n channel: BaseGuildVoiceChannel,\n state: State\n ): Promise {\n if (userId === this.client.user?.id) return false;\n const lowerMessage = message.toLowerCase();\n const botName = this.client.user.username.toLowerCase();\n const characterName = this.runtime.character.name.toLowerCase();\n const guild = channel.guild;\n const member = guild?.members.cache.get(this.client.user?.id as string);\n const nickname = member?.nickname;\n\n if (\n lowerMessage.includes(botName as string) ||\n lowerMessage.includes(characterName) ||\n lowerMessage.includes(\n this.client.user?.tag.toLowerCase() as string\n ) ||\n (nickname && lowerMessage.includes(nickname.toLowerCase()))\n ) {\n return true;\n }\n\n if (!channel.guild) {\n return true;\n }\n\n // If none of the above conditions are met, use the generateText to decide\n const shouldRespondContext = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordShouldRespondTemplate ||\n this.runtime.character.templates?.shouldRespondTemplate ||\n composeRandomUser(discordShouldRespondTemplate, 2),\n });\n\n const response = await generateShouldRespond({\n runtime: this.runtime,\n context: shouldRespondContext,\n modelClass: ModelClass.SMALL,\n });\n\n if (response === \"RESPOND\") {\n return true;\n } else if (response === \"IGNORE\") {\n return false;\n } else if (response === \"STOP\") {\n return false;\n } else {\n console.error(\n \"Invalid response from response generateText:\",\n response\n );\n return false;\n }\n }\n\n private async _generateResponse(\n message: Memory,\n state: State,\n context: string\n ): Promise {\n const { userId, roomId } = message;\n\n const response = await generateMessageResponse({\n runtime: this.runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n response.source = \"discord\";\n\n if (!response) {\n console.error(\"No response from generateMessageResponse\");\n return;\n }\n\n await this.runtime.databaseAdapter.log({\n body: { message, context, response },\n userId: userId,\n roomId,\n type: \"response\",\n });\n\n return response;\n }\n\n private async _shouldIgnore(message: Memory): Promise {\n // console.log(\"message: \", message);\n elizaLogger.debug(\"message.content: \", message.content);\n // if the message is 3 characters or less, ignore it\n if ((message.content as Content).text.length < 3) {\n return true;\n }\n\n const loseInterestWords = [\n // telling the bot to stop talking\n \"shut up\",\n \"stop\",\n \"dont talk\",\n \"silence\",\n \"stop talking\",\n \"be quiet\",\n \"hush\",\n \"stfu\",\n \"stupid bot\",\n \"dumb bot\",\n\n // offensive words\n \"fuck\",\n \"shit\",\n \"damn\",\n \"suck\",\n \"dick\",\n \"cock\",\n \"sex\",\n \"sexy\",\n ];\n if (\n (message.content as Content).text.length < 50 &&\n loseInterestWords.some((word) =>\n (message.content as Content).text?.toLowerCase().includes(word)\n )\n ) {\n return true;\n }\n\n const ignoreWords = [\"k\", \"ok\", \"bye\", \"lol\", \"nm\", \"uh\"];\n if (\n (message.content as Content).text?.length < 8 &&\n ignoreWords.some((word) =>\n (message.content as Content).text?.toLowerCase().includes(word)\n )\n ) {\n return true;\n }\n\n return false;\n }\n\n async scanGuild(guild: Guild) {\n let chosenChannel: BaseGuildVoiceChannel | null = null;\n\n try {\n const channelId = this.runtime.getSetting(\n \"DISCORD_VOICE_CHANNEL_ID\"\n ) as string;\n if (channelId) {\n const channel = await guild.channels.fetch(channelId);\n if (channel?.isVoiceBased()) {\n chosenChannel = channel as BaseGuildVoiceChannel;\n }\n }\n\n if (!chosenChannel) {\n const channels = (await guild.channels.fetch()).filter(\n (channel) => channel?.type == ChannelType.GuildVoice\n );\n for (const [, channel] of channels) {\n const voiceChannel = channel as BaseGuildVoiceChannel;\n if (\n voiceChannel.members.size > 0 &&\n (chosenChannel === null ||\n voiceChannel.members.size >\n chosenChannel.members.size)\n ) {\n chosenChannel = voiceChannel;\n }\n }\n }\n\n if (chosenChannel) {\n console.log(`Joining channel: ${chosenChannel.name}`);\n await this.joinChannel(chosenChannel);\n } else {\n console.warn(\"No suitable voice channel found to join.\");\n }\n } catch (error) {\n console.error(\"Error selecting or joining a voice channel:\", error);\n }\n }\n\n async playAudioStream(userId: UUID, audioStream: Readable) {\n const connection = this.connections.get(userId);\n if (connection == null) {\n console.log(`No connection for user ${userId}`);\n return;\n }\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n const audioPlayer = createAudioPlayer({\n behaviors: {\n noSubscriber: NoSubscriberBehavior.Pause,\n },\n });\n this.activeAudioPlayer = audioPlayer;\n connection.subscribe(audioPlayer);\n\n const audioStartTime = Date.now();\n\n const resource = createAudioResource(audioStream, {\n inputType: StreamType.Arbitrary,\n });\n audioPlayer.play(resource);\n\n audioPlayer.on(\"error\", (err: any) => {\n console.log(`Audio player error: ${err}`);\n });\n\n audioPlayer.on(\n \"stateChange\",\n (_oldState: any, newState: { status: string }) => {\n if (newState.status == \"idle\") {\n const idleTime = Date.now();\n console.log(\n `Audio playback took: ${idleTime - audioStartTime}ms`\n );\n }\n }\n );\n }\n\n cleanupAudioPlayer(audioPlayer: AudioPlayer) {\n if (!audioPlayer) return;\n\n audioPlayer.stop();\n audioPlayer.removeAllListeners();\n if (audioPlayer === this.activeAudioPlayer) {\n this.activeAudioPlayer = null;\n }\n }\n\n async handleJoinChannelCommand(interaction: any) {\n try {\n // Defer the reply immediately to prevent interaction timeout\n await interaction.deferReply();\n\n const channelId = interaction.options.get(\"channel\")\n ?.value as string;\n if (!channelId) {\n await interaction.editReply(\n \"Please provide a voice channel to join.\"\n );\n return;\n }\n\n const guild = interaction.guild;\n if (!guild) {\n await interaction.editReply(\"Could not find guild.\");\n return;\n }\n\n const voiceChannel = interaction.guild.channels.cache.find(\n (channel: VoiceChannel) =>\n channel.id === channelId &&\n channel.type === ChannelType.GuildVoice\n );\n\n if (!voiceChannel) {\n await interaction.editReply(\"Voice channel not found!\");\n return;\n }\n\n await this.joinChannel(voiceChannel as BaseGuildVoiceChannel);\n await interaction.editReply(\n `Joined voice channel: ${voiceChannel.name}`\n );\n } catch (error) {\n console.error(\"Error joining voice channel:\", error);\n // Use editReply instead of reply for the error case\n await interaction\n .editReply(\"Failed to join the voice channel.\")\n .catch(console.error);\n }\n }\n\n async handleLeaveChannelCommand(interaction: any) {\n const connection = this.getVoiceConnection(interaction.guildId as any);\n\n if (!connection) {\n await interaction.reply(\"Not currently in a voice channel.\");\n return;\n }\n\n try {\n connection.destroy();\n await interaction.reply(\"Left the voice channel.\");\n } catch (error) {\n console.error(\"Error leaving voice channel:\", error);\n await interaction.reply(\"Failed to leave the voice channel.\");\n }\n }\n}\n","import { DiscordClientInterface } from './client';\n\nconst discordPlugin = {\n name: \"discord\",\n description: \"Discord client plugin\",\n clients: [DiscordClientInterface],\n};\nexport default discordPlugin;"],"mappings":"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","names":["getEmbeddingZeroVector","stringToUuid","elizaLogger","EventEmitter","composeContext","parseJSONObjectFromText","ModelClass","generateText","composeContext","generateText","ModelClass","targetChannel","ChannelType","_a","composeContext","getModelSettings","generateText","trimTokens","parseJSONObjectFromText","ModelClass","summarizationTemplate","summarizeAction","_a","_b","composeContext","generateText","parseJSONObjectFromText","ModelClass","composeContext","generateText","ModelClass","parseJSONObjectFromText","attachment","composeContext","ModelClass","ServiceType","ChannelType","elizaLogger","generateText","trimTokens","parseJSONObjectFromText","ModelClass","ServiceType","fs","ModelClass","generateText","trimTokens","parseJSONObjectFromText","ChannelType","ChannelType","ChannelType","_a","elizaLogger","composeContext","content","action","memory","ServiceType","messages","_b","channelState","shouldRespondContext","ModelClass","ChannelType","getVoiceConnection","ChannelType","ModelClass","ServiceType","composeContext","composeRandomUser","elizaLogger","getEmbeddingZeroVector","generateMessageResponse","stringToUuid","generateShouldRespond","joinVoiceChannel","ChannelType","elizaLogger","joinVoiceChannel","connection","ServiceType","stringToUuid","getEmbeddingZeroVector","composeContext","content","_a","roomId","composeRandomUser","generateShouldRespond","ModelClass","generateMessageResponse","ChannelType","PermissionsBitField","EventEmitter","elizaLogger","stringToUuid","getEmbeddingZeroVector"]} \ No newline at end of file +{"version":3,"sources":["../src/client.ts","../src/actions/chat_with_attachments.ts","../src/actions/download_media.ts","../src/actions/joinvoice.ts","../src/actions/leavevoice.ts","../src/actions/summarize_conversation.ts","../src/actions/transcribe_media.ts","../src/messages.ts","../src/attachments.ts","../src/templates.ts","../src/constants.ts","../src/utils.ts","../src/providers/channelState.ts","../src/providers/voiceState.ts","../src/voice.ts","../src/index.ts"],"sourcesContent":["import {\n getEmbeddingZeroVector,\n stringToUuid,\n elizaLogger,\n type Character,\n type Client as ElizaClient,\n type IAgentRuntime,\n type Plugin,\n} from \"@elizaos/core\";\nimport {\n Client,\n Events,\n GatewayIntentBits,\n type Guild,\n type MessageReaction,\n Partials,\n type User,\n} from \"discord.js\";\nimport { EventEmitter } from \"events\";\nimport chat_with_attachments from \"./actions/chat_with_attachments.ts\";\nimport download_media from \"./actions/download_media.ts\";\nimport joinvoice from \"./actions/joinvoice.ts\";\nimport leavevoice from \"./actions/leavevoice.ts\";\nimport summarize from \"./actions/summarize_conversation.ts\";\nimport transcribe_media from \"./actions/transcribe_media.ts\";\nimport { MessageManager } from \"./messages.ts\";\nimport channelStateProvider from \"./providers/channelState.ts\";\nimport voiceStateProvider from \"./providers/voiceState.ts\";\nimport { VoiceManager } from \"./voice.ts\";\nimport { PermissionsBitField } from \"discord.js\";\n\nexport class DiscordClient extends EventEmitter {\n apiToken: string;\n client: Client;\n runtime: IAgentRuntime;\n character: Character;\n private messageManager: MessageManager;\n private voiceManager: VoiceManager;\n\n constructor(runtime: IAgentRuntime) {\n super();\n\n this.apiToken = runtime.getSetting(\"DISCORD_API_TOKEN\") as string;\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.GuildVoiceStates,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.DirectMessageTyping,\n GatewayIntentBits.GuildMessageTyping,\n GatewayIntentBits.GuildMessageReactions,\n ],\n partials: [\n Partials.Channel,\n Partials.Message,\n Partials.User,\n Partials.Reaction,\n ],\n });\n\n this.runtime = runtime;\n this.voiceManager = new VoiceManager(this);\n this.messageManager = new MessageManager(this, this.voiceManager);\n\n this.client.once(Events.ClientReady, this.onClientReady.bind(this));\n this.client.login(this.apiToken);\n\n this.setupEventListeners();\n\n this.runtime.registerAction(joinvoice);\n this.runtime.registerAction(leavevoice);\n this.runtime.registerAction(summarize);\n this.runtime.registerAction(chat_with_attachments);\n this.runtime.registerAction(transcribe_media);\n this.runtime.registerAction(download_media);\n\n this.runtime.providers.push(channelStateProvider);\n this.runtime.providers.push(voiceStateProvider);\n }\n\n private setupEventListeners() {\n // When joining to a new server\n this.client.on(\"guildCreate\", this.handleGuildCreate.bind(this));\n\n this.client.on(\n Events.MessageReactionAdd,\n this.handleReactionAdd.bind(this)\n );\n this.client.on(\n Events.MessageReactionRemove,\n this.handleReactionRemove.bind(this)\n );\n\n // Handle voice events with the voice manager\n this.client.on(\n \"voiceStateUpdate\",\n this.voiceManager.handleVoiceStateUpdate.bind(this.voiceManager)\n );\n this.client.on(\n \"userStream\",\n this.voiceManager.handleUserStream.bind(this.voiceManager)\n );\n\n // Handle a new message with the message manager\n this.client.on(\n Events.MessageCreate,\n this.messageManager.handleMessage.bind(this.messageManager)\n );\n\n // Handle a new interaction\n this.client.on(\n Events.InteractionCreate,\n this.handleInteractionCreate.bind(this)\n );\n }\n\n async stop() {\n try {\n // disconnect websocket\n // this unbinds all the listeners\n await this.client.destroy();\n } catch (e) {\n elizaLogger.error(\"client-discord instance stop err\", e);\n }\n }\n\n private async onClientReady(readyClient: { user: { tag: any; id: any } }) {\n elizaLogger.success(`Logged in as ${readyClient.user?.tag}`);\n\n // Register slash commands\n const commands = [\n {\n name: \"joinchannel\",\n description: \"Join a voice channel\",\n options: [\n {\n name: \"channel\",\n type: 7, // CHANNEL type\n description: \"The voice channel to join\",\n required: true,\n channel_types: [2], // GuildVoice type\n },\n ],\n },\n {\n name: \"leavechannel\",\n description: \"Leave the current voice channel\",\n },\n ];\n\n try {\n await this.client.application?.commands.set(commands);\n elizaLogger.success(\"Slash commands registered\");\n } catch (error) {\n console.error(\"Error registering slash commands:\", error);\n }\n\n // Required permissions for the bot\n const requiredPermissions = [\n // Text Permissions\n PermissionsBitField.Flags.ViewChannel,\n PermissionsBitField.Flags.SendMessages,\n PermissionsBitField.Flags.SendMessagesInThreads,\n PermissionsBitField.Flags.CreatePrivateThreads,\n PermissionsBitField.Flags.CreatePublicThreads,\n PermissionsBitField.Flags.EmbedLinks,\n PermissionsBitField.Flags.AttachFiles,\n PermissionsBitField.Flags.AddReactions,\n PermissionsBitField.Flags.UseExternalEmojis,\n PermissionsBitField.Flags.UseExternalStickers,\n PermissionsBitField.Flags.MentionEveryone,\n PermissionsBitField.Flags.ManageMessages,\n PermissionsBitField.Flags.ReadMessageHistory,\n // Voice Permissions\n PermissionsBitField.Flags.Connect,\n PermissionsBitField.Flags.Speak,\n PermissionsBitField.Flags.UseVAD,\n PermissionsBitField.Flags.PrioritySpeaker,\n ].reduce((a, b) => a | b, 0n);\n\n elizaLogger.success(\"Use this URL to add the bot to your server:\");\n elizaLogger.success(\n `https://discord.com/api/oauth2/authorize?client_id=${readyClient.user?.id}&permissions=${requiredPermissions}&scope=bot%20applications.commands`\n );\n await this.onReady();\n }\n\n async handleReactionAdd(reaction: MessageReaction, user: User) {\n try {\n elizaLogger.log(\"Reaction added\");\n\n // Early returns\n if (!reaction || !user) {\n elizaLogger.warn(\"Invalid reaction or user\");\n return;\n }\n\n // Get emoji info\n let emoji = reaction.emoji.name;\n if (!emoji && reaction.emoji.id) {\n emoji = `<:${reaction.emoji.name}:${reaction.emoji.id}>`;\n }\n\n // Fetch full message if partial\n if (reaction.partial) {\n try {\n await reaction.fetch();\n } catch (error) {\n elizaLogger.error(\n \"Failed to fetch partial reaction:\",\n error\n );\n return;\n }\n }\n\n // Generate IDs with timestamp to ensure uniqueness\n const timestamp = Date.now();\n const roomId = stringToUuid(\n `${reaction.message.channel.id}-${this.runtime.agentId}`\n );\n const userIdUUID = stringToUuid(\n `${user.id}-${this.runtime.agentId}`\n );\n const reactionUUID = stringToUuid(\n `${reaction.message.id}-${user.id}-${emoji}-${timestamp}-${this.runtime.agentId}`\n );\n\n // Validate IDs\n if (!userIdUUID || !roomId) {\n elizaLogger.error(\"Invalid user ID or room ID\", {\n userIdUUID,\n roomId,\n });\n return;\n }\n\n // Process message content\n const messageContent = reaction.message.content || \"\";\n const truncatedContent =\n messageContent.length > 100\n ? `${messageContent.substring(0, 100)}...`\n : messageContent;\n const reactionMessage = `*<${emoji}>: \"${truncatedContent}\"*`;\n\n // Get user info\n const userName = reaction.message.author?.username || \"unknown\";\n const name = reaction.message.author?.displayName || userName;\n\n // Ensure connection\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n // Create memory with retry logic\n const memory = {\n id: reactionUUID,\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n content: {\n text: reactionMessage,\n source: \"discord\",\n inReplyTo: stringToUuid(\n `${reaction.message.id}-${this.runtime.agentId}`\n ),\n },\n roomId,\n createdAt: timestamp,\n embedding: getEmbeddingZeroVector(),\n };\n\n try {\n await this.runtime.messageManager.createMemory(memory);\n elizaLogger.debug(\"Reaction memory created\", {\n reactionId: reactionUUID,\n emoji,\n userId: user.id,\n });\n } catch (error) {\n if (error.code === \"23505\") {\n // Duplicate key error\n elizaLogger.warn(\"Duplicate reaction memory, skipping\", {\n reactionId: reactionUUID,\n });\n return;\n }\n throw error; // Re-throw other errors\n }\n } catch (error) {\n elizaLogger.error(\"Error handling reaction:\", error);\n }\n }\n\n async handleReactionRemove(reaction: MessageReaction, user: User) {\n elizaLogger.log(\"Reaction removed\");\n // if (user.bot) return;\n\n let emoji = reaction.emoji.name;\n if (!emoji && reaction.emoji.id) {\n emoji = `<:${reaction.emoji.name}:${reaction.emoji.id}>`;\n }\n\n // Fetch the full message if it's a partial\n if (reaction.partial) {\n try {\n await reaction.fetch();\n } catch (error) {\n console.error(\n \"Something went wrong when fetching the message:\",\n error\n );\n return;\n }\n }\n\n const messageContent = reaction.message.content;\n const truncatedContent =\n messageContent.length > 50\n ? messageContent.substring(0, 50) + \"...\"\n : messageContent;\n\n const reactionMessage = `*Removed <${emoji} emoji> from: \"${truncatedContent}\"*`;\n\n const roomId = stringToUuid(\n reaction.message.channel.id + \"-\" + this.runtime.agentId\n );\n const userIdUUID = stringToUuid(user.id);\n\n // Generate a unique UUID for the reaction removal\n const reactionUUID = stringToUuid(\n `${reaction.message.id}-${user.id}-${emoji}-removed-${this.runtime.agentId}`\n );\n\n const userName = reaction.message.author.username;\n const name = reaction.message.author.displayName;\n\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n try {\n // Save the reaction removal as a message\n await this.runtime.messageManager.createMemory({\n id: reactionUUID, // This is the ID of the reaction removal message\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n content: {\n text: reactionMessage,\n source: \"discord\",\n inReplyTo: stringToUuid(\n reaction.message.id + \"-\" + this.runtime.agentId\n ), // This is the ID of the original message\n },\n roomId,\n createdAt: Date.now(),\n embedding: getEmbeddingZeroVector(),\n });\n } catch (error) {\n console.error(\"Error creating reaction removal message:\", error);\n }\n }\n\n private handleGuildCreate(guild: Guild) {\n console.log(`Joined guild ${guild.name}`);\n this.voiceManager.scanGuild(guild);\n }\n\n private async handleInteractionCreate(interaction: any) {\n if (!interaction.isCommand()) return;\n\n switch (interaction.commandName) {\n case \"joinchannel\":\n await this.voiceManager.handleJoinChannelCommand(interaction);\n break;\n case \"leavechannel\":\n await this.voiceManager.handleLeaveChannelCommand(interaction);\n break;\n }\n }\n\n private async onReady() {\n const guilds = await this.client.guilds.fetch();\n for (const [, guild] of guilds) {\n const fullGuild = await guild.fetch();\n this.voiceManager.scanGuild(fullGuild);\n }\n }\n}\n\n// function startDiscord(runtime: IAgentRuntime) {\n// return new DiscordClient(runtime);\n// }\n\nexport const DiscordClientInterface: ElizaClient = {\n name: 'discord',\n start: async (runtime: IAgentRuntime) => new DiscordClient(runtime),\n};","import { composeContext, getModelSettings } from \"@elizaos/core\";\nimport { generateText, trimTokens } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Memory,\n ModelClass,\n type State,\n} from \"@elizaos/core\";\nimport * as fs from \"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\": \"\",\n \"attachmentIds\": [\"\", \"\", ...]\n}\n\\`\\`\\`\n`;\n\nconst getAttachmentIds = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n): Promise<{ objective: string; attachmentIds: string[] } | null> => {\n state = (await runtime.composeState(message)) as State;\n\n const context = composeContext({\n state,\n template: attachmentIdsTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n console.log(\"response\", response);\n // try parsing to a json object\n const parsedResponse = parseJSONObjectFromText(response) as {\n objective: string;\n attachmentIds: string[];\n } | null;\n // see if it contains objective and attachmentIds\n if (parsedResponse?.objective && parsedResponse?.attachmentIds) {\n return parsedResponse;\n }\n }\n return null;\n};\n\nconst summarizeAction = {\n name: \"CHAT_WITH_ATTACHMENTS\",\n similes: [\n \"CHAT_WITH_ATTACHMENT\",\n \"SUMMARIZE_FILES\",\n \"SUMMARIZE_FILE\",\n \"SUMMARIZE_ATACHMENT\",\n \"CHAT_WITH_PDF\",\n \"ATTACHMENT_SUMMARY\",\n \"RECAP_ATTACHMENTS\",\n \"SUMMARIZE_FILE\",\n \"SUMMARIZE_VIDEO\",\n \"SUMMARIZE_AUDIO\",\n \"SUMMARIZE_IMAGE\",\n \"SUMMARIZE_DOCUMENT\",\n \"SUMMARIZE_LINK\",\n \"ATTACHMENT_SUMMARY\",\n \"FILE_SUMMARY\",\n ],\n description:\n \"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 validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n // only show if one of the keywords are in the message\n const keywords: string[] = [\n \"attachment\",\n \"summary\",\n \"summarize\",\n \"research\",\n \"pdf\",\n \"video\",\n \"audio\",\n \"image\",\n \"document\",\n \"link\",\n \"file\",\n \"attachment\",\n \"summarize\",\n \"code\",\n \"report\",\n \"write\",\n \"details\",\n \"information\",\n \"talk\",\n \"chat\",\n \"read\",\n \"listen\",\n \"watch\",\n ];\n return keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword.toLowerCase())\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n state = (await runtime.composeState(message)) as State;\n\n const callbackData: Content = {\n text: \"\", // fill in later\n action: \"CHAT_WITH_ATTACHMENTS_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n\n // 1. extract attachment IDs from the message\n const attachmentData = await getAttachmentIds(runtime, message, state);\n if (!attachmentData) {\n console.error(\"Couldn't get attachment IDs from message\");\n return;\n }\n\n const { objective, attachmentIds } = attachmentData;\n\n // This is pretty gross but it can catch cases where the returned generated UUID is stupidly wrong for some reason\n const attachments = state.recentMessagesData\n .filter(\n (msg) =>\n msg.content.attachments &&\n msg.content.attachments.length > 0\n )\n .flatMap((msg) => msg.content.attachments)\n // check by first 5 characters of uuid\n .filter(\n (attachment) =>\n attachmentIds\n .map((attch) => attch.toLowerCase().slice(0, 5))\n .includes(attachment.id.toLowerCase().slice(0, 5)) ||\n // or check the other way\n attachmentIds.some((id) => {\n const attachmentId = id.toLowerCase().slice(0, 5);\n return attachment.id\n .toLowerCase()\n .includes(attachmentId);\n })\n );\n\n const attachmentsWithText = attachments\n .map((attachment) => `# ${attachment.title}\\n${attachment.text}`)\n .join(\"\\n\\n\");\n\n let currentSummary = \"\";\n\n const modelSettings = getModelSettings(\n runtime.character.modelProvider,\n ModelClass.SMALL\n );\n const chunkSize = modelSettings.maxOutputTokens;\n\n state.attachmentsWithText = attachmentsWithText;\n state.objective = objective;\n const template = await trimTokens(\n summarizationTemplate,\n chunkSize + 500,\n runtime\n );\n const context = composeContext({\n state,\n // make sure it fits, we can pad the tokens a bit\n // Get the model's tokenizer based on the current model being used\n template,\n });\n\n const summary = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n currentSummary = currentSummary + \"\\n\" + summary;\n\n if (!currentSummary) {\n console.error(\"No summary found, that's not good!\");\n return;\n }\n\n callbackData.text = currentSummary.trim();\n if (\n callbackData.text &&\n (currentSummary.trim()?.split(\"\\n\").length < 4 ||\n currentSummary.trim()?.split(\" \").length < 100)\n ) {\n callbackData.text = `Here is the summary:\n\\`\\`\\`md\n${currentSummary.trim()}\n\\`\\`\\`\n`;\n await callback(callbackData);\n } else if (currentSummary.trim()) {\n const summaryFilename = `content/summary_${Date.now()}.md`;\n\n try {\n // Debug: Log before file operations\n console.log(\"Creating summary file:\", {\n filename: summaryFilename,\n summaryLength: currentSummary.length,\n });\n\n // Write file directly first\n await fs.promises.writeFile(\n summaryFilename,\n currentSummary,\n \"utf8\"\n );\n console.log(\"File written successfully\");\n\n // Then cache it\n await runtime.cacheManager.set(summaryFilename, currentSummary);\n console.log(\"Cache set operation completed\");\n\n await callback(\n {\n ...callbackData,\n text: `I've attached the summary of the requested attachments as a text file.`,\n },\n [summaryFilename]\n );\n console.log(\"Callback completed with summary file\");\n } catch (error) {\n console.error(\"Error in file/cache process:\", error);\n throw error;\n }\n } else {\n console.warn(\n \"Empty response from chat with attachments action, skipping\"\n );\n }\n\n return callbackData;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can you summarize the attachments b3e23, c4f67, and d5a89?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure thing! I'll pull up those specific attachments and provide a summary of their content.\",\n action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"I need a technical summary of the PDFs I sent earlier - a1b2c3.pdf, d4e5f6.pdf, and g7h8i9.pdf\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"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 action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"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 },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sure, no problem.\",\n action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"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 },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"great idea, give me a minute\",\n action: \"CHAT_WITH_ATTACHMENTS\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n\nexport default summarizeAction;\n","import path from \"path\";\nimport { composeContext } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type IVideoService,\n type Memory,\n ModelClass,\n ServiceType,\n type State,\n} from \"@elizaos/core\";\nimport { generateText } 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\": \"\"\n}\n\\`\\`\\`\n`;\n\nconst getMediaUrl = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n): Promise => {\n if (!state) {\n state = (await runtime.composeState(message)) as State;\n }\n\n const context = composeContext({\n state,\n template: mediaUrlTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n const parsedResponse = parseJSONObjectFromText(response) as {\n mediaUrl: string;\n } | null;\n\n if (parsedResponse?.mediaUrl) {\n return parsedResponse.mediaUrl;\n }\n }\n return null;\n};\n\nexport default {\n name: \"DOWNLOAD_MEDIA\",\n similes: [\n \"DOWNLOAD_VIDEO\",\n \"DOWNLOAD_AUDIO\",\n \"GET_MEDIA\",\n \"DOWNLOAD_PODCAST\",\n \"DOWNLOAD_YOUTUBE\",\n ],\n description:\n \"Downloads a video or audio file from a URL and attaches it to the response message.\",\n validate: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n const videoService = runtime\n .getService(ServiceType.VIDEO)\n .getInstance();\n if (!state) {\n state = (await runtime.composeState(message)) as State;\n }\n\n const mediaUrl = await getMediaUrl(runtime, message, state);\n if (!mediaUrl) {\n console.error(\"Couldn't get media URL from messages\");\n return;\n }\n\n const videoInfo = await videoService.fetchVideoInfo(mediaUrl);\n const mediaPath = await videoService.downloadVideo(videoInfo);\n\n const response: Content = {\n text: `I downloaded the video \"${videoInfo.title}\" and attached it below.`,\n action: \"DOWNLOAD_MEDIA_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n\n const filename = path.basename(mediaPath);\n\n const maxRetries = 3;\n let retries = 0;\n\n while (retries < maxRetries) {\n try {\n await callback(\n {\n ...response,\n },\n [\"content_cache/\" + filename]\n );\n break;\n } catch (error) {\n retries++;\n console.error(\n `Error sending message (attempt ${retries}):`,\n error\n );\n\n if (retries === maxRetries) {\n console.error(\n \"Max retries reached. Failed to send message with attachment.\"\n );\n break;\n }\n\n // Wait for a short delay before retrying\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n }\n\n return response;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Downloading the YouTube video now, one sec\",\n action: \"DOWNLOAD_MEDIA\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can you grab this video for me? https://vimeo.com/123456789\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure thing, I'll download that Vimeo video for you\",\n action: \"DOWNLOAD_MEDIA\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"I need this video downloaded: https://www.youtube.com/watch?v=abcdefg\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"No problem, I'm on it. I'll have that YouTube video downloaded in a jiffy\",\n action: \"DOWNLOAD_MEDIA\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n","// eslint-disable-next-line\n// @ts-nocheck\n// src/actions/joinVoice\nimport {\n type Action,\n type ActionExample,\n composeContext,\n type IAgentRuntime,\n type Memory,\n type State,\n generateText,\n ModelClass,\n} from \"@elizaos/core\";\nimport {\n type Channel,\n ChannelType,\n type Client,\n type Message as DiscordMessage,\n type Guild,\n type GuildMember,\n} from \"discord.js\";\nimport { joinVoiceChannel } from \"@discordjs/voice\";\n\nexport default {\n name: \"JOIN_VOICE\",\n similes: [\n \"JOIN_VOICE\",\n \"JOIN_VC\",\n \"JOIN_VOICE_CHAT\",\n \"JOIN_VOICE_CHANNEL\",\n \"JOIN_MEETING\",\n \"JOIN_CALL\",\n ],\n validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n state: State\n ) => {\n if (message.content.source !== \"discord\") {\n // not a discord message\n return false;\n }\n\n if (!state.discordClient) {\n return;\n }\n\n // did they say something about joining a voice channel? if not, don't validate\n const keywords = [\n \"join\",\n \"come to\",\n \"come on\",\n \"enter\",\n \"voice\",\n \"chat\",\n \"talk\",\n \"call\",\n \"hop on\",\n \"get on\",\n \"vc\",\n \"meeting\",\n \"discussion\",\n ];\n if (\n !keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword)\n )\n ) {\n return false;\n }\n\n return true;\n },\n description: \"Join a voice channel to participate in voice chat.\",\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n ): Promise => {\n if (!state) {\n console.error(\"State is not available.\");\n }\n\n // We normalize data in from voice channels\n const discordMessage = (state.discordChannel ||\n state.discordMessage) as DiscordMessage;\n\n if (!discordMessage.content) {\n discordMessage.content = message.content.text;\n }\n\n const id = (discordMessage as DiscordMessage).guild?.id as string;\n const client = state.discordClient as Client;\n const voiceChannels = (\n client.guilds.cache.get(id) as Guild\n ).channels.cache.filter(\n (channel: Channel) => channel.type === ChannelType.GuildVoice\n );\n\n const messageContent = discordMessage.content;\n\n const targetChannel = voiceChannels.find((channel) => {\n const name = (channel as { name: string }).name.toLowerCase();\n\n // remove all non-alphanumeric characters (keep spaces between words)\n const replacedName = name.replace(/[^a-z0-9 ]/g, \"\");\n\n return (\n name.includes(messageContent) ||\n messageContent.includes(name) ||\n replacedName.includes(messageContent) ||\n messageContent.includes(replacedName)\n );\n });\n\n if (targetChannel) {\n joinVoiceChannel({\n channelId: targetChannel.id,\n guildId: (discordMessage as DiscordMessage).guild?.id as string,\n adapterCreator: (client.guilds.cache.get(id) as Guild)\n .voiceAdapterCreator,\n selfDeaf: false,\n selfMute: false,\n group: client.user.id,\n });\n return true;\n } else {\n const member = (discordMessage as DiscordMessage)\n .member as GuildMember;\n if (member?.voice?.channel) {\n joinVoiceChannel({\n channelId: member.voice.channel.id,\n guildId: (discordMessage as DiscordMessage).guild\n ?.id as string,\n adapterCreator: (client.guilds.cache.get(id) as Guild)\n .voiceAdapterCreator,\n selfDeaf: false,\n selfMute: false,\n group: client.user.id,\n });\n return true;\n }\n\n const 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 const guessState = {\n userMessage: message.content.text,\n voiceChannels: voiceChannels\n .map((channel) => (channel as { name: string }).name)\n .join(\"\\n\"),\n };\n\n const context = composeContext({\n template: messageTemplate,\n state: guessState as unknown as State,\n });\n\n const _datestr = new Date().toUTCString().replace(/:/g, \"-\");\n\n const responseContent = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n runtime.databaseAdapter.log({\n body: { message, context, response: responseContent },\n userId: message.userId,\n roomId: message.roomId,\n type: \"joinvoice\",\n });\n\n if (responseContent && responseContent.trim().length > 0) {\n // join the voice channel\n const channelName = responseContent.toLowerCase();\n\n const targetChannel = voiceChannels.find((channel) => {\n const name = (\n channel as { name: string }\n ).name.toLowerCase();\n\n // remove all non-alphanumeric characters (keep spaces between words)\n const replacedName = name.replace(/[^a-z0-9 ]/g, \"\");\n\n return (\n name.includes(channelName) ||\n channelName.includes(name) ||\n replacedName.includes(channelName) ||\n channelName.includes(replacedName)\n );\n });\n\n if (targetChannel) {\n joinVoiceChannel({\n channelId: targetChannel.id,\n guildId: (discordMessage as DiscordMessage).guild\n ?.id as string,\n adapterCreator: (client.guilds.cache.get(id) as Guild)\n .voiceAdapterCreator,\n selfDeaf: false,\n selfMute: false,\n group: client.user.id,\n });\n return true;\n }\n }\n\n await (discordMessage as DiscordMessage).reply(\n \"I couldn't figure out which channel you wanted me to join.\"\n );\n return false;\n }\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey, let's jump into the 'General' voice and chat\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sounds good\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"{{user2}}, can you join the vc, I want to discuss our strat\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure I'll join right now\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"hey {{user2}}, we're having a team meeting in the 'conference' voice channel, plz join us\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"OK see you there\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"{{user2}}, let's have a quick voice chat in the 'Lounge' channel.\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"kk be there in a sec\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey {{user2}}, can you join me in the 'Music' voice channel\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"join voice chat with us {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"coming\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"hop in vc {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"joining now\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"get in vc with us {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"im in\",\n action: \"JOIN_VOICE\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n","// src/actions/leaveVoice\nimport { getVoiceConnection } from \"@discordjs/voice\";\nimport {\n type Channel,\n ChannelType,\n type Client,\n type Message as DiscordMessage,\n} from \"discord.js\";\nimport type {\n Action,\n ActionExample,\n IAgentRuntime,\n Memory,\n State,\n} from \"@elizaos/core\";\n\nexport default {\n name: \"LEAVE_VOICE\",\n similes: [\n \"LEAVE_VOICE\",\n \"LEAVE_VC\",\n \"LEAVE_VOICE_CHAT\",\n \"LEAVE_VOICE_CHANNEL\",\n \"LEAVE_MEETING\",\n \"LEAVE_CALL\",\n ],\n validate: async (runtime: IAgentRuntime, message: Memory, state: State) => {\n if (message.content.source !== \"discord\") {\n // not a discord message\n return false;\n }\n\n if (!state.discordClient) {\n return false;\n }\n\n const keywords = [\n \"leave\",\n \"exit\",\n \"stop\",\n \"quit\",\n \"get off\",\n \"get out\",\n \"bye\",\n \"cya\",\n \"see you\",\n \"hop off\",\n \"get off\",\n \"voice\",\n \"vc\",\n \"chat\",\n \"call\",\n \"meeting\",\n \"discussion\",\n ];\n if (\n !keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword)\n )\n ) {\n return false;\n }\n\n const client = state.discordClient as Client;\n\n // Check if the client is connected to any voice channel\n const isConnectedToVoice = client.voice.adapters.size > 0;\n\n return isConnectedToVoice;\n },\n description: \"Leave the current voice channel.\",\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n ): Promise => {\n if (!state.discordClient) {\n return;\n }\n\n const discordMessage = (state.discordMessage ||\n state.discordChannel) as DiscordMessage;\n\n if (!discordMessage) {\n throw new Error(\"Discord message is not available in the state.\");\n }\n const voiceChannels = (state.discordClient as Client)?.guilds.cache\n .get((discordMessage as DiscordMessage).guild?.id as string)\n ?.channels.cache.filter(\n (channel: Channel) => channel.type === ChannelType.GuildVoice\n );\n\n voiceChannels?.forEach((_channel: Channel) => {\n const connection = getVoiceConnection(\n (discordMessage as DiscordMessage).guild?.id as string\n );\n if (connection) {\n connection.destroy();\n }\n });\n return true;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey {{user2}} please leave the voice channel\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"I have to go now but thanks for the chat\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"You too, talk to you later\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Great call everyone, hopping off now\",\n action: \"LEAVE_VOICE\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Agreed, I'll hop off too\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Hey {{user2}} I need you to step away from the voice chat for a bit\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"No worries, I'll leave the voice channel\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"{{user2}}, I think we covered everything, you can leave the voice chat now\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sounds good, see you both later\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"leave voice {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"ok leaving\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"plz leave the voice chat {{user2}}\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"aight im out\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"yo {{user2}} gtfo the vc\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sorry, talk to you later\",\n action: \"LEAVE_VOICE\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n","import { composeContext, getModelSettings } from \"@elizaos/core\";\nimport { generateText, splitChunks, trimTokens } from \"@elizaos/core\";\nimport { getActorDetails } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Media,\n type Memory,\n ModelClass,\n type State,\n} from \"@elizaos/core\";\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. \" 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\": \"\",\n \"start\": \"0 minutes ago\",\n \"end\": \"2 hours ago\"\n}\n\\`\\`\\`\n`;\n\nconst getDateRange = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n) => {\n state = (await runtime.composeState(message)) as State;\n\n const context = composeContext({\n state,\n template: dateRangeTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n console.log(\"response\", response);\n // try parsing to a json object\n const parsedResponse = parseJSONObjectFromText(response) as {\n objective: string;\n start: string | number;\n end: string | number;\n } | null;\n // see if it contains objective, start and end\n if (parsedResponse) {\n if (\n parsedResponse.objective &&\n parsedResponse.start &&\n parsedResponse.end\n ) {\n // TODO: parse start and end into timestamps\n const startIntegerString = (\n parsedResponse.start as string\n ).match(/\\d+/)?.[0];\n const endIntegerString = (parsedResponse.end as string).match(\n /\\d+/\n )?.[0];\n\n // parse multiplier\n const multipliers = {\n second: 1 * 1000,\n minute: 60 * 1000,\n hour: 3600 * 1000,\n day: 86400 * 1000,\n };\n\n const startMultiplier = (parsedResponse.start as string).match(\n /second|minute|hour|day/\n )?.[0];\n const endMultiplier = (parsedResponse.end as string).match(\n /second|minute|hour|day/\n )?.[0];\n\n const startInteger = startIntegerString\n ? Number.parseInt(startIntegerString)\n : 0;\n const endInteger = endIntegerString\n ? Number.parseInt(endIntegerString)\n : 0;\n\n // multiply by multiplier\n const startTime =\n startInteger *\n multipliers[startMultiplier as keyof typeof multipliers];\n\n console.log(\"startTime\", startTime);\n\n const endTime =\n endInteger *\n multipliers[endMultiplier as keyof typeof multipliers];\n\n console.log(\"endTime\", endTime);\n\n // get the current time and subtract the start and end times\n parsedResponse.start = Date.now() - startTime;\n parsedResponse.end = Date.now() - endTime;\n\n return parsedResponse;\n }\n }\n }\n};\n\nconst summarizeAction = {\n name: \"SUMMARIZE_CONVERSATION\",\n similes: [\n \"RECAP\",\n \"RECAP_CONVERSATION\",\n \"SUMMARIZE_CHAT\",\n \"SUMMARIZATION\",\n \"CHAT_SUMMARY\",\n \"CONVERSATION_SUMMARY\",\n ],\n description: \"Summarizes the conversation and attachments.\",\n validate: async (\n runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n // only show if one of the keywords are in the message\n const keywords: string[] = [\n \"summarize\",\n \"summarization\",\n \"summary\",\n \"recap\",\n \"report\",\n \"overview\",\n \"review\",\n \"rundown\",\n \"wrap-up\",\n \"brief\",\n \"debrief\",\n \"abstract\",\n \"synopsis\",\n \"outline\",\n \"digest\",\n \"abridgment\",\n \"condensation\",\n \"encapsulation\",\n \"essence\",\n \"gist\",\n \"main points\",\n \"key points\",\n \"key takeaways\",\n \"bulletpoint\",\n \"highlights\",\n \"tldr\",\n \"tl;dr\",\n \"in a nutshell\",\n \"bottom line\",\n \"long story short\",\n \"sum up\",\n \"sum it up\",\n \"short version\",\n \"bring me up to speed\",\n \"catch me up\",\n ];\n return keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword.toLowerCase())\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n state = (await runtime.composeState(message)) as State;\n\n const callbackData: Content = {\n text: \"\", // fill in later\n action: \"SUMMARIZATION_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n const { roomId } = message;\n\n // 1. extract date range from the message\n const dateRange = await getDateRange(runtime, message, state);\n if (!dateRange) {\n console.error(\"Couldn't get date range from message\");\n return;\n }\n\n console.log(\"dateRange\", dateRange);\n\n const { objective, start, end } = dateRange;\n\n // 2. get these memories from the database\n const memories = await runtime.messageManager.getMemories({\n roomId,\n // subtract start from current time\n start: Number.parseInt(start as string),\n end: Number.parseInt(end as string),\n count: 10000,\n unique: false,\n });\n\n const actors = await getActorDetails({\n runtime: runtime as IAgentRuntime,\n roomId,\n });\n\n const actorMap = new Map(actors.map((actor) => [actor.id, actor]));\n\n const formattedMemories = memories\n .map((memory) => {\n const attachments = memory.content.attachments\n ?.map((attachment: Media) => {\n return `---\\nAttachment: ${attachment.id}\\n${attachment.description}\\n${attachment.text}\\n---`;\n })\n .join(\"\\n\");\n return `${actorMap.get(memory.userId)?.name ?? \"Unknown User\"} (${actorMap.get(memory.userId)?.username ?? \"\"}): ${memory.content.text}\\n${attachments}`;\n })\n .join(\"\\n\");\n\n let currentSummary = \"\";\n\n const modelSettings = getModelSettings(\n runtime.character.modelProvider,\n ModelClass.SMALL\n );\n const chunkSize = modelSettings.maxOutputTokens - 1000;\n\n const chunks = await splitChunks(formattedMemories, chunkSize, 0);\n\n const _datestr = new Date().toUTCString().replace(/:/g, \"-\");\n\n state.memoriesWithAttachments = formattedMemories;\n state.objective = objective;\n\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n state.currentSummary = currentSummary;\n state.currentChunk = chunk;\n const template = await trimTokens(\n summarizationTemplate,\n chunkSize + 500,\n runtime\n );\n const context = composeContext({\n state,\n // make sure it fits, we can pad the tokens a bit\n template,\n });\n\n const summary = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n currentSummary = currentSummary + \"\\n\" + summary;\n }\n\n if (!currentSummary) {\n console.error(\"No summary found, that's not good!\");\n return;\n }\n\n callbackData.text = currentSummary.trim();\n if (\n callbackData.text &&\n (currentSummary.trim()?.split(\"\\n\").length < 4 ||\n currentSummary.trim()?.split(\" \").length < 100)\n ) {\n callbackData.text = `Here is the summary:\n\\`\\`\\`md\n${currentSummary.trim()}\n\\`\\`\\`\n`;\n await callback(callbackData);\n } else if (currentSummary.trim()) {\n const summaryFilename = `content/conversation_summary_${Date.now()}`;\n await runtime.cacheManager.set(summaryFilename, currentSummary);\n // save the summary to a file\n await callback(\n {\n ...callbackData,\n text: `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 },\n [summaryFilename]\n );\n } else {\n console.warn(\n \"Empty response from summarize conversation action, skipping\"\n );\n }\n\n return callbackData;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"```js\\nconst x = 10\\n```\",\n },\n },\n {\n user: \"{{user1}}\",\n content: {\n text: \"can you give me a detailed report on what we're talking about?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sure, no problem, give me a minute to get that together for you\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"please summarize the conversation we just had and include this blogpost i'm linking (Attachment: b3e12)\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"sure, give me a sec\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can you summarize what moon and avf are talking about?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Yeah, just hold on a second while I get that together for you...\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"i need to write a blog post about farming, can you summarize the discussion from a few hours ago?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"no problem, give me a few minutes to read through everything\",\n action: \"SUMMARIZE\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n\nexport default summarizeAction;\n","import { composeContext } from \"@elizaos/core\";\nimport { generateText } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type Action,\n type ActionExample,\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Memory,\n ModelClass,\n type 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 context 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\": \"\"\n}\n\\`\\`\\`\n`;\n\nconst getMediaAttachmentId = async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State\n): Promise => {\n state = (await runtime.composeState(message)) as State;\n\n const context = composeContext({\n state,\n template: mediaAttachmentIdTemplate,\n });\n\n for (let i = 0; i < 5; i++) {\n const response = await generateText({\n runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n console.log(\"response\", response);\n\n const parsedResponse = parseJSONObjectFromText(response) as {\n attachmentId: string;\n } | null;\n\n if (parsedResponse?.attachmentId) {\n return parsedResponse.attachmentId;\n }\n }\n return null;\n};\n\nconst transcribeMediaAction = {\n name: \"TRANSCRIBE_MEDIA\",\n similes: [\n \"TRANSCRIBE_AUDIO\",\n \"TRANSCRIBE_VIDEO\",\n \"MEDIA_TRANSCRIPT\",\n \"VIDEO_TRANSCRIPT\",\n \"AUDIO_TRANSCRIPT\",\n ],\n description:\n \"Transcribe the full text of an audio or video file that the user has attached.\",\n validate: async (\n _runtime: IAgentRuntime,\n message: Memory,\n _state: State\n ) => {\n if (message.content.source !== \"discord\") {\n return false;\n }\n\n const keywords: string[] = [\n \"transcribe\",\n \"transcript\",\n \"audio\",\n \"video\",\n \"media\",\n \"youtube\",\n \"meeting\",\n \"recording\",\n \"podcast\",\n \"call\",\n \"conference\",\n \"interview\",\n \"speech\",\n \"lecture\",\n \"presentation\",\n ];\n return keywords.some((keyword) =>\n message.content.text.toLowerCase().includes(keyword.toLowerCase())\n );\n },\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state: State,\n options: any,\n callback: HandlerCallback\n ) => {\n state = (await runtime.composeState(message)) as State;\n\n const callbackData: Content = {\n text: \"\", // fill in later\n action: \"TRANSCRIBE_MEDIA_RESPONSE\",\n source: message.content.source,\n attachments: [],\n };\n\n const attachmentId = await getMediaAttachmentId(\n runtime,\n message,\n state\n );\n if (!attachmentId) {\n console.error(\"Couldn't get media attachment ID from message\");\n return;\n }\n\n const attachment = state.recentMessagesData\n .filter(\n (msg) =>\n msg.content.attachments &&\n msg.content.attachments.length > 0\n )\n .flatMap((msg) => msg.content.attachments)\n .find(\n (attachment) =>\n attachment.id.toLowerCase() === attachmentId.toLowerCase()\n );\n\n if (!attachment) {\n console.error(`Couldn't find attachment with ID ${attachmentId}`);\n return;\n }\n\n const mediaTranscript = attachment.text;\n\n callbackData.text = mediaTranscript.trim();\n\n // if callbackData.text is < 4 lines or < 100 words, then we we callback with normal message wrapped in markdown block\n if (\n callbackData.text &&\n (callbackData.text?.split(\"\\n\").length < 4 ||\n callbackData.text?.split(\" \").length < 100)\n ) {\n callbackData.text = `Here is the transcript:\n\\`\\`\\`md\n${mediaTranscript.trim()}\n\\`\\`\\`\n`;\n await callback(callbackData);\n }\n // if text is big, let's send as an attachment\n else if (callbackData.text) {\n const transcriptFilename = `content/transcript_${Date.now()}`;\n\n // save the transcript to a file\n await runtime.cacheManager.set(\n transcriptFilename,\n callbackData.text\n );\n\n await callback(\n {\n ...callbackData,\n text: `I've attached the transcript as a text file.`,\n },\n [transcriptFilename]\n );\n } else {\n console.warn(\n \"Empty response from transcribe media action, skipping\"\n );\n }\n\n return callbackData;\n },\n examples: [\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Please transcribe the audio file I just sent.\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Sure, I'll transcribe the full audio for you.\",\n action: \"TRANSCRIBE_MEDIA\",\n },\n },\n ],\n [\n {\n user: \"{{user1}}\",\n content: {\n text: \"Can I get a transcript of that video recording?\",\n },\n },\n {\n user: \"{{user2}}\",\n content: {\n text: \"Absolutely, give me a moment to generate the full transcript of the video.\",\n action: \"TRANSCRIBE_MEDIA\",\n },\n },\n ],\n ] as ActionExample[][],\n} as Action;\n\nexport default transcribeMediaAction;\n","import { composeContext, composeRandomUser } from \"@elizaos/core\";\nimport { generateMessageResponse, generateShouldRespond } from \"@elizaos/core\";\nimport {\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type IBrowserService,\n type ISpeechService,\n type IVideoService,\n type Media,\n type Memory,\n ModelClass,\n ServiceType,\n type State,\n type UUID,\n} from \"@elizaos/core\";\nimport { stringToUuid, getEmbeddingZeroVector } from \"@elizaos/core\";\nimport {\n ChannelType,\n type Client,\n type Message as DiscordMessage,\n type TextChannel,\n} from \"discord.js\";\nimport { elizaLogger } from \"@elizaos/core\";\nimport { AttachmentManager } from \"./attachments.ts\";\nimport type { VoiceManager } from \"./voice.ts\";\nimport {\n discordShouldRespondTemplate,\n discordMessageHandlerTemplate,\n discordAutoPostTemplate,\n discordAnnouncementHypeTemplate\n} from \"./templates.ts\";\nimport {\n IGNORE_RESPONSE_WORDS,\n LOSE_INTEREST_WORDS,\n MESSAGE_CONSTANTS,\n MESSAGE_LENGTH_THRESHOLDS,\n RESPONSE_CHANCES,\n TEAM_COORDINATION,\n TIMING_CONSTANTS,\n} from \"./constants\";\nimport {\n sendMessageInChunks,\n canSendMessage,\n cosineSimilarity,\n} from \"./utils.ts\";\n\ninterface MessageContext {\n content: string;\n timestamp: number;\n}\n\ninterface AutoPostConfig {\n enabled: boolean;\n monitorTime: number;\n inactivityThreshold: number; // milliseconds\n mainChannelId: string;\n announcementChannelIds: string[];\n lastAutoPost?: number;\n minTimeBetweenPosts?: number; // minimum time between auto posts\n}\n\nexport type InterestChannels = {\n [key: string]: {\n currentHandler: string | undefined;\n lastMessageSent: number;\n messages: { userId: UUID; userName: string; content: Content }[];\n previousContext?: MessageContext;\n contextSimilarityThreshold?: number;\n };\n};\n\nexport class MessageManager {\n private client: Client;\n private runtime: IAgentRuntime;\n private attachmentManager: AttachmentManager;\n private interestChannels: InterestChannels = {};\n private discordClient: any;\n private voiceManager: VoiceManager;\n //Auto post\n private autoPostConfig: AutoPostConfig;\n private lastChannelActivity: { [channelId: string]: number } = {};\n private autoPostInterval: NodeJS.Timeout;\n\n constructor(discordClient: any, voiceManager: VoiceManager) {\n this.client = discordClient.client;\n this.voiceManager = voiceManager;\n this.discordClient = discordClient;\n this.runtime = discordClient.runtime;\n this.attachmentManager = new AttachmentManager(this.runtime);\n\n this.autoPostConfig = {\n enabled: this.runtime.character.clientConfig?.discord?.autoPost?.enabled || false,\n monitorTime: this.runtime.character.clientConfig?.discord?.autoPost?.monitorTime || 300000,\n inactivityThreshold: this.runtime.character.clientConfig?.discord?.autoPost?.inactivityThreshold || 3600000, // 1 hour default\n mainChannelId: this.runtime.character.clientConfig?.discord?.autoPost?.mainChannelId,\n announcementChannelIds: this.runtime.character.clientConfig?.discord?.autoPost?.announcementChannelIds || [],\n minTimeBetweenPosts: this.runtime.character.clientConfig?.discord?.autoPost?.minTimeBetweenPosts || 7200000, // 2 hours default\n };\n\n if (this.autoPostConfig.enabled) {\n this._startAutoPostMonitoring();\n }\n }\n\n async handleMessage(message: DiscordMessage) {\n\n if (this.runtime.character.clientConfig?.discord?.allowedChannelIds &&\n !this.runtime.character.clientConfig.discord.allowedChannelIds.includes(message.channelId)) {\n return;\n }\n\n // Update last activity time for the channel\n this.lastChannelActivity[message.channelId] = Date.now();\n\n if (\n message.interaction ||\n message.author.id ===\n this.client.user?.id /* || message.author?.bot*/\n ) {\n return;\n }\n\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldIgnoreBotMessages &&\n message.author?.bot\n ) {\n return;\n }\n\n // Check for mentions-only mode setting\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n if (!this._isMessageForMe(message)) {\n return;\n }\n }\n\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldIgnoreDirectMessages &&\n message.channel.type === ChannelType.DM\n ) {\n return;\n }\n\n const userId = message.author.id as UUID;\n const userName = message.author.username;\n const name = message.author.displayName;\n const channelId = message.channel.id;\n const isDirectlyMentioned = this._isMessageForMe(message);\n const hasInterest = this._checkInterest(message.channelId);\n\n // Team handling\n if (\n this.runtime.character.clientConfig?.discord?.isPartOfTeam &&\n !this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n const authorId = this._getNormalizedUserId(message.author.id);\n\n if (\n !this._isTeamLeader() &&\n this._isRelevantToTeamMember(message.content, channelId)\n ) {\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n }\n\n const isTeamRequest = this._isTeamCoordinationRequest(\n message.content\n );\n const isLeader = this._isTeamLeader();\n\n // After team-wide responses, check if we should maintain interest\n if (hasInterest && !isDirectlyMentioned) {\n const lastSelfMemories =\n await this.runtime.messageManager.getMemories({\n roomId: stringToUuid(\n channelId + \"-\" + this.runtime.agentId\n ),\n unique: false,\n count: 5,\n });\n\n const lastSelfSortedMemories = lastSelfMemories\n ?.filter((m) => m.userId === this.runtime.agentId)\n .sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n\n const isRelevant = this._isRelevantToTeamMember(\n message.content,\n channelId,\n lastSelfSortedMemories?.[0]\n );\n\n if (!isRelevant) {\n // Clearing interest - conversation not relevant to team member\n delete this.interestChannels[message.channelId];\n return;\n }\n }\n\n if (isTeamRequest) {\n if (isLeader) {\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n } else {\n // Set temporary interest for this response\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n\n // Clear interest after this cycle unless directly mentioned\n if (!isDirectlyMentioned) {\n // Use existing message cycle to clear interest\n this.interestChannels[\n message.channelId\n ].lastMessageSent = 0;\n }\n }\n }\n\n // Check for other team member mentions\n const otherTeamMembers =\n this.runtime.character.clientConfig.discord.teamAgentIds.filter(\n (id) => id !== this.client.user?.id\n );\n const mentionedTeamMember = otherTeamMembers.find((id) =>\n message.content.includes(`<@${id}>`)\n );\n\n // If another team member is mentioned, clear our interest\n if (mentionedTeamMember) {\n if (\n hasInterest ||\n this.interestChannels[message.channelId]?.currentHandler ===\n this.client.user?.id\n ) {\n delete this.interestChannels[message.channelId];\n\n // Only return if we're not the mentioned member\n if (!isDirectlyMentioned) {\n return;\n }\n }\n }\n\n // Set/maintain interest only if we're mentioned or already have interest\n if (isDirectlyMentioned) {\n this.interestChannels[message.channelId] = {\n currentHandler: this.client.user?.id,\n lastMessageSent: Date.now(),\n messages: [],\n };\n } else if (!isTeamRequest && !hasInterest) {\n return;\n }\n\n // Bot-specific checks\n if (message.author.bot) {\n if (this._isTeamMember(authorId) && !isDirectlyMentioned) {\n return;\n } else if (\n this.runtime.character.clientConfig.discord\n .shouldIgnoreBotMessages\n ) {\n return;\n }\n }\n }\n\n try {\n const { processedContent, attachments } =\n await this.processMessageMedia(message);\n\n const audioAttachments = message.attachments.filter((attachment) =>\n attachment.contentType?.startsWith(\"audio/\")\n );\n if (audioAttachments.size > 0) {\n const processedAudioAttachments =\n await this.attachmentManager.processAttachments(\n audioAttachments\n );\n attachments.push(...processedAudioAttachments);\n }\n\n const roomId = stringToUuid(channelId + \"-\" + this.runtime.agentId);\n const userIdUUID = stringToUuid(userId);\n\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n const messageId = stringToUuid(\n message.id + \"-\" + this.runtime.agentId\n );\n\n let shouldIgnore = false;\n let shouldRespond = true;\n\n const content: Content = {\n text: processedContent,\n attachments: attachments,\n source: \"discord\",\n url: message.url,\n inReplyTo: message.reference?.messageId\n ? stringToUuid(\n message.reference.messageId +\n \"-\" +\n this.runtime.agentId\n )\n : undefined,\n };\n\n const userMessage = {\n content,\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n roomId,\n };\n\n const memory: Memory = {\n id: stringToUuid(message.id + \"-\" + this.runtime.agentId),\n ...userMessage,\n userId: userIdUUID,\n agentId: this.runtime.agentId,\n roomId,\n content,\n createdAt: message.createdTimestamp,\n };\n\n if (content.text) {\n await this.runtime.messageManager.addEmbeddingToMemory(memory);\n await this.runtime.messageManager.createMemory(memory);\n\n if (this.interestChannels[message.channelId]) {\n // Add new message\n this.interestChannels[message.channelId].messages.push({\n userId: userIdUUID,\n userName: userName,\n content: content,\n });\n\n // Trim to keep only recent messages\n if (\n this.interestChannels[message.channelId].messages\n .length > MESSAGE_CONSTANTS.MAX_MESSAGES\n ) {\n this.interestChannels[message.channelId].messages =\n this.interestChannels[\n message.channelId\n ].messages.slice(-MESSAGE_CONSTANTS.MAX_MESSAGES);\n }\n }\n }\n\n let state = await this.runtime.composeState(userMessage, {\n discordClient: this.client,\n discordMessage: message,\n agentName:\n this.runtime.character.name ||\n this.client.user?.displayName,\n });\n\n const canSendResult = canSendMessage(message.channel);\n if (!canSendResult.canSend) {\n return elizaLogger.warn(\n `Cannot send message to channel ${message.channel}`,\n canSendResult\n );\n }\n\n if (!shouldIgnore) {\n shouldIgnore = await this._shouldIgnore(message);\n }\n\n if (shouldIgnore) {\n return;\n }\n\n const agentUserState =\n await this.runtime.databaseAdapter.getParticipantUserState(\n roomId,\n this.runtime.agentId\n );\n\n if (\n agentUserState === \"MUTED\" &&\n !message.mentions.has(this.client.user.id) &&\n !hasInterest\n ) {\n console.log(\"Ignoring muted room\");\n // Ignore muted rooms unless explicitly mentioned\n return;\n }\n\n if (agentUserState === \"FOLLOWED\") {\n shouldRespond = true; // Always respond in followed rooms\n } else if (\n (!shouldRespond && hasInterest) ||\n (shouldRespond && !hasInterest)\n ) {\n shouldRespond = await this._shouldRespond(message, state);\n }\n\n if (shouldRespond) {\n const context = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordMessageHandlerTemplate ||\n discordMessageHandlerTemplate,\n });\n\n // simulate discord typing while generating a response\n const stopTyping = this.simulateTyping(message);\n\n const responseContent = await this._generateResponse(\n memory,\n state,\n context\n ).finally(() => {\n stopTyping();\n });\n\n responseContent.text = responseContent.text?.trim();\n responseContent.inReplyTo = stringToUuid(\n message.id + \"-\" + this.runtime.agentId\n );\n\n if (!responseContent.text) {\n return;\n }\n\n const callback: HandlerCallback = async (\n content: Content,\n files: any[]\n ) => {\n try {\n if (message.id && !content.inReplyTo) {\n content.inReplyTo = stringToUuid(\n message.id + \"-\" + this.runtime.agentId\n );\n }\n const messages = await sendMessageInChunks(\n message.channel as TextChannel,\n content.text,\n message.id,\n files\n );\n\n const memories: Memory[] = [];\n for (const m of messages) {\n let action = content.action;\n // If there's only one message or it's the last message, keep the original action\n // For multiple messages, set all but the last to 'CONTINUE'\n if (\n messages.length > 1 &&\n m !== messages[messages.length - 1]\n ) {\n action = \"CONTINUE\";\n }\n\n const memory: Memory = {\n id: stringToUuid(\n m.id + \"-\" + this.runtime.agentId\n ),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: {\n ...content,\n action,\n inReplyTo: messageId,\n url: m.url,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: m.createdTimestamp,\n };\n memories.push(memory);\n }\n for (const m of memories) {\n await this.runtime.messageManager.createMemory(m);\n }\n return memories;\n } catch (error) {\n console.error(\"Error sending message:\", error);\n return [];\n }\n };\n\n const action = this.runtime.actions.find((a) => a.name === responseContent.action);\n const shouldSuppressInitialMessage = action?.suppressInitialMessage;\n\n let responseMessages = [];\n\n if (!shouldSuppressInitialMessage) {\n responseMessages = await callback(responseContent);\n } else {\n responseMessages = [\n {\n id: stringToUuid(messageId + \"-\" + this.runtime.agentId),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: responseContent,\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now(),\n }\n ]\n }\n\n state = await this.runtime.updateRecentMessageState(state);\n\n await this.runtime.processActions(\n memory,\n responseMessages,\n state,\n callback\n );\n }\n await this.runtime.evaluate(memory, state, shouldRespond);\n } catch (error) {\n console.error(\"Error handling message:\", error);\n if (message.channel.type === ChannelType.GuildVoice) {\n // For voice channels, use text-to-speech for the error message\n const errorMessage = \"Sorry, I had a glitch. What was that?\";\n\n const speechService = this.runtime.getService(\n ServiceType.SPEECH_GENERATION\n );\n if (!speechService) {\n throw new Error(\"Speech generation service not found\");\n }\n\n const audioStream = await speechService.generate(\n this.runtime,\n errorMessage\n );\n await this.voiceManager.playAudioStream(userId, audioStream);\n } else {\n // For text channels, send the error message\n console.error(\"Error sending message:\", error);\n }\n }\n }\n\n async cacheMessages(channel: TextChannel, count = 20) {\n const messages = await channel.messages.fetch({ limit: count });\n\n // TODO: This is throwing an error but seems to work?\n for (const [_, message] of messages) {\n await this.handleMessage(message);\n }\n }\n\n private _startAutoPostMonitoring(): void {\n // Wait for client to be ready\n if (!this.client.isReady()) {\n elizaLogger.info('[AutoPost Discord] Client not ready, waiting for ready event')\n this.client.once('ready', () => {\n elizaLogger.info('[AutoPost Discord] Client ready, starting monitoring')\n this._initializeAutoPost();\n });\n } else {\n elizaLogger.info('[AutoPost Discord] Client already ready, starting monitoring')\n this._initializeAutoPost();\n }\n }\n\n private _initializeAutoPost(): void {\n // Give the client a moment to fully load its cache\n setTimeout(() => {\n // Monitor with random intervals between 2-6 hours\n this.autoPostInterval = setInterval(() => {\n this._checkChannelActivity();\n }, Math.floor(Math.random() * (4 * 60 * 60 * 1000) + 2 * 60 * 60 * 1000));\n\n // Start monitoring announcement channels\n this._monitorAnnouncementChannels();\n }, 5000); // 5 second delay to ensure everything is loaded\n }\n\n private async _checkChannelActivity(): Promise {\n if (!this.autoPostConfig.enabled || !this.autoPostConfig.mainChannelId) return;\n\n const channel = this.client.channels.cache.get(this.autoPostConfig.mainChannelId) as TextChannel;\n if (!channel) return;\n\n try {\n // Get last message time\n const messages = await channel.messages.fetch({ limit: 1 });\n const lastMessage = messages.first();\n const lastMessageTime = lastMessage ? lastMessage.createdTimestamp : 0;\n\n const now = Date.now();\n const timeSinceLastMessage = now - lastMessageTime;\n const timeSinceLastAutoPost = now - (this.autoPostConfig.lastAutoPost || 0);\n\n // Add some randomness to the inactivity threshold (±30 minutes)\n const randomThreshold = this.autoPostConfig.inactivityThreshold +\n (Math.random() * 1800000 - 900000);\n\n // Check if we should post\n if ((timeSinceLastMessage > randomThreshold) &&\n timeSinceLastAutoPost > (this.autoPostConfig.minTimeBetweenPosts || 0)) {\n\n try {\n // Create memory and generate response\n const roomId = stringToUuid(channel.id + \"-\" + this.runtime.agentId);\n\n const memory = {\n id: stringToUuid(`autopost-${Date.now()}`),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n roomId,\n content: { text: \"AUTO_POST_ENGAGEMENT\", source: \"discord\" },\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now()\n };\n\n let state = await this.runtime.composeState(memory, {\n discordClient: this.client,\n discordMessage: null,\n agentName: this.runtime.character.name || this.client.user?.displayName\n });\n\n // Generate response using template\n const context = composeContext({\n state,\n template: this.runtime.character.templates?.discordAutoPostTemplate || discordAutoPostTemplate\n });\n\n const responseContent = await this._generateResponse(memory, state, context);\n if (!responseContent?.text) return;\n\n // Send message and update memory\n const messages = await sendMessageInChunks(channel, responseContent.text.trim(), null, []);\n\n // Create and store memories\n const memories = messages.map(m => ({\n id: stringToUuid(m.id + \"-\" + this.runtime.agentId),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: {\n ...responseContent,\n url: m.url,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: m.createdTimestamp,\n }));\n\n for (const m of memories) {\n await this.runtime.messageManager.createMemory(m);\n }\n\n // Update state and last post time\n this.autoPostConfig.lastAutoPost = Date.now();\n state = await this.runtime.updateRecentMessageState(state);\n await this.runtime.evaluate(memory, state, true);\n } catch (error) {\n elizaLogger.warn(\"[AutoPost Discord] Error:\", error);\n }\n } else {\n elizaLogger.warn(\"[AutoPost Discord] Activity within threshold. Not posting.\");\n }\n } catch (error) {\n elizaLogger.warn(\"[AutoPost Discord] Error checking last message:\", error);\n }\n }\n\n private async _monitorAnnouncementChannels(): Promise {\n if (!this.autoPostConfig.enabled || !this.autoPostConfig.announcementChannelIds.length) {\n elizaLogger.warn('[AutoPost Discord] Auto post config disabled or no announcement channels')\n return;\n }\n\n for (const announcementChannelId of this.autoPostConfig.announcementChannelIds) {\n const channel = this.client.channels.cache.get(announcementChannelId);\n\n if (channel) {\n // Check if it's either a text channel or announcement channel\n // ChannelType.GuildAnnouncement is 5\n // ChannelType.GuildText is 0\n if (channel instanceof TextChannel || channel.type === ChannelType.GuildAnnouncement) {\n const newsChannel = channel as TextChannel;\n try {\n newsChannel.createMessageCollector().on('collect', async (message: DiscordMessage) => {\n if (message.author.bot || Date.now() - message.createdTimestamp > 300000) return;\n\n const mainChannel = this.client.channels.cache.get(this.autoPostConfig.mainChannelId) as TextChannel;\n if (!mainChannel) return;\n\n try {\n // Create memory and generate response\n const roomId = stringToUuid(mainChannel.id + \"-\" + this.runtime.agentId);\n const memory = {\n id: stringToUuid(`announcement-${Date.now()}`),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n roomId,\n content: {\n text: message.content,\n source: \"discord\",\n metadata: { announcementUrl: message.url }\n },\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now()\n };\n\n let state = await this.runtime.composeState(memory, {\n discordClient: this.client,\n discordMessage: message,\n announcementContent: message?.content,\n announcementChannelId: channel.id,\n agentName: this.runtime.character.name || this.client.user?.displayName\n });\n\n // Generate response using template\n const context = composeContext({\n state,\n template: this.runtime.character.templates?.discordAnnouncementHypeTemplate || discordAnnouncementHypeTemplate\n\n });\n\n const responseContent = await this._generateResponse(memory, state, context);\n if (!responseContent?.text) return;\n\n // Send message and update memory\n const messages = await sendMessageInChunks(mainChannel, responseContent.text.trim(), null, []);\n\n // Create and store memories\n const memories = messages.map(m => ({\n id: stringToUuid(m.id + \"-\" + this.runtime.agentId),\n userId: this.runtime.agentId,\n agentId: this.runtime.agentId,\n content: {\n ...responseContent,\n url: m.url,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: m.createdTimestamp,\n }));\n\n for (const m of memories) {\n await this.runtime.messageManager.createMemory(m);\n }\n\n // Update state\n state = await this.runtime.updateRecentMessageState(state);\n await this.runtime.evaluate(memory, state, true);\n } catch (error) {\n elizaLogger.warn(\"[AutoPost Discord] Announcement Error:\", error);\n }\n });\n elizaLogger.info(`[AutoPost Discord] Successfully set up collector for announcement channel: ${newsChannel.name}`);\n } catch (error) {\n elizaLogger.warn(`[AutoPost Discord] Error setting up announcement channel collector:`, error);\n }\n } else {\n elizaLogger.warn(`[AutoPost Discord] Channel ${announcementChannelId} is not a valid announcement or text channel, type:`, channel.type);\n }\n } else {\n elizaLogger.warn(`[AutoPost Discord] Could not find channel ${announcementChannelId} directly`);\n }\n }\n }\n\n private _isMessageForMe(message: DiscordMessage): boolean {\n const isMentioned = message.mentions.users?.has(\n this.client.user?.id as string\n );\n const guild = message.guild;\n const member = guild?.members.cache.get(this.client.user?.id as string);\n const nickname = member?.nickname;\n\n // Don't consider role mentions as direct mentions\n const hasRoleMentionOnly =\n message.mentions.roles.size > 0 && !isMentioned;\n\n // If it's only a role mention and we're in team mode, let team logic handle it\n if (\n hasRoleMentionOnly &&\n this.runtime.character.clientConfig?.discord?.isPartOfTeam\n ) {\n return false;\n }\n\n return (\n isMentioned ||\n (!this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions &&\n (message.content\n .toLowerCase()\n .includes(\n this.client.user?.username.toLowerCase() as string\n ) ||\n message.content\n .toLowerCase()\n .includes(\n this.client.user?.tag.toLowerCase() as string\n ) ||\n (nickname &&\n message.content\n .toLowerCase()\n .includes(nickname.toLowerCase()))))\n );\n }\n\n async processMessageMedia(\n message: DiscordMessage\n ): Promise<{ processedContent: string; attachments: Media[] }> {\n let processedContent = message.content;\n\n let attachments: Media[] = [];\n\n // Process code blocks in the message content\n const codeBlockRegex = /```([\\s\\S]*?)```/g;\n let match;\n while ((match = codeBlockRegex.exec(processedContent))) {\n const codeBlock = match[1];\n const lines = codeBlock.split(\"\\n\");\n const title = lines[0];\n const description = lines.slice(0, 3).join(\"\\n\");\n const attachmentId =\n `code-${Date.now()}-${Math.floor(Math.random() * 1000)}`.slice(\n -5\n );\n attachments.push({\n id: attachmentId,\n url: \"\",\n title: title || \"Code Block\",\n source: \"Code\",\n description: description,\n text: codeBlock,\n });\n processedContent = processedContent.replace(\n match[0],\n `Code Block (${attachmentId})`\n );\n }\n\n // Process message attachments\n if (message.attachments.size > 0) {\n attachments = await this.attachmentManager.processAttachments(\n message.attachments\n );\n }\n\n // TODO: Move to attachments manager\n const urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n const urls = processedContent.match(urlRegex) || [];\n\n for (const url of urls) {\n if (\n this.runtime\n .getService(ServiceType.VIDEO)\n ?.isVideoUrl(url)\n ) {\n const videoService = this.runtime.getService(\n ServiceType.VIDEO\n );\n if (!videoService) {\n throw new Error(\"Video service not found\");\n }\n const videoInfo = await videoService.processVideo(\n url,\n this.runtime\n );\n\n attachments.push({\n id: `youtube-${Date.now()}`,\n url: url,\n title: videoInfo.title,\n source: \"YouTube\",\n description: videoInfo.description,\n text: videoInfo.text,\n });\n } else {\n const browserService = this.runtime.getService(\n ServiceType.BROWSER\n );\n if (!browserService) {\n throw new Error(\"Browser service not found\");\n }\n\n const { title, description: summary } =\n await browserService.getPageContent(url, this.runtime);\n\n attachments.push({\n id: `webpage-${Date.now()}`,\n url: url,\n title: title || \"Web Page\",\n source: \"Web\",\n description: summary,\n text: summary,\n });\n }\n }\n\n return { processedContent, attachments };\n }\n\n private _getNormalizedUserId(id: string): string {\n return id.toString().replace(/[^0-9]/g, \"\");\n }\n\n private _isTeamMember(userId: string): boolean {\n const teamConfig = this.runtime.character.clientConfig?.discord;\n if (!teamConfig?.isPartOfTeam || !teamConfig.teamAgentIds) return false;\n\n const normalizedUserId = this._getNormalizedUserId(userId);\n\n const isTeamMember = teamConfig.teamAgentIds.some(\n (teamId) => this._getNormalizedUserId(teamId) === normalizedUserId\n );\n\n return isTeamMember;\n }\n\n private _isTeamLeader(): boolean {\n return (\n this.client.user?.id ===\n this.runtime.character.clientConfig?.discord?.teamLeaderId\n );\n }\n\n private _isTeamCoordinationRequest(content: string): boolean {\n const contentLower = content.toLowerCase();\n return TEAM_COORDINATION.KEYWORDS?.some((keyword) =>\n contentLower.includes(keyword.toLowerCase())\n );\n }\n\n private _isRelevantToTeamMember(\n content: string,\n channelId: string,\n lastAgentMemory: Memory | null = null\n ): boolean {\n const teamConfig = this.runtime.character.clientConfig?.discord;\n\n if (this._isTeamLeader() && lastAgentMemory?.content.text) {\n const timeSinceLastMessage = Date.now() - lastAgentMemory.createdAt;\n if (timeSinceLastMessage > MESSAGE_CONSTANTS.INTEREST_DECAY_TIME) {\n return false; // Memory too old, not relevant\n }\n\n const similarity = cosineSimilarity(\n content.toLowerCase(),\n lastAgentMemory.content.text.toLowerCase()\n );\n\n return (\n similarity >=\n MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS\n );\n }\n\n // If no keywords defined, only leader maintains conversation\n if (!teamConfig?.teamMemberInterestKeywords) {\n return false;\n }\n\n return teamConfig.teamMemberInterestKeywords.some((keyword) =>\n content.toLowerCase().includes(keyword.toLowerCase())\n );\n }\n\n private async _analyzeContextSimilarity(\n currentMessage: string,\n previousContext?: MessageContext,\n agentLastMessage?: string\n ): Promise {\n if (!previousContext) return 1; // No previous context to compare against\n\n // If more than 5 minutes have passed, reduce similarity weight\n const timeDiff = Date.now() - previousContext.timestamp;\n const timeWeight = Math.max(0, 1 - timeDiff / (5 * 60 * 1000)); // 5 minutes threshold\n\n // Calculate content similarity\n const similarity = cosineSimilarity(\n currentMessage.toLowerCase(),\n previousContext.content.toLowerCase(),\n agentLastMessage?.toLowerCase()\n );\n\n // Weight the similarity by time factor\n const weightedSimilarity = similarity * timeWeight;\n\n return weightedSimilarity;\n }\n\n private async _shouldRespondBasedOnContext(\n message: DiscordMessage,\n channelState: InterestChannels[string]\n ): Promise {\n // Always respond if directly mentioned\n if (this._isMessageForMe(message)) return true;\n\n // If we're not the current handler, don't respond\n if (channelState?.currentHandler !== this.client.user?.id) return false;\n\n // Check if we have messages to compare\n if (!channelState.messages?.length) return false;\n\n // Get last user message (not from the bot)\n const lastUserMessage = [...channelState.messages].reverse().find(\n (m, index) =>\n index > 0 && // Skip first message (current)\n m.userId !== this.runtime.agentId\n );\n\n if (!lastUserMessage) return false;\n\n const lastSelfMemories = await this.runtime.messageManager.getMemories({\n roomId: stringToUuid(\n message.channel.id + \"-\" + this.runtime.agentId\n ),\n unique: false,\n count: 5,\n });\n\n const lastSelfSortedMemories = lastSelfMemories\n ?.filter((m) => m.userId === this.runtime.agentId)\n .sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));\n\n // Calculate context similarity\n const contextSimilarity = await this._analyzeContextSimilarity(\n message.content,\n {\n content: lastUserMessage.content.text || \"\",\n timestamp: Date.now(),\n },\n lastSelfSortedMemories?.[0]?.content?.text\n );\n\n const similarityThreshold =\n this.runtime.character.clientConfig?.discord\n ?.messageSimilarityThreshold ||\n channelState.contextSimilarityThreshold ||\n MESSAGE_CONSTANTS.DEFAULT_SIMILARITY_THRESHOLD;\n\n return contextSimilarity >= similarityThreshold;\n }\n\n private _checkInterest(channelId: string): boolean {\n const channelState = this.interestChannels[channelId];\n if (!channelState) return false;\n\n const lastMessage =\n channelState.messages[channelState.messages.length - 1];\n // If it's been more than 5 minutes since last message, reduce interest\n const timeSinceLastMessage = Date.now() - channelState.lastMessageSent;\n\n if (timeSinceLastMessage > MESSAGE_CONSTANTS.INTEREST_DECAY_TIME) {\n delete this.interestChannels[channelId];\n return false;\n } else if (\n timeSinceLastMessage > MESSAGE_CONSTANTS.PARTIAL_INTEREST_DECAY\n ) {\n // Require stronger relevance for continued interest\n return this._isRelevantToTeamMember(\n lastMessage.content.text || \"\",\n channelId\n );\n }\n\n // If team leader and messages exist, check for topic changes and team member responses\n if (this._isTeamLeader() && channelState.messages.length > 0) {\n // If leader's keywords don't match and another team member has responded, drop interest\n if (\n !this._isRelevantToTeamMember(\n lastMessage.content.text || \"\",\n channelId\n )\n ) {\n const recentTeamResponses = channelState.messages\n .slice(-3)\n .some(\n (m) =>\n m.userId !== this.client.user?.id &&\n this._isTeamMember(m.userId)\n );\n\n if (recentTeamResponses) {\n delete this.interestChannels[channelId];\n return false;\n }\n }\n }\n\n // Check if conversation has shifted to a new topic\n if (channelState.messages.length > 0) {\n const recentMessages = channelState.messages.slice(\n -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT\n );\n const differentUsers = new Set(recentMessages.map((m) => m.userId))\n .size;\n\n // If multiple users are talking and we're not involved, reduce interest\n if (\n differentUsers > 1 &&\n !recentMessages.some((m) => m.userId === this.client.user?.id)\n ) {\n delete this.interestChannels[channelId];\n return false;\n }\n }\n\n return true;\n }\n\n private async _shouldIgnore(message: DiscordMessage): Promise {\n // if the message is from us, ignore\n if (message.author.id === this.client.user?.id) return true;\n\n // Honor mentions-only mode\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n return !this._isMessageForMe(message);\n }\n\n // Team-based ignore logic\n if (this.runtime.character.clientConfig?.discord?.isPartOfTeam) {\n const authorId = this._getNormalizedUserId(message.author.id);\n\n if (this._isTeamLeader()) {\n if (this._isTeamCoordinationRequest(message.content)) {\n return false;\n }\n // Ignore if message is only about team member interests and not directed to leader\n if (!this._isMessageForMe(message)) {\n const otherMemberInterests =\n this.runtime.character.clientConfig?.discord\n ?.teamMemberInterestKeywords || [];\n const hasOtherInterests = otherMemberInterests.some(\n (keyword) =>\n message.content\n .toLowerCase()\n .includes(keyword.toLowerCase())\n );\n if (hasOtherInterests) {\n return true;\n }\n }\n } else if (this._isTeamCoordinationRequest(message.content)) {\n const randomDelay =\n Math.floor(\n Math.random() *\n (TIMING_CONSTANTS.TEAM_MEMBER_DELAY_MAX -\n TIMING_CONSTANTS.TEAM_MEMBER_DELAY_MIN)\n ) + TIMING_CONSTANTS.TEAM_MEMBER_DELAY_MIN; // 1-3 second random delay\n await new Promise((resolve) =>\n setTimeout(resolve, randomDelay)\n );\n return false;\n }\n\n if (this._isTeamMember(authorId)) {\n if (!this._isMessageForMe(message)) {\n // If message contains our interests, don't ignore\n if (\n this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n return false;\n }\n return true;\n }\n }\n\n // Check if we're in an active conversation based on context\n const channelState = this.interestChannels[message.channelId];\n\n if (channelState?.currentHandler) {\n // If we're the current handler, check context\n if (channelState.currentHandler === this.client.user?.id) {\n //If it's our keywords, bypass context check\n if (\n this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n return false;\n }\n\n const shouldRespondContext =\n await this._shouldRespondBasedOnContext(\n message,\n channelState\n );\n\n // If context is different, ignore. If similar, don't ignore\n return !shouldRespondContext;\n }\n\n // If another team member is handling and we're not mentioned or coordinating\n else if (\n !this._isMessageForMe(message) &&\n !this._isTeamCoordinationRequest(message.content)\n ) {\n return true;\n }\n }\n }\n\n let messageContent = message.content.toLowerCase();\n\n // Replace the bot's @ping with the character name\n const botMention = `<@!?${this.client.user?.id}>`;\n messageContent = messageContent.replace(\n new RegExp(botMention, \"gi\"),\n this.runtime.character.name.toLowerCase()\n );\n\n // Replace the bot's username with the character name\n const botUsername = this.client.user?.username.toLowerCase();\n messageContent = messageContent.replace(\n new RegExp(`\\\\b${botUsername}\\\\b`, \"g\"),\n this.runtime.character.name.toLowerCase()\n );\n\n // strip all special characters\n messageContent = messageContent.replace(/[^a-zA-Z0-9\\s]/g, \"\");\n\n // short responses where eliza should stop talking and disengage unless mentioned again\n if (\n messageContent.length < MESSAGE_LENGTH_THRESHOLDS.LOSE_INTEREST &&\n LOSE_INTEREST_WORDS.some((word) => messageContent.includes(word))\n ) {\n delete this.interestChannels[message.channelId];\n return true;\n }\n\n // If we're not interested in the channel and it's a short message, ignore it\n if (\n messageContent.length < MESSAGE_LENGTH_THRESHOLDS.SHORT_MESSAGE &&\n !this.interestChannels[message.channelId]\n ) {\n return true;\n }\n\n const targetedPhrases = [\n this.runtime.character.name + \" stop responding\",\n this.runtime.character.name + \" stop talking\",\n this.runtime.character.name + \" shut up\",\n this.runtime.character.name + \" stfu\",\n \"stop talking\" + this.runtime.character.name,\n this.runtime.character.name + \" stop talking\",\n \"shut up \" + this.runtime.character.name,\n this.runtime.character.name + \" shut up\",\n \"stfu \" + this.runtime.character.name,\n this.runtime.character.name + \" stfu\",\n \"chill\" + this.runtime.character.name,\n this.runtime.character.name + \" chill\",\n ];\n\n // lose interest if pinged and told to stop responding\n if (targetedPhrases.some((phrase) => messageContent.includes(phrase))) {\n delete this.interestChannels[message.channelId];\n return true;\n }\n\n // if the message is short, ignore but maintain interest\n if (\n !this.interestChannels[message.channelId] &&\n messageContent.length < MESSAGE_LENGTH_THRESHOLDS.VERY_SHORT_MESSAGE\n ) {\n return true;\n }\n\n if (\n message.content.length <\n MESSAGE_LENGTH_THRESHOLDS.IGNORE_RESPONSE &&\n IGNORE_RESPONSE_WORDS.some((word) =>\n message.content.toLowerCase().includes(word)\n )\n ) {\n return true;\n }\n return false;\n }\n\n private async _shouldRespond(\n message: DiscordMessage,\n state: State\n ): Promise {\n if (message.author.id === this.client.user?.id) return false;\n // if (message.author.bot) return false;\n\n // Honor mentions-only mode\n if (\n this.runtime.character.clientConfig?.discord\n ?.shouldRespondOnlyToMentions\n ) {\n return this._isMessageForMe(message);\n }\n\n const channelState = this.interestChannels[message.channelId];\n\n // Check if team member has direct interest first\n if (\n this.runtime.character.clientConfig?.discord?.isPartOfTeam &&\n !this._isTeamLeader() &&\n this._isRelevantToTeamMember(message.content, message.channelId)\n ) {\n return true;\n }\n\n try {\n // Team-based response logic\n if (this.runtime.character.clientConfig?.discord?.isPartOfTeam) {\n // Team leader coordination\n if (\n this._isTeamLeader() &&\n this._isTeamCoordinationRequest(message.content)\n ) {\n return true;\n }\n\n if (\n !this._isTeamLeader() &&\n this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n // Add small delay for non-leader responses\n await new Promise((resolve) =>\n setTimeout(resolve, TIMING_CONSTANTS.TEAM_MEMBER_DELAY)\n ); //1.5 second delay\n\n // If leader has responded in last few seconds, reduce chance of responding\n\n if (channelState?.messages?.length) {\n const recentMessages = channelState.messages.slice(\n -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT\n );\n const leaderResponded = recentMessages.some(\n (m) =>\n m.userId ===\n this.runtime.character.clientConfig?.discord\n ?.teamLeaderId &&\n Date.now() - channelState.lastMessageSent < 3000\n );\n\n if (leaderResponded) {\n // 50% chance to respond if leader just did\n return (\n Math.random() > RESPONSE_CHANCES.AFTER_LEADER\n );\n }\n }\n\n return true;\n }\n\n // If I'm the leader but message doesn't match my keywords, add delay and check for team responses\n if (\n this._isTeamLeader() &&\n !this._isRelevantToTeamMember(\n message.content,\n message.channelId\n )\n ) {\n const randomDelay =\n Math.floor(\n Math.random() *\n (TIMING_CONSTANTS.LEADER_DELAY_MAX -\n TIMING_CONSTANTS.LEADER_DELAY_MIN)\n ) + TIMING_CONSTANTS.LEADER_DELAY_MIN; // 2-4 second random delay\n await new Promise((resolve) =>\n setTimeout(resolve, randomDelay)\n );\n\n // After delay, check if another team member has already responded\n if (channelState?.messages?.length) {\n const recentResponses = channelState.messages.slice(\n -MESSAGE_CONSTANTS.RECENT_MESSAGE_COUNT\n );\n const otherTeamMemberResponded = recentResponses.some(\n (m) =>\n m.userId !== this.client.user?.id &&\n this._isTeamMember(m.userId)\n );\n\n if (otherTeamMemberResponded) {\n return false;\n }\n }\n }\n\n // Update current handler if we're mentioned\n if (this._isMessageForMe(message)) {\n const channelState =\n this.interestChannels[message.channelId];\n if (channelState) {\n channelState.currentHandler = this.client.user?.id;\n channelState.lastMessageSent = Date.now();\n }\n return true;\n }\n\n // Don't respond if another teammate is handling the conversation\n if (channelState?.currentHandler) {\n if (\n channelState.currentHandler !== this.client.user?.id &&\n this._isTeamMember(channelState.currentHandler)\n ) {\n return false;\n }\n }\n\n // Natural conversation cadence\n if (!this._isMessageForMe(message) && channelState) {\n // Count our recent messages\n const recentMessages = channelState.messages.slice(\n -MESSAGE_CONSTANTS.CHAT_HISTORY_COUNT\n );\n const ourMessageCount = recentMessages.filter(\n (m) => m.userId === this.client.user?.id\n ).length;\n\n // Reduce responses if we've been talking a lot\n if (ourMessageCount > 2) {\n // Exponentially decrease chance to respond\n const responseChance = Math.pow(\n 0.5,\n ourMessageCount - 2\n );\n if (Math.random() > responseChance) {\n return false;\n }\n }\n }\n }\n } catch (error) {\n elizaLogger.error(\"Error in _shouldRespond team processing:\", {\n error,\n agentId: this.runtime.agentId,\n channelId: message.channelId,\n });\n }\n\n // Otherwise do context check\n if (channelState?.previousContext) {\n const shouldRespondContext =\n await this._shouldRespondBasedOnContext(message, channelState);\n if (!shouldRespondContext) {\n delete this.interestChannels[message.channelId];\n return false;\n }\n }\n\n if (message.mentions.has(this.client.user?.id as string)) return true;\n\n const guild = message.guild;\n const member = guild?.members.cache.get(this.client.user?.id as string);\n const nickname = member?.nickname;\n\n if (\n message.content\n .toLowerCase()\n .includes(this.client.user?.username.toLowerCase() as string) ||\n message.content\n .toLowerCase()\n .includes(this.client.user?.tag.toLowerCase() as string) ||\n (nickname &&\n message.content.toLowerCase().includes(nickname.toLowerCase()))\n ) {\n return true;\n }\n\n if (!message.guild) {\n return true;\n }\n\n // If none of the above conditions are met, use the generateText to decide\n const shouldRespondContext = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordShouldRespondTemplate ||\n this.runtime.character.templates?.shouldRespondTemplate ||\n composeRandomUser(discordShouldRespondTemplate, 2),\n });\n\n const response = await generateShouldRespond({\n runtime: this.runtime,\n context: shouldRespondContext,\n modelClass: ModelClass.SMALL,\n });\n\n if (response === \"RESPOND\") {\n if (channelState) {\n channelState.previousContext = {\n content: message.content,\n timestamp: Date.now(),\n };\n }\n\n return true;\n } else if (response === \"IGNORE\") {\n return false;\n } else if (response === \"STOP\") {\n delete this.interestChannels[message.channelId];\n return false;\n } else {\n console.error(\n \"Invalid response from response generateText:\",\n response\n );\n return false;\n }\n }\n\n private async _generateResponse(\n message: Memory,\n state: State,\n context: string\n ): Promise {\n const { userId, roomId } = message;\n\n const response = await generateMessageResponse({\n runtime: this.runtime,\n context,\n modelClass: ModelClass.LARGE,\n });\n\n if (!response) {\n console.error(\"No response from generateMessageResponse\");\n return;\n }\n\n await this.runtime.databaseAdapter.log({\n body: { message, context, response },\n userId: userId,\n roomId,\n type: \"response\",\n });\n\n return response;\n }\n\n async fetchBotName(botToken: string) {\n const url = \"https://discord.com/api/v10/users/@me\";\n\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bot ${botToken}`,\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Error fetching bot details: ${response.statusText}`\n );\n }\n\n const data = await response.json();\n return data.username;\n }\n\n /**\n * Simulate discord typing while generating a response;\n * returns a function to interrupt the typing loop\n *\n * @param message\n */\n private simulateTyping(message: DiscordMessage) {\n let typing = true;\n\n const typingLoop = async () => {\n while (typing) {\n await message.channel.sendTyping();\n await new Promise((resolve) => setTimeout(resolve, 3000));\n }\n };\n\n typingLoop();\n\n return function stopTyping() {\n typing = false;\n };\n }\n}\n","import { generateText, trimTokens } from \"@elizaos/core\";\nimport { parseJSONObjectFromText } from \"@elizaos/core\";\nimport {\n type IAgentRuntime,\n type IImageDescriptionService,\n type IPdfService,\n type ITranscriptionService,\n type IVideoService,\n type Media,\n ModelClass,\n ServiceType,\n} from \"@elizaos/core\";\nimport { type Attachment, Collection } from \"discord.js\";\nimport ffmpeg from \"fluent-ffmpeg\";\nimport fs from \"fs\";\n\nasync function generateSummary(\n runtime: IAgentRuntime,\n text: string\n): Promise<{ title: string; description: string }> {\n // make sure text is under 128k characters\n text = await trimTokens(text, 100000, runtime);\n\n const 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 const response = await generateText({\n runtime,\n context: prompt,\n modelClass: ModelClass.SMALL,\n });\n\n const parsedResponse = parseJSONObjectFromText(response);\n\n if (parsedResponse?.title && parsedResponse?.summary) {\n return {\n title: parsedResponse.title,\n description: parsedResponse.summary,\n };\n }\n\n return {\n title: \"\",\n description: \"\",\n };\n}\n\nexport class AttachmentManager {\n private attachmentCache: Map = new Map();\n private runtime: IAgentRuntime;\n\n constructor(runtime: IAgentRuntime) {\n this.runtime = runtime;\n }\n\n async processAttachments(\n attachments: Collection | Attachment[]\n ): Promise {\n const processedAttachments: Media[] = [];\n const attachmentCollection =\n attachments instanceof Collection\n ? attachments\n : new Collection(attachments.map((att) => [att.id, att]));\n\n for (const [, attachment] of attachmentCollection) {\n const media = await this.processAttachment(attachment);\n if (media) {\n processedAttachments.push(media);\n }\n }\n\n return processedAttachments;\n }\n\n async processAttachment(attachment: Attachment): Promise {\n if (this.attachmentCache.has(attachment.url)) {\n return this.attachmentCache.get(attachment.url)!;\n }\n\n let media: Media | null = null;\n if (attachment.contentType?.startsWith(\"application/pdf\")) {\n media = await this.processPdfAttachment(attachment);\n } else if (attachment.contentType?.startsWith(\"text/plain\")) {\n media = await this.processPlaintextAttachment(attachment);\n } else if (\n attachment.contentType?.startsWith(\"audio/\") ||\n attachment.contentType?.startsWith(\"video/mp4\")\n ) {\n media = await this.processAudioVideoAttachment(attachment);\n } else if (attachment.contentType?.startsWith(\"image/\")) {\n media = await this.processImageAttachment(attachment);\n } else if (\n attachment.contentType?.startsWith(\"video/\") ||\n this.runtime\n .getService(ServiceType.VIDEO)\n .isVideoUrl(attachment.url)\n ) {\n media = await this.processVideoAttachment(attachment);\n } else {\n media = await this.processGenericAttachment(attachment);\n }\n\n if (media) {\n this.attachmentCache.set(attachment.url, media);\n }\n return media;\n }\n\n private async processAudioVideoAttachment(\n attachment: Attachment\n ): Promise {\n try {\n const response = await fetch(attachment.url);\n const audioVideoArrayBuffer = await response.arrayBuffer();\n\n let audioBuffer: Buffer;\n if (attachment.contentType?.startsWith(\"audio/\")) {\n audioBuffer = Buffer.from(audioVideoArrayBuffer);\n } else if (attachment.contentType?.startsWith(\"video/mp4\")) {\n audioBuffer = await this.extractAudioFromMP4(\n audioVideoArrayBuffer\n );\n } else {\n throw new Error(\"Unsupported audio/video format\");\n }\n\n const transcriptionService =\n this.runtime.getService(\n ServiceType.TRANSCRIPTION\n );\n if (!transcriptionService) {\n throw new Error(\"Transcription service not found\");\n }\n\n const transcription =\n await transcriptionService.transcribeAttachment(audioBuffer);\n const { title, description } = await generateSummary(\n this.runtime,\n transcription\n );\n\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"Audio/Video Attachment\",\n source: attachment.contentType?.startsWith(\"audio/\")\n ? \"Audio\"\n : \"Video\",\n description:\n description ||\n \"User-uploaded audio/video attachment which has been transcribed\",\n text: transcription || \"Audio/video content not available\",\n };\n } catch (error) {\n console.error(\n `Error processing audio/video attachment: ${error.message}`\n );\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Audio/Video Attachment\",\n source: attachment.contentType?.startsWith(\"audio/\")\n ? \"Audio\"\n : \"Video\",\n description: \"An audio/video attachment (transcription failed)\",\n text: `This is an audio/video attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}`,\n };\n }\n }\n\n private async extractAudioFromMP4(mp4Data: ArrayBuffer): Promise {\n // Use a library like 'fluent-ffmpeg' or 'ffmpeg-static' to extract the audio stream from the MP4 data\n // and convert it to MP3 or WAV format\n // Example using fluent-ffmpeg:\n const tempMP4File = `temp_${Date.now()}.mp4`;\n const tempAudioFile = `temp_${Date.now()}.mp3`;\n\n try {\n // Write the MP4 data to a temporary file\n fs.writeFileSync(tempMP4File, Buffer.from(mp4Data));\n\n // Extract the audio stream and convert it to MP3\n await new Promise((resolve, reject) => {\n ffmpeg(tempMP4File)\n .outputOptions(\"-vn\") // Disable video output\n .audioCodec(\"libmp3lame\") // Set audio codec to MP3\n .save(tempAudioFile) // Save the output to the specified file\n .on(\"end\", () => {\n resolve();\n })\n .on(\"error\", (err) => {\n reject(err);\n })\n .run();\n });\n\n // Read the converted audio file and return it as a Buffer\n const audioData = fs.readFileSync(tempAudioFile);\n return audioData;\n } finally {\n // Clean up the temporary files\n if (fs.existsSync(tempMP4File)) {\n fs.unlinkSync(tempMP4File);\n }\n if (fs.existsSync(tempAudioFile)) {\n fs.unlinkSync(tempAudioFile);\n }\n }\n }\n\n private async processPdfAttachment(attachment: Attachment): Promise {\n try {\n const response = await fetch(attachment.url);\n const pdfBuffer = await response.arrayBuffer();\n const text = await this.runtime\n .getService(ServiceType.PDF)\n .convertPdfToText(Buffer.from(pdfBuffer));\n const { title, description } = await generateSummary(\n this.runtime,\n text\n );\n\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"PDF Attachment\",\n source: \"PDF\",\n description: description || \"A PDF document\",\n text: text,\n };\n } catch (error) {\n console.error(`Error processing PDF attachment: ${error.message}`);\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"PDF Attachment (conversion failed)\",\n source: \"PDF\",\n description:\n \"A PDF document that could not be converted to text\",\n text: `This is a PDF attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes`,\n };\n }\n }\n\n private async processPlaintextAttachment(\n attachment: Attachment\n ): Promise {\n try {\n const response = await fetch(attachment.url);\n const text = await response.text();\n const { title, description } = await generateSummary(\n this.runtime,\n text\n );\n\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"Plaintext Attachment\",\n source: \"Plaintext\",\n description: description || \"A plaintext document\",\n text: text,\n };\n } catch (error) {\n console.error(\n `Error processing plaintext attachment: ${error.message}`\n );\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Plaintext Attachment (retrieval failed)\",\n source: \"Plaintext\",\n description: \"A plaintext document that could not be retrieved\",\n text: `This is a plaintext attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes`,\n };\n }\n }\n\n private async processImageAttachment(\n attachment: Attachment\n ): Promise {\n try {\n const { description, title } = await this.runtime\n .getService(\n ServiceType.IMAGE_DESCRIPTION\n )\n .describeImage(attachment.url);\n return {\n id: attachment.id,\n url: attachment.url,\n title: title || \"Image Attachment\",\n source: \"Image\",\n description: description || \"An image attachment\",\n text: description || \"Image content not available\",\n };\n } catch (error) {\n console.error(\n `Error processing image attachment: ${error.message}`\n );\n return this.createFallbackImageMedia(attachment);\n }\n }\n\n private createFallbackImageMedia(attachment: Attachment): Media {\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Image Attachment\",\n source: \"Image\",\n description: \"An image attachment (recognition failed)\",\n text: `This is an image attachment. File name: ${attachment.name}, Size: ${attachment.size} bytes, Content type: ${attachment.contentType}`,\n };\n }\n\n private async processVideoAttachment(\n attachment: Attachment\n ): Promise {\n const videoService = this.runtime.getService(\n ServiceType.VIDEO\n );\n\n if (!videoService) {\n throw new Error(\"Video service not found\");\n }\n\n if (videoService.isVideoUrl(attachment.url)) {\n const videoInfo = await videoService.processVideo(\n attachment.url,\n this.runtime\n );\n return {\n id: attachment.id,\n url: attachment.url,\n title: videoInfo.title,\n source: \"YouTube\",\n description: videoInfo.description,\n text: videoInfo.text,\n };\n } else {\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Video Attachment\",\n source: \"Video\",\n description: \"A video attachment\",\n text: \"Video content not available\",\n };\n }\n }\n\n private async processGenericAttachment(\n attachment: Attachment\n ): Promise {\n return {\n id: attachment.id,\n url: attachment.url,\n title: \"Generic Attachment\",\n source: \"Generic\",\n description: \"A generic attachment\",\n text: \"Attachment content not available\",\n };\n }\n}\n","import { messageCompletionFooter, shouldRespondFooter } from \"@elizaos/core\";\n\nexport const discordShouldRespondTemplate =\n `# Task: Decide if {{agentName}} should respond.\nAbout {{agentName}}:\n{{bio}}\n\n# INSTRUCTIONS: Determine if {{agentName}} should respond to the message and participate in the conversation. Do not comment. Just respond with \"RESPOND\" or \"IGNORE\" or \"STOP\".\n\n# RESPONSE EXAMPLES\n{{user1}}: I just saw a really great movie\n{{user2}}: Oh? Which movie?\nResult: [IGNORE]\n\n{{agentName}}: Oh, this is my favorite scene\n{{user1}}: sick\n{{user2}}: wait, why is it your favorite scene\nResult: [RESPOND]\n\n{{user1}}: stfu bot\nResult: [STOP]\n\n{{user1}}: Hey {{agent}}, can you help me with something\nResult: [RESPOND]\n\n{{user1}}: {{agentName}} stfu plz\nResult: [STOP]\n\n{{user1}}: i need help\n{{agentName}}: how can I help you?\n{{user1}}: no. i need help from someone else\nResult: [IGNORE]\n\n{{user1}}: Hey {{agent}}, can I ask you a question\n{{agentName}}: Sure, what is it\n{{user1}}: can you ask claude to create a basic react module that demonstrates a counter\nResult: [RESPOND]\n\n{{user1}}: {{agentName}} can you tell me a story\n{{user1}}: about a girl named elara\n{{agentName}}: Sure.\n{{agentName}}: Once upon a time, in a quaint little village, there was a curious girl named Elara.\n{{agentName}}: Elara was known for her adventurous spirit and her knack for finding beauty in the mundane.\n{{user1}}: I'm loving it, keep going\nResult: [RESPOND]\n\n{{user1}}: {{agentName}} stop responding plz\nResult: [STOP]\n\n{{user1}}: okay, i want to test something. can you say marco?\n{{agentName}}: marco\n{{user1}}: great. okay, now do it again\nResult: [RESPOND]\n\nResponse options are [RESPOND], [IGNORE] and [STOP].\n\n{{agentName}} is in a room with other users and is very worried about being annoying and saying too much.\nRespond with [RESPOND] to messages that are directed at {{agentName}}, or participate in conversations that are interesting or relevant to their background.\nIf a message is not interesting or relevant, respond with [IGNORE]\nUnless directly responding to a user, respond with [IGNORE] to messages that are very short or do not contain much information.\nIf a user asks {{agentName}} to be quiet, respond with [STOP]\nIf {{agentName}} concludes a conversation and isn't part of the conversation anymore, respond with [STOP]\n\nIMPORTANT: {{agentName}} is particularly sensitive about being annoying, so if there is any doubt, it is better to respond with [IGNORE].\nIf {{agentName}} is conversing with a user and they have not asked to stop, it is better to respond with [RESPOND].\n\n{{recentMessages}}\n\n# INSTRUCTIONS: Choose the option that best describes {{agentName}}'s response to the last message. Ignore messages if they are addressed to someone else.\n` + shouldRespondFooter;\n\nexport const discordVoiceHandlerTemplate =\n `# Task: Generate conversational voice dialog for {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n\n# Attachments\n{{attachments}}\n\n# Capabilities\nNote that {{agentName}} is capable of reading/seeing/hearing various forms of media, including images, videos, audio, plaintext and PDFs. Recent attachments have been included above under the \"Attachments\" section.\n\n{{actions}}\n\n{{messageDirections}}\n\n{{recentMessages}}\n\n# Instructions: Write the next message for {{agentName}}. Include an optional action if appropriate. {{actionNames}}\n` + messageCompletionFooter;\n\nexport const discordMessageHandlerTemplate =\n // {{goals}}\n `# Action Examples\n{{actionExamples}}\n(Action examples are for reference only. Do not use the information from them in your response.)\n\n# Knowledge\n{{knowledge}}\n\n# Task: Generate dialog and actions for the character {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n{{lore}}\n\nExamples of {{agentName}}'s dialog and actions:\n{{characterMessageExamples}}\n\n{{providers}}\n\n{{attachments}}\n\n{{actions}}\n\n# Capabilities\nNote that {{agentName}} is capable of reading/seeing/hearing various forms of media, including images, videos, audio, plaintext and PDFs. Recent attachments have been included above under the \"Attachments\" section.\n\n{{messageDirections}}\n\n{{recentMessages}}\n\n# Instructions: Write the next message for {{agentName}}. Include an action, if appropriate. {{actionNames}}\n` + messageCompletionFooter;\n\nexport const discordAutoPostTemplate =\n `# Action Examples\nNONE: Respond but perform no additional action. This is the default if the agent is speaking and not doing anything additional.\n\n# Task: Generate an engaging community message as {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n{{lore}}\n\nExamples of {{agentName}}'s dialog and actions:\n{{characterMessageExamples}}\n\n{{messageDirections}}\n\n# Recent Chat History:\n{{recentMessages}}\n\n# Instructions: Write a natural, engaging message to restart community conversation. Focus on:\n- Community engagement\n- Educational topics\n- General discusions\n- Support queries\n- Keep message warm and inviting\n- Maximum 3 lines\n- Use 1-2 emojis maximum\n- Avoid financial advice\n- Stay within known facts\n- No team member mentions\n- Be hyped, not repetitive\n- Be natural, act like a human, connect with the community\n- Don't sound so robotic like\n- Randomly grab the most recent 5 messages for some context. Validate the context randomly and use that as a reference point for your next message, but not always, only when relevant.\n- If the recent messages are mostly from {{agentName}}, make sure to create conversation starters, given there is no messages from others to reference.\n- DO NOT REPEAT THE SAME thing that you just said from your recent chat history, start the message different each time, and be organic, non reptitive.\n\n# Instructions: Write the next message for {{agentName}}. Include the \"NONE\" action only, as the only valid action for auto-posts is \"NONE\".\n` + messageCompletionFooter;\n\nexport const discordAnnouncementHypeTemplate =\n `# Action Examples\nNONE: Respond but perform no additional action. This is the default if the agent is speaking and not doing anything additional.\n\n# Task: Generate announcement hype message as {{agentName}}.\nAbout {{agentName}}:\n{{bio}}\n{{lore}}\n\nExamples of {{agentName}}'s dialog and actions:\n{{characterMessageExamples}}\n\n{{messageDirections}}\n\n# Announcement Content:\n{{announcementContent}}\n\n# Instructions: Write an exciting message to bring attention to the announcement. Requirements:\n- Reference the announcement channel using <#{{announcementChannelId}}>\n- Reference the announcement content to get information about the announcement to use where appropriate to make the message dynamic vs a static post\n- Create genuine excitement\n- Encourage community participation\n- If there are links like Twitter/X posts, encourage users to like/retweet/comment to spread awarenress, but directly say that, wrap that into the post so its natural.\n- Stay within announced facts only\n- No additional promises or assumptions\n- No team member mentions\n- Start the message differently each time. Don't start with the same word like \"hey\", \"hey hey\", etc. be dynamic\n- Address everyone, not as a direct reply to whoever made the announcement or wrote it, but you can reference them\n- Maximum 3-7 lines formatted nicely if needed, based on the context of the announcement\n- Use 1-2 emojis maximum\n\n# Instructions: Write the next message for {{agentName}}. Include the \"NONE\" action only, as no other actions are appropriate for announcement hype.\n` + messageCompletionFooter;","export const TEAM_COORDINATION = {\n KEYWORDS: [\n \"team\",\n \"all agents\",\n \"team update\",\n \"gm team\",\n \"hello team\",\n \"hey team\",\n \"hi team\",\n \"morning team\",\n \"evening team\",\n \"night team\",\n \"update team\",\n ],\n} as const;\n\nexport const MESSAGE_CONSTANTS = {\n MAX_MESSAGES: 10,\n RECENT_MESSAGE_COUNT: 3,\n CHAT_HISTORY_COUNT: 5,\n INTEREST_DECAY_TIME: 5 * 60 * 1000, // 5 minutes\n PARTIAL_INTEREST_DECAY: 3 * 60 * 1000, // 3 minutes\n DEFAULT_SIMILARITY_THRESHOLD: 0.3,\n DEFAULT_SIMILARITY_THRESHOLD_FOLLOW_UPS: 0.2,\n} as const;\n\nexport const MESSAGE_LENGTH_THRESHOLDS = {\n LOSE_INTEREST: 100,\n SHORT_MESSAGE: 10,\n VERY_SHORT_MESSAGE: 2,\n IGNORE_RESPONSE: 4,\n} as const;\n\nexport const TIMING_CONSTANTS = {\n LEADER_RESPONSE_TIMEOUT: 3000,\n TEAM_MEMBER_DELAY: 1500,\n LEADER_DELAY_MIN: 3000,\n LEADER_DELAY_MAX: 4000,\n TEAM_MEMBER_DELAY_MIN: 1000,\n TEAM_MEMBER_DELAY_MAX: 3000,\n} as const;\n\nexport const RESPONSE_CHANCES = {\n AFTER_LEADER: 0.5, // 50% chance\n FREQUENT_CHATTER: 0.5, // Base chance for frequent responders\n} as const;\n\nexport const LOSE_INTEREST_WORDS = [\n \"shut up\",\n \"stop\",\n \"please shut up\",\n \"shut up please\",\n \"dont talk\",\n \"silence\",\n \"stop talking\",\n \"be quiet\",\n \"hush\",\n \"wtf\",\n \"chill\",\n \"stfu\",\n \"stupid bot\",\n \"dumb bot\",\n \"stop responding\",\n \"god damn it\",\n \"god damn\",\n \"goddamnit\",\n \"can you not\",\n \"can you stop\",\n \"be quiet\",\n \"hate you\",\n \"hate this\",\n \"fuck up\",\n] as const;\n\nexport const IGNORE_RESPONSE_WORDS = [\n \"lol\",\n \"nm\",\n \"uh\",\n \"wtf\",\n \"stfu\",\n \"dumb\",\n \"jfc\",\n \"omg\",\n] as const;\n","import {\n type IAgentRuntime,\n ModelClass,\n elizaLogger,\n generateText,\n trimTokens,\n parseJSONObjectFromText,\n} from \"@elizaos/core\";\nimport {\n ChannelType,\n type Message as DiscordMessage,\n PermissionsBitField,\n type TextChannel,\n ThreadChannel,\n} from \"discord.js\";\n\nexport function getWavHeader(\n audioLength: number,\n sampleRate: number,\n channelCount = 1,\n bitsPerSample = 16\n): Buffer {\n const wavHeader = Buffer.alloc(44);\n wavHeader.write(\"RIFF\", 0);\n wavHeader.writeUInt32LE(36 + audioLength, 4); // Length of entire file in bytes minus 8\n wavHeader.write(\"WAVE\", 8);\n wavHeader.write(\"fmt \", 12);\n wavHeader.writeUInt32LE(16, 16); // Length of format data\n wavHeader.writeUInt16LE(1, 20); // Type of format (1 is PCM)\n wavHeader.writeUInt16LE(channelCount, 22); // Number of channels\n wavHeader.writeUInt32LE(sampleRate, 24); // Sample rate\n wavHeader.writeUInt32LE(\n (sampleRate * bitsPerSample * channelCount) / 8,\n 28\n ); // Byte rate\n wavHeader.writeUInt16LE((bitsPerSample * channelCount) / 8, 32); // Block align ((BitsPerSample * Channels) / 8)\n wavHeader.writeUInt16LE(bitsPerSample, 34); // Bits per sample\n wavHeader.write(\"data\", 36); // Data chunk header\n wavHeader.writeUInt32LE(audioLength, 40); // Data chunk size\n return wavHeader;\n}\n\nconst MAX_MESSAGE_LENGTH = 1900;\n\nexport async function generateSummary(\n runtime: IAgentRuntime,\n text: string\n): Promise<{ title: string; description: string }> {\n // make sure text is under 128k characters\n text = await trimTokens(text, 100000, runtime);\n\n const 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 const response = await generateText({\n runtime,\n context: prompt,\n modelClass: ModelClass.SMALL,\n });\n\n const parsedResponse = parseJSONObjectFromText(response);\n\n if (parsedResponse?.title && parsedResponse?.summary) {\n return {\n title: parsedResponse.title,\n description: parsedResponse.summary,\n };\n }\n\n return {\n title: \"\",\n description: \"\",\n };\n}\n\nexport async function sendMessageInChunks(\n channel: TextChannel,\n content: string,\n inReplyTo: string,\n files: any[]\n): Promise {\n const sentMessages: DiscordMessage[] = [];\n const messages = splitMessage(content);\n try {\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i];\n if (\n message.trim().length > 0 ||\n (i === messages.length - 1 && files && files.length > 0)\n ) {\n const options: any = {\n content: message.trim(),\n };\n\n // if (i === 0 && inReplyTo) {\n // // Reply to the specified message for the first chunk\n // options.reply = {\n // messageReference: inReplyTo,\n // };\n // }\n\n if (i === messages.length - 1 && files && files.length > 0) {\n // Attach files to the last message chunk\n options.files = files;\n }\n\n const m = await channel.send(options);\n sentMessages.push(m);\n }\n }\n } catch (error) {\n elizaLogger.error(\"Error sending message:\", error);\n }\n\n return sentMessages;\n}\n\nfunction splitMessage(content: string): string[] {\n const messages: string[] = [];\n let currentMessage = \"\";\n\n const rawLines = content?.split(\"\\n\") || [];\n // split all lines into MAX_MESSAGE_LENGTH chunks so any long lines are split\n const lines = rawLines.flatMap((line) => {\n const chunks = [];\n while (line.length > MAX_MESSAGE_LENGTH) {\n chunks.push(line.slice(0, MAX_MESSAGE_LENGTH));\n line = line.slice(MAX_MESSAGE_LENGTH);\n }\n chunks.push(line);\n return chunks;\n });\n\n for (const line of lines) {\n if (currentMessage.length + line.length + 1 > MAX_MESSAGE_LENGTH) {\n messages.push(currentMessage.trim());\n currentMessage = \"\";\n }\n currentMessage += line + \"\\n\";\n }\n\n if (currentMessage.trim().length > 0) {\n messages.push(currentMessage.trim());\n }\n\n return messages;\n}\n\nexport function canSendMessage(channel) {\n // validate input\n if (!channel) {\n return {\n canSend: false,\n reason: \"No channel given\",\n };\n }\n // if it is a DM channel, we can always send messages\n if (channel.type === ChannelType.DM) {\n return {\n canSend: true,\n reason: null,\n };\n }\n const botMember = channel.guild?.members.cache.get(channel.client.user.id);\n\n if (!botMember) {\n return {\n canSend: false,\n reason: \"Not a guild channel or bot member not found\",\n };\n }\n\n // Required permissions for sending messages\n const requiredPermissions = [\n PermissionsBitField.Flags.ViewChannel,\n PermissionsBitField.Flags.SendMessages,\n PermissionsBitField.Flags.ReadMessageHistory,\n ];\n\n // Add thread-specific permission if it's a thread\n if (channel instanceof ThreadChannel) {\n requiredPermissions.push(\n PermissionsBitField.Flags.SendMessagesInThreads\n );\n }\n\n // Check permissions\n const permissions = channel.permissionsFor(botMember);\n\n if (!permissions) {\n return {\n canSend: false,\n reason: \"Could not retrieve permissions\",\n };\n }\n\n // Check each required permission\n const missingPermissions = requiredPermissions.filter(\n (perm) => !permissions.has(perm)\n );\n\n return {\n canSend: missingPermissions.length === 0,\n missingPermissions: missingPermissions,\n reason:\n missingPermissions.length > 0\n ? `Missing permissions: ${missingPermissions\n .map((p) => String(p))\n .join(\", \")}`\n : null,\n };\n}\n\nexport function cosineSimilarity(\n text1: string,\n text2: string,\n text3?: string\n): number {\n const preprocessText = (text: string) =>\n text\n .toLowerCase()\n .replace(/[^\\w\\s'_-]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n\n const getWords = (text: string) => {\n return text.split(\" \").filter((word) => word.length > 1);\n };\n\n const words1 = getWords(preprocessText(text1));\n const words2 = getWords(preprocessText(text2));\n const words3 = text3 ? getWords(preprocessText(text3)) : [];\n\n const freq1: { [key: string]: number } = {};\n const freq2: { [key: string]: number } = {};\n const freq3: { [key: string]: number } = {};\n\n words1.forEach((word) => (freq1[word] = (freq1[word] || 0) + 1));\n words2.forEach((word) => (freq2[word] = (freq2[word] || 0) + 1));\n if (words3.length) {\n words3.forEach((word) => (freq3[word] = (freq3[word] || 0) + 1));\n }\n\n const uniqueWords = new Set([\n ...Object.keys(freq1),\n ...Object.keys(freq2),\n ...(words3.length ? Object.keys(freq3) : []),\n ]);\n\n let dotProduct = 0;\n let magnitude1 = 0;\n let magnitude2 = 0;\n let magnitude3 = 0;\n\n uniqueWords.forEach((word) => {\n const val1 = freq1[word] || 0;\n const val2 = freq2[word] || 0;\n const val3 = freq3[word] || 0;\n\n if (words3.length) {\n // For three-way, calculate pairwise similarities\n const sim12 = val1 * val2;\n const sim23 = val2 * val3;\n const sim13 = val1 * val3;\n\n // Take maximum similarity between any pair\n dotProduct += Math.max(sim12, sim23, sim13);\n } else {\n dotProduct += val1 * val2;\n }\n\n magnitude1 += val1 * val1;\n magnitude2 += val2 * val2;\n if (words3.length) {\n magnitude3 += val3 * val3;\n }\n });\n\n magnitude1 = Math.sqrt(magnitude1);\n magnitude2 = Math.sqrt(magnitude2);\n magnitude3 = words3.length ? Math.sqrt(magnitude3) : 1;\n\n if (\n magnitude1 === 0 ||\n magnitude2 === 0 ||\n (words3.length && magnitude3 === 0)\n )\n return 0;\n\n // For two texts, use original calculation\n if (!words3.length) {\n return dotProduct / (magnitude1 * magnitude2);\n }\n\n // For three texts, use max magnitude pair to maintain scale\n const maxMagnitude = Math.max(\n magnitude1 * magnitude2,\n magnitude2 * magnitude3,\n magnitude1 * magnitude3\n );\n\n return dotProduct / maxMagnitude;\n}\n","import {\n ChannelType,\n type Message as DiscordMessage,\n type TextChannel,\n} from \"discord.js\";\nimport type { IAgentRuntime, Memory, Provider, State } from \"@elizaos/core\";\n\nconst channelStateProvider: Provider = {\n get: async (runtime: IAgentRuntime, message: Memory, state?: State) => {\n const discordMessage =\n (state?.discordMessage as DiscordMessage) ||\n (state?.discordChannel as DiscordMessage);\n if (!discordMessage) {\n return \"\";\n }\n\n const guild = discordMessage?.guild;\n const agentName = state?.agentName || \"The agent\";\n const senderName = state?.senderName || \"someone\";\n\n if (!guild) {\n return (\n agentName +\n \" is currently in a direct message conversation with \" +\n senderName\n );\n }\n\n const serverName = guild.name; // The name of the server\n const guildId = guild.id; // The ID of the guild\n const channel = discordMessage.channel;\n\n if (!channel) {\n console.log(\"channel is null\");\n return \"\";\n }\n\n let response =\n agentName +\n \" is currently having a conversation in the channel `@\" +\n channel.id +\n \" in the server `\" +\n serverName +\n \"` (@\" +\n guildId +\n \")\";\n if (\n channel.type === ChannelType.GuildText &&\n (channel as TextChannel).topic\n ) {\n // Check if the channel is a text channel\n response +=\n \"\\nThe topic of the channel is: \" +\n (channel as TextChannel).topic;\n }\n return response;\n },\n};\n\nexport default channelStateProvider;\n","import { getVoiceConnection } from \"@discordjs/voice\";\nimport { ChannelType, type Message as DiscordMessage } from \"discord.js\";\nimport type { IAgentRuntime, Memory, Provider, State } from \"@elizaos/core\";\n\nconst voiceStateProvider: Provider = {\n get: async (runtime: IAgentRuntime, message: Memory, state?: State) => {\n // Voice doesn't get a discord message, so we need to use the channel for guild data\n const discordMessage = (state?.discordMessage ||\n state.discordChannel) as DiscordMessage;\n const connection = getVoiceConnection(\n (discordMessage as DiscordMessage)?.guild?.id as string\n );\n const agentName = state?.agentName || \"The agent\";\n if (!connection) {\n return agentName + \" is not currently in a voice channel\";\n }\n\n const channel = (\n (state?.discordMessage as DiscordMessage) ||\n (state.discordChannel as DiscordMessage)\n )?.guild?.channels?.cache?.get(\n connection.joinConfig.channelId as string\n );\n\n if (!channel || channel.type !== ChannelType.GuildVoice) {\n return agentName + \" is in an invalid voice channel\";\n }\n\n return `${agentName} is currently in the voice channel: ${channel.name} (ID: ${channel.id})`;\n },\n};\n\nexport default voiceStateProvider;\n","const record_files = false;\nimport {\n type Content,\n type HandlerCallback,\n type IAgentRuntime,\n type Memory,\n ModelClass,\n ServiceType,\n type State,\n type UUID,\n composeContext,\n composeRandomUser,\n elizaLogger,\n getEmbeddingZeroVector,\n generateMessageResponse,\n stringToUuid,\n generateShouldRespond,\n type ITranscriptionService,\n type ISpeechService,\n} from \"@elizaos/core\";\nimport {\n type AudioPlayer,\n type AudioReceiveStream,\n NoSubscriberBehavior,\n StreamType,\n type VoiceConnection,\n VoiceConnectionStatus,\n createAudioPlayer,\n createAudioResource,\n getVoiceConnections,\n joinVoiceChannel,\n entersState,\n} from \"@discordjs/voice\";\nimport {\n type BaseGuildVoiceChannel,\n ChannelType,\n type Client,\n type Guild,\n type GuildMember,\n type VoiceChannel,\n type VoiceState,\n} from \"discord.js\";\nimport EventEmitter from \"events\";\nimport prism from \"prism-media\";\nimport { type Readable, pipeline } from \"stream\";\nimport type { DiscordClient } from \"./client.ts\";\n\nimport {\n discordShouldRespondTemplate,\n discordVoiceHandlerTemplate,\n} from \"./templates.ts\";\nimport { getWavHeader } from \"./utils.ts\";\nimport fs from 'fs';\nimport path from 'path';\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 private readable: Readable;\n private buffers: Buffer[] = [];\n private maxSize: number;\n private lastFlagged = -1;\n private ended = false;\n\n constructor(\n readable: Readable,\n maxSize: number,\n onStart: () => void,\n callback: (buffer: Buffer) => void\n ) {\n this.readable = readable;\n this.maxSize = maxSize;\n this.readable.on(\"data\", (chunk: Buffer) => {\n //console.log('AudioMonitor got data');\n if (this.lastFlagged < 0) {\n this.lastFlagged = this.buffers.length;\n }\n this.buffers.push(chunk);\n const currentSize = this.buffers.reduce(\n (acc, cur) => acc + cur.length,\n 0\n );\n while (currentSize > this.maxSize) {\n this.buffers.shift();\n this.lastFlagged--;\n }\n });\n this.readable.on(\"end\", () => {\n elizaLogger.log(\"AudioMonitor ended\");\n this.ended = true;\n if (this.lastFlagged < 0) return;\n callback(this.getBufferFromStart());\n this.lastFlagged = -1;\n });\n this.readable.on(\"speakingStopped\", () => {\n if (this.ended) return;\n elizaLogger.log(\"Speaking stopped\");\n if (this.lastFlagged < 0) return;\n callback(this.getBufferFromStart());\n });\n this.readable.on(\"speakingStarted\", () => {\n if (this.ended) return;\n onStart();\n elizaLogger.log(\"Speaking started\");\n this.reset();\n });\n }\n\n stop() {\n this.readable.removeAllListeners(\"data\");\n this.readable.removeAllListeners(\"end\");\n this.readable.removeAllListeners(\"speakingStopped\");\n this.readable.removeAllListeners(\"speakingStarted\");\n }\n\n isFlagged() {\n return this.lastFlagged >= 0;\n }\n\n getBufferFromFlag() {\n if (this.lastFlagged < 0) {\n return null;\n }\n const buffer = Buffer.concat(this.buffers.slice(this.lastFlagged));\n return buffer;\n }\n\n getBufferFromStart() {\n const buffer = Buffer.concat(this.buffers);\n return buffer;\n }\n\n reset() {\n this.buffers = [];\n this.lastFlagged = -1;\n }\n\n isEnded() {\n return this.ended;\n }\n}\n\nexport class VoiceManager extends EventEmitter {\n private processingVoice = false;\n private transcriptionTimeout: NodeJS.Timeout | null = null;\n private userStates: Map<\n string,\n {\n buffers: Buffer[];\n totalLength: number;\n lastActive: number;\n transcriptionText: string;\n }\n > = new Map();\n private activeAudioPlayer: AudioPlayer | null = null;\n private client: Client;\n private runtime: IAgentRuntime;\n private streams: Map = new Map();\n private connections: Map = new Map();\n private activeMonitors: Map<\n string,\n { channel: BaseGuildVoiceChannel; monitor: AudioMonitor }\n > = new Map();\n\n constructor(client: DiscordClient) {\n super();\n this.client = client.client;\n this.runtime = client.runtime;\n }\n\n async handleVoiceStateUpdate(oldState: VoiceState, newState: VoiceState) {\n const oldChannelId = oldState.channelId;\n const newChannelId = newState.channelId;\n const member = newState.member;\n if (!member) return;\n if (member.id === this.client.user?.id) {\n return;\n }\n\n // Ignore mute/unmute events\n if (oldChannelId === newChannelId) {\n return;\n }\n\n // User leaving a channel where the bot is present\n if (oldChannelId && this.connections.has(oldChannelId)) {\n this.stopMonitoringMember(member.id);\n }\n\n // User joining a channel where the bot is present\n if (newChannelId && this.connections.has(newChannelId)) {\n await this.monitorMember(\n member,\n newState.channel as BaseGuildVoiceChannel\n );\n }\n }\n\n async joinChannel(channel: BaseGuildVoiceChannel) {\n const oldConnection = this.getVoiceConnection(\n channel.guildId as string\n );\n if (oldConnection) {\n try {\n oldConnection.destroy();\n // Remove all associated streams and monitors\n this.streams.clear();\n this.activeMonitors.clear();\n } catch (error) {\n console.error(\"Error leaving voice channel:\", error);\n }\n }\n\n const connection = joinVoiceChannel({\n channelId: channel.id,\n guildId: channel.guild.id,\n adapterCreator: channel.guild.voiceAdapterCreator as any,\n selfDeaf: false,\n selfMute: false,\n group: this.client.user.id,\n });\n\n try {\n // Wait for either Ready or Signalling state\n await Promise.race([\n entersState(connection, VoiceConnectionStatus.Ready, 20_000),\n entersState(\n connection,\n VoiceConnectionStatus.Signalling,\n 20_000\n ),\n ]);\n\n // Log connection success\n elizaLogger.log(\n `Voice connection established in state: ${connection.state.status}`\n );\n\n // Set up ongoing state change monitoring\n connection.on(\"stateChange\", async (oldState, newState) => {\n elizaLogger.log(\n `Voice connection state changed from ${oldState.status} to ${newState.status}`\n );\n\n if (newState.status === VoiceConnectionStatus.Disconnected) {\n elizaLogger.log(\"Handling disconnection...\");\n\n try {\n // Try to reconnect if disconnected\n await Promise.race([\n entersState(\n connection,\n VoiceConnectionStatus.Signalling,\n 5_000\n ),\n entersState(\n connection,\n VoiceConnectionStatus.Connecting,\n 5_000\n ),\n ]);\n // Seems to be reconnecting to a new channel\n elizaLogger.log(\"Reconnecting to channel...\");\n } catch (e) {\n // Seems to be a real disconnect, destroy and cleanup\n elizaLogger.log(\n \"Disconnection confirmed - cleaning up...\" + e\n );\n connection.destroy();\n this.connections.delete(channel.id);\n }\n } else if (\n newState.status === VoiceConnectionStatus.Destroyed\n ) {\n this.connections.delete(channel.id);\n } else if (\n !this.connections.has(channel.id) &&\n (newState.status === VoiceConnectionStatus.Ready ||\n newState.status === VoiceConnectionStatus.Signalling)\n ) {\n this.connections.set(channel.id, connection);\n }\n });\n\n connection.on(\"error\", (error) => {\n elizaLogger.log(\"Voice connection error:\", error);\n // Don't immediately destroy - let the state change handler deal with it\n elizaLogger.log(\n \"Connection error - will attempt to recover...\"\n );\n });\n\n // Store the connection\n this.connections.set(channel.id, connection);\n\n // Continue with voice state modifications\n const me = channel.guild.members.me;\n if (me?.voice && me.permissions.has(\"DeafenMembers\")) {\n try {\n await me.voice.setDeaf(false);\n await me.voice.setMute(false);\n } catch (error) {\n elizaLogger.log(\"Failed to modify voice state:\", error);\n // Continue even if this fails\n }\n }\n\n connection.receiver.speaking.on(\"start\", async (userId: string) => {\n let user = channel.members.get(userId);\n if (!user) {\n try {\n user = await channel.guild.members.fetch(userId);\n } catch (error) {\n console.error(\"Failed to fetch user:\", error);\n }\n }\n if (user && !user?.user.bot) {\n this.monitorMember(user as GuildMember, channel);\n this.streams.get(userId)?.emit(\"speakingStarted\");\n }\n });\n\n connection.receiver.speaking.on(\"end\", async (userId: string) => {\n const user = channel.members.get(userId);\n if (!user?.user.bot) {\n this.streams.get(userId)?.emit(\"speakingStopped\");\n }\n });\n } catch (error) {\n elizaLogger.log(\"Failed to establish voice connection:\", error);\n connection.destroy();\n this.connections.delete(channel.id);\n throw error;\n }\n }\n\n private getVoiceConnection(guildId: string) {\n const connections = getVoiceConnections(this.client.user.id);\n if (!connections) {\n return;\n }\n const connection = [...connections.values()].find(\n (connection) => connection.joinConfig.guildId === guildId\n );\n return connection;\n }\n\n private async monitorMember(\n member: GuildMember,\n channel: BaseGuildVoiceChannel\n ) {\n const userId = member?.id;\n const userName = member?.user?.username;\n const name = member?.user?.displayName;\n const connection = this.getVoiceConnection(member?.guild?.id);\n const receiveStream = connection?.receiver.subscribe(userId, {\n autoDestroy: true,\n emitClose: true,\n });\n if (!receiveStream || receiveStream.readableLength === 0) {\n return;\n }\n const opusDecoder = new prism.opus.Decoder({\n channels: 1,\n rate: DECODE_SAMPLE_RATE,\n frameSize: DECODE_FRAME_SIZE,\n });\n const volumeBuffer: number[] = [];\n const VOLUME_WINDOW_SIZE = 30;\n const SPEAKING_THRESHOLD = 0.05;\n opusDecoder.on(\"data\", (pcmData: Buffer) => {\n // Monitor the audio volume while the agent is speaking.\n // If the average volume of the user's audio exceeds the defined threshold, it indicates active speaking.\n // When active speaking is detected, stop the agent's current audio playback to avoid overlap.\n\n if (this.activeAudioPlayer) {\n const samples = new Int16Array(\n pcmData.buffer,\n pcmData.byteOffset,\n pcmData.length / 2\n );\n const maxAmplitude = Math.max(...samples.map(Math.abs)) / 32768;\n volumeBuffer.push(maxAmplitude);\n\n if (volumeBuffer.length > VOLUME_WINDOW_SIZE) {\n volumeBuffer.shift();\n }\n const avgVolume =\n volumeBuffer.reduce((sum, v) => sum + v, 0) /\n VOLUME_WINDOW_SIZE;\n\n if (avgVolume > SPEAKING_THRESHOLD) {\n volumeBuffer.length = 0;\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n this.processingVoice = false;\n }\n }\n });\n pipeline(\n receiveStream as AudioReceiveStream,\n opusDecoder as any,\n (err: Error | null) => {\n if (err) {\n console.log(`Opus decoding pipeline error: ${err}`);\n }\n }\n );\n this.streams.set(userId, opusDecoder);\n this.connections.set(userId, connection as VoiceConnection);\n opusDecoder.on(\"error\", (err: any) => {\n console.log(`Opus decoding error: ${err}`);\n });\n const errorHandler = (err: any) => {\n console.log(`Opus decoding error: ${err}`);\n };\n const streamCloseHandler = () => {\n console.log(`voice stream from ${member?.displayName} closed`);\n this.streams.delete(userId);\n this.connections.delete(userId);\n };\n const closeHandler = () => {\n console.log(`Opus decoder for ${member?.displayName} closed`);\n opusDecoder.removeListener(\"error\", errorHandler);\n opusDecoder.removeListener(\"close\", closeHandler);\n receiveStream?.removeListener(\"close\", streamCloseHandler);\n };\n opusDecoder.on(\"error\", errorHandler);\n opusDecoder.on(\"close\", closeHandler);\n receiveStream?.on(\"close\", streamCloseHandler);\n\n this.client.emit(\n \"userStream\",\n userId,\n name,\n userName,\n channel,\n opusDecoder\n );\n }\n\n leaveChannel(channel: BaseGuildVoiceChannel) {\n const connection = this.connections.get(channel.id);\n if (connection) {\n connection.destroy();\n this.connections.delete(channel.id);\n }\n\n // Stop monitoring all members in this channel\n for (const [memberId, monitorInfo] of this.activeMonitors) {\n if (\n monitorInfo.channel.id === channel.id &&\n memberId !== this.client.user?.id\n ) {\n this.stopMonitoringMember(memberId);\n }\n }\n\n console.log(`Left voice channel: ${channel.name} (${channel.id})`);\n }\n\n stopMonitoringMember(memberId: string) {\n const monitorInfo = this.activeMonitors.get(memberId);\n if (monitorInfo) {\n monitorInfo.monitor.stop();\n this.activeMonitors.delete(memberId);\n this.streams.delete(memberId);\n console.log(`Stopped monitoring user ${memberId}`);\n }\n }\n\n async handleGuildCreate(guild: Guild) {\n console.log(`Joined guild ${guild.name}`);\n // this.scanGuild(guild);\n }\n\n async debouncedProcessTranscription(\n userId: UUID,\n name: string,\n userName: string,\n channel: BaseGuildVoiceChannel\n ) {\n const DEBOUNCE_TRANSCRIPTION_THRESHOLD = 1500; // wait for 1.5 seconds of silence\n\n if (this.activeAudioPlayer?.state?.status === \"idle\") {\n elizaLogger.log(\"Cleaning up idle audio player.\");\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n }\n\n if (this.activeAudioPlayer || this.processingVoice) {\n const state = this.userStates.get(userId);\n state.buffers.length = 0;\n state.totalLength = 0;\n return;\n }\n\n if (this.transcriptionTimeout) {\n clearTimeout(this.transcriptionTimeout);\n }\n\n this.transcriptionTimeout = setTimeout(async () => {\n this.processingVoice = true;\n try {\n await this.processTranscription(\n userId,\n channel.id,\n channel,\n name,\n userName\n );\n\n // Clean all users' previous buffers\n this.userStates.forEach((state, _) => {\n state.buffers.length = 0;\n state.totalLength = 0;\n });\n } finally {\n this.processingVoice = false;\n }\n }, DEBOUNCE_TRANSCRIPTION_THRESHOLD);\n }\n\n async handleUserStream(\n userId: UUID,\n name: string,\n userName: string,\n channel: BaseGuildVoiceChannel,\n audioStream: Readable\n ) {\n console.log(`Starting audio monitor for user: ${userId}`);\n if (!this.userStates.has(userId)) {\n this.userStates.set(userId, {\n buffers: [],\n totalLength: 0,\n lastActive: Date.now(),\n transcriptionText: \"\",\n });\n }\n\n const state = this.userStates.get(userId);\n\n const processBuffer = async (buffer: Buffer) => {\n try {\n state!.buffers.push(buffer);\n state!.totalLength += buffer.length;\n state!.lastActive = Date.now();\n this.debouncedProcessTranscription(\n userId,\n name,\n userName,\n channel\n );\n } catch (error) {\n console.error(\n `Error processing buffer for user ${userId}:`,\n error\n );\n }\n };\n\n new AudioMonitor(\n audioStream,\n 10000000,\n () => {\n if (this.transcriptionTimeout) {\n clearTimeout(this.transcriptionTimeout);\n }\n },\n async (buffer) => {\n if (!buffer) {\n console.error(\"Received empty buffer\");\n return;\n }\n await processBuffer(buffer);\n }\n );\n }\n\n private async processTranscription(\n userId: UUID,\n channelId: string,\n channel: BaseGuildVoiceChannel,\n name: string,\n userName: string\n ) {\n const state = this.userStates.get(userId);\n if (!state || state.buffers.length === 0) return;\n try {\n const inputBuffer = Buffer.concat(state.buffers, state.totalLength);\n\n state.buffers.length = 0; // Clear the buffers\n state.totalLength = 0;\n // Convert Opus to WAV\n const wavBuffer = await this.convertOpusToWav(inputBuffer);\n console.log(\"Starting transcription...\");\n\n let arrayBuffer : ArrayBuffer|SharedArrayBuffer= wavBuffer.buffer.slice(\n wavBuffer.byteOffset,\n wavBuffer.byteOffset + wavBuffer.byteLength\n );\n if (arrayBuffer instanceof SharedArrayBuffer) {\n const tempArrayBuffer = new ArrayBuffer(arrayBuffer.byteLength);\n new Uint8Array(tempArrayBuffer).set(new Uint8Array(arrayBuffer));\n arrayBuffer = tempArrayBuffer;\n }\n // Generate a timestamp and create a filename with the user's name\n if (record_files){\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const userName = name.replace(/\\s+/g, '_'); // Replace spaces with underscores\n const fileName = `${userName}_${timestamp}.wav`;\n const filePath = path.join(\".\", 'recordings', fileName);\n\n // Ensure the recordings directory exists\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n\n // Write the wavBuffer to the file\n fs.writeFileSync(filePath, wavBuffer);\n\n console.log(`WAV file saved as ${filePath}`);\n }\n const transcriptionText = await this.runtime\n .getService(ServiceType.TRANSCRIPTION)\n .transcribe(arrayBuffer);\n\n function isValidTranscription(text: string): boolean {\n if (!text || text.includes(\"[BLANK_AUDIO]\")) return false;\n return true;\n }\n\n if (transcriptionText && isValidTranscription(transcriptionText)) {\n state.transcriptionText += transcriptionText;\n }\n\n if (state.transcriptionText.length) {\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n const finalText = state.transcriptionText;\n state.transcriptionText = \"\";\n await this.handleUserMessage(\n finalText,\n userId,\n channelId,\n channel,\n name,\n userName\n );\n }\n } catch (error) {\n console.error(\n `Error transcribing audio for user ${userId}:`,\n error\n );\n }\n }\n\n private async handleUserMessage(\n message: string,\n userId: UUID,\n channelId: string,\n channel: BaseGuildVoiceChannel,\n name: string,\n userName: string\n ) {\n try {\n const roomId = stringToUuid(channelId + \"-\" + this.runtime.agentId);\n const userIdUUID = stringToUuid(userId);\n\n await this.runtime.ensureConnection(\n userIdUUID,\n roomId,\n userName,\n name,\n \"discord\"\n );\n\n let state = await this.runtime.composeState(\n {\n agentId: this.runtime.agentId,\n content: { text: message, source: \"Discord\" },\n userId: userIdUUID,\n roomId,\n },\n {\n discordChannel: channel,\n discordClient: this.client,\n agentName: this.runtime.character.name,\n }\n );\n\n if (message && message.startsWith(\"/\")) {\n return null;\n }\n\n const memory = {\n id: stringToUuid(channelId + \"-voice-message-\" + Date.now()),\n agentId: this.runtime.agentId,\n content: {\n text: message,\n source: \"discord\",\n url: channel.url,\n },\n userId: userIdUUID,\n roomId,\n embedding: getEmbeddingZeroVector(),\n createdAt: Date.now(),\n };\n\n if (!memory.content.text) {\n return { text: \"\", action: \"IGNORE\" };\n }\n\n await this.runtime.messageManager.createMemory(memory);\n\n state = await this.runtime.updateRecentMessageState(state);\n\n const shouldIgnore = await this._shouldIgnore(memory);\n\n if (shouldIgnore) {\n return { text: \"\", action: \"IGNORE\" };\n }\n\n const shouldRespond = await this._shouldRespond(\n message,\n userId,\n channel,\n state\n );\n\n if (!shouldRespond) {\n return;\n }\n\n const context = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordVoiceHandlerTemplate ||\n this.runtime.character.templates?.messageHandlerTemplate ||\n discordVoiceHandlerTemplate,\n });\n\n const responseContent = await this._generateResponse(\n memory,\n state,\n context\n );\n\n const callback: HandlerCallback = async (content: Content) => {\n console.log(\"callback content: \", content);\n const { roomId } = memory;\n\n const responseMemory: Memory = {\n id: stringToUuid(\n memory.id + \"-voice-response-\" + Date.now()\n ),\n agentId: this.runtime.agentId,\n userId: this.runtime.agentId,\n content: {\n ...content,\n user: this.runtime.character.name,\n inReplyTo: memory.id,\n },\n roomId,\n embedding: getEmbeddingZeroVector(),\n };\n\n if (responseMemory.content.text?.trim()) {\n await this.runtime.messageManager.createMemory(\n responseMemory\n );\n state = await this.runtime.updateRecentMessageState(state);\n\n const responseStream = await this.runtime\n .getService(\n ServiceType.SPEECH_GENERATION\n )\n .generate(this.runtime, content.text);\n\n if (responseStream) {\n await this.playAudioStream(\n userId,\n responseStream as Readable\n );\n }\n\n await this.runtime.evaluate(memory, state);\n } else {\n console.warn(\"Empty response, skipping\");\n }\n return [responseMemory];\n };\n\n const responseMemories = await callback(responseContent);\n\n const response = responseContent;\n\n const content = (response.responseMessage ||\n response.content ||\n response.message) as string;\n\n if (!content) {\n return null;\n }\n\n console.log(\"responseMemories: \", responseMemories);\n\n await this.runtime.processActions(\n memory,\n responseMemories,\n state,\n callback\n );\n } catch (error) {\n console.error(\"Error processing transcribed text:\", error);\n }\n }\n\n private async convertOpusToWav(pcmBuffer: Buffer): Promise {\n try {\n // Generate the WAV header\n const wavHeader = getWavHeader(\n pcmBuffer.length,\n DECODE_SAMPLE_RATE\n );\n\n // Concatenate the WAV header and PCM data\n const wavBuffer = Buffer.concat([wavHeader, pcmBuffer]);\n\n return wavBuffer;\n } catch (error) {\n console.error(\"Error converting PCM to WAV:\", error);\n throw error;\n }\n }\n\n private async _shouldRespond(\n message: string,\n userId: UUID,\n channel: BaseGuildVoiceChannel,\n state: State\n ): Promise {\n if (userId === this.client.user?.id) return false;\n const lowerMessage = message.toLowerCase();\n const botName = this.client.user.username.toLowerCase();\n const characterName = this.runtime.character.name.toLowerCase();\n const guild = channel.guild;\n const member = guild?.members.cache.get(this.client.user?.id as string);\n const nickname = member?.nickname;\n\n if (\n lowerMessage.includes(botName as string) ||\n lowerMessage.includes(characterName) ||\n lowerMessage.includes(\n this.client.user?.tag.toLowerCase() as string\n ) ||\n (nickname && lowerMessage.includes(nickname.toLowerCase()))\n ) {\n return true;\n }\n\n if (!channel.guild) {\n return true;\n }\n\n // If none of the above conditions are met, use the generateText to decide\n const shouldRespondContext = composeContext({\n state,\n template:\n this.runtime.character.templates\n ?.discordShouldRespondTemplate ||\n this.runtime.character.templates?.shouldRespondTemplate ||\n composeRandomUser(discordShouldRespondTemplate, 2),\n });\n\n const response = await generateShouldRespond({\n runtime: this.runtime,\n context: shouldRespondContext,\n modelClass: ModelClass.SMALL,\n });\n\n if (response === \"RESPOND\") {\n return true;\n } else if (response === \"IGNORE\") {\n return false;\n } else if (response === \"STOP\") {\n return false;\n } else {\n console.error(\n \"Invalid response from response generateText:\",\n response\n );\n return false;\n }\n }\n\n private async _generateResponse(\n message: Memory,\n state: State,\n context: string\n ): Promise {\n const { userId, roomId } = message;\n\n const response = await generateMessageResponse({\n runtime: this.runtime,\n context,\n modelClass: ModelClass.SMALL,\n });\n\n response.source = \"discord\";\n\n if (!response) {\n console.error(\"No response from generateMessageResponse\");\n return;\n }\n\n await this.runtime.databaseAdapter.log({\n body: { message, context, response },\n userId: userId,\n roomId,\n type: \"response\",\n });\n\n return response;\n }\n\n private async _shouldIgnore(message: Memory): Promise {\n // console.log(\"message: \", message);\n elizaLogger.debug(\"message.content: \", message.content);\n // if the message is 3 characters or less, ignore it\n if ((message.content as Content).text.length < 3) {\n return true;\n }\n\n const loseInterestWords = [\n // telling the bot to stop talking\n \"shut up\",\n \"stop\",\n \"dont talk\",\n \"silence\",\n \"stop talking\",\n \"be quiet\",\n \"hush\",\n \"stfu\",\n \"stupid bot\",\n \"dumb bot\",\n\n // offensive words\n \"fuck\",\n \"shit\",\n \"damn\",\n \"suck\",\n \"dick\",\n \"cock\",\n \"sex\",\n \"sexy\",\n ];\n if (\n (message.content as Content).text.length < 50 &&\n loseInterestWords.some((word) =>\n (message.content as Content).text?.toLowerCase().includes(word)\n )\n ) {\n return true;\n }\n\n const ignoreWords = [\"k\", \"ok\", \"bye\", \"lol\", \"nm\", \"uh\"];\n if (\n (message.content as Content).text?.length < 8 &&\n ignoreWords.some((word) =>\n (message.content as Content).text?.toLowerCase().includes(word)\n )\n ) {\n return true;\n }\n\n return false;\n }\n\n async scanGuild(guild: Guild) {\n let chosenChannel: BaseGuildVoiceChannel | null = null;\n\n try {\n const channelId = this.runtime.getSetting(\n \"DISCORD_VOICE_CHANNEL_ID\"\n ) as string;\n if (channelId) {\n const channel = await guild.channels.fetch(channelId);\n if (channel?.isVoiceBased()) {\n chosenChannel = channel as BaseGuildVoiceChannel;\n }\n }\n\n if (!chosenChannel) {\n const channels = (await guild.channels.fetch()).filter(\n (channel) => channel?.type == ChannelType.GuildVoice\n );\n for (const [, channel] of channels) {\n const voiceChannel = channel as BaseGuildVoiceChannel;\n if (\n voiceChannel.members.size > 0 &&\n (chosenChannel === null ||\n voiceChannel.members.size >\n chosenChannel.members.size)\n ) {\n chosenChannel = voiceChannel;\n }\n }\n }\n\n if (chosenChannel) {\n console.log(`Joining channel: ${chosenChannel.name}`);\n await this.joinChannel(chosenChannel);\n } else {\n console.warn(\"No suitable voice channel found to join.\");\n }\n } catch (error) {\n console.error(\"Error selecting or joining a voice channel:\", error);\n }\n }\n\n async playAudioStream(userId: UUID, audioStream: Readable) {\n const connection = this.connections.get(userId);\n if (connection == null) {\n console.log(`No connection for user ${userId}`);\n return;\n }\n this.cleanupAudioPlayer(this.activeAudioPlayer);\n const audioPlayer = createAudioPlayer({\n behaviors: {\n noSubscriber: NoSubscriberBehavior.Pause,\n },\n });\n this.activeAudioPlayer = audioPlayer;\n connection.subscribe(audioPlayer);\n\n const audioStartTime = Date.now();\n\n const resource = createAudioResource(audioStream, {\n inputType: StreamType.Arbitrary,\n });\n audioPlayer.play(resource);\n\n audioPlayer.on(\"error\", (err: any) => {\n console.log(`Audio player error: ${err}`);\n });\n\n audioPlayer.on(\n \"stateChange\",\n (_oldState: any, newState: { status: string }) => {\n if (newState.status == \"idle\") {\n const idleTime = Date.now();\n console.log(\n `Audio playback took: ${idleTime - audioStartTime}ms`\n );\n }\n }\n );\n }\n\n cleanupAudioPlayer(audioPlayer: AudioPlayer) {\n if (!audioPlayer) return;\n\n audioPlayer.stop();\n audioPlayer.removeAllListeners();\n if (audioPlayer === this.activeAudioPlayer) {\n this.activeAudioPlayer = null;\n }\n }\n\n async handleJoinChannelCommand(interaction: any) {\n try {\n // Defer the reply immediately to prevent interaction timeout\n await interaction.deferReply();\n\n const channelId = interaction.options.get(\"channel\")\n ?.value as string;\n if (!channelId) {\n await interaction.editReply(\n \"Please provide a voice channel to join.\"\n );\n return;\n }\n\n const guild = interaction.guild;\n if (!guild) {\n await interaction.editReply(\"Could not find guild.\");\n return;\n }\n\n const voiceChannel = interaction.guild.channels.cache.find(\n (channel: VoiceChannel) =>\n channel.id === channelId &&\n channel.type === ChannelType.GuildVoice\n );\n\n if (!voiceChannel) {\n await interaction.editReply(\"Voice channel not found!\");\n return;\n }\n\n await this.joinChannel(voiceChannel as BaseGuildVoiceChannel);\n await interaction.editReply(\n `Joined voice channel: ${voiceChannel.name}`\n );\n } catch (error) {\n console.error(\"Error joining voice channel:\", error);\n // Use editReply instead of reply for the error case\n await interaction\n .editReply(\"Failed to join the voice channel.\")\n .catch(console.error);\n }\n }\n\n async handleLeaveChannelCommand(interaction: any) {\n const connection = this.getVoiceConnection(interaction.guildId as any);\n\n if (!connection) {\n await interaction.reply(\"Not currently in a voice channel.\");\n return;\n }\n\n try {\n connection.destroy();\n await interaction.reply(\"Left the voice channel.\");\n } catch (error) {\n console.error(\"Error leaving voice channel:\", error);\n await interaction.reply(\"Failed to leave the voice channel.\");\n }\n }\n}\n","import { DiscordClientInterface } from './client';\n\nconst discordPlugin = {\n name: \"discord\",\n description: \"Discord client plugin\",\n clients: [DiscordClientInterface],\n};\nexport default discordPlugin;"],"mappings":"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","names":["getEmbeddingZeroVector","stringToUuid","elizaLogger","EventEmitter","composeContext","parseJSONObjectFromText","ModelClass","generateText","composeContext","generateText","ModelClass","targetChannel","ChannelType","composeContext","getModelSettings","generateText","trimTokens","parseJSONObjectFromText","ModelClass","summarizationTemplate","summarizeAction","composeContext","generateText","parseJSONObjectFromText","ModelClass","composeContext","generateText","ModelClass","parseJSONObjectFromText","attachment","composeContext","ModelClass","ServiceType","ChannelType","elizaLogger","generateText","trimTokens","parseJSONObjectFromText","ModelClass","ServiceType","fs","ModelClass","generateText","trimTokens","parseJSONObjectFromText","ChannelType","ChannelType","ChannelType","elizaLogger","composeContext","content","action","memory","ServiceType","messages","channelState","shouldRespondContext","ModelClass","ChannelType","getVoiceConnection","ChannelType","ModelClass","ServiceType","composeContext","composeRandomUser","elizaLogger","getEmbeddingZeroVector","generateMessageResponse","stringToUuid","generateShouldRespond","joinVoiceChannel","ChannelType","fs","path","elizaLogger","joinVoiceChannel","connection","userName","ServiceType","stringToUuid","getEmbeddingZeroVector","composeContext","content","roomId","composeRandomUser","generateShouldRespond","ModelClass","generateMessageResponse","ChannelType","PermissionsBitField","EventEmitter","elizaLogger","stringToUuid","getEmbeddingZeroVector"]} \ No newline at end of file diff --git a/package.json b/package.json index 4c7f88f..4e35b07 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,12 @@ "dist" ], "dependencies": { + "@elizaos/core": "workspace:*", "@discordjs/opus": "github:discordjs/opus", "@discordjs/rest": "2.4.0", - "@discordjs/voice": "0.17.0", + "@discordjs/voice": "0.18.0", + "@hapi/shot": "^6.0.1", + "@types/hapi": "^18.0.14", "discord.js": "14.16.3", "fluent-ffmpeg": "^2.1.3", "libsodium-wrappers": "0.7.15", @@ -48,16 +51,16 @@ "access": "public" }, "agentConfig": { - "pluginType": "elizaos:client:1.0.0", - "pluginParameters": { - "DISCORD_APPLICATION_ID": { - "type": "string", - "description": "Your aplication id, is required" - }, - "DISCORD_API_TOKEN": { - "type": "string", - "description": "Discord api token is required" + "pluginType": "elizaos:client:1.0.0", + "pluginParameters": { + "DISCORD_APPLICATION_ID": { + "type": "string", + "description": "Your aplication id, is required" + }, + "DISCORD_API_TOKEN": { + "type": "string", + "description": "Discord api token is required" + } } - } } } diff --git a/src/client.ts b/src/client.ts index 0ad72bb..5f1a024 100644 --- a/src/client.ts +++ b/src/client.ts @@ -29,7 +29,7 @@ import voiceStateProvider from "./providers/voiceState.ts"; import { VoiceManager } from "./voice.ts"; import { PermissionsBitField } from "discord.js"; -class DiscordClient extends EventEmitter { +export class DiscordClient extends EventEmitter { apiToken: string; client: Client; runtime: IAgentRuntime; diff --git a/src/templates.ts b/src/templates.ts index 8982854..a8fd9aa 100644 --- a/src/templates.ts +++ b/src/templates.ts @@ -8,62 +8,17 @@ About {{agentName}}: # INSTRUCTIONS: Determine if {{agentName}} should respond to the message and participate in the conversation. Do not comment. Just respond with "RESPOND" or "IGNORE" or "STOP". # RESPONSE EXAMPLES -{{user1}}: I just saw a really great movie {{user2}}: Oh? Which movie? Result: [IGNORE] -{{agentName}}: Oh, this is my favorite scene -{{user1}}: sick {{user2}}: wait, why is it your favorite scene Result: [RESPOND] {{user1}}: stfu bot Result: [STOP] -{{user1}}: Hey {{agent}}, can you help me with something -Result: [RESPOND] - -{{user1}}: {{agentName}} stfu plz -Result: [STOP] - -{{user1}}: i need help -{{agentName}}: how can I help you? -{{user1}}: no. i need help from someone else -Result: [IGNORE] - -{{user1}}: Hey {{agent}}, can I ask you a question -{{agentName}}: Sure, what is it -{{user1}}: can you ask claude to create a basic react module that demonstrates a counter -Result: [RESPOND] - -{{user1}}: {{agentName}} can you tell me a story -{{user1}}: about a girl named elara -{{agentName}}: Sure. -{{agentName}}: Once upon a time, in a quaint little village, there was a curious girl named Elara. -{{agentName}}: Elara was known for her adventurous spirit and her knack for finding beauty in the mundane. -{{user1}}: I'm loving it, keep going -Result: [RESPOND] - -{{user1}}: {{agentName}} stop responding plz -Result: [STOP] - -{{user1}}: okay, i want to test something. can you say marco? -{{agentName}}: marco -{{user1}}: great. okay, now do it again -Result: [RESPOND] - Response options are [RESPOND], [IGNORE] and [STOP]. -{{agentName}} is in a room with other users and is very worried about being annoying and saying too much. -Respond with [RESPOND] to messages that are directed at {{agentName}}, or participate in conversations that are interesting or relevant to their background. -If a message is not interesting or relevant, respond with [IGNORE] -Unless directly responding to a user, respond with [IGNORE] to messages that are very short or do not contain much information. -If a user asks {{agentName}} to be quiet, respond with [STOP] -If {{agentName}} concludes a conversation and isn't part of the conversation anymore, respond with [STOP] - -IMPORTANT: {{agentName}} is particularly sensitive about being annoying, so if there is any doubt, it is better to respond with [IGNORE]. -If {{agentName}} is conversing with a user and they have not asked to stop, it is better to respond with [RESPOND]. - {{recentMessages}} # INSTRUCTIONS: Choose the option that best describes {{agentName}}'s response to the last message. Ignore messages if they are addressed to someone else. @@ -139,23 +94,7 @@ Examples of {{agentName}}'s dialog and actions: # Recent Chat History: {{recentMessages}} -# Instructions: Write a natural, engaging message to restart community conversation. Focus on: -- Community engagement -- Educational topics -- General discusions -- Support queries -- Keep message warm and inviting -- Maximum 3 lines -- Use 1-2 emojis maximum -- Avoid financial advice -- Stay within known facts -- No team member mentions -- Be hyped, not repetitive -- Be natural, act like a human, connect with the community -- Don't sound so robotic like -- Randomly grab the most recent 5 messages for some context. Validate the context randomly and use that as a reference point for your next message, but not always, only when relevant. -- If the recent messages are mostly from {{agentName}}, make sure to create conversation starters, given there is no messages from others to reference. -- DO NOT REPEAT THE SAME thing that you just said from your recent chat history, start the message different each time, and be organic, non reptitive. +# Instructions: Write a natural, engaging message to restart community conversation. # Instructions: Write the next message for {{agentName}}. Include the "NONE" action only, as the only valid action for auto-posts is "NONE". ` + messageCompletionFooter; @@ -177,19 +116,5 @@ Examples of {{agentName}}'s dialog and actions: # Announcement Content: {{announcementContent}} -# Instructions: Write an exciting message to bring attention to the announcement. Requirements: -- Reference the announcement channel using <#{{announcementChannelId}}> -- Reference the announcement content to get information about the announcement to use where appropriate to make the message dynamic vs a static post -- Create genuine excitement -- Encourage community participation -- If there are links like Twitter/X posts, encourage users to like/retweet/comment to spread awarenress, but directly say that, wrap that into the post so its natural. -- Stay within announced facts only -- No additional promises or assumptions -- No team member mentions -- Start the message differently each time. Don't start with the same word like "hey", "hey hey", etc. be dynamic -- Address everyone, not as a direct reply to whoever made the announcement or wrote it, but you can reference them -- Maximum 3-7 lines formatted nicely if needed, based on the context of the announcement -- Use 1-2 emojis maximum - # Instructions: Write the next message for {{agentName}}. Include the "NONE" action only, as no other actions are appropriate for announcement hype. ` + messageCompletionFooter; \ No newline at end of file diff --git a/src/voice.ts b/src/voice.ts index 715826e..58cbfd9 100644 --- a/src/voice.ts +++ b/src/voice.ts @@ -1,3 +1,4 @@ +const record_files = false; import { type Content, type HandlerCallback, @@ -42,12 +43,15 @@ import { import EventEmitter from "events"; import prism from "prism-media"; import { type Readable, pipeline } from "stream"; -import type { DiscordClient } from "./index.ts"; +import type { DiscordClient } from "./client.ts"; + import { discordShouldRespondTemplate, discordVoiceHandlerTemplate, } from "./templates.ts"; import { getWavHeader } from "./utils.ts"; +import fs from 'fs'; +import path from 'path'; // These values are chosen for compatibility with picovoice components const DECODE_FRAME_SIZE = 1024; @@ -591,9 +595,33 @@ export class VoiceManager extends EventEmitter { const wavBuffer = await this.convertOpusToWav(inputBuffer); console.log("Starting transcription..."); + let arrayBuffer : ArrayBuffer|SharedArrayBuffer= wavBuffer.buffer.slice( + wavBuffer.byteOffset, + wavBuffer.byteOffset + wavBuffer.byteLength + ); + if (arrayBuffer instanceof SharedArrayBuffer) { + const tempArrayBuffer = new ArrayBuffer(arrayBuffer.byteLength); + new Uint8Array(tempArrayBuffer).set(new Uint8Array(arrayBuffer)); + arrayBuffer = tempArrayBuffer; + } + // Generate a timestamp and create a filename with the user's name + if (record_files){ + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + const userName = name.replace(/\s+/g, '_'); // Replace spaces with underscores + const fileName = `${userName}_${timestamp}.wav`; + const filePath = path.join(".", 'recordings', fileName); + + // Ensure the recordings directory exists + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + + // Write the wavBuffer to the file + fs.writeFileSync(filePath, wavBuffer); + + console.log(`WAV file saved as ${filePath}`); + } const transcriptionText = await this.runtime .getService(ServiceType.TRANSCRIPTION) - .transcribe(wavBuffer); + .transcribe(arrayBuffer); function isValidTranscription(text: string): boolean { if (!text || text.includes("[BLANK_AUDIO]")) return false; diff --git a/tsconfig.json b/tsconfig.json index ba81284..1ab8019 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,8 +17,11 @@ "allowJs": true, "checkJs": false, "noEmitOnError": false, + "target": "esnext", + "downlevelIteration": true, "moduleDetection": "force", - "allowArbitraryExtensions": true + "allowArbitraryExtensions": true, + "typeRoots":["./node_modules/@types"] }, "include": ["src/**/*.ts"] } \ No newline at end of file