@elizaos/plugin-discord 1.0.0-alpha.20 → 1.0.0-alpha.21

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
@@ -1,6 +1,7 @@
1
1
  // src/index.ts
2
2
  import {
3
3
  ChannelType as ChannelType10,
4
+ EventTypes as EventTypes2,
4
5
  Role,
5
6
  Service,
6
7
  createUniqueUuid as createUniqueUuid6,
@@ -16,11 +17,11 @@ import {
16
17
  } from "discord.js";
17
18
 
18
19
  // src/actions/chatWithAttachments.ts
19
- import * as fs from "node:fs";
20
+ import fs from "node:fs";
20
21
  import {
21
22
  ChannelType,
22
23
  ModelTypes,
23
- composePrompt,
24
+ composePromptFromState,
24
25
  parseJSONObjectFromText,
25
26
  trimTokens
26
27
  } from "@elizaos/core";
@@ -49,7 +50,7 @@ Your response must be formatted as a JSON block with this structure:
49
50
  \`\`\`
50
51
  `;
51
52
  var getAttachmentIds = async (runtime, _message, state) => {
52
- const prompt = composePrompt({
53
+ const prompt = composePromptFromState({
53
54
  state,
54
55
  template: attachmentIdsTemplate
55
56
  });
@@ -86,7 +87,7 @@ var summarizeAction = {
86
87
  ],
87
88
  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.",
88
89
  validate: async (_runtime, message, _state) => {
89
- const room = await _runtime.getDatabaseAdapter().getRoom(message.roomId);
90
+ const room = await _runtime.getRoom(message.roomId);
90
91
  if (room?.type !== ChannelType.GROUP) {
91
92
  return false;
92
93
  }
@@ -166,7 +167,7 @@ ${attachment.text}`).join("\n\n");
166
167
  chunkSize,
167
168
  runtime
168
169
  );
169
- const prompt = composePrompt({
170
+ const prompt = composePromptFromState({
170
171
  state,
171
172
  // make sure it fits, we can pad the tokens a bit
172
173
  // Get the model's tokenizer based on the current model being used
@@ -213,7 +214,7 @@ ${currentSummary.trim()}
213
214
  });
214
215
  await fs.promises.writeFile(summaryFilename, currentSummary, "utf8");
215
216
  console.log("File written successfully");
216
- await runtime.getDatabaseAdapter().setCache(summaryFilename, currentSummary);
217
+ await runtime.setCache(summaryFilename, currentSummary);
217
218
  console.log("Cache set operation completed");
218
219
  await callback(
219
220
  {
@@ -303,7 +304,7 @@ var chatWithAttachments_default = summarizeAction;
303
304
  import {
304
305
  ModelTypes as ModelTypes2,
305
306
  ServiceTypes,
306
- composePrompt as composePrompt2,
307
+ composePromptFromState as composePromptFromState2,
307
308
  parseJSONObjectFromText as parseJSONObjectFromText2
308
309
  } from "@elizaos/core";
309
310
  var mediaUrlTemplate = `# Messages we are searching for a media URL
@@ -320,7 +321,7 @@ Your response must be formatted as a JSON block with this structure:
320
321
  \`\`\`
321
322
  `;
322
323
  var getMediaUrl = async (runtime, _message, state) => {
323
- const prompt = composePrompt2({
324
+ const prompt = composePromptFromState2({
324
325
  state,
325
326
  template: mediaUrlTemplate
326
327
  });
@@ -453,10 +454,10 @@ var downloadMedia_default = {
453
454
  };
454
455
 
455
456
  // src/actions/summarizeConversation.ts
456
- import * as fs2 from "node:fs";
457
+ import fs2 from "node:fs";
457
458
  import {
458
459
  ModelTypes as ModelTypes3,
459
- composePrompt as composePrompt3,
460
+ composePromptFromState as composePromptFromState3,
460
461
  getEntityDetails,
461
462
  parseJSONObjectFromText as parseJSONObjectFromText3,
462
463
  splitChunks,
@@ -490,7 +491,7 @@ Your response must be formatted as a JSON block with this structure:
490
491
  \`\`\`
491
492
  `;
492
493
  var getDateRange = async (runtime, _message, state) => {
493
- const prompt = composePrompt3({
494
+ const prompt = composePromptFromState3({
494
495
  state,
495
496
  template: dateRangeTemplate
496
497
  });
@@ -656,7 +657,7 @@ ${attachments}`;
656
657
  chunkSize + 500,
657
658
  runtime
658
659
  );
659
- const prompt = composePrompt3({
660
+ const prompt = composePromptFromState3({
660
661
  state,
661
662
  // make sure it fits, we can pad the tokens a bit
662
663
  template
@@ -695,7 +696,7 @@ ${currentSummary.trim()}
695
696
  } else if (currentSummary.trim()) {
696
697
  const summaryDir = "cache";
697
698
  const summaryFilename = `${summaryDir}/conversation_summary_${Date.now()}`;
698
- await runtime.getDatabaseAdapter().setCache(summaryFilename, currentSummary);
699
+ await runtime.setCache(summaryFilename, currentSummary);
699
700
  await fs2.promises.mkdir(summaryDir, { recursive: true });
700
701
  await fs2.promises.writeFile(summaryFilename, currentSummary, "utf8");
701
702
  await callback(
@@ -786,7 +787,7 @@ var summarizeConversation_default = summarizeAction2;
786
787
  // src/actions/transcribeMedia.ts
787
788
  import {
788
789
  ModelTypes as ModelTypes4,
789
- composePrompt as composePrompt4,
790
+ composePromptFromState as composePromptFromState4,
790
791
  parseJSONObjectFromText as parseJSONObjectFromText4
791
792
  } from "@elizaos/core";
792
793
  var mediaAttachmentIdTemplate = `# Messages we are transcribing
@@ -803,7 +804,7 @@ Your response must be formatted as a JSON block with this structure:
803
804
  \`\`\`
804
805
  `;
805
806
  var getMediaAttachmentId = async (runtime, _message, state) => {
806
- const prompt = composePrompt4({
807
+ const prompt = composePromptFromState4({
807
808
  state,
808
809
  template: mediaAttachmentIdTemplate
809
810
  });
@@ -913,7 +914,7 @@ ${mediaTranscript.trim()}
913
914
  await callback(callbackData);
914
915
  } else if (callbackData.text) {
915
916
  const transcriptFilename = `content/transcript_${Date.now()}`;
916
- await runtime.getDatabaseAdapter().setCache(transcriptFilename, callbackData.text);
917
+ await runtime.setCache(transcriptFilename, callbackData.text);
917
918
  await callback(
918
919
  {
919
920
  ...callbackData,
@@ -965,7 +966,7 @@ var transcribeMedia_default = transcribeMediaAction;
965
966
  import {
966
967
  ChannelType as ChannelType2,
967
968
  ModelTypes as ModelTypes5,
968
- composePrompt as composePrompt5,
969
+ composePromptFromState as composePromptFromState5,
969
970
  createUniqueUuid as createUniqueUuid2,
970
971
  logger
971
972
  } from "@elizaos/core";
@@ -993,7 +994,7 @@ var voiceJoin_default = {
993
994
  if (message.content.source !== "discord") {
994
995
  return false;
995
996
  }
996
- const room = state.data.room ?? await runtime.getDatabaseAdapter().getRoom(message.roomId);
997
+ const room = state.data.room ?? await runtime.getRoom(message.roomId);
997
998
  if (room?.type !== ChannelType2.GROUP) {
998
999
  return false;
999
1000
  }
@@ -1006,7 +1007,7 @@ var voiceJoin_default = {
1006
1007
  },
1007
1008
  description: "Join a voice channel to participate in voice chat.",
1008
1009
  handler: async (runtime, message, state, _options, callback) => {
1009
- const room = state.data.room ?? await runtime.getDatabaseAdapter().getRoom(message.roomId);
1010
+ const room = state.data.room ?? await runtime.getRoom(message.roomId);
1010
1011
  if (!room) {
1011
1012
  throw new Error("No room found");
1012
1013
  }
@@ -1090,7 +1091,7 @@ You should only respond with the name of the voice channel or none, no commentar
1090
1091
  userMessage: message.content.text,
1091
1092
  voiceChannels: voiceChannels.map((channel) => channel.name).join("\n")
1092
1093
  };
1093
- const prompt = composePrompt5({
1094
+ const prompt = composePromptFromState5({
1094
1095
  template: messageTemplate,
1095
1096
  state: guessState
1096
1097
  });
@@ -1291,7 +1292,7 @@ var voiceLeave_default = {
1291
1292
  logger2.error("Discord client not found");
1292
1293
  return false;
1293
1294
  }
1294
- const room = state.data.room ?? await runtime.getDatabaseAdapter().getRoom(message.roomId);
1295
+ const room = state.data.room ?? await runtime.getRoom(message.roomId);
1295
1296
  if (room?.type !== ChannelType3.GROUP) {
1296
1297
  return false;
1297
1298
  }
@@ -1300,7 +1301,7 @@ var voiceLeave_default = {
1300
1301
  },
1301
1302
  description: "Leave the current voice channel.",
1302
1303
  handler: async (runtime, message, _state, _options) => {
1303
- const room = await runtime.getDatabaseAdapter().getRoom(message.roomId);
1304
+ const room = await runtime.getRoom(message.roomId);
1304
1305
  if (!room) {
1305
1306
  throw new Error("No room found");
1306
1307
  }
@@ -1536,6 +1537,7 @@ var DISCORD_SERVICE_NAME = "discord";
1536
1537
  // src/messages.ts
1537
1538
  import {
1538
1539
  ChannelType as ChannelType5,
1540
+ EventTypes,
1539
1541
  ServiceTypes as ServiceTypes4,
1540
1542
  createUniqueUuid as createUniqueUuid4,
1541
1543
  logger as logger4
@@ -2142,7 +2144,7 @@ var MessageManager = class {
2142
2144
  return [];
2143
2145
  }
2144
2146
  };
2145
- this.runtime.emitEvent(["DISCORD_MESSAGE_RECEIVED", "MESSAGE_RECEIVED"], {
2147
+ this.runtime.emitEvent(["DISCORD_MESSAGE_RECEIVED" /* MESSAGE_RECEIVED */, EventTypes.MESSAGE_RECEIVED], {
2146
2148
  runtime: this.runtime,
2147
2149
  message: newMessage,
2148
2150
  callback
@@ -2268,7 +2270,7 @@ import { ChannelType as ChannelType6 } from "@elizaos/core";
2268
2270
  var channelStateProvider = {
2269
2271
  name: "channelState",
2270
2272
  get: async (runtime, message, state) => {
2271
- const room = state.data?.room ?? await runtime.getDatabaseAdapter().getRoom(message.roomId);
2273
+ const room = state.data?.room ?? await runtime.getRoom(message.roomId);
2272
2274
  if (!room) {
2273
2275
  throw new Error("No room found");
2274
2276
  }
@@ -2354,7 +2356,7 @@ import { ChannelType as ChannelType7 } from "@elizaos/core";
2354
2356
  var voiceStateProvider = {
2355
2357
  name: "voiceState",
2356
2358
  get: async (runtime, message, state) => {
2357
- const room = await runtime.getDatabaseAdapter().getRoom(message.roomId);
2359
+ const room = await runtime.getRoom(message.roomId);
2358
2360
  if (!room) {
2359
2361
  throw new Error("No room found");
2360
2362
  }
@@ -2392,7 +2394,7 @@ var voiceStateProvider = {
2392
2394
  };
2393
2395
  }
2394
2396
  const worldId = room.worldId;
2395
- const world = await runtime.getDatabaseAdapter().getWorld(worldId);
2397
+ const world = await runtime.getWorld(worldId);
2396
2398
  if (!world) {
2397
2399
  throw new Error("No world found");
2398
2400
  }
@@ -2966,7 +2968,7 @@ var VoiceManager = class extends EventEmitter {
2966
2968
  setReady(status) {
2967
2969
  this.ready = status;
2968
2970
  this.emit("ready");
2969
- logger6.success(`VoiceManager is now ready: ${this.ready}`);
2971
+ logger6.debug(`VoiceManager is now ready: ${this.ready}`);
2970
2972
  }
2971
2973
  /**
2972
2974
  * Check if the object is ready.
@@ -3641,7 +3643,6 @@ var DiscordService = class _DiscordService extends Service {
3641
3643
  */
3642
3644
  constructor(runtime) {
3643
3645
  super(runtime);
3644
- logger7.log("Discord client constructor was engaged");
3645
3646
  const token = runtime.getSetting("DISCORD_API_TOKEN");
3646
3647
  if (!token || token.trim() === "") {
3647
3648
  logger7.warn(
@@ -3699,11 +3700,25 @@ var DiscordService = class _DiscordService extends Service {
3699
3700
  * @returns {Promise<void>} - A Promise that resolves once all channels are ensured.
3700
3701
  */
3701
3702
  async ensureAllChannelsExist(runtime, guild) {
3702
- const guildObj = await guild.fetch();
3703
- const guildChannels = await guild.fetch();
3703
+ let guildObj;
3704
+ let guildChannels;
3705
+ let retries = 3;
3706
+ while (retries > 0) {
3707
+ try {
3708
+ guildObj = await guild.fetch();
3709
+ guildChannels = await guild.fetch();
3710
+ break;
3711
+ } catch (error) {
3712
+ retries--;
3713
+ if (retries === 0) {
3714
+ throw error;
3715
+ }
3716
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3717
+ }
3718
+ }
3704
3719
  for (const [, channel] of guildChannels.channels.cache) {
3705
3720
  const roomId = createUniqueUuid6(this.runtime, channel.id);
3706
- const room = await runtime.getDatabaseAdapter().getRoom(roomId);
3721
+ const room = await runtime.getRoom(roomId);
3707
3722
  if (room) {
3708
3723
  continue;
3709
3724
  }
@@ -3801,21 +3816,20 @@ var DiscordService = class _DiscordService extends Service {
3801
3816
  logger7.log(`New member joined: ${member.user.username}`);
3802
3817
  const guild = member.guild;
3803
3818
  const tag = member.user.bot ? `${member.user.username}#${member.user.discriminator}` : member.user.username;
3804
- this.runtime.emitEvent("USER_JOINED", {
3819
+ this.runtime.emitEvent([EventTypes2.ENTITY_JOINED], {
3805
3820
  runtime: this.runtime,
3806
3821
  entityId: createUniqueUuid6(this.runtime, member.id),
3807
- user: {
3808
- id: member.id,
3822
+ worldId: createUniqueUuid6(this.runtime, guild.id),
3823
+ source: "discord",
3824
+ metadata: {
3825
+ originalId: member.id,
3809
3826
  username: tag,
3810
- displayName: member.displayName || member.user.username
3811
- },
3812
- serverId: guild.id,
3813
- channelId: null,
3814
- // No specific channel for server joins
3815
- channelType: ChannelType10.WORLD,
3816
- source: "discord"
3827
+ displayName: member.displayName || member.user.username,
3828
+ roles: member.roles.cache.map((r) => r.name),
3829
+ joinedAt: member.joinedAt?.getTime()
3830
+ }
3817
3831
  });
3818
- this.runtime.emitEvent("DISCORD_USER_JOINED", {
3832
+ this.runtime.emitEvent(["DISCORD_USER_JOINED" /* ENTITY_JOINED */], {
3819
3833
  runtime: this.runtime,
3820
3834
  entityId: createUniqueUuid6(this.runtime, member.id),
3821
3835
  member,
@@ -3830,8 +3844,41 @@ var DiscordService = class _DiscordService extends Service {
3830
3844
  *
3831
3845
  */
3832
3846
  static async start(runtime) {
3833
- const client = new _DiscordService(runtime);
3834
- return client;
3847
+ const token = runtime.getSetting("DISCORD_API_TOKEN");
3848
+ if (!token || token.trim() === "") {
3849
+ throw new Error("Discord API Token not provided");
3850
+ }
3851
+ const maxRetries = 5;
3852
+ let retryCount = 0;
3853
+ let lastError = null;
3854
+ while (retryCount < maxRetries) {
3855
+ try {
3856
+ const service = new _DiscordService(runtime);
3857
+ if (!service.client) {
3858
+ throw new Error("Failed to initialize Discord client");
3859
+ }
3860
+ await new Promise((resolve, reject) => {
3861
+ const timeout = setTimeout(() => {
3862
+ reject(new Error("Discord client ready timeout"));
3863
+ }, 3e4);
3864
+ service.client?.once("ready", () => {
3865
+ clearTimeout(timeout);
3866
+ resolve();
3867
+ });
3868
+ });
3869
+ return service;
3870
+ } catch (error) {
3871
+ lastError = error instanceof Error ? error : new Error(String(error));
3872
+ logger7.error(`Discord initialization attempt ${retryCount + 1} failed: ${lastError.message}`);
3873
+ retryCount++;
3874
+ if (retryCount < maxRetries) {
3875
+ const delay = 2 ** retryCount * 1e3;
3876
+ logger7.info(`Retrying Discord initialization in ${delay / 1e3} seconds...`);
3877
+ await new Promise((resolve) => setTimeout(resolve, delay));
3878
+ }
3879
+ }
3880
+ }
3881
+ throw new Error(`Discord initialization failed after ${maxRetries} attempts. Last error: ${lastError?.message}`);
3835
3882
  }
3836
3883
  /**
3837
3884
  * Stops the Discord client associated with the given runtime.
@@ -3867,7 +3914,7 @@ var DiscordService = class _DiscordService extends Service {
3867
3914
  * @returns {Promise<void>}
3868
3915
  */
3869
3916
  async onClientReady(readyClient) {
3870
- logger7.success(`Logged in as ${readyClient.user?.tag}`);
3917
+ logger7.success(`DISCORD: Logged in as ${readyClient.user?.tag}`);
3871
3918
  const commands = [
3872
3919
  {
3873
3920
  name: "joinchannel",
@@ -3891,7 +3938,7 @@ var DiscordService = class _DiscordService extends Service {
3891
3938
  ];
3892
3939
  try {
3893
3940
  await this.client?.application?.commands.set(commands);
3894
- logger7.success("Slash commands registered");
3941
+ logger7.success("DISCORD: Slash commands registered");
3895
3942
  } catch (error) {
3896
3943
  console.error("Error registering slash commands:", error);
3897
3944
  }
@@ -3941,8 +3988,8 @@ var DiscordService = class _DiscordService extends Service {
3941
3988
  /**
3942
3989
  * Handles the addition of a reaction on a message.
3943
3990
  *
3944
- * @param {MessageReaction} reaction The reaction that was added.
3945
- * @param {User} user The user who added the reaction.
3991
+ * @param {MessageReaction | PartialMessageReaction} reaction The reaction that was added.
3992
+ * @param {User | PartialUser} user The user who added the reaction.
3946
3993
  * @returns {void}
3947
3994
  */
3948
3995
  async handleReactionAdd(reaction, user) {
@@ -4037,8 +4084,8 @@ var DiscordService = class _DiscordService extends Service {
4037
4084
  /**
4038
4085
  * Handles the removal of a reaction on a message.
4039
4086
  *
4040
- * @param {MessageReaction} reaction - The reaction that was removed.
4041
- * @param {User} user - The user who removed the reaction.
4087
+ * @param {MessageReaction | PartialMessageReaction} reaction - The reaction that was removed.
4088
+ * @param {User | PartialUser} user - The user who removed the reaction.
4042
4089
  * @returns {Promise<void>} - A Promise that resolves after handling the reaction removal.
4043
4090
  */
4044
4091
  async handleReactionRemove(reaction, user) {
@@ -4109,7 +4156,7 @@ var DiscordService = class _DiscordService extends Service {
4109
4156
  await reaction.message.channel.send(content.text);
4110
4157
  return [];
4111
4158
  };
4112
- this.runtime.emitEvent(["DISCORD_REACTION_EVENT", "REACTION_RECEIVED"], {
4159
+ this.runtime.emitEvent(["DISCORD_REACTION_RECEIVED" /* REACTION_RECEIVED */], {
4113
4160
  runtime: this.runtime,
4114
4161
  message: memory,
4115
4162
  callback
@@ -4147,12 +4194,12 @@ var DiscordService = class _DiscordService extends Service {
4147
4194
  },
4148
4195
  source: "discord"
4149
4196
  };
4150
- this.runtime.emitEvent(["DISCORD_SERVER_JOINED"], {
4197
+ this.runtime.emitEvent(["DISCORD_WORLD_JOINED" /* WORLD_JOINED */], {
4151
4198
  runtime: this.runtime,
4152
4199
  server: fullGuild,
4153
4200
  source: "discord"
4154
4201
  });
4155
- this.runtime.emitEvent(["SERVER_JOINED"], standardizedData);
4202
+ this.runtime.emitEvent([EventTypes2.WORLD_JOINED], standardizedData);
4156
4203
  }
4157
4204
  /**
4158
4205
  * Handles interactions created by the user, specifically commands.
@@ -4358,7 +4405,7 @@ var DiscordService = class _DiscordService extends Service {
4358
4405
  setTimeout(async () => {
4359
4406
  const fullGuild2 = await guild.fetch();
4360
4407
  logger7.log("DISCORD SERVER CONNECTED", fullGuild2.name);
4361
- this.runtime.emitEvent(["DISCORD_SERVER_CONNECTED"], {
4408
+ this.runtime.emitEvent(["DISCORD_SERVER_CONNECTED" /* WORLD_CONNECTED */], {
4362
4409
  runtime: this.runtime,
4363
4410
  server: fullGuild2,
4364
4411
  source: "discord"
@@ -4369,7 +4416,7 @@ var DiscordService = class _DiscordService extends Service {
4369
4416
  name: fullGuild2.name,
4370
4417
  runtime: this.runtime,
4371
4418
  rooms: await this.buildStandardizedRooms(fullGuild2, worldId),
4372
- users: await this.buildStandardizedUsers(fullGuild2),
4419
+ entities: await this.buildStandardizedUsers(fullGuild2),
4373
4420
  world: {
4374
4421
  id: worldId,
4375
4422
  name: fullGuild2.name,
@@ -4384,7 +4431,7 @@ var DiscordService = class _DiscordService extends Service {
4384
4431
  },
4385
4432
  source: "discord"
4386
4433
  };
4387
- this.runtime.emitEvent(["SERVER_CONNECTED"], standardizedData);
4434
+ this.runtime.emitEvent([EventTypes2.WORLD_CONNECTED], standardizedData);
4388
4435
  }, 1e3);
4389
4436
  }
4390
4437
  this.client?.emit("voiceManagerReady");