@elizaos/plugin-twitter 1.2.5 → 1.2.7

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
@@ -5,7 +5,10 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/index.ts
8
- import { logger as logger9 } from "@elizaos/core";
8
+ import { logger as logger10 } from "@elizaos/core";
9
+
10
+ // src/services/twitter.service.ts
11
+ import { Service, logger as logger8 } from "@elizaos/core";
9
12
 
10
13
  // src/interactions.ts
11
14
  import {
@@ -1983,6 +1986,17 @@ var parseActionResponseFromText = (text) => {
1983
1986
  return { actions };
1984
1987
  };
1985
1988
 
1989
+ // src/utils/settings.ts
1990
+ function getSetting(runtime, key, defaultValue) {
1991
+ if (runtime && typeof runtime.getSetting === "function") {
1992
+ const value = runtime.getSetting(key);
1993
+ if (value !== void 0 && value !== null) {
1994
+ return String(value);
1995
+ }
1996
+ }
1997
+ return process.env[key] ?? defaultValue;
1998
+ }
1999
+
1986
2000
  // node_modules/zod/dist/esm/v3/external.js
1987
2001
  var external_exports = {};
1988
2002
  __export(external_exports, {
@@ -6077,15 +6091,6 @@ function getTargetUsers(targetUsersConfig) {
6077
6091
  const users = parseTargetUsers(targetUsersConfig);
6078
6092
  return users.filter((u) => u !== "*");
6079
6093
  }
6080
- function getSetting(runtime, key, defaultValue) {
6081
- if (runtime && typeof runtime.getSetting === "function") {
6082
- const value = runtime.getSetting(key);
6083
- if (value !== void 0 && value !== null) {
6084
- return String(value);
6085
- }
6086
- }
6087
- return process.env[key] ?? defaultValue;
6088
- }
6089
6094
  async function validateTwitterConfig(runtime, config = {}) {
6090
6095
  try {
6091
6096
  const validatedConfig = {
@@ -6123,17 +6128,6 @@ async function validateTwitterConfig(runtime, config = {}) {
6123
6128
  }
6124
6129
  }
6125
6130
 
6126
- // src/utils/settings.ts
6127
- function getSetting2(runtime, key, defaultValue) {
6128
- if (runtime && typeof runtime.getSetting === "function") {
6129
- const value = runtime.getSetting(key);
6130
- if (value !== void 0 && value !== null) {
6131
- return String(value);
6132
- }
6133
- }
6134
- return process.env[key] ?? defaultValue;
6135
- }
6136
-
6137
6131
  // src/interactions.ts
6138
6132
  var TwitterInteractionClient = class {
6139
6133
  /**
@@ -6149,7 +6143,7 @@ var TwitterInteractionClient = class {
6149
6143
  this.client = client;
6150
6144
  this.runtime = runtime;
6151
6145
  this.state = state;
6152
- const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6146
+ const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6153
6147
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
6154
6148
  }
6155
6149
  /**
@@ -6164,7 +6158,7 @@ var TwitterInteractionClient = class {
6164
6158
  return;
6165
6159
  }
6166
6160
  const engagementIntervalMinutes = parseInt(
6167
- this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting2(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
6161
+ this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
6168
6162
  );
6169
6163
  const interactionInterval = engagementIntervalMinutes * 60 * 1e3;
6170
6164
  logger3.info(`Twitter interaction client will check every ${engagementIntervalMinutes} minutes`);
@@ -6189,11 +6183,11 @@ var TwitterInteractionClient = class {
6189
6183
  logger3.log("Checking Twitter interactions");
6190
6184
  const twitterUsername = this.client.profile?.username;
6191
6185
  try {
6192
- const repliesEnabled = (getSetting2(this.runtime, "TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
6186
+ const repliesEnabled = (getSetting(this.runtime, "TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
6193
6187
  if (repliesEnabled) {
6194
6188
  await this.handleMentions(twitterUsername);
6195
6189
  }
6196
- const targetUsersConfig = (getSetting2(this.runtime, "TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6190
+ const targetUsersConfig = (getSetting(this.runtime, "TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6197
6191
  if (targetUsersConfig?.trim()) {
6198
6192
  await this.handleTargetUserPosts(targetUsersConfig);
6199
6193
  }
@@ -6267,7 +6261,7 @@ var TwitterInteractionClient = class {
6267
6261
  */
6268
6262
  async processTargetUserTweets(tweets, username) {
6269
6263
  const maxEngagementsPerRun = parseInt(
6270
- getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6264
+ getSetting(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6271
6265
  );
6272
6266
  let engagementCount = 0;
6273
6267
  for (const tweet of tweets) {
@@ -6344,7 +6338,8 @@ var TwitterInteractionClient = class {
6344
6338
  createdAt: Date.now()
6345
6339
  };
6346
6340
  const state = await this.runtime.composeState(shouldEngageMemory);
6347
- const context = `You are ${this.runtime.character.name}. Should you reply to this tweet based on your interests and expertise?
6341
+ const characterName = this.runtime?.character?.name || "AI Assistant";
6342
+ const context = `You are ${characterName}. Should you reply to this tweet based on your interests and expertise?
6348
6343
 
6349
6344
  Tweet by @${tweet.username}: "${tweet.text}"
6350
6345
 
@@ -6463,7 +6458,7 @@ Response (YES/NO):`;
6463
6458
  );
6464
6459
  let uniqueTweetCandidates = [...mentionCandidates];
6465
6460
  uniqueTweetCandidates = uniqueTweetCandidates.sort((a, b) => a.id.localeCompare(b.id)).filter((tweet) => tweet.userId !== this.client.profile.id);
6466
- const targetUsersConfig = (getSetting2(this.runtime, "TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6461
+ const targetUsersConfig = (getSetting(this.runtime, "TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6467
6462
  if (targetUsersConfig?.trim()) {
6468
6463
  uniqueTweetCandidates = uniqueTweetCandidates.filter((tweet) => {
6469
6464
  const shouldTarget = shouldTargetUser(
@@ -6479,7 +6474,7 @@ Response (YES/NO):`;
6479
6474
  });
6480
6475
  }
6481
6476
  const maxInteractionsPerRun = parseInt(
6482
- getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6477
+ getSetting(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6483
6478
  );
6484
6479
  const tweetsToProcess = uniqueTweetCandidates.slice(0, maxInteractionsPerRun);
6485
6480
  logger3.info(`Processing ${tweetsToProcess.length} of ${uniqueTweetCandidates.length} mention tweets (max: ${maxInteractionsPerRun})`);
@@ -6838,12 +6833,12 @@ var TwitterPostClient = class {
6838
6833
  this.client = client;
6839
6834
  this.state = state;
6840
6835
  this.runtime = runtime;
6841
- const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6836
+ const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6842
6837
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
6843
6838
  logger4.log("Twitter Post Client Configuration:");
6844
6839
  logger4.log(`- Dry Run Mode: ${this.isDryRun ? "Enabled" : "Disabled"}`);
6845
6840
  const postIntervalMinutes = parseInt(
6846
- this.state?.TWITTER_POST_INTERVAL || getSetting2(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6841
+ this.state?.TWITTER_POST_INTERVAL || getSetting(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6847
6842
  );
6848
6843
  logger4.log(`- Post Interval: ${postIntervalMinutes} minutes`);
6849
6844
  }
@@ -6866,7 +6861,7 @@ var TwitterPostClient = class {
6866
6861
  return;
6867
6862
  }
6868
6863
  const postIntervalMinutes = parseInt(
6869
- this.state?.TWITTER_POST_INTERVAL || getSetting2(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6864
+ this.state?.TWITTER_POST_INTERVAL || getSetting(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6870
6865
  );
6871
6866
  const interval = postIntervalMinutes * 60 * 1e3;
6872
6867
  logger4.info(`Next tweet scheduled in ${postIntervalMinutes} minutes`);
@@ -6877,7 +6872,7 @@ var TwitterPostClient = class {
6877
6872
  };
6878
6873
  await new Promise((resolve) => setTimeout(resolve, 1e3));
6879
6874
  const postImmediately = parseInt(
6880
- this.state?.TWITTER_POST_INTERVAL || getSetting2(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6875
+ this.state?.TWITTER_POST_INTERVAL || getSetting(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6881
6876
  ) === 0;
6882
6877
  if (postImmediately) {
6883
6878
  logger4.info("TWITTER_POST_IMMEDIATELY is true, generating initial tweet now");
@@ -7093,9 +7088,9 @@ var TwitterTimelineClient = class {
7093
7088
  this.twitterClient = client.twitterClient;
7094
7089
  this.runtime = runtime;
7095
7090
  this.state = state;
7096
- const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7091
+ const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7097
7092
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
7098
- const timelineMode = getSetting2(this.runtime, "TWITTER_TIMELINE_MODE") ?? process.env.TWITTER_TIMELINE_MODE;
7093
+ const timelineMode = getSetting(this.runtime, "TWITTER_TIMELINE_MODE") ?? process.env.TWITTER_TIMELINE_MODE;
7099
7094
  this.timelineType = timelineMode === "following" /* Following */ ? "following" /* Following */ : "foryou" /* ForYou */;
7100
7095
  }
7101
7096
  async start() {
@@ -7107,7 +7102,7 @@ var TwitterTimelineClient = class {
7107
7102
  return;
7108
7103
  }
7109
7104
  const engagementIntervalMinutes = parseInt(
7110
- this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting2(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
7105
+ this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
7111
7106
  );
7112
7107
  const actionInterval = engagementIntervalMinutes * 60 * 1e3;
7113
7108
  logger5.info(`Timeline client will check every ${engagementIntervalMinutes} minutes`);
@@ -7153,7 +7148,7 @@ var TwitterTimelineClient = class {
7153
7148
  const tweets = await this.getTimeline(20);
7154
7149
  logger5.info(`Fetched ${tweets.length} tweets from timeline`);
7155
7150
  const maxActionsPerCycle = parseInt(
7156
- getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7151
+ getSetting(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7157
7152
  );
7158
7153
  const tweetDecisions = [];
7159
7154
  for (const tweet of tweets) {
@@ -7451,7 +7446,7 @@ var TwitterDiscoveryClient = class {
7451
7446
  this.client = client;
7452
7447
  this.twitterClient = client.twitterClient;
7453
7448
  this.runtime = runtime;
7454
- const dryRunSetting = state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7449
+ const dryRunSetting = state?.TWITTER_DRY_RUN ?? getSetting(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7455
7450
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
7456
7451
  this.config = this.buildDiscoveryConfig();
7457
7452
  logger6.info("Twitter Discovery Config:", {
@@ -7463,18 +7458,36 @@ var TwitterDiscoveryClient = class {
7463
7458
  });
7464
7459
  }
7465
7460
  buildDiscoveryConfig() {
7466
- const character = this.runtime.character;
7467
- const topics = character.topics || this.extractTopicsFromBio(character.bio);
7461
+ const character = this.runtime?.character;
7462
+ const defaultTopics = [
7463
+ "ai",
7464
+ "technology",
7465
+ "blockchain",
7466
+ "web3",
7467
+ "crypto",
7468
+ "programming",
7469
+ "innovation"
7470
+ ];
7471
+ let topics = defaultTopics;
7472
+ if (character) {
7473
+ if (character.topics && Array.isArray(character.topics) && character.topics.length > 0) {
7474
+ topics = character.topics;
7475
+ } else if (character.bio) {
7476
+ topics = this.extractTopicsFromBio(character.bio);
7477
+ }
7478
+ } else {
7479
+ logger6.warn("Character not available in runtime, using default topics for discovery");
7480
+ }
7468
7481
  return {
7469
7482
  topics,
7470
7483
  minFollowerCount: parseInt(
7471
- getSetting2(this.runtime, "TWITTER_MIN_FOLLOWER_COUNT") || process.env.TWITTER_MIN_FOLLOWER_COUNT || "100"
7484
+ getSetting(this.runtime, "TWITTER_MIN_FOLLOWER_COUNT") || process.env.TWITTER_MIN_FOLLOWER_COUNT || "100"
7472
7485
  ),
7473
7486
  maxFollowsPerCycle: parseInt(
7474
- getSetting2(this.runtime, "TWITTER_MAX_FOLLOWS_PER_CYCLE") || process.env.TWITTER_MAX_FOLLOWS_PER_CYCLE || "5"
7487
+ getSetting(this.runtime, "TWITTER_MAX_FOLLOWS_PER_CYCLE") || process.env.TWITTER_MAX_FOLLOWS_PER_CYCLE || "5"
7475
7488
  ),
7476
7489
  maxEngagementsPerCycle: parseInt(
7477
- getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7490
+ getSetting(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7478
7491
  ),
7479
7492
  likeThreshold: 0.6,
7480
7493
  replyThreshold: 0.8,
@@ -7482,6 +7495,9 @@ var TwitterDiscoveryClient = class {
7482
7495
  };
7483
7496
  }
7484
7497
  extractTopicsFromBio(bio) {
7498
+ if (!bio) {
7499
+ return [];
7500
+ }
7485
7501
  const bioText = Array.isArray(bio) ? bio.join(" ") : bio;
7486
7502
  const words = bioText.toLowerCase().split(/\s+/).filter((word) => word.length > 4).filter((word) => !["about", "helping", "working", "people", "making", "building"].includes(word));
7487
7503
  return [...new Set(words)].slice(0, 5);
@@ -7500,7 +7516,7 @@ var TwitterDiscoveryClient = class {
7500
7516
  logger6.error("Discovery cycle error:", error);
7501
7517
  }
7502
7518
  const baseInterval = parseInt(
7503
- getSetting2(this.runtime, "TWITTER_DISCOVERY_INTERVAL") || process.env.TWITTER_DISCOVERY_INTERVAL || "30"
7519
+ getSetting(this.runtime, "TWITTER_DISCOVERY_INTERVAL") || process.env.TWITTER_DISCOVERY_INTERVAL || "30"
7504
7520
  );
7505
7521
  const variance = Math.random() * 20 - 10;
7506
7522
  const nextInterval = (baseInterval + variance) * 60 * 1e3;
@@ -7814,12 +7830,21 @@ var TwitterDiscoveryClient = class {
7814
7830
  return followMemories.length > 0;
7815
7831
  }
7816
7832
  async generateReply(tweet) {
7817
- const prompt = `You are ${this.runtime.character.name}. Generate a thoughtful reply to this tweet:
7833
+ const characterName = this.runtime?.character?.name || "AI Assistant";
7834
+ let characterBio = "";
7835
+ if (this.runtime?.character?.bio) {
7836
+ if (Array.isArray(this.runtime.character.bio)) {
7837
+ characterBio = this.runtime.character.bio.join(" ");
7838
+ } else {
7839
+ characterBio = this.runtime.character.bio;
7840
+ }
7841
+ }
7842
+ const prompt = `You are ${characterName}. Generate a thoughtful reply to this tweet:
7818
7843
 
7819
7844
  Tweet by @${tweet.username}: "${tweet.text}"
7820
7845
 
7821
7846
  Your interests: ${this.config.topics.join(", ")}
7822
- Character bio: ${Array.isArray(this.runtime.character.bio) ? this.runtime.character.bio.join(" ") : this.runtime.character.bio}
7847
+ Character bio: ${characterBio}
7823
7848
 
7824
7849
  Keep the reply:
7825
7850
  - Relevant and adding value to the conversation
@@ -7837,12 +7862,21 @@ Reply:`;
7837
7862
  return response.trim();
7838
7863
  }
7839
7864
  async generateQuote(tweet) {
7840
- const prompt = `You are ${this.runtime.character.name}. Add your perspective to this tweet with a quote tweet:
7865
+ const characterName = this.runtime?.character?.name || "AI Assistant";
7866
+ let characterBio = "";
7867
+ if (this.runtime?.character?.bio) {
7868
+ if (Array.isArray(this.runtime.character.bio)) {
7869
+ characterBio = this.runtime.character.bio.join(" ");
7870
+ } else {
7871
+ characterBio = this.runtime.character.bio;
7872
+ }
7873
+ }
7874
+ const prompt = `You are ${characterName}. Add your perspective to this tweet with a quote tweet:
7841
7875
 
7842
7876
  Original tweet by @${tweet.username}: "${tweet.text}"
7843
7877
 
7844
7878
  Your interests: ${this.config.topics.join(", ")}
7845
- Character bio: ${Array.isArray(this.runtime.character.bio) ? this.runtime.character.bio.join(" ") : this.runtime.character.bio}
7879
+ Character bio: ${characterBio}
7846
7880
 
7847
7881
  Create a quote tweet that:
7848
7882
  - Adds unique insight or perspective
@@ -8414,11 +8448,23 @@ var _ClientBase = class _ClientBase {
8414
8448
  try {
8415
8449
  const profile = await this.requestQueue.add(async () => {
8416
8450
  const profile2 = await this.twitterClient.getProfile(username);
8451
+ const defaultName = "AI Assistant";
8452
+ const defaultBio = "";
8453
+ let characterName = defaultName;
8454
+ let characterBio = defaultBio;
8455
+ if (this.runtime?.character) {
8456
+ characterName = this.runtime.character.name || defaultName;
8457
+ if (typeof this.runtime.character.bio === "string") {
8458
+ characterBio = this.runtime.character.bio;
8459
+ } else if (Array.isArray(this.runtime.character.bio) && this.runtime.character.bio.length > 0) {
8460
+ characterBio = this.runtime.character.bio[0];
8461
+ }
8462
+ }
8417
8463
  return {
8418
8464
  id: profile2.userId,
8419
8465
  username,
8420
- screenName: profile2.name || this.runtime.character.name,
8421
- bio: profile2.biography || typeof this.runtime.character.bio === "string" ? this.runtime.character.bio : this.runtime.character.bio.length > 0 ? this.runtime.character.bio[0] : "",
8466
+ screenName: profile2.name || characterName,
8467
+ bio: profile2.biography || characterBio,
8422
8468
  nicknames: this.profile?.nicknames || []
8423
8469
  };
8424
8470
  });
@@ -8471,7 +8517,45 @@ _ClientBase._twitterClients = {};
8471
8517
  var ClientBase = _ClientBase;
8472
8518
 
8473
8519
  // src/services/twitter.service.ts
8474
- import { Service } from "@elizaos/core";
8520
+ var TwitterClientInstance = class {
8521
+ constructor(runtime, state) {
8522
+ this.client = new ClientBase(runtime, state);
8523
+ const postEnabledSetting = getSetting(runtime, "TWITTER_ENABLE_POST") ?? process.env.TWITTER_ENABLE_POST;
8524
+ logger8.debug(`TWITTER_ENABLE_POST setting value: ${JSON.stringify(postEnabledSetting)}, type: ${typeof postEnabledSetting}`);
8525
+ const postEnabled = postEnabledSetting === "true" || postEnabledSetting === true;
8526
+ if (postEnabled) {
8527
+ logger8.info("Twitter posting is ENABLED - creating post client");
8528
+ this.post = new TwitterPostClient(this.client, runtime, state);
8529
+ } else {
8530
+ logger8.info("Twitter posting is DISABLED - set TWITTER_ENABLE_POST=true to enable automatic posting");
8531
+ }
8532
+ const repliesEnabled = (getSetting(runtime, "TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
8533
+ if (repliesEnabled) {
8534
+ logger8.info("Twitter replies/interactions are ENABLED");
8535
+ this.interaction = new TwitterInteractionClient(
8536
+ this.client,
8537
+ runtime,
8538
+ state
8539
+ );
8540
+ } else {
8541
+ logger8.info("Twitter replies/interactions are DISABLED");
8542
+ }
8543
+ const actionsEnabled = (getSetting(runtime, "TWITTER_ENABLE_ACTIONS") ?? process.env.TWITTER_ENABLE_ACTIONS) === "true";
8544
+ if (actionsEnabled) {
8545
+ logger8.info("Twitter timeline actions are ENABLED");
8546
+ this.timeline = new TwitterTimelineClient(this.client, runtime, state);
8547
+ } else {
8548
+ logger8.info("Twitter timeline actions are DISABLED");
8549
+ }
8550
+ const discoveryEnabled = (getSetting(runtime, "TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) === "true" || actionsEnabled && (getSetting(runtime, "TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) !== "false";
8551
+ if (discoveryEnabled) {
8552
+ logger8.info("Twitter discovery service is ENABLED");
8553
+ this.discovery = new TwitterDiscoveryClient(this.client, runtime, state);
8554
+ } else {
8555
+ logger8.info("Twitter discovery service is DISABLED - set TWITTER_ENABLE_DISCOVERY=true to enable");
8556
+ }
8557
+ }
8558
+ };
8475
8559
  var _TwitterService = class _TwitterService extends Service {
8476
8560
  constructor() {
8477
8561
  super();
@@ -8481,9 +8565,48 @@ var _TwitterService = class _TwitterService extends Service {
8481
8565
  static async start(runtime) {
8482
8566
  const service = new _TwitterService();
8483
8567
  service.runtime = runtime;
8568
+ try {
8569
+ await validateTwitterConfig(runtime);
8570
+ logger8.log("\u2705 Twitter configuration validated successfully");
8571
+ service.twitterClient = new TwitterClientInstance(runtime, {});
8572
+ await service.twitterClient.client.init();
8573
+ if (service.twitterClient.post) {
8574
+ logger8.log("\u{1F4EE} Starting Twitter post client...");
8575
+ await service.twitterClient.post.start();
8576
+ }
8577
+ if (service.twitterClient.interaction) {
8578
+ logger8.log("\u{1F4AC} Starting Twitter interaction client...");
8579
+ await service.twitterClient.interaction.start();
8580
+ }
8581
+ if (service.twitterClient.timeline) {
8582
+ logger8.log("\u{1F4CA} Starting Twitter timeline client...");
8583
+ await service.twitterClient.timeline.start();
8584
+ }
8585
+ if (service.twitterClient.discovery) {
8586
+ logger8.log("\u{1F50D} Starting Twitter discovery client...");
8587
+ await service.twitterClient.discovery.start();
8588
+ }
8589
+ logger8.log("\u2705 Twitter service started successfully");
8590
+ } catch (error) {
8591
+ logger8.error("\u{1F6A8} Failed to start Twitter service:", error);
8592
+ throw error;
8593
+ }
8484
8594
  return service;
8485
8595
  }
8486
8596
  async stop() {
8597
+ if (this.twitterClient?.post) {
8598
+ await this.twitterClient.post.stop();
8599
+ }
8600
+ if (this.twitterClient?.interaction) {
8601
+ await this.twitterClient.interaction.stop();
8602
+ }
8603
+ if (this.twitterClient?.timeline) {
8604
+ await this.twitterClient.timeline.stop();
8605
+ }
8606
+ if (this.twitterClient?.discovery) {
8607
+ await this.twitterClient.discovery.stop();
8608
+ }
8609
+ logger8.log("Twitter service stopped");
8487
8610
  }
8488
8611
  };
8489
8612
  _TwitterService.serviceType = "twitter";
@@ -8491,27 +8614,27 @@ var TwitterService = _TwitterService;
8491
8614
 
8492
8615
  // src/actions/postTweet.ts
8493
8616
  import {
8494
- logger as logger8,
8617
+ logger as logger9,
8495
8618
  ModelType as ModelType4
8496
8619
  } from "@elizaos/core";
8497
8620
  var postTweetAction = {
8498
8621
  name: "POST_TWEET",
8499
8622
  similes: ["TWEET", "SEND_TWEET", "TWITTER_POST", "POST_ON_TWITTER", "SHARE_ON_TWITTER"],
8500
8623
  validate: async (runtime, message) => {
8501
- logger8.debug("Validating POST_TWEET action");
8624
+ logger9.debug("Validating POST_TWEET action");
8502
8625
  const text = message.content?.text?.trim();
8503
8626
  if (!text || text.length === 0) {
8504
- logger8.error("No text content for tweet");
8627
+ logger9.error("No text content for tweet");
8505
8628
  return false;
8506
8629
  }
8507
8630
  if (text.length > 280) {
8508
- logger8.warn(`Tweet too long: ${text.length} characters`);
8631
+ logger9.warn(`Tweet too long: ${text.length} characters`);
8509
8632
  }
8510
8633
  return true;
8511
8634
  },
8512
8635
  description: "Post a tweet on Twitter",
8513
8636
  handler: async (runtime, message, state, _options, callback) => {
8514
- logger8.info("Executing POST_TWEET action");
8637
+ logger9.info("Executing POST_TWEET action");
8515
8638
  try {
8516
8639
  const client = new ClientBase(runtime, {});
8517
8640
  if (!client.twitterClient) {
@@ -8558,7 +8681,7 @@ Tweet:`;
8558
8681
  tweetId = Date.now().toString();
8559
8682
  }
8560
8683
  const tweetUrl = `https://twitter.com/${client.profile.username}/status/${tweetId}`;
8561
- logger8.info(`Successfully posted tweet: ${tweetId}`);
8684
+ logger9.info(`Successfully posted tweet: ${tweetId}`);
8562
8685
  await runtime.createMemory({
8563
8686
  entityId: runtime.agentId,
8564
8687
  content: {
@@ -8585,7 +8708,7 @@ View it here: ${tweetUrl}`,
8585
8708
  throw new Error("Failed to post tweet - no response data");
8586
8709
  }
8587
8710
  } catch (error) {
8588
- logger8.error("Error posting tweet:", error);
8711
+ logger9.error("Error posting tweet:", error);
8589
8712
  if (callback) {
8590
8713
  await callback({
8591
8714
  text: `Sorry, I couldn't post the tweet. Error: ${error.message}`,
@@ -8645,91 +8768,37 @@ View it here: ${tweetUrl}`,
8645
8768
  };
8646
8769
 
8647
8770
  // src/index.ts
8648
- var TwitterClientInstance = class {
8649
- constructor(runtime, state) {
8650
- this.client = new ClientBase(runtime, state);
8651
- const getSetting3 = (key) => {
8652
- if (runtime && typeof runtime.getSetting === "function") {
8653
- return runtime.getSetting(key);
8654
- }
8655
- return void 0;
8656
- };
8657
- const postEnabledSetting = getSetting3("TWITTER_ENABLE_POST") ?? process.env.TWITTER_ENABLE_POST;
8658
- logger9.debug(`TWITTER_ENABLE_POST setting value: ${JSON.stringify(postEnabledSetting)}, type: ${typeof postEnabledSetting}`);
8659
- const postEnabled = postEnabledSetting === "true" || postEnabledSetting === true;
8660
- if (postEnabled) {
8661
- logger9.info("Twitter posting is ENABLED - creating post client");
8662
- this.post = new TwitterPostClient(this.client, runtime, state);
8663
- } else {
8664
- logger9.info("Twitter posting is DISABLED - set TWITTER_ENABLE_POST=true to enable automatic posting");
8665
- }
8666
- const repliesEnabled = (getSetting3("TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
8667
- if (repliesEnabled) {
8668
- logger9.info("Twitter replies/interactions are ENABLED");
8669
- this.interaction = new TwitterInteractionClient(
8670
- this.client,
8671
- runtime,
8672
- state
8673
- );
8674
- } else {
8675
- logger9.info("Twitter replies/interactions are DISABLED");
8676
- }
8677
- const actionsEnabled = (getSetting3("TWITTER_ENABLE_ACTIONS") ?? process.env.TWITTER_ENABLE_ACTIONS) === "true";
8678
- if (actionsEnabled) {
8679
- logger9.info("Twitter timeline actions are ENABLED");
8680
- this.timeline = new TwitterTimelineClient(this.client, runtime, state);
8681
- } else {
8682
- logger9.info("Twitter timeline actions are DISABLED");
8683
- }
8684
- const discoveryEnabled = (getSetting3("TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) === "true" || actionsEnabled && (getSetting3("TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) !== "false";
8685
- if (discoveryEnabled) {
8686
- logger9.info("Twitter discovery service is ENABLED");
8687
- this.discovery = new TwitterDiscoveryClient(this.client, runtime, state);
8688
- } else {
8689
- logger9.info("Twitter discovery service is DISABLED - set TWITTER_ENABLE_DISCOVERY=true to enable");
8690
- }
8691
- }
8692
- };
8693
- async function startTwitterClient(runtime) {
8694
- try {
8695
- logger9.log("\u{1F527} Initializing Twitter plugin...");
8696
- await validateTwitterConfig(runtime);
8697
- logger9.log("\u2705 Twitter configuration validated successfully");
8698
- const twitterClient = new TwitterClientInstance(runtime, {});
8699
- await twitterClient.client.init();
8700
- await runtime.registerService(TwitterService);
8701
- if (twitterClient.post) {
8702
- logger9.log("\u{1F4EE} Starting Twitter post client...");
8703
- await twitterClient.post.start();
8704
- }
8705
- if (twitterClient.interaction) {
8706
- logger9.log("\u{1F4AC} Starting Twitter interaction client...");
8707
- await twitterClient.interaction.start();
8708
- }
8709
- if (twitterClient.timeline) {
8710
- logger9.log("\u{1F4CA} Starting Twitter timeline client...");
8711
- await twitterClient.timeline.start();
8712
- }
8713
- if (twitterClient.discovery) {
8714
- logger9.log("\u{1F50D} Starting Twitter discovery client...");
8715
- await twitterClient.discovery.start();
8716
- }
8717
- logger9.log("\u2705 Twitter plugin started successfully");
8718
- } catch (error) {
8719
- logger9.error("\u{1F6A8} Failed to start Twitter plugin:", error);
8720
- throw error;
8721
- }
8722
- }
8723
8771
  var TwitterPlugin = {
8724
8772
  name: "twitter",
8725
8773
  description: "Twitter client with posting, interactions, and timeline actions",
8726
8774
  actions: [postTweetAction],
8727
8775
  services: [TwitterService],
8728
- init: startTwitterClient
8776
+ init: async (_config, runtime) => {
8777
+ logger10.log("\u{1F527} Initializing Twitter plugin...");
8778
+ const hasGetSetting = runtime && typeof runtime.getSetting === "function";
8779
+ const apiKey = hasGetSetting ? runtime.getSetting("TWITTER_API_KEY") : process.env.TWITTER_API_KEY;
8780
+ const apiSecretKey = hasGetSetting ? runtime.getSetting("TWITTER_API_SECRET_KEY") : process.env.TWITTER_API_SECRET_KEY;
8781
+ const accessToken = hasGetSetting ? runtime.getSetting("TWITTER_ACCESS_TOKEN") : process.env.TWITTER_ACCESS_TOKEN;
8782
+ const accessTokenSecret = hasGetSetting ? runtime.getSetting("TWITTER_ACCESS_TOKEN_SECRET") : process.env.TWITTER_ACCESS_TOKEN_SECRET;
8783
+ if (!apiKey || !apiSecretKey || !accessToken || !accessTokenSecret) {
8784
+ const missing = [];
8785
+ if (!apiKey) missing.push("TWITTER_API_KEY");
8786
+ if (!apiSecretKey) missing.push("TWITTER_API_SECRET_KEY");
8787
+ if (!accessToken) missing.push("TWITTER_ACCESS_TOKEN");
8788
+ if (!accessTokenSecret) missing.push("TWITTER_ACCESS_TOKEN_SECRET");
8789
+ logger10.warn(
8790
+ `Twitter API credentials not configured - Twitter functionality will be limited. Missing: ${missing.join(", ")}`
8791
+ );
8792
+ logger10.warn(
8793
+ "To enable Twitter functionality, please provide the missing credentials in your .env file"
8794
+ );
8795
+ } else {
8796
+ logger10.log("\u2705 Twitter credentials found");
8797
+ }
8798
+ }
8729
8799
  };
8730
8800
  var index_default = TwitterPlugin;
8731
8801
  export {
8732
- TwitterClientInstance,
8733
8802
  TwitterPlugin,
8734
8803
  index_default as default
8735
8804
  };