@elizaos/plugin-discord 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -79,7 +79,7 @@ var chatWithAttachments = {
79
79
  description: "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.",
80
80
  validate: async (_runtime, message, _state) => {
81
81
  const room = await _runtime.getRoom(message.roomId);
82
- if (room?.type !== ChannelType.GROUP) {
82
+ if (room?.type !== ChannelType.GROUP || room?.source !== "discord") {
83
83
  return false;
84
84
  }
85
85
  const keywords = [
@@ -148,20 +148,28 @@ var chatWithAttachments = {
148
148
  count: conversationLength,
149
149
  unique: false
150
150
  });
151
- const attachments = recentMessages.filter((msg) => msg.content.attachments && msg.content.attachments.length > 0).flatMap((msg) => msg.content.attachments).filter(
151
+ const attachments = recentMessages.filter(
152
+ (msg) => msg.content.attachments && msg.content.attachments.length > 0
153
+ ).flatMap((msg) => msg.content.attachments).filter(
152
154
  (attachment) => attachment && (attachmentIds.map((attch) => attch.toLowerCase().slice(0, 5)).includes(attachment.id.toLowerCase().slice(0, 5)) || // or check the other way
153
155
  attachmentIds.some((id) => {
154
156
  const attachmentId = id.toLowerCase().slice(0, 5);
155
157
  return attachment && attachment.id.toLowerCase().includes(attachmentId);
156
158
  }))
157
159
  );
158
- const attachmentsWithText = attachments.filter((attachment) => !!attachment).map((attachment) => `# ${attachment.title}
160
+ const attachmentsWithText = attachments.filter(
161
+ (attachment) => !!attachment
162
+ ).map((attachment) => `# ${attachment.title}
159
163
  ${attachment.text}`).join("\n\n");
160
164
  let currentSummary = "";
161
165
  const chunkSize = 8192;
162
166
  state.values.attachmentsWithText = attachmentsWithText;
163
167
  state.values.objective = objective;
164
- const template = await trimTokens(summarizationTemplate, chunkSize, runtime);
168
+ const template = await trimTokens(
169
+ summarizationTemplate,
170
+ chunkSize,
171
+ runtime
172
+ );
165
173
  const prompt = composePromptFromState({
166
174
  state,
167
175
  // make sure it fits, we can pad the tokens a bit
@@ -220,7 +228,9 @@ ${currentSummary.trim()}
220
228
  throw error;
221
229
  }
222
230
  } else {
223
- console.warn("Empty response from chat with attachments action, skipping");
231
+ console.warn(
232
+ "Empty response from chat with attachments action, skipping"
233
+ );
224
234
  }
225
235
  return callbackData;
226
236
  },
@@ -390,7 +400,9 @@ var downloadMedia = {
390
400
  retries++;
391
401
  console.error(`Error sending message (attempt ${retries}):`, error);
392
402
  if (retries === maxRetries) {
393
- console.error("Max retries reached. Failed to send message with attachment.");
403
+ console.error(
404
+ "Max retries reached. Failed to send message with attachment."
405
+ );
394
406
  break;
395
407
  }
396
408
  await new Promise((resolve) => setTimeout(resolve, 2e3));
@@ -496,8 +508,12 @@ var getDateRange = async (runtime, _message, state) => {
496
508
  const parsedResponse = parseJSONObjectFromText3(response);
497
509
  if (parsedResponse) {
498
510
  if (parsedResponse.objective && parsedResponse.start && parsedResponse.end) {
499
- const startIntegerString = parsedResponse.start.match(/\d+/)?.[0];
500
- const endIntegerString = parsedResponse.end.match(/\d+/)?.[0];
511
+ const startIntegerString = parsedResponse.start.match(
512
+ /\d+/
513
+ )?.[0];
514
+ const endIntegerString = parsedResponse.end.match(
515
+ /\d+/
516
+ )?.[0];
501
517
  const multipliers = {
502
518
  second: 1 * 1e3,
503
519
  minute: 60 * 1e3,
@@ -507,7 +523,9 @@ var getDateRange = async (runtime, _message, state) => {
507
523
  const startMultiplier = parsedResponse.start.match(
508
524
  /second|minute|hour|day/
509
525
  )?.[0];
510
- const endMultiplier = parsedResponse.end.match(/second|minute|hour|day/)?.[0];
526
+ const endMultiplier = parsedResponse.end.match(
527
+ /second|minute|hour|day/
528
+ )?.[0];
511
529
  const startInteger = startIntegerString ? Number.parseInt(startIntegerString) : 0;
512
530
  const endInteger = endIntegerString ? Number.parseInt(endIntegerString) : 0;
513
531
  const startTime = startInteger * multipliers[startMultiplier];
@@ -641,7 +659,11 @@ ${attachments}`;
641
659
  const chunk = chunks[i];
642
660
  state.values.currentSummary = currentSummary;
643
661
  state.values.currentChunk = chunk;
644
- const template = await trimTokens2(summarizationTemplate2, chunkSize + 500, runtime);
662
+ const template = await trimTokens2(
663
+ summarizationTemplate2,
664
+ chunkSize + 500,
665
+ runtime
666
+ );
645
667
  const prompt = composePromptFromState3({
646
668
  state,
647
669
  // make sure it fits, we can pad the tokens a bit
@@ -695,7 +717,9 @@ ${currentSummary.trim()}
695
717
  [summaryFilename]
696
718
  );
697
719
  } else {
698
- console.warn("Empty response from summarize conversation action, skipping");
720
+ console.warn(
721
+ "Empty response from summarize conversation action, skipping"
722
+ );
699
723
  }
700
724
  return callbackData;
701
725
  },
@@ -875,7 +899,11 @@ var transcribeMedia = {
875
899
  count: conversationLength,
876
900
  unique: false
877
901
  });
878
- const attachment = recentMessages.filter((msg) => msg.content.attachments && msg.content.attachments.length > 0).flatMap((msg) => msg.content.attachments).find((attachment2) => attachment2?.id.toLowerCase() === attachmentId.toLowerCase());
902
+ const attachment = recentMessages.filter(
903
+ (msg) => msg.content.attachments && msg.content.attachments.length > 0
904
+ ).flatMap((msg) => msg.content.attachments).find(
905
+ (attachment2) => attachment2?.id.toLowerCase() === attachmentId.toLowerCase()
906
+ );
879
907
  if (!attachment) {
880
908
  console.error(`Couldn't find attachment with ID ${attachmentId}`);
881
909
  await runtime.createMemory(
@@ -1011,7 +1039,9 @@ var joinVoice = {
1011
1039
  if (!serverId) {
1012
1040
  throw new Error("No server ID found");
1013
1041
  }
1014
- const discordClient = runtime.getService(ServiceType2.DISCORD);
1042
+ const discordClient = runtime.getService(
1043
+ ServiceType2.DISCORD
1044
+ );
1015
1045
  const client = discordClient.client;
1016
1046
  const voiceManager = discordClient.voiceManager;
1017
1047
  if (!client) {
@@ -1314,7 +1344,9 @@ var leaveVoice = {
1314
1344
  if (!serverId) {
1315
1345
  throw new Error("No server ID found 9");
1316
1346
  }
1317
- const discordClient = runtime.getService(ServiceType2.DISCORD);
1347
+ const discordClient = runtime.getService(
1348
+ ServiceType2.DISCORD
1349
+ );
1318
1350
  const voiceManager = discordClient.voiceManager;
1319
1351
  const client = discordClient.client;
1320
1352
  if (!client) {
@@ -1574,7 +1606,9 @@ var channelStateProvider = {
1574
1606
  };
1575
1607
  }
1576
1608
  channelId = room.channelId;
1577
- const discordService = runtime.getService(ServiceType2.DISCORD);
1609
+ const discordService = runtime.getService(
1610
+ ServiceType2.DISCORD
1611
+ );
1578
1612
  if (!discordService) {
1579
1613
  console.warn("No discord client found");
1580
1614
  return {
@@ -1772,7 +1806,10 @@ import {
1772
1806
  import fs3 from "node:fs";
1773
1807
  import { trimTokens as trimTokens3 } from "@elizaos/core";
1774
1808
  import { parseJSONObjectFromText as parseJSONObjectFromText5 } from "@elizaos/core";
1775
- import { ModelType as ModelType6, ServiceType as ServiceType3 } from "@elizaos/core";
1809
+ import {
1810
+ ModelType as ModelType6,
1811
+ ServiceType as ServiceType3
1812
+ } from "@elizaos/core";
1776
1813
  import { Collection } from "discord.js";
1777
1814
  import ffmpeg from "fluent-ffmpeg";
1778
1815
  async function generateSummary(runtime, text) {
@@ -1854,7 +1891,9 @@ var AttachmentManager = class {
1854
1891
  media = await this.processAudioVideoAttachment(attachment);
1855
1892
  } else if (attachment.contentType?.startsWith("image/")) {
1856
1893
  media = await this.processImageAttachment(attachment);
1857
- } else if (attachment.contentType?.startsWith("video/") || this.runtime.getService(ServiceType3.VIDEO)?.isVideoUrl(attachment.url)) {
1894
+ } else if (attachment.contentType?.startsWith("video/") || this.runtime.getService(ServiceType3.VIDEO)?.isVideoUrl(
1895
+ attachment.url
1896
+ )) {
1858
1897
  media = await this.processVideoAttachment(attachment);
1859
1898
  } else {
1860
1899
  media = await this.processGenericAttachment(attachment);
@@ -1881,8 +1920,14 @@ var AttachmentManager = class {
1881
1920
  } else {
1882
1921
  throw new Error("Unsupported audio/video format");
1883
1922
  }
1884
- const transcription = await this.runtime.useModel(ModelType6.TRANSCRIPTION, audioBuffer);
1885
- const { title, description } = await generateSummary(this.runtime, transcription);
1923
+ const transcription = await this.runtime.useModel(
1924
+ ModelType6.TRANSCRIPTION,
1925
+ audioBuffer
1926
+ );
1927
+ const { title, description } = await generateSummary(
1928
+ this.runtime,
1929
+ transcription
1930
+ );
1886
1931
  return {
1887
1932
  id: attachment.id,
1888
1933
  url: attachment.url,
@@ -1893,7 +1938,9 @@ var AttachmentManager = class {
1893
1938
  };
1894
1939
  } catch (error) {
1895
1940
  if (error instanceof Error) {
1896
- console.error(`Error processing audio/video attachment: ${error.message}`);
1941
+ console.error(
1942
+ `Error processing audio/video attachment: ${error.message}`
1943
+ );
1897
1944
  }
1898
1945
  return {
1899
1946
  id: attachment.id,
@@ -1997,9 +2044,13 @@ var AttachmentManager = class {
1997
2044
  };
1998
2045
  } catch (error) {
1999
2046
  if (error instanceof Error) {
2000
- console.error(`Error processing plaintext attachment: ${error.message}`);
2047
+ console.error(
2048
+ `Error processing plaintext attachment: ${error.message}`
2049
+ );
2001
2050
  } else {
2002
- console.error(`An unknown error occurred during plaintext attachment processing`);
2051
+ console.error(
2052
+ `An unknown error occurred during plaintext attachment processing`
2053
+ );
2003
2054
  }
2004
2055
  return {
2005
2056
  id: attachment.id,
@@ -2075,7 +2126,10 @@ var AttachmentManager = class {
2075
2126
  };
2076
2127
  }
2077
2128
  if (typeof videoService.isVideoUrl === "function" && videoService.isVideoUrl(attachment.url)) {
2078
- const videoInfo = await videoService.processVideo(attachment.url, this.runtime);
2129
+ const videoInfo = await videoService.processVideo(
2130
+ attachment.url,
2131
+ this.runtime
2132
+ );
2079
2133
  return {
2080
2134
  id: attachment.id,
2081
2135
  url: attachment.url,
@@ -2147,7 +2201,9 @@ async function sendMessageInChunks(channel, content, _inReplyTo, files, componen
2147
2201
  };
2148
2202
  logger3.info(`Components received: ${safeStringify(components)}`);
2149
2203
  if (!Array.isArray(components)) {
2150
- logger3.warn("Components is not an array, skipping component processing");
2204
+ logger3.warn(
2205
+ "Components is not an array, skipping component processing"
2206
+ );
2151
2207
  } else if (components.length > 0 && components[0] && typeof components[0].toJSON === "function") {
2152
2208
  options.components = components;
2153
2209
  } else {
@@ -2177,7 +2233,9 @@ async function sendMessageInChunks(channel, content, _inReplyTo, files, componen
2177
2233
  return new ButtonBuilder().setCustomId(comp.custom_id).setLabel(comp.label || "").setStyle(comp.style || 1);
2178
2234
  }
2179
2235
  if (comp.type === 3) {
2180
- const selectMenu = new StringSelectMenuBuilder().setCustomId(comp.custom_id).setPlaceholder(comp.placeholder || "Select an option");
2236
+ const selectMenu = new StringSelectMenuBuilder().setCustomId(comp.custom_id).setPlaceholder(
2237
+ comp.placeholder || "Select an option"
2238
+ );
2181
2239
  if (typeof comp.min_values === "number")
2182
2240
  selectMenu.setMinValues(comp.min_values);
2183
2241
  if (typeof comp.max_values === "number")
@@ -2284,7 +2342,9 @@ function canSendMessage(channel) {
2284
2342
  reason: "Could not retrieve permissions"
2285
2343
  };
2286
2344
  }
2287
- const missingPermissions = requiredPermissions.filter((perm) => !permissions.has(perm));
2345
+ const missingPermissions = requiredPermissions.filter(
2346
+ (perm) => !permissions.has(perm)
2347
+ );
2288
2348
  return {
2289
2349
  canSend: missingPermissions.length === 0,
2290
2350
  missingPermissions,
@@ -2364,7 +2424,10 @@ var MessageManager = class {
2364
2424
  try {
2365
2425
  const canSendResult = canSendMessage(message.channel);
2366
2426
  if (!canSendResult.canSend) {
2367
- return logger4.warn(`Cannot send message to channel ${message.channel}`, canSendResult);
2427
+ return logger4.warn(
2428
+ `Cannot send message to channel ${message.channel}`,
2429
+ canSendResult
2430
+ );
2368
2431
  }
2369
2432
  const { processedContent, attachments } = await this.processMessage(message);
2370
2433
  const audioAttachments = message.attachments.filter(
@@ -2389,10 +2452,8 @@ var MessageManager = class {
2389
2452
  logger4.warn("Error sending typing indicator:", err);
2390
2453
  }
2391
2454
  };
2392
- startTyping();
2393
- const typingInterval = setInterval(startTyping, 8e3);
2394
2455
  const typingData = {
2395
- interval: typingInterval,
2456
+ interval: null,
2396
2457
  cleared: false
2397
2458
  };
2398
2459
  const newMessage = {
@@ -2406,62 +2467,75 @@ var MessageManager = class {
2406
2467
  text: processedContent || " ",
2407
2468
  attachments,
2408
2469
  source: "discord",
2470
+ channelType: type,
2409
2471
  url: message.url,
2410
2472
  inReplyTo: message.reference?.messageId ? createUniqueUuid4(this.runtime, message.reference?.messageId) : void 0
2411
2473
  },
2474
+ // metadata of memory
2412
2475
  metadata: {
2413
2476
  entityName: name,
2477
+ // include very technical/exact reference to this user for security reasons
2478
+ // don't remove or change this, spartan needs this
2479
+ fromId: message.author.id,
2480
+ // why message? all Memories contain content (which is basically a message)
2481
+ // what are the other types?
2414
2482
  type: "message"
2415
2483
  },
2416
2484
  createdAt: message.createdTimestamp
2417
2485
  };
2418
2486
  const callback = async (content, files) => {
2419
2487
  try {
2488
+ startTyping();
2489
+ const typingInterval = setInterval(startTyping, 8e3);
2490
+ typingData.interval = typingInterval;
2491
+ typingData.cleared = false;
2420
2492
  if (message.id && !content.inReplyTo) {
2421
2493
  content.inReplyTo = createUniqueUuid4(this.runtime, message.id);
2422
2494
  }
2423
- try {
2424
- const messages = await sendMessageInChunks(
2495
+ let messages = [];
2496
+ if (content?.source === "DM") {
2497
+ const u = await this.client.users.fetch(message.author.id);
2498
+ if (!u) {
2499
+ logger4.warn("Discord - User not found", message.author.id);
2500
+ return [];
2501
+ }
2502
+ u.send(content.text);
2503
+ messages = [content];
2504
+ } else {
2505
+ messages = await sendMessageInChunks(
2425
2506
  channel,
2426
2507
  content.text ?? "",
2427
2508
  message.id,
2428
2509
  files
2429
2510
  );
2430
- const memories = [];
2431
- for (const m of messages) {
2432
- const actions = content.actions;
2433
- const memory = {
2434
- id: createUniqueUuid4(this.runtime, m.id),
2435
- entityId: this.runtime.agentId,
2436
- agentId: this.runtime.agentId,
2437
- content: {
2438
- ...content,
2439
- actions,
2440
- inReplyTo: messageId,
2441
- url: m.url,
2442
- channelType: type
2443
- },
2444
- roomId,
2445
- createdAt: m.createdTimestamp
2446
- };
2447
- memories.push(memory);
2448
- }
2449
- for (const m of memories) {
2450
- await this.runtime.createMemory(m, "messages");
2451
- }
2452
- if (typingData.interval && !typingData.cleared) {
2453
- clearInterval(typingData.interval);
2454
- typingData.cleared = true;
2455
- }
2456
- return memories;
2457
- } catch (error) {
2458
- console.error("Error sending message:", error);
2459
- if (typingData.interval && !typingData.cleared) {
2460
- clearInterval(typingData.interval);
2461
- typingData.cleared = true;
2462
- }
2463
- return [];
2464
2511
  }
2512
+ const memories = [];
2513
+ for (const m of messages) {
2514
+ const actions = content.actions;
2515
+ const memory = {
2516
+ id: createUniqueUuid4(this.runtime, m.id),
2517
+ entityId: this.runtime.agentId,
2518
+ agentId: this.runtime.agentId,
2519
+ content: {
2520
+ ...content,
2521
+ actions,
2522
+ inReplyTo: messageId,
2523
+ url: m.url,
2524
+ channelType: type
2525
+ },
2526
+ roomId,
2527
+ createdAt: m.createdTimestamp
2528
+ };
2529
+ memories.push(memory);
2530
+ }
2531
+ for (const m of memories) {
2532
+ await this.runtime.createMemory(m, "messages");
2533
+ }
2534
+ if (typingData.interval && !typingData.cleared) {
2535
+ clearInterval(typingData.interval);
2536
+ typingData.cleared = true;
2537
+ }
2538
+ return memories;
2465
2539
  } catch (error) {
2466
2540
  console.error("Error handling message:", error);
2467
2541
  if (typingData.interval && !typingData.cleared) {
@@ -2471,11 +2545,14 @@ var MessageManager = class {
2471
2545
  return [];
2472
2546
  }
2473
2547
  };
2474
- this.runtime.emitEvent(["DISCORD_MESSAGE_RECEIVED" /* MESSAGE_RECEIVED */, EventType.MESSAGE_RECEIVED], {
2475
- runtime: this.runtime,
2476
- message: newMessage,
2477
- callback
2478
- });
2548
+ this.runtime.emitEvent(
2549
+ ["DISCORD_MESSAGE_RECEIVED" /* MESSAGE_RECEIVED */, EventType.MESSAGE_RECEIVED],
2550
+ {
2551
+ runtime: this.runtime,
2552
+ message: newMessage,
2553
+ callback
2554
+ }
2555
+ );
2479
2556
  setTimeout(() => {
2480
2557
  if (typingData.interval && !typingData.cleared) {
2481
2558
  clearInterval(typingData.interval);
@@ -2497,13 +2574,16 @@ var MessageManager = class {
2497
2574
  let processedContent = message.content;
2498
2575
  let attachments = [];
2499
2576
  const mentionRegex = /<@!?(\d+)>/g;
2500
- processedContent = processedContent.replace(mentionRegex, (match2, entityId) => {
2501
- const user = message.mentions.users.get(entityId);
2502
- if (user) {
2503
- return `${user.username} (@${entityId})`;
2577
+ processedContent = processedContent.replace(
2578
+ mentionRegex,
2579
+ (match2, entityId) => {
2580
+ const user = message.mentions.users.get(entityId);
2581
+ if (user) {
2582
+ return `${user.username} (@${entityId})`;
2583
+ }
2584
+ return match2;
2504
2585
  }
2505
- return match2;
2506
- });
2586
+ );
2507
2587
  const codeBlockRegex = /```([\s\S]*?)```/g;
2508
2588
  let match;
2509
2589
  while (match = codeBlockRegex.exec(processedContent)) {
@@ -2520,10 +2600,15 @@ var MessageManager = class {
2520
2600
  description,
2521
2601
  text: codeBlock
2522
2602
  });
2523
- processedContent = processedContent.replace(match[0], `Code Block (${attachmentId})`);
2603
+ processedContent = processedContent.replace(
2604
+ match[0],
2605
+ `Code Block (${attachmentId})`
2606
+ );
2524
2607
  }
2525
2608
  if (message.attachments.size > 0) {
2526
- attachments = await this.attachmentManager.processAttachments(message.attachments);
2609
+ attachments = await this.attachmentManager.processAttachments(
2610
+ message.attachments
2611
+ );
2527
2612
  }
2528
2613
  const urlRegex = /(https?:\/\/[^\s]+)/g;
2529
2614
  const urls = processedContent.match(urlRegex) || [];
@@ -2540,15 +2625,14 @@ var MessageManager = class {
2540
2625
  text: videoInfo.text
2541
2626
  });
2542
2627
  } else {
2543
- const browserService = this.runtime.getService(ServiceType4.BROWSER);
2628
+ const browserService = this.runtime.getService(
2629
+ ServiceType4.BROWSER
2630
+ );
2544
2631
  if (!browserService) {
2545
2632
  logger4.warn("Browser service not found");
2546
2633
  continue;
2547
2634
  }
2548
- const { title, description: summary } = await browserService.getPageContent(
2549
- url,
2550
- this.runtime
2551
- );
2635
+ const { title, description: summary } = await browserService.getPageContent(url, this.runtime);
2552
2636
  attachments.push({
2553
2637
  id: `webpage-${Date.now()}`,
2554
2638
  url,
@@ -2586,8 +2670,6 @@ var MessageManager = class {
2586
2670
  };
2587
2671
 
2588
2672
  // src/voice.ts
2589
- import { EventEmitter } from "node:events";
2590
- import { pipeline } from "node:stream";
2591
2673
  import {
2592
2674
  NoSubscriberBehavior,
2593
2675
  StreamType,
@@ -2602,15 +2684,48 @@ import {
2602
2684
  ChannelType as ChannelType8,
2603
2685
  ModelType as ModelType8,
2604
2686
  createUniqueUuid as createUniqueUuid5,
2605
- getWavHeader,
2606
2687
  logger as logger5
2607
2688
  } from "@elizaos/core";
2608
2689
  import {
2609
2690
  ChannelType as DiscordChannelType3
2610
2691
  } from "discord.js";
2692
+ import { EventEmitter } from "node:events";
2693
+ import { pipeline } from "node:stream";
2611
2694
  import prism from "prism-media";
2612
2695
  var DECODE_FRAME_SIZE = 1024;
2613
2696
  var DECODE_SAMPLE_RATE = 16e3;
2697
+ function createOpusDecoder(options) {
2698
+ try {
2699
+ return new prism.opus.Decoder(options);
2700
+ } catch (error) {
2701
+ logger5.warn(`Failed to create opus decoder with prism-media: ${error}`);
2702
+ try {
2703
+ const { generateDependencyReport } = __require("@discordjs/voice");
2704
+ const report = generateDependencyReport();
2705
+ logger5.debug("Voice dependency report:", report);
2706
+ } catch (reportError) {
2707
+ logger5.warn("Could not generate dependency report:", reportError);
2708
+ }
2709
+ throw error;
2710
+ }
2711
+ }
2712
+ function getWavHeader(audioLength, sampleRate, channelCount = 1, bitsPerSample = 16) {
2713
+ const wavHeader = Buffer.alloc(44);
2714
+ wavHeader.write("RIFF", 0);
2715
+ wavHeader.writeUInt32LE(36 + audioLength, 4);
2716
+ wavHeader.write("WAVE", 8);
2717
+ wavHeader.write("fmt ", 12);
2718
+ wavHeader.writeUInt32LE(16, 16);
2719
+ wavHeader.writeUInt16LE(1, 20);
2720
+ wavHeader.writeUInt16LE(channelCount, 22);
2721
+ wavHeader.writeUInt32LE(sampleRate, 24);
2722
+ wavHeader.writeUInt32LE(sampleRate * bitsPerSample * channelCount / 8, 28);
2723
+ wavHeader.writeUInt16LE(bitsPerSample * channelCount / 8, 32);
2724
+ wavHeader.writeUInt16LE(bitsPerSample, 34);
2725
+ wavHeader.write("data", 36);
2726
+ wavHeader.writeUInt32LE(audioLength, 40);
2727
+ return wavHeader;
2728
+ }
2614
2729
  var AudioMonitor = class {
2615
2730
  readable;
2616
2731
  buffers = [];
@@ -2632,7 +2747,10 @@ var AudioMonitor = class {
2632
2747
  this.lastFlagged = this.buffers.length;
2633
2748
  }
2634
2749
  this.buffers.push(chunk);
2635
- const currentSize = this.buffers.reduce((acc, cur) => acc + cur.length, 0);
2750
+ const currentSize = this.buffers.reduce(
2751
+ (acc, cur) => acc + cur.length,
2752
+ 0
2753
+ );
2636
2754
  while (currentSize > this.maxSize) {
2637
2755
  this.buffers.shift();
2638
2756
  this.lastFlagged--;
@@ -2799,7 +2917,10 @@ var VoiceManager = class extends EventEmitter {
2799
2917
  this.stopMonitoringMember(member.id);
2800
2918
  }
2801
2919
  if (newChannelId && this.connections.has(newChannelId)) {
2802
- await this.monitorMember(member, newState.channel);
2920
+ await this.monitorMember(
2921
+ member,
2922
+ newState.channel
2923
+ );
2803
2924
  }
2804
2925
  }
2805
2926
  /**
@@ -2830,9 +2951,13 @@ var VoiceManager = class extends EventEmitter {
2830
2951
  entersState(connection, VoiceConnectionStatus.Ready, 2e4),
2831
2952
  entersState(connection, VoiceConnectionStatus.Signalling, 2e4)
2832
2953
  ]);
2833
- logger5.log(`Voice connection established in state: ${connection.state.status}`);
2954
+ logger5.log(
2955
+ `Voice connection established in state: ${connection.state.status}`
2956
+ );
2834
2957
  connection.on("stateChange", async (oldState, newState) => {
2835
- logger5.log(`Voice connection state changed from ${oldState.status} to ${newState.status}`);
2958
+ logger5.log(
2959
+ `Voice connection state changed from ${oldState.status} to ${newState.status}`
2960
+ );
2836
2961
  if (newState.status === VoiceConnectionStatus.Disconnected) {
2837
2962
  logger5.log("Handling disconnection...");
2838
2963
  try {
@@ -2929,20 +3054,34 @@ var VoiceManager = class extends EventEmitter {
2929
3054
  emitClose: true
2930
3055
  });
2931
3056
  if (!receiveStream || receiveStream.readableLength === 0) {
2932
- logger5.warn(`[monitorMember] No receiveStream or empty stream for user ${entityId}`);
3057
+ logger5.warn(
3058
+ `[monitorMember] No receiveStream or empty stream for user ${entityId}`
3059
+ );
3060
+ return;
3061
+ }
3062
+ let opusDecoder;
3063
+ try {
3064
+ opusDecoder = createOpusDecoder({
3065
+ channels: 1,
3066
+ rate: DECODE_SAMPLE_RATE,
3067
+ frameSize: DECODE_FRAME_SIZE
3068
+ });
3069
+ } catch (error) {
3070
+ logger5.error(
3071
+ `[monitorMember] Failed to create opus decoder for user ${entityId}: ${error}`
3072
+ );
2933
3073
  return;
2934
3074
  }
2935
- const opusDecoder = new prism.opus.Decoder({
2936
- channels: 1,
2937
- rate: DECODE_SAMPLE_RATE,
2938
- frameSize: DECODE_FRAME_SIZE
2939
- });
2940
3075
  const volumeBuffer = [];
2941
3076
  const VOLUME_WINDOW_SIZE = 30;
2942
3077
  const SPEAKING_THRESHOLD = 0.05;
2943
3078
  opusDecoder.on("data", (pcmData) => {
2944
3079
  if (this.activeAudioPlayer) {
2945
- const samples = new Int16Array(pcmData.buffer, pcmData.byteOffset, pcmData.length / 2);
3080
+ const samples = new Int16Array(
3081
+ pcmData.buffer,
3082
+ pcmData.byteOffset,
3083
+ pcmData.length / 2
3084
+ );
2946
3085
  const maxAmplitude = Math.max(...samples.map(Math.abs)) / 32768;
2947
3086
  volumeBuffer.push(maxAmplitude);
2948
3087
  if (volumeBuffer.length > VOLUME_WINDOW_SIZE) {
@@ -2956,15 +3095,21 @@ var VoiceManager = class extends EventEmitter {
2956
3095
  }
2957
3096
  }
2958
3097
  });
2959
- pipeline(receiveStream, opusDecoder, (err) => {
2960
- if (err) {
2961
- logger5.debug(`[monitorMember] Opus decoding pipeline error for user ${entityId}: ${err}`);
2962
- } else {
2963
- logger5.debug(
2964
- `[monitorMember] Opus decoding pipeline finished successfully for user ${entityId}`
2965
- );
3098
+ pipeline(
3099
+ receiveStream,
3100
+ opusDecoder,
3101
+ (err) => {
3102
+ if (err) {
3103
+ logger5.debug(
3104
+ `[monitorMember] Opus decoding pipeline error for user ${entityId}: ${err}`
3105
+ );
3106
+ } else {
3107
+ logger5.debug(
3108
+ `[monitorMember] Opus decoding pipeline finished successfully for user ${entityId}`
3109
+ );
3110
+ }
2966
3111
  }
2967
- });
3112
+ );
2968
3113
  this.streams.set(entityId, opusDecoder);
2969
3114
  this.connections.set(entityId, connection);
2970
3115
  opusDecoder.on("error", (err) => {
@@ -2987,7 +3132,14 @@ var VoiceManager = class extends EventEmitter {
2987
3132
  opusDecoder.on("error", errorHandler);
2988
3133
  opusDecoder.on("close", closeHandler);
2989
3134
  receiveStream?.on("close", streamCloseHandler);
2990
- this.client?.emit("userStream", entityId, name, userName, channel, opusDecoder);
3135
+ this.client?.emit(
3136
+ "userStream",
3137
+ entityId,
3138
+ name,
3139
+ userName,
3140
+ channel,
3141
+ opusDecoder
3142
+ );
2991
3143
  }
2992
3144
  /**
2993
3145
  * Leaves the specified voice channel and stops monitoring all members in that channel.
@@ -3049,7 +3201,13 @@ var VoiceManager = class extends EventEmitter {
3049
3201
  this.transcriptionTimeout = setTimeout(async () => {
3050
3202
  this.processingVoice = true;
3051
3203
  try {
3052
- await this.processTranscription(entityId, channel.id, channel, name, userName);
3204
+ await this.processTranscription(
3205
+ entityId,
3206
+ channel.id,
3207
+ channel,
3208
+ name,
3209
+ userName
3210
+ );
3053
3211
  this.userStates.forEach((state, _) => {
3054
3212
  state.buffers.length = 0;
3055
3213
  state.totalLength = 0;
@@ -3130,7 +3288,10 @@ var VoiceManager = class extends EventEmitter {
3130
3288
  state.totalLength = 0;
3131
3289
  const wavBuffer = await this.convertOpusToWav(inputBuffer);
3132
3290
  logger5.debug("Starting transcription...");
3133
- const transcriptionText = await this.runtime.useModel(ModelType8.TRANSCRIPTION, wavBuffer);
3291
+ const transcriptionText = await this.runtime.useModel(
3292
+ ModelType8.TRANSCRIPTION,
3293
+ wavBuffer
3294
+ );
3134
3295
  if (transcriptionText && isValidTranscription2(transcriptionText)) {
3135
3296
  state.transcriptionText += transcriptionText;
3136
3297
  }
@@ -3138,7 +3299,14 @@ var VoiceManager = class extends EventEmitter {
3138
3299
  this.cleanupAudioPlayer(this.activeAudioPlayer);
3139
3300
  const finalText = state.transcriptionText;
3140
3301
  state.transcriptionText = "";
3141
- await this.handleMessage(finalText, entityId, channelId, channel, name, userName);
3302
+ await this.handleMessage(
3303
+ finalText,
3304
+ entityId,
3305
+ channelId,
3306
+ channel,
3307
+ name,
3308
+ userName
3309
+ );
3142
3310
  }
3143
3311
  } catch (error) {
3144
3312
  console.error(`Error transcribing audio for user ${entityId}:`, error);
@@ -3176,7 +3344,10 @@ var VoiceManager = class extends EventEmitter {
3176
3344
  worldName: channel.guild.name
3177
3345
  });
3178
3346
  const memory = {
3179
- id: createUniqueUuid5(this.runtime, `${channelId}-voice-message-${Date.now()}`),
3347
+ id: createUniqueUuid5(
3348
+ this.runtime,
3349
+ `${channelId}-voice-message-${Date.now()}`
3350
+ ),
3180
3351
  agentId: this.runtime.agentId,
3181
3352
  entityId: uniqueEntityId,
3182
3353
  roomId,
@@ -3194,7 +3365,10 @@ var VoiceManager = class extends EventEmitter {
3194
3365
  const callback = async (content, _files = []) => {
3195
3366
  try {
3196
3367
  const responseMemory = {
3197
- id: createUniqueUuid5(this.runtime, `${memory.id}-voice-response-${Date.now()}`),
3368
+ id: createUniqueUuid5(
3369
+ this.runtime,
3370
+ `${memory.id}-voice-response-${Date.now()}`
3371
+ ),
3198
3372
  entityId: this.runtime.agentId,
3199
3373
  agentId: this.runtime.agentId,
3200
3374
  content: {
@@ -3223,11 +3397,14 @@ var VoiceManager = class extends EventEmitter {
3223
3397
  return [];
3224
3398
  }
3225
3399
  };
3226
- this.runtime.emitEvent(["DISCORD_VOICE_MESSAGE_RECEIVED", "VOICE_MESSAGE_RECEIVED"], {
3227
- runtime: this.runtime,
3228
- message: memory,
3229
- callback
3230
- });
3400
+ this.runtime.emitEvent(
3401
+ ["DISCORD_VOICE_MESSAGE_RECEIVED", "VOICE_MESSAGE_RECEIVED"],
3402
+ {
3403
+ runtime: this.runtime,
3404
+ message: memory,
3405
+ callback
3406
+ }
3407
+ );
3231
3408
  } catch (error) {
3232
3409
  console.error("Error processing voice message:", error);
3233
3410
  }
@@ -3256,7 +3433,9 @@ var VoiceManager = class extends EventEmitter {
3256
3433
  async scanGuild(guild) {
3257
3434
  let chosenChannel = null;
3258
3435
  try {
3259
- const channelId = this.runtime.getSetting("DISCORD_VOICE_CHANNEL_ID");
3436
+ const channelId = this.runtime.getSetting(
3437
+ "DISCORD_VOICE_CHANNEL_ID"
3438
+ );
3260
3439
  if (channelId) {
3261
3440
  const channel = await guild.channels.fetch(channelId);
3262
3441
  if (channel?.isVoiceBased()) {
@@ -3313,12 +3492,15 @@ var VoiceManager = class extends EventEmitter {
3313
3492
  audioPlayer.on("error", (err) => {
3314
3493
  logger5.debug(`Audio player error: ${err}`);
3315
3494
  });
3316
- audioPlayer.on("stateChange", (_oldState, newState) => {
3317
- if (newState.status === "idle") {
3318
- const idleTime = Date.now();
3319
- logger5.debug(`Audio playback took: ${idleTime - audioStartTime}ms`);
3495
+ audioPlayer.on(
3496
+ "stateChange",
3497
+ (_oldState, newState) => {
3498
+ if (newState.status === "idle") {
3499
+ const idleTime = Date.now();
3500
+ logger5.debug(`Audio playback took: ${idleTime - audioStartTime}ms`);
3501
+ }
3320
3502
  }
3321
- });
3503
+ );
3322
3504
  }
3323
3505
  /**
3324
3506
  * Cleans up the provided audio player by stopping it, removing all listeners,
@@ -3420,7 +3602,9 @@ var DiscordService = class _DiscordService extends Service {
3420
3602
  }
3421
3603
  const token = runtime.getSetting("DISCORD_API_TOKEN");
3422
3604
  if (!token || token.trim() === "") {
3423
- logger6.warn("Discord API Token not provided - Discord functionality will be unavailable");
3605
+ logger6.warn(
3606
+ "Discord API Token not provided - Discord functionality will be unavailable"
3607
+ );
3424
3608
  this.client = null;
3425
3609
  return;
3426
3610
  }
@@ -3438,7 +3622,12 @@ var DiscordService = class _DiscordService extends Service {
3438
3622
  GatewayIntentBits.GuildMessageTyping,
3439
3623
  GatewayIntentBits.GuildMessageReactions
3440
3624
  ],
3441
- partials: [Partials.Channel, Partials.Message, Partials.User, Partials.Reaction]
3625
+ partials: [
3626
+ Partials.Channel,
3627
+ Partials.Message,
3628
+ Partials.User,
3629
+ Partials.Reaction
3630
+ ]
3442
3631
  });
3443
3632
  this.runtime = runtime;
3444
3633
  this.voiceManager = new VoiceManager(this, runtime);
@@ -3469,7 +3658,10 @@ var DiscordService = class _DiscordService extends Service {
3469
3658
  */
3470
3659
  registerSendHandler() {
3471
3660
  if (this.runtime) {
3472
- this.runtime.registerSendHandler("discord", this.handleSendMessage.bind(this));
3661
+ this.runtime.registerSendHandler(
3662
+ "discord",
3663
+ this.handleSendMessage.bind(this)
3664
+ );
3473
3665
  }
3474
3666
  }
3475
3667
  /**
@@ -3517,10 +3709,14 @@ var DiscordService = class _DiscordService extends Service {
3517
3709
  await targetChannel.send(chunk);
3518
3710
  }
3519
3711
  } else {
3520
- logger6.warn("[Discord SendHandler] No text content provided to send.");
3712
+ logger6.warn(
3713
+ "[Discord SendHandler] No text content provided to send."
3714
+ );
3521
3715
  }
3522
3716
  } else {
3523
- throw new Error(`Target channel ${targetChannel.id} does not have a send method.`);
3717
+ throw new Error(
3718
+ `Target channel ${targetChannel.id} does not have a send method.`
3719
+ );
3524
3720
  }
3525
3721
  } else {
3526
3722
  throw new Error(
@@ -3577,12 +3773,32 @@ var DiscordService = class _DiscordService extends Service {
3577
3773
  if (!this.client) {
3578
3774
  return;
3579
3775
  }
3580
- this.client.on("messageCreate", (message) => {
3581
- if (message.author.id === this.client?.user?.id || message.author.bot) {
3776
+ this.client.on("messageCreate", async (message) => {
3777
+ if (message.author.id === this.client?.user?.id || message.author.bot && this.runtime.character.settings?.discord?.shouldIgnoreBotMessages) {
3778
+ logger6.info(
3779
+ `Got message where author is ${message.author.bot && this.runtime.character.settings?.discord?.shouldIgnoreBotMessages ? "a bot. To reply anyway, set `shouldIgnoreBotMessages=true`." : "the current user. Ignore!"}`
3780
+ );
3582
3781
  return;
3583
3782
  }
3584
3783
  if (this.allowedChannelIds && !this.allowedChannelIds.includes(message.channel.id)) {
3585
- return;
3784
+ const channel = await this.client?.channels.fetch(message.channel.id);
3785
+ if (!channel) {
3786
+ logger6.error(`Channel id ${message.channel.id} not found. Ignore!`);
3787
+ return;
3788
+ }
3789
+ if (channel.isThread()) {
3790
+ if (!channel.parentId || !this.allowedChannelIds.includes(channel.parentId)) {
3791
+ logger6.info(
3792
+ `Thread not in an allowed channel. Add the channel ${channel.parentId} to CHANNEL_IDS to enable replies.`
3793
+ );
3794
+ return;
3795
+ }
3796
+ } else {
3797
+ logger6.info(
3798
+ `Channel not allowed. Add the channel ${message.channel.id} to CHANNEL_IDS to enable replies.`
3799
+ );
3800
+ return;
3801
+ }
3586
3802
  }
3587
3803
  try {
3588
3804
  this.messageManager?.handleMessage(message);
@@ -3640,11 +3856,20 @@ var DiscordService = class _DiscordService extends Service {
3640
3856
  logger6.error(`Error handling interaction: ${error}`);
3641
3857
  }
3642
3858
  });
3643
- this.client.on("userStream", (entityId, name, userName, channel, opusDecoder) => {
3644
- if (entityId !== this.client?.user?.id) {
3645
- this.voiceManager?.handleUserStream(entityId, name, userName, channel, opusDecoder);
3859
+ this.client.on(
3860
+ "userStream",
3861
+ (entityId, name, userName, channel, opusDecoder) => {
3862
+ if (entityId !== this.client?.user?.id) {
3863
+ this.voiceManager?.handleUserStream(
3864
+ entityId,
3865
+ name,
3866
+ userName,
3867
+ channel,
3868
+ opusDecoder
3869
+ );
3870
+ }
3646
3871
  }
3647
- });
3872
+ );
3648
3873
  }
3649
3874
  /**
3650
3875
  * Handles the event when a new member joins a guild.
@@ -3743,7 +3968,9 @@ var DiscordService = class _DiscordService extends Service {
3743
3968
  }
3744
3969
  const userSelections = this.userSelections.get(userId);
3745
3970
  if (!userSelections) {
3746
- logger6.error(`User selections map unexpectedly missing for user ${userId}`);
3971
+ logger6.error(
3972
+ `User selections map unexpectedly missing for user ${userId}`
3973
+ );
3747
3974
  return;
3748
3975
  }
3749
3976
  try {
@@ -3763,9 +3990,13 @@ var DiscordService = class _DiscordService extends Service {
3763
3990
  }
3764
3991
  if (interaction.isButton()) {
3765
3992
  logger6.info("Button interaction detected");
3766
- logger6.info(`Button pressed by user ${userId}: ${interaction.customId}`);
3993
+ logger6.info(
3994
+ `Button pressed by user ${userId}: ${interaction.customId}`
3995
+ );
3767
3996
  const formSelections = userSelections[messageId] || {};
3768
- logger6.info(`Form data being submitted: ${JSON.stringify(formSelections)}`);
3997
+ logger6.info(
3998
+ `Form data being submitted: ${JSON.stringify(formSelections)}`
3999
+ );
3769
4000
  this.runtime.emitEvent(["DISCORD_INTERACTION"], {
3770
4001
  interaction: {
3771
4002
  customId: interaction.customId,
@@ -3829,7 +4060,10 @@ var DiscordService = class _DiscordService extends Service {
3829
4060
  (member) => channel.permissionsFor(member)?.has(PermissionsBitField2.Flags.ViewChannel)
3830
4061
  ).map((member) => createUniqueUuid6(this.runtime, member.id));
3831
4062
  } catch (error) {
3832
- logger6.warn(`Failed to get participants for channel ${channel.name}:`, error);
4063
+ logger6.warn(
4064
+ `Failed to get participants for channel ${channel.name}:`,
4065
+ error
4066
+ );
3833
4067
  }
3834
4068
  }
3835
4069
  rooms.push({
@@ -3866,9 +4100,11 @@ var DiscordService = class _DiscordService extends Service {
3866
4100
  id: createUniqueUuid6(this.runtime, member.id),
3867
4101
  names: Array.from(
3868
4102
  new Set(
3869
- [member.user.username, member.displayName, member.user.globalName].filter(
3870
- Boolean
3871
- )
4103
+ [
4104
+ member.user.username,
4105
+ member.displayName,
4106
+ member.user.globalName
4107
+ ].filter(Boolean)
3872
4108
  )
3873
4109
  ),
3874
4110
  agentId: this.runtime.agentId,
@@ -3903,9 +4139,11 @@ var DiscordService = class _DiscordService extends Service {
3903
4139
  id: entityId,
3904
4140
  names: Array.from(
3905
4141
  new Set(
3906
- [member.user.username, member.displayName, member.user.globalName].filter(
3907
- Boolean
3908
- )
4142
+ [
4143
+ member.user.username,
4144
+ member.displayName,
4145
+ member.user.globalName
4146
+ ].filter(Boolean)
3909
4147
  )
3910
4148
  ),
3911
4149
  agentId: this.runtime.agentId,
@@ -3946,9 +4184,11 @@ var DiscordService = class _DiscordService extends Service {
3946
4184
  id: createUniqueUuid6(this.runtime, member.id),
3947
4185
  names: Array.from(
3948
4186
  new Set(
3949
- [member.user.username, member.displayName, member.user.globalName].filter(
3950
- Boolean
3951
- )
4187
+ [
4188
+ member.user.username,
4189
+ member.displayName,
4190
+ member.user.globalName
4191
+ ].filter(Boolean)
3952
4192
  )
3953
4193
  ),
3954
4194
  agentId: this.runtime.agentId,
@@ -4056,9 +4296,13 @@ var DiscordService = class _DiscordService extends Service {
4056
4296
  * @returns {Promise<Array<{id: string, username: string, displayName: string}>>} A promise that resolves with an array of channel member objects, each containing id, username, and displayName.
4057
4297
  */
4058
4298
  async getTextChannelMembers(channelId, useCache = true) {
4059
- logger6.info(`Fetching members for text channel ${channelId}, useCache=${useCache}`);
4299
+ logger6.info(
4300
+ `Fetching members for text channel ${channelId}, useCache=${useCache}`
4301
+ );
4060
4302
  try {
4061
- const channel = await this.client?.channels.fetch(channelId);
4303
+ const channel = await this.client?.channels.fetch(
4304
+ channelId
4305
+ );
4062
4306
  if (!channel) {
4063
4307
  logger6.error(`Channel not found: ${channelId}`);
4064
4308
  return [];
@@ -4082,7 +4326,9 @@ var DiscordService = class _DiscordService extends Service {
4082
4326
  } else {
4083
4327
  try {
4084
4328
  if (useCache && guild.members.cache.size > 0) {
4085
- logger6.info(`Using cached members (${guild.members.cache.size} members)`);
4329
+ logger6.info(
4330
+ `Using cached members (${guild.members.cache.size} members)`
4331
+ );
4086
4332
  members = guild.members.cache;
4087
4333
  } else {
4088
4334
  logger6.info(`Fetching members for guild ${guild.name}`);
@@ -4107,7 +4353,9 @@ var DiscordService = class _DiscordService extends Service {
4107
4353
  username: member.user.username,
4108
4354
  displayName: member.displayName || member.user.username
4109
4355
  }));
4110
- logger6.info(`Found ${channelMembers.length} members with access to channel ${channel.name}`);
4356
+ logger6.info(
4357
+ `Found ${channelMembers.length} members with access to channel ${channel.name}`
4358
+ );
4111
4359
  return channelMembers;
4112
4360
  } catch (error) {
4113
4361
  logger6.error(`Error fetching channel members: ${error}`);
@@ -4138,7 +4386,10 @@ var DiscordService = class _DiscordService extends Service {
4138
4386
  }
4139
4387
  }
4140
4388
  const timestamp = Date.now();
4141
- const roomId = createUniqueUuid6(this.runtime, reaction.message.channel.id);
4389
+ const roomId = createUniqueUuid6(
4390
+ this.runtime,
4391
+ reaction.message.channel.id
4392
+ );
4142
4393
  const entityId = createUniqueUuid6(this.runtime, user.id);
4143
4394
  const reactionUUID = createUniqueUuid6(
4144
4395
  this.runtime,
@@ -4160,7 +4411,10 @@ var DiscordService = class _DiscordService extends Service {
4160
4411
  entityId,
4161
4412
  roomId,
4162
4413
  userName,
4163
- worldId: createUniqueUuid6(this.runtime, reaction.message.guild?.id ?? roomId),
4414
+ worldId: createUniqueUuid6(
4415
+ this.runtime,
4416
+ reaction.message.guild?.id ?? roomId
4417
+ ),
4164
4418
  worldName: reaction.message.guild?.name,
4165
4419
  name,
4166
4420
  source: "discord",
@@ -4179,7 +4433,9 @@ var DiscordService = class _DiscordService extends Service {
4179
4433
  text: reactionMessage,
4180
4434
  source: "discord",
4181
4435
  inReplyTo,
4182
- channelType: await this.getChannelType(reaction.message.channel)
4436
+ channelType: await this.getChannelType(
4437
+ reaction.message.channel
4438
+ )
4183
4439
  },
4184
4440
  roomId,
4185
4441
  createdAt: timestamp
@@ -4189,14 +4445,19 @@ var DiscordService = class _DiscordService extends Service {
4189
4445
  logger6.error("No channel found for reaction message");
4190
4446
  return [];
4191
4447
  }
4192
- await reaction.message.channel.send(content.text ?? "");
4448
+ await reaction.message.channel.send(
4449
+ content.text ?? ""
4450
+ );
4193
4451
  return [];
4194
4452
  };
4195
- this.runtime.emitEvent(["DISCORD_REACTION_RECEIVED", "REACTION_RECEIVED"], {
4196
- runtime: this.runtime,
4197
- message: memory,
4198
- callback
4199
- });
4453
+ this.runtime.emitEvent(
4454
+ ["DISCORD_REACTION_RECEIVED", "REACTION_RECEIVED"],
4455
+ {
4456
+ runtime: this.runtime,
4457
+ message: memory,
4458
+ callback
4459
+ }
4460
+ );
4200
4461
  } catch (error) {
4201
4462
  logger6.error("Error handling reaction:", error);
4202
4463
  }
@@ -4216,14 +4477,20 @@ var DiscordService = class _DiscordService extends Service {
4216
4477
  try {
4217
4478
  await reaction.fetch();
4218
4479
  } catch (error) {
4219
- logger6.error("Something went wrong when fetching the message:", error);
4480
+ logger6.error(
4481
+ "Something went wrong when fetching the message:",
4482
+ error
4483
+ );
4220
4484
  return;
4221
4485
  }
4222
4486
  }
4223
4487
  const messageContent = reaction.message.content || "";
4224
4488
  const truncatedContent = messageContent.length > 50 ? `${messageContent.substring(0, 50)}...` : messageContent;
4225
4489
  const reactionMessage = `*Removed <${emoji}> from: \\"${truncatedContent}\\"*`;
4226
- const roomId = createUniqueUuid6(this.runtime, reaction.message.channel.id);
4490
+ const roomId = createUniqueUuid6(
4491
+ this.runtime,
4492
+ reaction.message.channel.id
4493
+ );
4227
4494
  const entityId = createUniqueUuid6(this.runtime, user.id);
4228
4495
  const timestamp = Date.now();
4229
4496
  const reactionUUID = createUniqueUuid6(
@@ -4236,7 +4503,10 @@ var DiscordService = class _DiscordService extends Service {
4236
4503
  entityId,
4237
4504
  roomId,
4238
4505
  userName,
4239
- worldId: createUniqueUuid6(this.runtime, reaction.message.guild?.id ?? roomId),
4506
+ worldId: createUniqueUuid6(
4507
+ this.runtime,
4508
+ reaction.message.guild?.id ?? roomId
4509
+ ),
4240
4510
  worldName: reaction.message.guild?.name,
4241
4511
  name,
4242
4512
  source: "discord",
@@ -4254,7 +4524,9 @@ var DiscordService = class _DiscordService extends Service {
4254
4524
  text: reactionMessage,
4255
4525
  source: "discord",
4256
4526
  inReplyTo: createUniqueUuid6(this.runtime, reaction.message.id),
4257
- channelType: await this.getChannelType(reaction.message.channel)
4527
+ channelType: await this.getChannelType(
4528
+ reaction.message.channel
4529
+ )
4258
4530
  },
4259
4531
  roomId,
4260
4532
  createdAt: Date.now()
@@ -4264,7 +4536,9 @@ var DiscordService = class _DiscordService extends Service {
4264
4536
  logger6.error("No channel found for reaction message");
4265
4537
  return [];
4266
4538
  }
4267
- await reaction.message.channel.send(content.text ?? "");
4539
+ await reaction.message.channel.send(
4540
+ content.text ?? ""
4541
+ );
4268
4542
  return [];
4269
4543
  };
4270
4544
  this.runtime.emitEvent(["DISCORD_REACTION_RECEIVED" /* REACTION_RECEIVED */], {
@@ -4323,8 +4597,15 @@ import {
4323
4597
  createAudioResource as createAudioResource2,
4324
4598
  entersState as entersState2
4325
4599
  } from "@discordjs/voice";
4326
- import { ModelType as ModelType9, logger as logger7 } from "@elizaos/core";
4327
- import { ChannelType as ChannelType10, Events as Events2, AttachmentBuilder } from "discord.js";
4600
+ import {
4601
+ ModelType as ModelType9,
4602
+ logger as logger7
4603
+ } from "@elizaos/core";
4604
+ import {
4605
+ ChannelType as ChannelType10,
4606
+ Events as Events2,
4607
+ AttachmentBuilder
4608
+ } from "discord.js";
4328
4609
  var TEST_IMAGE_URL = "https://github.com/elizaOS/awesome-eliza/blob/main/assets/eliza-logo.jpg?raw=true";
4329
4610
  var DiscordTestSuite = class {
4330
4611
  name = "discord";
@@ -4374,7 +4655,9 @@ var DiscordTestSuite = class {
4374
4655
  */
4375
4656
  async testCreatingDiscordClient(runtime) {
4376
4657
  try {
4377
- this.discordClient = runtime.getService(ServiceType2.DISCORD);
4658
+ this.discordClient = runtime.getService(
4659
+ ServiceType2.DISCORD
4660
+ );
4378
4661
  if (!this.discordClient) {
4379
4662
  throw new Error("Failed to get DiscordService from runtime.");
4380
4663
  }
@@ -4383,7 +4666,9 @@ var DiscordTestSuite = class {
4383
4666
  } else {
4384
4667
  logger7.info("Waiting for DiscordService to be ready...");
4385
4668
  if (!this.discordClient.client) {
4386
- throw new Error("Discord client instance is missing within the service.");
4669
+ throw new Error(
4670
+ "Discord client instance is missing within the service."
4671
+ );
4387
4672
  }
4388
4673
  await new Promise((resolve, reject) => {
4389
4674
  this.discordClient.client?.once(Events2.ClientReady, resolve);
@@ -4425,7 +4710,9 @@ var DiscordTestSuite = class {
4425
4710
  if (!this.discordClient.voiceManager) {
4426
4711
  throw new Error("VoiceManager is not available on the Discord client.");
4427
4712
  }
4428
- await this.discordClient.voiceManager.handleJoinChannelCommand(fakeJoinInteraction);
4713
+ await this.discordClient.voiceManager.handleJoinChannelCommand(
4714
+ fakeJoinInteraction
4715
+ );
4429
4716
  logger7.success("Join voice slash command test completed successfully.");
4430
4717
  } catch (error) {
4431
4718
  throw new Error(`Error in join voice slash commands test: ${error}`);
@@ -4456,7 +4743,9 @@ var DiscordTestSuite = class {
4456
4743
  if (!this.discordClient.voiceManager) {
4457
4744
  throw new Error("VoiceManager is not available on the Discord client.");
4458
4745
  }
4459
- await this.discordClient.voiceManager.handleLeaveChannelCommand(fakeLeaveInteraction);
4746
+ await this.discordClient.voiceManager.handleLeaveChannelCommand(
4747
+ fakeLeaveInteraction
4748
+ );
4460
4749
  logger7.success("Leave voice slash command test completed successfully.");
4461
4750
  } catch (error) {
4462
4751
  throw new Error(`Error in leave voice slash commands test: ${error}`);
@@ -4526,7 +4815,11 @@ var DiscordTestSuite = class {
4526
4815
  throw new Error("Cannot send message to a non-text channel.");
4527
4816
  }
4528
4817
  const attachment = new AttachmentBuilder(TEST_IMAGE_URL);
4529
- await this.sendMessageToChannel(channel, "Testing Message", [attachment]);
4818
+ await this.sendMessageToChannel(
4819
+ channel,
4820
+ "Testing Message",
4821
+ [attachment]
4822
+ );
4530
4823
  } catch (error) {
4531
4824
  throw new Error(`Error in sending text message: ${error}`);
4532
4825
  }
@@ -4558,7 +4851,9 @@ var DiscordTestSuite = class {
4558
4851
  attachments: []
4559
4852
  };
4560
4853
  if (!this.discordClient.messageManager) {
4561
- throw new Error("MessageManager is not available on the Discord client.");
4854
+ throw new Error(
4855
+ "MessageManager is not available on the Discord client."
4856
+ );
4562
4857
  }
4563
4858
  await this.discordClient.messageManager.handleMessage(fakeMessage);
4564
4859
  } catch (error) {
@@ -4594,9 +4889,16 @@ var DiscordTestSuite = class {
4594
4889
  async sendMessageToChannel(channel, messageContent, files) {
4595
4890
  try {
4596
4891
  if (!channel || !channel.isTextBased()) {
4597
- throw new Error("Channel is not a text-based channel or does not exist.");
4892
+ throw new Error(
4893
+ "Channel is not a text-based channel or does not exist."
4894
+ );
4598
4895
  }
4599
- await sendMessageInChunks(channel, messageContent, "", files);
4896
+ await sendMessageInChunks(
4897
+ channel,
4898
+ messageContent,
4899
+ "",
4900
+ files
4901
+ );
4600
4902
  } catch (error) {
4601
4903
  throw new Error(`Error sending message: ${error}`);
4602
4904
  }
@@ -4692,7 +4994,14 @@ var discordPlugin = {
4692
4994
  name: "discord",
4693
4995
  description: "Discord service plugin for integration with Discord servers and channels",
4694
4996
  services: [DiscordService],
4695
- actions: [chatWithAttachments_default, downloadMedia, joinVoice, leaveVoice, summarize, transcribeMedia],
4997
+ actions: [
4998
+ chatWithAttachments_default,
4999
+ downloadMedia,
5000
+ joinVoice,
5001
+ leaveVoice,
5002
+ summarize,
5003
+ transcribeMedia
5004
+ ],
4696
5005
  providers: [channelStateProvider, voiceStateProvider],
4697
5006
  tests: [new DiscordTestSuite()],
4698
5007
  init: async (config, runtime) => {