@elizaos/plugin-discord 1.0.0-beta.4 → 1.0.0-beta.40

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Shaw Walters, aka Moon aka @lalalune
3
+ Copyright (c) 2025 Shaw Walters and elizaOS Contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.js CHANGED
@@ -134,7 +134,14 @@ var chatWithAttachments = {
134
134
  return;
135
135
  }
136
136
  const { objective, attachmentIds } = attachmentData;
137
- const attachments = state.data.recentMessages.filter((msg) => msg.content.attachments && msg.content.attachments.length > 0).flatMap((msg) => msg.content.attachments).filter(
137
+ const conversationLength = runtime.getConversationLength();
138
+ const recentMessages = await runtime.getMemories({
139
+ tableName: "messages",
140
+ roomId: message.roomId,
141
+ count: conversationLength,
142
+ unique: false
143
+ });
144
+ const attachments = recentMessages.filter((msg) => msg.content.attachments && msg.content.attachments.length > 0).flatMap((msg) => msg.content.attachments).filter(
138
145
  (attachment) => attachmentIds.map((attch) => attch.toLowerCase().slice(0, 5)).includes(attachment.id.toLowerCase().slice(0, 5)) || // or check the other way
139
146
  attachmentIds.some((id) => {
140
147
  const attachmentId = id.toLowerCase().slice(0, 5);
@@ -850,7 +857,14 @@ var transcribeMedia = {
850
857
  );
851
858
  return;
852
859
  }
853
- const attachment = state.data.recentMessages.filter((msg) => msg.content.attachments && msg.content.attachments.length > 0).flatMap((msg) => msg.content.attachments).find((attachment2) => attachment2.id.toLowerCase() === attachmentId.toLowerCase());
860
+ const conversationLength = runtime.getConversationLength();
861
+ const recentMessages = await runtime.getMemories({
862
+ tableName: "messages",
863
+ roomId: message.roomId,
864
+ count: conversationLength,
865
+ unique: false
866
+ });
867
+ 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());
854
868
  if (!attachment) {
855
869
  console.error(`Couldn't find attachment with ID ${attachmentId}`);
856
870
  await runtime.createMemory(
@@ -962,7 +976,7 @@ var joinVoice = {
962
976
  return false;
963
977
  }
964
978
  const room = state.data.room ?? await runtime.getRoom(message.roomId);
965
- if (room?.type !== ChannelType2.GROUP) {
979
+ if (room?.type !== ChannelType2.GROUP && room?.type !== ChannelType2.VOICE_GROUP) {
966
980
  return false;
967
981
  }
968
982
  const client = runtime.getService(ServiceType2.DISCORD);
@@ -978,7 +992,7 @@ var joinVoice = {
978
992
  if (!room) {
979
993
  throw new Error("No room found");
980
994
  }
981
- if (room.type !== ChannelType2.GROUP) {
995
+ if (room?.type !== ChannelType2.GROUP && room?.type !== ChannelType2.VOICE_GROUP) {
982
996
  return false;
983
997
  }
984
998
  const serverId = room.serverId;
@@ -1269,7 +1283,7 @@ var leaveVoice = {
1269
1283
  return false;
1270
1284
  }
1271
1285
  const room = state.data.room ?? await runtime.getRoom(message.roomId);
1272
- if (room?.type !== ChannelType3.GROUP) {
1286
+ if (room?.type !== ChannelType3.GROUP && room?.type !== ChannelType3.VOICE_GROUP) {
1273
1287
  return false;
1274
1288
  }
1275
1289
  const isConnectedToVoice = service.client.voice.adapters.size > 0;
@@ -1281,7 +1295,7 @@ var leaveVoice = {
1281
1295
  if (!room) {
1282
1296
  throw new Error("No room found");
1283
1297
  }
1284
- if (room.type !== ChannelType3.GROUP) {
1298
+ if (room?.type !== ChannelType3.GROUP && room?.type !== ChannelType3.VOICE_GROUP) {
1285
1299
  throw new Error("Not a group");
1286
1300
  }
1287
1301
  const serverId = room.serverId;
@@ -2062,23 +2076,6 @@ import {
2062
2076
  PermissionsBitField,
2063
2077
  ThreadChannel
2064
2078
  } from "discord.js";
2065
- function getWavHeader(audioLength, sampleRate, channelCount = 1, bitsPerSample = 16) {
2066
- const wavHeader = Buffer.alloc(44);
2067
- wavHeader.write("RIFF", 0);
2068
- wavHeader.writeUInt32LE(36 + audioLength, 4);
2069
- wavHeader.write("WAVE", 8);
2070
- wavHeader.write("fmt ", 12);
2071
- wavHeader.writeUInt32LE(16, 16);
2072
- wavHeader.writeUInt16LE(1, 20);
2073
- wavHeader.writeUInt16LE(channelCount, 22);
2074
- wavHeader.writeUInt32LE(sampleRate, 24);
2075
- wavHeader.writeUInt32LE(sampleRate * bitsPerSample * channelCount / 8, 28);
2076
- wavHeader.writeUInt16LE(bitsPerSample * channelCount / 8, 32);
2077
- wavHeader.writeUInt16LE(bitsPerSample, 34);
2078
- wavHeader.write("data", 36);
2079
- wavHeader.writeUInt32LE(audioLength, 40);
2080
- return wavHeader;
2081
- }
2082
2079
  var MAX_MESSAGE_LENGTH = 1900;
2083
2080
  async function sendMessageInChunks(channel, content, _inReplyTo, files) {
2084
2081
  const sentMessages = [];
@@ -2207,6 +2204,9 @@ var MessageManager = class {
2207
2204
  if (this.runtime.character.settings?.discord?.shouldIgnoreDirectMessages && message.channel.type === DiscordChannelType2.DM) {
2208
2205
  return;
2209
2206
  }
2207
+ if (this.runtime.character.settings?.discord?.shouldRespondOnlyToMentions && !message.mentions.users?.has(this.client.user?.id)) {
2208
+ return;
2209
+ }
2210
2210
  const entityId = createUniqueUuid4(this.runtime, message.author.id);
2211
2211
  const userName = message.author.bot ? `${message.author.username}#${message.author.discriminator}` : message.author.username;
2212
2212
  const name = message.author.displayName;
@@ -2217,6 +2217,9 @@ var MessageManager = class {
2217
2217
  if (message.guild) {
2218
2218
  const guild = await message.guild.fetch();
2219
2219
  type = await this.getChannelType(message.channel);
2220
+ if (type === null) {
2221
+ logger4.warn("null channel type, discord message", message);
2222
+ }
2220
2223
  serverId = guild.id;
2221
2224
  } else {
2222
2225
  type = ChannelType7.DM;
@@ -2250,6 +2253,20 @@ var MessageManager = class {
2250
2253
  }
2251
2254
  const entityId2 = createUniqueUuid4(this.runtime, message.author.id);
2252
2255
  const messageId = createUniqueUuid4(this.runtime, message.id);
2256
+ const channel = message.channel;
2257
+ const startTyping = () => {
2258
+ try {
2259
+ channel.sendTyping();
2260
+ } catch (err) {
2261
+ logger4.warn("Error sending typing indicator:", err);
2262
+ }
2263
+ };
2264
+ startTyping();
2265
+ const typingInterval = setInterval(startTyping, 8e3);
2266
+ const typingData = {
2267
+ interval: typingInterval,
2268
+ cleared: false
2269
+ };
2253
2270
  const newMessage = {
2254
2271
  id: messageId,
2255
2272
  entityId: entityId2,
@@ -2264,6 +2281,10 @@ var MessageManager = class {
2264
2281
  url: message.url,
2265
2282
  inReplyTo: message.reference?.messageId ? createUniqueUuid4(this.runtime, message.reference?.messageId) : void 0
2266
2283
  },
2284
+ metadata: {
2285
+ entityName: name,
2286
+ type: "message"
2287
+ },
2267
2288
  createdAt: message.createdTimestamp
2268
2289
  };
2269
2290
  const callback = async (content, files) => {
@@ -2271,38 +2292,49 @@ var MessageManager = class {
2271
2292
  if (message.id && !content.inReplyTo) {
2272
2293
  content.inReplyTo = createUniqueUuid4(this.runtime, message.id);
2273
2294
  }
2274
- const messages = await sendMessageInChunks(
2275
- message.channel,
2276
- content.text,
2277
- message.id,
2278
- files
2279
- );
2280
- const memories = [];
2281
- for (const m of messages) {
2282
- const actions = content.actions;
2283
- const memory = {
2284
- id: createUniqueUuid4(this.runtime, m.id),
2285
- entityId: this.runtime.agentId,
2286
- agentId: this.runtime.agentId,
2287
- content: {
2288
- ...content,
2289
- actions,
2290
- inReplyTo: messageId,
2291
- url: m.url,
2292
- channelType: type
2293
- },
2294
- roomId,
2295
- createdAt: m.createdTimestamp
2296
- };
2297
- memories.push(memory);
2298
- }
2299
- for (const m of memories) {
2300
- await this.runtime.createMemory(m, "messages");
2295
+ try {
2296
+ const messages = await sendMessageInChunks(channel, content.text, message.id, files);
2297
+ const memories = [];
2298
+ for (const m of messages) {
2299
+ const actions = content.actions;
2300
+ const memory = {
2301
+ id: createUniqueUuid4(this.runtime, m.id),
2302
+ entityId: this.runtime.agentId,
2303
+ agentId: this.runtime.agentId,
2304
+ content: {
2305
+ ...content,
2306
+ actions,
2307
+ inReplyTo: messageId,
2308
+ url: m.url,
2309
+ channelType: type
2310
+ },
2311
+ roomId,
2312
+ createdAt: m.createdTimestamp
2313
+ };
2314
+ memories.push(memory);
2315
+ }
2316
+ for (const m of memories) {
2317
+ await this.runtime.createMemory(m, "messages");
2318
+ }
2319
+ if (typingData.interval && !typingData.cleared) {
2320
+ clearInterval(typingData.interval);
2321
+ typingData.cleared = true;
2322
+ }
2323
+ return memories;
2324
+ } catch (error) {
2325
+ console.error("Error sending message:", error);
2326
+ if (typingData.interval && !typingData.cleared) {
2327
+ clearInterval(typingData.interval);
2328
+ typingData.cleared = true;
2329
+ }
2330
+ return [];
2301
2331
  }
2302
- return memories;
2303
2332
  } catch (error) {
2304
- console.error("Error sending message:", error);
2305
- return [];
2333
+ console.error("Error handling message:", error);
2334
+ if (typingData.interval && !typingData.cleared) {
2335
+ clearInterval(typingData.interval);
2336
+ typingData.cleared = true;
2337
+ }
2306
2338
  }
2307
2339
  };
2308
2340
  this.runtime.emitEvent(["DISCORD_MESSAGE_RECEIVED" /* MESSAGE_RECEIVED */, EventType.MESSAGE_RECEIVED], {
@@ -2310,6 +2342,12 @@ var MessageManager = class {
2310
2342
  message: newMessage,
2311
2343
  callback
2312
2344
  });
2345
+ setTimeout(() => {
2346
+ if (typingData.interval && !typingData.cleared) {
2347
+ clearInterval(typingData.interval);
2348
+ typingData.cleared = true;
2349
+ }
2350
+ }, 500);
2313
2351
  } catch (error) {
2314
2352
  console.error("Error handling message:", error);
2315
2353
  }
@@ -2359,7 +2397,8 @@ var MessageManager = class {
2359
2397
  if (this.runtime.getService(ServiceType4.VIDEO)?.isVideoUrl(url)) {
2360
2398
  const videoService = this.runtime.getService(ServiceType4.VIDEO);
2361
2399
  if (!videoService) {
2362
- throw new Error("Video service not found");
2400
+ logger4.warn("Video service not found");
2401
+ continue;
2363
2402
  }
2364
2403
  const videoInfo = await videoService.processVideo(url, this.runtime);
2365
2404
  attachments.push({
@@ -2373,7 +2412,8 @@ var MessageManager = class {
2373
2412
  } else {
2374
2413
  const browserService = this.runtime.getService(ServiceType4.BROWSER);
2375
2414
  if (!browserService) {
2376
- throw new Error("Browser service not found");
2415
+ logger4.warn("Browser service not found");
2416
+ continue;
2377
2417
  }
2378
2418
  const { title, description: summary } = await browserService.getPageContent(
2379
2419
  url,
@@ -2432,6 +2472,7 @@ import {
2432
2472
  ChannelType as ChannelType8,
2433
2473
  ModelType as ModelType8,
2434
2474
  createUniqueUuid as createUniqueUuid5,
2475
+ getWavHeader,
2435
2476
  logger as logger5
2436
2477
  } from "@elizaos/core";
2437
2478
  import {
@@ -2872,8 +2913,7 @@ var VoiceManager = class extends EventEmitter {
2872
2913
  * @param {BaseGuildVoiceChannel} channel - The voice channel the user is in.
2873
2914
  * @param {Readable} audioStream - The audio stream to monitor.
2874
2915
  */
2875
- async handleUserStream(userId, name, userName, channel, audioStream) {
2876
- const entityId = createUniqueUuid5(this.runtime, userId);
2916
+ async handleUserStream(entityId, name, userName, channel, audioStream) {
2877
2917
  logger5.debug(`Starting audio monitor for user: ${entityId}`);
2878
2918
  if (!this.userStates.has(entityId)) {
2879
2919
  this.userStates.set(entityId, {
@@ -2965,9 +3005,10 @@ var VoiceManager = class extends EventEmitter {
2965
3005
  return { text: "", actions: ["IGNORE"] };
2966
3006
  }
2967
3007
  const roomId = createUniqueUuid5(this.runtime, channelId);
3008
+ const uniqueEntityId = createUniqueUuid5(this.runtime, entityId);
2968
3009
  const type = await this.getChannelType(channel);
2969
3010
  await this.runtime.ensureConnection({
2970
- entityId,
3011
+ entityId: uniqueEntityId,
2971
3012
  roomId,
2972
3013
  userName,
2973
3014
  name,
@@ -2979,7 +3020,7 @@ var VoiceManager = class extends EventEmitter {
2979
3020
  const memory = {
2980
3021
  id: createUniqueUuid5(this.runtime, `${channelId}-voice-message-${Date.now()}`),
2981
3022
  agentId: this.runtime.agentId,
2982
- entityId,
3023
+ entityId: uniqueEntityId,
2983
3024
  roomId,
2984
3025
  content: {
2985
3026
  text: message,
@@ -3009,7 +3050,7 @@ var VoiceManager = class extends EventEmitter {
3009
3050
  createdAt: Date.now()
3010
3051
  };
3011
3052
  if (responseMemory.content.text?.trim()) {
3012
- await this.runtime.createMemory(responseMemory);
3053
+ await this.runtime.createMemory(responseMemory, "messages");
3013
3054
  const responseStream = await this.runtime.useModel(
3014
3055
  ModelType8.TEXT_TO_SPEECH,
3015
3056
  content.text
@@ -3301,6 +3342,11 @@ var DiscordService = class _DiscordService extends Service {
3301
3342
  logger6.error(`Error handling interaction: ${error}`);
3302
3343
  }
3303
3344
  });
3345
+ this.client.on("userStream", (entityId, name, userName, channel, opusDecoder) => {
3346
+ if (entityId !== this.client?.user?.id) {
3347
+ this.voiceManager.handleUserStream(entityId, name, userName, channel, opusDecoder);
3348
+ }
3349
+ });
3304
3350
  }
3305
3351
  /**
3306
3352
  * Handles the event when a new member joins a guild.
@@ -3312,10 +3358,12 @@ var DiscordService = class _DiscordService extends Service {
3312
3358
  logger6.log(`New member joined: ${member.user.username}`);
3313
3359
  const guild = member.guild;
3314
3360
  const tag = member.user.bot ? `${member.user.username}#${member.user.discriminator}` : member.user.username;
3361
+ const worldId = createUniqueUuid6(this.runtime, guild.id);
3362
+ const entityId = createUniqueUuid6(this.runtime, member.id);
3315
3363
  this.runtime.emitEvent([EventType2.ENTITY_JOINED], {
3316
3364
  runtime: this.runtime,
3317
- entityId: createUniqueUuid6(this.runtime, member.id),
3318
- worldId: createUniqueUuid6(this.runtime, guild.id),
3365
+ entityId,
3366
+ worldId,
3319
3367
  source: "discord",
3320
3368
  metadata: {
3321
3369
  originalId: member.id,
@@ -3327,7 +3375,8 @@ var DiscordService = class _DiscordService extends Service {
3327
3375
  });
3328
3376
  this.runtime.emitEvent(["DISCORD_USER_JOINED" /* ENTITY_JOINED */], {
3329
3377
  runtime: this.runtime,
3330
- entityId: createUniqueUuid6(this.runtime, member.id),
3378
+ entityId,
3379
+ worldId,
3331
3380
  member,
3332
3381
  guild
3333
3382
  });