@elizaos/plugin-twitter 1.0.0-beta.23 → 1.0.0-beta.24

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
@@ -4,7 +4,7 @@ import {
4
4
  EventType as EventType4,
5
5
  Role,
6
6
  Service,
7
- createUniqueUuid as createUniqueUuid8,
7
+ createUniqueUuid as createUniqueUuid7,
8
8
  logger as logger10
9
9
  } from "@elizaos/core";
10
10
 
@@ -6606,8 +6606,6 @@ var SttTtsPlugin2 = class {
6606
6606
  };
6607
6607
 
6608
6608
  // src/utils.ts
6609
- import fs from "node:fs";
6610
- import path from "node:path";
6611
6609
  import {
6612
6610
  ChannelType as ChannelType2,
6613
6611
  ModelType as ModelType2,
@@ -6615,27 +6613,6 @@ import {
6615
6613
  createUniqueUuid as createUniqueUuid2,
6616
6614
  logger as logger3
6617
6615
  } from "@elizaos/core";
6618
- async function fetchMediaData(attachments) {
6619
- return Promise.all(
6620
- attachments.map(async (attachment) => {
6621
- if (/^(http|https):\/\//.test(attachment.url)) {
6622
- const response = await fetch(attachment.url);
6623
- if (!response.ok) {
6624
- throw new Error(`Failed to fetch file: ${attachment.url}`);
6625
- }
6626
- const mediaBuffer = Buffer.from(await response.arrayBuffer());
6627
- const mediaType = attachment.contentType || "image/png";
6628
- return { data: mediaBuffer, mediaType };
6629
- }
6630
- if (fs.existsSync(attachment.url)) {
6631
- const mediaBuffer = await fs.promises.readFile(path.resolve(attachment.url));
6632
- const mediaType = attachment.contentType || "image/png";
6633
- return { data: mediaBuffer, mediaType };
6634
- }
6635
- throw new Error(`File not found: ${attachment.url}. Make sure the path is correct.`);
6636
- })
6637
- );
6638
- }
6639
6616
  async function generateFiller(runtime, fillerType) {
6640
6617
  try {
6641
6618
  const prompt = composePrompt({
@@ -7821,22 +7798,29 @@ var _ClientBase = class _ClientBase {
7821
7798
  const mentionsResponse = await this.requestQueue.add(
7822
7799
  () => this.twitterClient.fetchSearchTweets(`@${username}`, 100, 1 /* Latest */)
7823
7800
  );
7824
- return mentionsResponse.tweets.map((tweet) => ({
7825
- id: tweet.id,
7826
- type: tweet.isQuoted ? "quote" : tweet.retweetedStatus ? "retweet" : "like",
7827
- userId: tweet.userId,
7828
- username: tweet.username,
7829
- name: tweet.name || tweet.username,
7830
- targetTweetId: tweet.inReplyToStatusId || tweet.quotedStatusId,
7831
- targetTweet: tweet.quotedStatus || tweet,
7832
- quoteTweet: tweet.isQuoted ? tweet : void 0,
7833
- retweetId: tweet.retweetedStatus?.id
7834
- }));
7801
+ return mentionsResponse.tweets.map((tweet) => this.formatTweetToInteraction(tweet));
7835
7802
  } catch (error) {
7836
7803
  logger6.error("Error fetching Twitter interactions:", error);
7837
7804
  return [];
7838
7805
  }
7839
7806
  }
7807
+ formatTweetToInteraction(tweet) {
7808
+ if (!tweet) return null;
7809
+ const isQuote = tweet.isQuoted;
7810
+ const isRetweet = !!tweet.retweetedStatus;
7811
+ const type = isQuote ? "quote" : isRetweet ? "retweet" : "like";
7812
+ return {
7813
+ id: tweet.id,
7814
+ type,
7815
+ userId: tweet.userId,
7816
+ username: tweet.username,
7817
+ name: tweet.name || tweet.username,
7818
+ targetTweetId: tweet.inReplyToStatusId || tweet.quotedStatusId,
7819
+ targetTweet: tweet.quotedStatus || tweet,
7820
+ quoteTweet: isQuote ? tweet : void 0,
7821
+ retweetId: tweet.retweetedStatus?.id
7822
+ };
7823
+ }
7840
7824
  };
7841
7825
  _ClientBase._twitterClients = {};
7842
7826
  var ClientBase = _ClientBase;
@@ -7852,13 +7836,6 @@ import {
7852
7836
  createUniqueUuid as createUniqueUuid5,
7853
7837
  logger as logger7
7854
7838
  } from "@elizaos/core";
7855
-
7856
- // src/types.ts
7857
- var ServiceType = {
7858
- TWITTER: "twitter"
7859
- };
7860
-
7861
- // src/interactions.ts
7862
7839
  var convertToCoreTweet = (tweet) => ({
7863
7840
  id: tweet.id,
7864
7841
  text: tweet.text,
@@ -7923,256 +7900,224 @@ var TwitterInteractionClient = class {
7923
7900
  } else if (!searchResult.previous && !searchResult.next) {
7924
7901
  await this.runtime.setCache(cursorKey, null);
7925
7902
  }
7926
- logger7.log("Completed checking mentioned tweets:", mentionCandidates.length);
7927
- let uniqueTweetCandidates = [...mentionCandidates];
7928
- uniqueTweetCandidates = uniqueTweetCandidates.sort((a, b) => a.id.localeCompare(b.id)).filter((tweet) => tweet.userId !== this.client.profile.id);
7929
- for (const tweet of uniqueTweetCandidates) {
7930
- if (!this.client.lastCheckedTweetId || BigInt(tweet.id) > this.client.lastCheckedTweetId) {
7931
- const tweetId = createUniqueUuid5(this.runtime, tweet.id);
7932
- const existingResponse = await this.runtime.getMemoryById(tweetId);
7933
- if (existingResponse) {
7934
- logger7.log(`Already responded to tweet ${tweet.id}, skipping`);
7935
- continue;
7936
- }
7937
- logger7.log("New Tweet found", tweet.permanentUrl);
7938
- const entityId = createUniqueUuid5(
7939
- this.runtime,
7940
- tweet.userId === this.client.profile.id ? this.runtime.agentId : tweet.userId
7941
- );
7942
- const worldId = createUniqueUuid5(this.runtime, tweet.userId);
7943
- const roomId = createUniqueUuid5(this.runtime, tweet.conversationId);
7944
- await this.runtime.ensureWorldExists({
7945
- id: worldId,
7946
- name: `${tweet.name}'s Twitter`,
7947
- agentId: this.runtime.agentId,
7948
- serverId: tweet.userId,
7949
- metadata: {
7950
- ownership: { ownerId: tweet.userId },
7951
- twitter: {
7952
- username: tweet.username,
7953
- id: tweet.userId,
7954
- name: tweet.name
7955
- }
7903
+ await this.processMentionTweets(mentionCandidates);
7904
+ await this.client.cacheLatestCheckedTweetId();
7905
+ logger7.log("Finished checking Twitter interactions");
7906
+ } catch (error) {
7907
+ logger7.error("Error handling Twitter interactions:", error);
7908
+ }
7909
+ }
7910
+ /**
7911
+ * Processes all incoming tweets that mention the bot.
7912
+ * For each new tweet:
7913
+ * - Ensures world, room, and connection exist
7914
+ * - Saves the tweet as memory
7915
+ * - Emits thread-related events (THREAD_CREATED / THREAD_UPDATED)
7916
+ * - Delegates tweet content to `handleTweet` for reply generation
7917
+ *
7918
+ * Note: MENTION_RECEIVED is currently disabled (see TODO below)
7919
+ */
7920
+ async processMentionTweets(mentionCandidates) {
7921
+ logger7.log("Completed checking mentioned tweets:", mentionCandidates.length);
7922
+ let uniqueTweetCandidates = [...mentionCandidates];
7923
+ uniqueTweetCandidates = uniqueTweetCandidates.sort((a, b) => a.id.localeCompare(b.id)).filter((tweet) => tweet.userId !== this.client.profile.id);
7924
+ for (const tweet of uniqueTweetCandidates) {
7925
+ if (!this.client.lastCheckedTweetId || BigInt(tweet.id) > this.client.lastCheckedTweetId) {
7926
+ const tweetId = createUniqueUuid5(this.runtime, tweet.id);
7927
+ const existingResponse = await this.runtime.getMemoryById(tweetId);
7928
+ if (existingResponse) {
7929
+ logger7.log(`Already responded to tweet ${tweet.id}, skipping`);
7930
+ continue;
7931
+ }
7932
+ logger7.log("New Tweet found", tweet.permanentUrl);
7933
+ const entityId = createUniqueUuid5(
7934
+ this.runtime,
7935
+ tweet.userId === this.client.profile.id ? this.runtime.agentId : tweet.userId
7936
+ );
7937
+ const worldId = createUniqueUuid5(this.runtime, tweet.userId);
7938
+ const roomId = createUniqueUuid5(this.runtime, tweet.conversationId);
7939
+ await this.runtime.ensureWorldExists({
7940
+ id: worldId,
7941
+ name: `${tweet.name}'s Twitter`,
7942
+ agentId: this.runtime.agentId,
7943
+ serverId: tweet.userId,
7944
+ metadata: {
7945
+ ownership: { ownerId: tweet.userId },
7946
+ twitter: {
7947
+ username: tweet.username,
7948
+ id: tweet.userId,
7949
+ name: tweet.name
7956
7950
  }
7957
- });
7958
- await this.runtime.ensureConnection({
7959
- entityId,
7960
- roomId,
7961
- userName: tweet.username,
7962
- name: tweet.name,
7963
- source: "twitter",
7964
- type: ChannelType5.GROUP,
7965
- channelId: tweet.conversationId,
7966
- serverId: tweet.userId,
7967
- worldId
7968
- });
7969
- await this.runtime.ensureRoomExists({
7970
- id: roomId,
7971
- name: `Conversation with ${tweet.name}`,
7951
+ }
7952
+ });
7953
+ await this.runtime.ensureConnection({
7954
+ entityId,
7955
+ roomId,
7956
+ userName: tweet.username,
7957
+ name: tweet.name,
7958
+ source: "twitter",
7959
+ type: ChannelType5.GROUP,
7960
+ channelId: tweet.conversationId,
7961
+ serverId: tweet.userId,
7962
+ worldId
7963
+ });
7964
+ await this.runtime.ensureRoomExists({
7965
+ id: roomId,
7966
+ name: `Conversation with ${tweet.name}`,
7967
+ source: "twitter",
7968
+ type: ChannelType5.GROUP,
7969
+ channelId: tweet.conversationId,
7970
+ serverId: tweet.userId,
7971
+ worldId
7972
+ });
7973
+ const memory = {
7974
+ id: tweetId,
7975
+ agentId: this.runtime.agentId,
7976
+ content: {
7977
+ text: tweet.text,
7978
+ url: tweet.permanentUrl,
7979
+ imageUrls: tweet.photos?.map((photo) => photo.url) || [],
7980
+ inReplyTo: tweet.inReplyToStatusId ? createUniqueUuid5(this.runtime, tweet.inReplyToStatusId) : void 0,
7972
7981
  source: "twitter",
7973
- type: ChannelType5.GROUP,
7974
- channelId: tweet.conversationId,
7975
- serverId: tweet.userId,
7976
- worldId
7977
- });
7978
- const memory = {
7979
- id: tweetId,
7980
- agentId: this.runtime.agentId,
7981
- content: {
7982
- text: tweet.text,
7983
- url: tweet.permanentUrl,
7984
- imageUrls: tweet.photos?.map((photo) => photo.url) || [],
7985
- inReplyTo: tweet.inReplyToStatusId ? createUniqueUuid5(this.runtime, tweet.inReplyToStatusId) : void 0,
7986
- source: "twitter",
7987
- channelType: ChannelType5.GROUP,
7988
- tweet
7982
+ channelType: ChannelType5.GROUP,
7983
+ tweet
7984
+ },
7985
+ entityId,
7986
+ roomId,
7987
+ createdAt: tweet.timestamp * 1e3
7988
+ };
7989
+ await this.runtime.createMemory(memory, "messages");
7990
+ if (tweet.thread.length > 1) {
7991
+ const threadPayload = {
7992
+ runtime: this.runtime,
7993
+ tweets: convertToCoreTweets(tweet.thread),
7994
+ user: {
7995
+ id: tweet.userId,
7996
+ username: tweet.username,
7997
+ name: tweet.name
7989
7998
  },
7990
- entityId,
7991
- roomId,
7992
- createdAt: tweet.timestamp * 1e3
7999
+ source: "twitter"
7993
8000
  };
7994
- await this.runtime.createMemory(memory, "messages");
7995
- if (tweet.text.includes(`@${twitterUsername}`)) {
7996
- const messagePayload = {
7997
- runtime: this.runtime,
7998
- message: {
7999
- ...memory,
8000
- source: "twitter"
8001
- },
8002
- source: "twitter",
8003
- callback: async (response) => {
8004
- logger7.info("Received message response:", response);
8005
- return [];
8006
- }
8007
- };
8008
- const mentionPayload = {
8009
- runtime: this.runtime,
8010
- message: {
8011
- ...memory,
8012
- source: "twitter"
8013
- },
8014
- tweet: convertToCoreTweet(tweet),
8015
- user: {
8016
- id: tweet.userId,
8017
- username: tweet.username,
8018
- name: tweet.name
8019
- },
8020
- source: "twitter",
8021
- callback: async (response) => {
8022
- logger7.info("Received mention response:", response);
8023
- return [];
8024
- }
8025
- };
8026
- this.runtime.emitEvent("TWITTER_MENTION_RECEIVED" /* MENTION_RECEIVED */, mentionPayload);
8027
- }
8028
- if (tweet.thread.length > 1) {
8029
- const threadPayload = {
8030
- runtime: this.runtime,
8031
- tweets: convertToCoreTweets(tweet.thread),
8032
- user: {
8033
- id: tweet.userId,
8034
- username: tweet.username,
8035
- name: tweet.name
8036
- },
8037
- source: "twitter"
8038
- };
8039
- if (tweet.thread[tweet.thread.length - 1].id === tweet.id) {
8040
- this.runtime.emitEvent("TWITTER_THREAD_UPDATED" /* THREAD_UPDATED */, {
8041
- ...threadPayload,
8042
- newTweet: convertToCoreTweet(tweet)
8043
- });
8044
- } else if (tweet.thread[0].id === tweet.id) {
8045
- this.runtime.emitEvent("TWITTER_THREAD_CREATED" /* THREAD_CREATED */, threadPayload);
8046
- }
8001
+ if (tweet.thread[tweet.thread.length - 1].id === tweet.id) {
8002
+ this.runtime.emitEvent("TWITTER_THREAD_UPDATED" /* THREAD_UPDATED */, {
8003
+ ...threadPayload,
8004
+ newTweet: convertToCoreTweet(tweet)
8005
+ });
8006
+ } else if (tweet.thread[0].id === tweet.id) {
8007
+ this.runtime.emitEvent("TWITTER_THREAD_CREATED" /* THREAD_CREATED */, threadPayload);
8047
8008
  }
8048
- await this.handleTweet({
8049
- tweet,
8050
- message: memory,
8051
- thread: tweet.thread
8052
- });
8053
- this.client.lastCheckedTweetId = BigInt(tweet.id);
8054
8009
  }
8010
+ await this.handleTweet({
8011
+ tweet,
8012
+ message: memory,
8013
+ thread: tweet.thread
8014
+ });
8015
+ this.client.lastCheckedTweetId = BigInt(tweet.id);
8055
8016
  }
8056
- const interactions = await this.client.fetchInteractions();
8057
- const handleInteraction = async (interaction) => {
8058
- if (interaction?.targetTweet?.conversationId) {
8059
- const memory = this.createMemoryObject(
8060
- interaction.type,
8061
- `${interaction.id}-${interaction.type}`,
8062
- interaction.userId,
8063
- interaction.targetTweet.conversationId
8064
- );
8065
- await this.runtime.createMemory(memory, "messages");
8066
- const reactionMessage = {
8067
- id: createUniqueUuid5(this.runtime, interaction.targetTweetId),
8068
- content: {
8069
- text: interaction.targetTweet.text,
8070
- source: "twitter"
8071
- },
8072
- entityId: createUniqueUuid5(this.runtime, interaction.targetTweet.userId),
8073
- roomId: createUniqueUuid5(this.runtime, interaction.targetTweet.conversationId),
8074
- agentId: this.runtime.agentId
8017
+ }
8018
+ }
8019
+ /**
8020
+ * Handles Twitter interactions such as likes, retweets, and quotes.
8021
+ * For each interaction:
8022
+ * - Creates a memory object
8023
+ * - Emits platform-specific events (LIKE_RECEIVED, RETWEET_RECEIVED, QUOTE_RECEIVED)
8024
+ * - Emits a generic REACTION_RECEIVED event with metadata
8025
+ */
8026
+ async handleInteraction(interaction) {
8027
+ if (interaction?.targetTweet?.conversationId) {
8028
+ const memory = this.createMemoryObject(
8029
+ interaction.type,
8030
+ `${interaction.id}-${interaction.type}`,
8031
+ interaction.userId,
8032
+ interaction.targetTweet.conversationId
8033
+ );
8034
+ await this.runtime.createMemory(memory, "messages");
8035
+ const reactionMessage = {
8036
+ id: createUniqueUuid5(this.runtime, interaction.targetTweetId),
8037
+ content: {
8038
+ text: interaction.targetTweet.text,
8039
+ source: "twitter"
8040
+ },
8041
+ entityId: createUniqueUuid5(this.runtime, interaction.targetTweet.userId),
8042
+ roomId: createUniqueUuid5(this.runtime, interaction.targetTweet.conversationId),
8043
+ agentId: this.runtime.agentId
8044
+ };
8045
+ const basePayload = {
8046
+ runtime: this.runtime,
8047
+ user: {
8048
+ id: interaction.userId,
8049
+ username: interaction.username,
8050
+ name: interaction.name
8051
+ },
8052
+ source: "twitter"
8053
+ };
8054
+ switch (interaction.type) {
8055
+ case "like": {
8056
+ const likePayload = {
8057
+ ...basePayload,
8058
+ tweet: interaction.targetTweet
8075
8059
  };
8076
- const basePayload = {
8077
- runtime: this.runtime,
8078
- user: {
8079
- id: interaction.userId,
8080
- username: interaction.username,
8081
- name: interaction.name
8060
+ this.runtime.emitEvent("TWITTER_LIKE_RECEIVED" /* LIKE_RECEIVED */, likePayload);
8061
+ this.runtime.emitEvent(EventType2.REACTION_RECEIVED, {
8062
+ ...basePayload,
8063
+ reaction: {
8064
+ type: "like",
8065
+ entityId: createUniqueUuid5(this.runtime, interaction.userId)
8082
8066
  },
8083
- source: "twitter"
8067
+ message: reactionMessage,
8068
+ callback: async () => {
8069
+ return [];
8070
+ }
8071
+ });
8072
+ break;
8073
+ }
8074
+ case "retweet": {
8075
+ const retweetPayload = {
8076
+ ...basePayload,
8077
+ tweet: interaction.targetTweet,
8078
+ retweetId: interaction.retweetId
8084
8079
  };
8085
- switch (interaction.type) {
8086
- case "like": {
8087
- const likePayload = {
8088
- ...basePayload,
8089
- tweet: interaction.targetTweet
8090
- };
8091
- this.runtime.emitEvent("TWITTER_LIKE_RECEIVED" /* LIKE_RECEIVED */, likePayload);
8092
- this.runtime.emitEvent(EventType2.REACTION_RECEIVED, {
8093
- ...basePayload,
8094
- reaction: {
8095
- type: "like",
8096
- entityId: createUniqueUuid5(this.runtime, interaction.userId)
8097
- },
8098
- message: reactionMessage,
8099
- callback: async () => {
8100
- return [];
8101
- }
8102
- });
8103
- break;
8080
+ this.runtime.emitEvent("TWITTER_RETWEET_RECEIVED" /* RETWEET_RECEIVED */, retweetPayload);
8081
+ this.runtime.emitEvent(EventType2.REACTION_RECEIVED, {
8082
+ ...basePayload,
8083
+ reaction: {
8084
+ type: "retweet",
8085
+ entityId: createUniqueUuid5(this.runtime, interaction.userId)
8086
+ },
8087
+ message: reactionMessage,
8088
+ callback: async () => {
8089
+ return [];
8104
8090
  }
8105
- case "retweet": {
8106
- const retweetPayload = {
8107
- ...basePayload,
8108
- tweet: interaction.targetTweet,
8109
- retweetId: interaction.retweetId
8110
- };
8111
- this.runtime.emitEvent("TWITTER_RETWEET_RECEIVED" /* RETWEET_RECEIVED */, retweetPayload);
8112
- this.runtime.emitEvent(EventType2.REACTION_RECEIVED, {
8113
- ...basePayload,
8114
- reaction: {
8115
- type: "retweet",
8116
- entityId: createUniqueUuid5(this.runtime, interaction.userId)
8117
- },
8118
- message: reactionMessage,
8119
- callback: async () => {
8120
- return [];
8121
- }
8122
- });
8123
- break;
8091
+ });
8092
+ break;
8093
+ }
8094
+ case "quote": {
8095
+ const quotePayload = {
8096
+ ...basePayload,
8097
+ message: reactionMessage,
8098
+ quotedTweet: interaction.targetTweet,
8099
+ quoteTweet: interaction.quoteTweet || interaction.targetTweet,
8100
+ callback: async () => [],
8101
+ reaction: {
8102
+ type: "quote",
8103
+ entityId: createUniqueUuid5(this.runtime, interaction.userId)
8124
8104
  }
8125
- case "quote": {
8126
- const quotePayload = {
8127
- ...basePayload,
8128
- message: reactionMessage,
8129
- quotedTweet: interaction.targetTweet,
8130
- quoteTweet: interaction.quoteTweet || interaction.targetTweet,
8131
- callback: async () => [],
8132
- reaction: {
8133
- type: "quote",
8134
- entityId: createUniqueUuid5(this.runtime, interaction.userId)
8135
- }
8136
- };
8137
- this.runtime.emitEvent("TWITTER_QUOTE_RECEIVED" /* QUOTE_RECEIVED */, quotePayload);
8138
- this.runtime.emitEvent(EventType2.REACTION_RECEIVED, {
8139
- ...basePayload,
8140
- reaction: {
8141
- type: "quote",
8142
- entityId: createUniqueUuid5(this.runtime, interaction.userId)
8143
- },
8144
- message: reactionMessage,
8145
- callback: async () => {
8146
- return [];
8147
- }
8148
- });
8149
- break;
8105
+ };
8106
+ this.runtime.emitEvent("TWITTER_QUOTE_RECEIVED" /* QUOTE_RECEIVED */, quotePayload);
8107
+ this.runtime.emitEvent(EventType2.REACTION_RECEIVED, {
8108
+ ...basePayload,
8109
+ reaction: {
8110
+ type: "quote",
8111
+ entityId: createUniqueUuid5(this.runtime, interaction.userId)
8112
+ },
8113
+ message: reactionMessage,
8114
+ callback: async () => {
8115
+ return [];
8150
8116
  }
8151
- }
8152
- }
8153
- };
8154
- const processInteractions = async (interactions2) => {
8155
- for (const interaction of interactions2) {
8156
- if (interaction?.targetTweet?.conversationId) {
8157
- await handleInteraction(interaction);
8158
- }
8159
- }
8160
- };
8161
- const processFollowerChange = async (change, profileId) => {
8162
- if (change?.type && change?.userId && profileId) {
8163
- const followerMemory = this.createMemoryObject(
8164
- change.type,
8165
- `${change.type}-${change.userId}`,
8166
- change.userId,
8167
- profileId
8168
- );
8169
- await this.runtime.createMemory(followerMemory, "follower-changes");
8117
+ });
8118
+ break;
8170
8119
  }
8171
- };
8172
- await this.client.cacheLatestCheckedTweetId();
8173
- logger7.log("Finished checking Twitter interactions");
8174
- } catch (error) {
8175
- logger7.error("Error handling Twitter interactions:", error);
8120
+ }
8176
8121
  }
8177
8122
  }
8178
8123
  /**
@@ -8228,48 +8173,9 @@ var TwitterInteractionClient = class {
8228
8173
  currentPost,
8229
8174
  formattedConversation
8230
8175
  };
8231
- const tweetId = message.id || createUniqueUuid5(this.runtime, tweet.id);
8232
- const tweetExists = (await this.runtime.getMemoryById(tweetId))?.id === tweetId;
8233
- if (!tweetExists) {
8234
- logger7.log("tweet does not exist, saving");
8235
- const entityId = createUniqueUuid5(this.runtime, tweet.userId);
8236
- const roomId = createUniqueUuid5(this.runtime, tweet.conversationId);
8237
- await this.runtime.ensureConnection({
8238
- entityId,
8239
- roomId,
8240
- userName: tweet.username,
8241
- name: tweet.name,
8242
- source: "twitter",
8243
- type: ChannelType5.GROUP
8244
- });
8245
- await this.runtime.ensureRoomExists({
8246
- id: roomId,
8247
- name: `Conversation with ${tweet.name}`,
8248
- source: "twitter",
8249
- type: ChannelType5.GROUP,
8250
- channelId: tweet.conversationId,
8251
- worldId: createUniqueUuid5(this.runtime, tweet.userId)
8252
- });
8253
- const memory = {
8254
- id: tweetId,
8255
- agentId: this.runtime.agentId,
8256
- content: {
8257
- text: tweet.text,
8258
- url: tweet.permanentUrl,
8259
- imageUrls: tweet.photos?.map((photo) => photo.url) || [],
8260
- inReplyTo: tweet.inReplyToStatusId ? createUniqueUuid5(this.runtime, tweet.inReplyToStatusId) : void 0,
8261
- source: "twitter",
8262
- channelType: ChannelType5.GROUP
8263
- },
8264
- entityId,
8265
- roomId,
8266
- createdAt: tweet.timestamp * 1e3
8267
- };
8268
- this.client.saveRequestMessage(memory, state);
8269
- }
8270
- const callback = async (response, tweetId2) => {
8176
+ const callback = async (response, tweetId) => {
8271
8177
  try {
8272
- const tweetToReplyTo = tweetId2 || tweet.id;
8178
+ const tweetToReplyTo = tweetId || tweet.id;
8273
8179
  if (this.isDryRun) {
8274
8180
  logger7.info(`[DRY RUN] Would have replied to ${tweet.username} with: ${response.text}`);
8275
8181
  return [];
@@ -8741,287 +8647,80 @@ var TwitterPostClient = class {
8741
8647
  };
8742
8648
 
8743
8649
  // src/tests.ts
8744
- import {
8745
- ModelType as ModelType5,
8746
- createUniqueUuid as createUniqueUuid7,
8747
- logger as logger9,
8748
- stringToUuid
8749
- } from "@elizaos/core";
8750
- var TEST_IMAGE_URL = "https://github.com/elizaOS/awesome-eliza/blob/main/assets/eliza-logo.jpg?raw=true";
8751
- var TEST_IMAGE = {
8752
- id: "mock-image-id",
8753
- text: "mock image",
8754
- description: "mock image descirption",
8755
- source: "mock image source",
8756
- url: TEST_IMAGE_URL,
8757
- title: "mock image",
8758
- contentType: "image/jpeg",
8759
- alt_text: "mock image"
8760
- };
8761
- var TwitterTestSuite = class {
8762
- /**
8763
- * Constructor for TestSuite class.
8764
- * Initializes an array of test functions to be executed.
8765
- */
8650
+ import { logger as logger9 } from "@elizaos/core";
8651
+ var ClientBaseTestSuite = class {
8766
8652
  constructor() {
8767
- this.name = "twitter";
8768
- this.twitterClient = null;
8653
+ this.name = "twitter-client-base";
8769
8654
  this.tests = [
8770
- {
8771
- name: "Initialize Twitter Client",
8772
- fn: this.testInitializingClient.bind(this)
8773
- },
8774
- { name: "Fetch Profile", fn: this.testFetchProfile.bind(this) },
8775
- {
8776
- name: "Fetch Search Tweets",
8777
- fn: this.testFetchSearchTweets.bind(this)
8778
- },
8779
- {
8780
- name: "Fetch Home Timeline",
8781
- fn: this.testFetchHomeTimeline.bind(this)
8782
- },
8783
- { name: "Fetch Own Posts", fn: this.testFetchOwnPosts.bind(this) },
8784
- { name: "Post Tweet", fn: this.testPostTweet.bind(this) },
8785
- { name: "Post Tweet With Image", fn: this.testPostImageTweet.bind(this) },
8786
- { name: "Generate New Tweet", fn: this.testGenerateNewTweet.bind(this) },
8787
- {
8788
- name: "Handle Tweet Response",
8789
- fn: this.testHandleTweetResponse.bind(this)
8790
- }
8655
+ { name: "Create instance with correct configuration", fn: this.testInstanceCreation.bind(this) },
8656
+ { name: "Initialize with correct post intervals", fn: this.testPostIntervals.bind(this) }
8791
8657
  ];
8792
- }
8793
- /**
8794
- * Asynchronously initializes the Twitter client for the provided agent runtime.
8795
- *
8796
- * @param {IAgentRuntime} runtime - The agent runtime to use for initializing the Twitter client.
8797
- * @throws {Error} If the Twitter client manager is not found or if the Twitter client fails to initialize.
8798
- */
8799
- async testInitializingClient(runtime) {
8800
- try {
8801
- const manager = runtime.getService(ServiceType.TWITTER);
8802
- if (!manager) {
8803
- throw new Error("Twitter client manager not found");
8804
- }
8805
- const clientId = stringToUuid("default");
8806
- this.twitterClient = manager.clients.get(manager.getClientKey(clientId, runtime.agentId));
8807
- if (this.twitterClient) {
8808
- logger9.debug("TwitterClient initialized successfully.");
8809
- } else {
8810
- throw new Error("TwitterClient failed to initialize.");
8658
+ this.mockRuntime = {
8659
+ env: {
8660
+ TWITTER_USERNAME: "testuser",
8661
+ TWITTER_DRY_RUN: "true",
8662
+ TWITTER_POST_INTERVAL_MIN: "90",
8663
+ TWITTER_POST_INTERVAL_MAX: "180",
8664
+ TWITTER_ENABLE_ACTION_PROCESSING: "true",
8665
+ TWITTER_POST_IMMEDIATELY: "false"
8666
+ },
8667
+ getEnv: (key) => this.mockRuntime.env[key] || null,
8668
+ getSetting: (key) => this.mockRuntime.env[key] || null,
8669
+ character: {
8670
+ style: {
8671
+ all: ["Test style 1", "Test style 2"],
8672
+ post: ["Post style 1", "Post style 2"]
8673
+ }
8811
8674
  }
8812
- } catch (error) {
8813
- throw new Error(`Error in initializing Twitter client: ${error}`);
8814
- }
8675
+ };
8676
+ this.mockConfig = {
8677
+ TWITTER_USERNAME: "testuser",
8678
+ TWITTER_DRY_RUN: true,
8679
+ TWITTER_SPACES_ENABLE: false,
8680
+ TWITTER_TARGET_USERS: [],
8681
+ TWITTER_PASSWORD: "hashedpassword",
8682
+ TWITTER_EMAIL: "test@example.com",
8683
+ TWITTER_2FA_SECRET: "",
8684
+ TWITTER_RETRY_LIMIT: 5,
8685
+ TWITTER_POLL_INTERVAL: 120,
8686
+ TWITTER_ENABLE_POST_GENERATION: true,
8687
+ TWITTER_POST_INTERVAL_MIN: 90,
8688
+ TWITTER_POST_INTERVAL_MAX: 180,
8689
+ TWITTER_POST_IMMEDIATELY: false
8690
+ };
8815
8691
  }
8816
- /**
8817
- * Asynchronously fetches the profile of a user from Twitter using the given runtime.
8818
- *
8819
- * @param {IAgentRuntime} runtime The runtime to use for fetching the profile.
8820
- * @returns {Promise<void>} A Promise that resolves when the profile is successfully fetched, or rejects with an error.
8821
- */
8822
- async testFetchProfile(runtime) {
8823
- try {
8824
- const username = runtime.getSetting("TWITTER_USERNAME");
8825
- const profile = await this.twitterClient.client.fetchProfile(username);
8826
- if (!profile || !profile.id) {
8827
- throw new Error("Profile fetch failed.");
8828
- }
8829
- logger9.log("Successfully fetched Twitter profile:", profile);
8830
- } catch (error) {
8831
- throw new Error(`Error fetching Twitter profile: ${error}`);
8692
+ async testInstanceCreation() {
8693
+ const client = new ClientBase(this.mockRuntime, this.mockConfig);
8694
+ if (!client) throw new Error("ClientBase instance creation failed.");
8695
+ if (this.mockRuntime.getSetting("TWITTER_USERNAME") !== "testuser") {
8696
+ throw new Error("TWITTER_USERNAME setting mismatch.");
8832
8697
  }
8833
- }
8834
- /**
8835
- * Asynchronously fetches search tweets from the Twitter API.
8836
- *
8837
- * @param {IAgentRuntime} _runtime - The runtime object used to access certain functionalities.
8838
- * @returns {Promise<void>} - A Promise that resolves once the search tweets have been successfully fetched.
8839
- * @throws {Error} - If there is an error while fetching the search tweets.
8840
- */
8841
- async testFetchSearchTweets(_runtime) {
8842
- try {
8843
- const tweets = await this.twitterClient.client.fetchSearchTweets(
8844
- `@${this.twitterClient.client.profile?.username}`,
8845
- 5,
8846
- 1 /* Latest */
8847
- );
8848
- logger9.debug(`Successfully fetched ${tweets.tweets.length} search tweets.`);
8849
- } catch (error) {
8850
- throw new Error(`Error fetching search tweets: ${error}`);
8698
+ if (client.state.TWITTER_USERNAME !== "testuser") {
8699
+ throw new Error("Client state TWITTER_USERNAME mismatch.");
8851
8700
  }
8852
- }
8853
- /**
8854
- * Asynchronously fetches the home timeline from the Twitter client.
8855
- *
8856
- * @param {IAgentRuntime} _runtime - The agent runtime object.
8857
- * @throws {Error} If there are no tweets in the home timeline.
8858
- * @throws {Error} If an error occurs while fetching the home timeline.
8859
- */
8860
- async testFetchHomeTimeline(_runtime) {
8861
- try {
8862
- const timeline = await this.twitterClient.client.fetchHomeTimeline(5);
8863
- if (!timeline || timeline.length === 0) {
8864
- throw new Error("No tweets in home timeline.");
8865
- }
8866
- logger9.log(`Successfully fetched ${timeline.length} tweets from home timeline.`);
8867
- } catch (error) {
8868
- throw new Error(`Error fetching home timeline: ${error}`);
8701
+ if (this.mockRuntime.getSetting("TWITTER_DRY_RUN") !== "true") {
8702
+ throw new Error("TWITTER_DRY_RUN setting mismatch.");
8869
8703
  }
8870
- }
8871
- /**
8872
- * Fetches own posts using the Twitter client.
8873
- *
8874
- * @param {IAgentRuntime} _runtime - The Agent Runtime object.
8875
- * @throws {Error} If no own posts are found or if there is an error fetching the posts.
8876
- */
8877
- async testFetchOwnPosts(_runtime) {
8878
- try {
8879
- const posts = await this.twitterClient.client.fetchOwnPosts(5);
8880
- if (!posts || posts.length === 0) {
8881
- throw new Error("No own posts found.");
8882
- }
8883
- logger9.log(`Successfully fetched ${posts.length} own posts.`);
8884
- } catch (error) {
8885
- throw new Error(`Error fetching own posts: ${error}`);
8704
+ if (client.state.TWITTER_DRY_RUN !== true) {
8705
+ throw new Error("Client state TWITTER_DRY_RUN mismatch.");
8886
8706
  }
8707
+ logger9.success("ClientBase instance created with correct configuration.");
8887
8708
  }
8888
- /**
8889
- * Asynchronously posts a test tweet using the Twitter API.
8890
- *
8891
- * @param {IAgentRuntime} runtime - The agent runtime object.
8892
- * @returns {Promise<void>} A Promise that resolves when the tweet is successfully posted.
8893
- * @throws {Error} If there is an error posting the tweet.
8894
- */
8895
- async testPostTweet(runtime) {
8896
- try {
8897
- const roomId = createUniqueUuid7(runtime, "twitter_mock_room");
8898
- const postClient = this.twitterClient.post;
8899
- const tweetText = await this.generateRandomTweetContent(runtime);
8900
- await postClient.postTweet(
8901
- runtime,
8902
- this.twitterClient.client,
8903
- tweetText,
8904
- roomId,
8905
- tweetText,
8906
- "test-username"
8907
- );
8908
- logger9.success("Successfully posted a test tweet.");
8909
- } catch (error) {
8910
- throw new Error(`Error posting a tweet: ${error}`);
8709
+ async testPostIntervals() {
8710
+ const client = new ClientBase(this.mockRuntime, this.mockConfig);
8711
+ if (this.mockRuntime.getSetting("TWITTER_POST_INTERVAL_MIN") !== "90") {
8712
+ throw new Error("TWITTER_POST_INTERVAL_MIN setting mismatch.");
8911
8713
  }
8912
- }
8913
- /**
8914
- * Asynchronously posts an image tweet on Twitter using the provided runtime and tweet content.
8915
- *
8916
- * @param {IAgentRuntime} runtime - The runtime environment for the action.
8917
- * @returns {Promise<void>} A Promise that resolves when the tweet is successfully posted.
8918
- * @throws {Error} If there is an error posting the tweet.
8919
- */
8920
- async testPostImageTweet(runtime) {
8921
- try {
8922
- const roomId = createUniqueUuid7(runtime, "twitter_mock_room");
8923
- const postClient = this.twitterClient.post;
8924
- const tweetText = await this.generateRandomTweetContent(runtime, "image_post");
8925
- const mediaData = await fetchMediaData([TEST_IMAGE]);
8926
- await postClient.postTweet(
8927
- runtime,
8928
- this.twitterClient.client,
8929
- tweetText,
8930
- roomId,
8931
- tweetText,
8932
- "test-username",
8933
- mediaData
8934
- );
8935
- logger9.success("Successfully posted a test tweet.");
8936
- } catch (error) {
8937
- throw new Error(`Error posting a tweet: ${error}`);
8714
+ if (client.state.TWITTER_POST_INTERVAL_MIN !== 90) {
8715
+ throw new Error("Client state TWITTER_POST_INTERVAL_MIN mismatch.");
8938
8716
  }
8939
- }
8940
- /**
8941
- * Asynchronously generates a new tweet using the provided agent runtime.
8942
- *
8943
- * @param {IAgentRuntime} _runtime - The agent runtime used to generate the new tweet.
8944
- * @returns {Promise<void>} - A promise that resolves once the tweet has been successfully generated.
8945
- * @throws {Error} - If there is an error generating the new tweet.
8946
- */
8947
- async testGenerateNewTweet(_runtime) {
8948
- try {
8949
- const postClient = this.twitterClient.post;
8950
- await postClient.generateNewTweet();
8951
- logger9.success("Successfully generated a new tweet.");
8952
- } catch (error) {
8953
- throw new Error(`Error generating new tweet: ${error}`);
8717
+ if (this.mockRuntime.getSetting("TWITTER_POST_INTERVAL_MAX") !== "180") {
8718
+ throw new Error("TWITTER_POST_INTERVAL_MAX setting mismatch.");
8954
8719
  }
8955
- }
8956
- /**
8957
- * Asynchronously handles a fake tweet response using the given runtime.
8958
- *
8959
- * @param {IAgentRuntime} runtime - The runtime object for the agent
8960
- * @returns {Promise<void>} - A promise that resolves when the tweet response is handled
8961
- * @throws {Error} - If there is an error handling the tweet response
8962
- */
8963
- async testHandleTweetResponse(runtime) {
8964
- try {
8965
- const testTweet = {
8966
- id: "12345",
8967
- text: "@testUser What do you think about AI?",
8968
- username: "randomUser",
8969
- entityId: "randomUserId",
8970
- timestamp: Date.now() / 1e3,
8971
- conversationId: "67890",
8972
- permanentUrl: "https://twitter.com/randomUser/status/12345",
8973
- photos: [TEST_IMAGE],
8974
- hashtags: [],
8975
- mentions: [],
8976
- thread: [],
8977
- urls: [],
8978
- videos: []
8979
- };
8980
- await this.twitterClient.interaction.handleTweet({
8981
- tweet: testTweet,
8982
- message: {
8983
- content: { text: testTweet.text, source: "twitter" },
8984
- agentId: runtime.agentId,
8985
- entityId: createUniqueUuid7(runtime, testTweet.entityId),
8986
- roomId: createUniqueUuid7(runtime, testTweet.conversationId)
8987
- },
8988
- thread: []
8989
- });
8990
- logger9.success("Correct response decision.");
8991
- } catch (error) {
8992
- throw new Error(`Error handling tweet response: ${error}`);
8720
+ if (client.state.TWITTER_POST_INTERVAL_MAX !== 180) {
8721
+ throw new Error("Client state TWITTER_POST_INTERVAL_MAX mismatch.");
8993
8722
  }
8994
- }
8995
- /**
8996
- * Generates a random tweet content based on the given context.
8997
- *
8998
- * @param {IAgentRuntime} runtime - The runtime environment.
8999
- * @param {string} [context] - The context to determine the type of tweet content to generate. Optional.
9000
- * @returns {Promise<string>} The generated tweet content.
9001
- */
9002
- async generateRandomTweetContent(runtime, context) {
9003
- let prompt;
9004
- if (context === "image_post") {
9005
- prompt = `Generate a short, engaging tweet to accompany an image.
9006
- It should feel natural and fit the tone of social media.
9007
- Keep it brief (under 150 characters).
9008
- It can be witty, descriptive, or thought-provoking.
9009
- Avoid generic captions like "Look at this" or "Nice picture."`;
9010
- } else {
9011
- prompt = `Generate a natural and engaging tweet.
9012
- It should feel human, casual, and slightly thought-provoking.
9013
- Keep it under 280 characters.
9014
- Avoid generic bot-like statements.
9015
- Make it sound like something a real person would tweet.
9016
- Here\u2019s an example format:
9017
- - A random thought about life, technology, or human nature.
9018
- - A short, witty observation about the current moment.
9019
- - A lighthearted take on everyday situations.
9020
- Do not include hashtags or emojis.`;
9021
- }
9022
- return await runtime.useModel(ModelType5.TEXT_SMALL, {
9023
- prompt
9024
- });
8723
+ logger9.success("ClientBase initialized with correct post intervals.");
9025
8724
  }
9026
8725
  };
9027
8726
 
@@ -9093,7 +8792,7 @@ var _TwitterService = class _TwitterService extends Service {
9093
8792
  const profile = client.client.profile;
9094
8793
  const twitterId = profile.id;
9095
8794
  const username = profile.username;
9096
- const worldId = createUniqueUuid8(runtime, twitterId);
8795
+ const worldId = createUniqueUuid7(runtime, twitterId);
9097
8796
  const world = {
9098
8797
  id: worldId,
9099
8798
  name: `${username}'s Twitter`,
@@ -9110,7 +8809,7 @@ var _TwitterService = class _TwitterService extends Service {
9110
8809
  }
9111
8810
  }
9112
8811
  };
9113
- const homeTimelineRoomId = createUniqueUuid8(runtime, `${twitterId}-home`);
8812
+ const homeTimelineRoomId = createUniqueUuid7(runtime, `${twitterId}-home`);
9114
8813
  const homeTimelineRoom = {
9115
8814
  id: homeTimelineRoomId,
9116
8815
  name: `${username}'s Timeline`,
@@ -9120,7 +8819,7 @@ var _TwitterService = class _TwitterService extends Service {
9120
8819
  serverId: twitterId,
9121
8820
  worldId
9122
8821
  };
9123
- const mentionsRoomId = createUniqueUuid8(runtime, `${twitterId}-mentions`);
8822
+ const mentionsRoomId = createUniqueUuid7(runtime, `${twitterId}-mentions`);
9124
8823
  const mentionsRoom = {
9125
8824
  id: mentionsRoomId,
9126
8825
  name: `${username}'s Mentions`,
@@ -9130,7 +8829,7 @@ var _TwitterService = class _TwitterService extends Service {
9130
8829
  serverId: twitterId,
9131
8830
  worldId
9132
8831
  };
9133
- const twitterUserId = createUniqueUuid8(runtime, twitterId);
8832
+ const twitterUserId = createUniqueUuid7(runtime, twitterId);
9134
8833
  const twitterUser = {
9135
8834
  id: twitterUserId,
9136
8835
  names: [profile.screenName || username],
@@ -9218,7 +8917,7 @@ var twitterPlugin = {
9218
8917
  description: "Twitter client with per-server instance management",
9219
8918
  services: [TwitterService],
9220
8919
  actions: [spaceJoin_default],
9221
- tests: [new TwitterTestSuite()]
8920
+ tests: [new ClientBaseTestSuite()]
9222
8921
  };
9223
8922
  var index_default = twitterPlugin;
9224
8923
  export {