@elizaos/plugin-twitter 1.2.14 → 1.2.15

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,10 +5,10 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/index.ts
8
- import { logger as logger10 } from "@elizaos/core";
8
+ import { logger as logger11 } from "@elizaos/core";
9
9
 
10
10
  // src/services/twitter.service.ts
11
- import { Service, logger as logger8 } from "@elizaos/core";
11
+ import { Service, logger as logger9 } from "@elizaos/core";
12
12
 
13
13
  // src/interactions.ts
14
14
  import {
@@ -16,7 +16,7 @@ import {
16
16
  EventType,
17
17
  ModelType,
18
18
  createUniqueUuid as createUniqueUuid2,
19
- logger as logger3
19
+ logger as logger4
20
20
  } from "@elizaos/core";
21
21
 
22
22
  // src/client/auth.ts
@@ -2014,6 +2014,9 @@ var parseActionResponseFromText = (text) => {
2014
2014
  return { actions };
2015
2015
  };
2016
2016
 
2017
+ // src/environment.ts
2018
+ import { logger as logger3 } from "@elizaos/core";
2019
+
2017
2020
  // src/utils/settings.ts
2018
2021
  function getSetting(runtime, key, defaultValue) {
2019
2022
  if (runtime && typeof runtime.getSetting === "function") {
@@ -6079,11 +6082,24 @@ var twitterEnvSchema = external_exports.object({
6079
6082
  // likes, retweets, quotes
6080
6083
  // Timing configuration (all in minutes)
6081
6084
  TWITTER_POST_INTERVAL: external_exports.string().default("120"),
6082
- // minutes between posts
6085
+ // minutes between posts (deprecated, kept for backwards compatibility)
6086
+ TWITTER_POST_INTERVAL_MIN: external_exports.string().default("90"),
6087
+ // minimum minutes between posts
6088
+ TWITTER_POST_INTERVAL_MAX: external_exports.string().default("150"),
6089
+ // maximum minutes between posts
6083
6090
  TWITTER_ENGAGEMENT_INTERVAL: external_exports.string().default("30"),
6084
- // minutes between all interactions
6091
+ // minutes between all interactions (deprecated, kept for backwards compatibility)
6092
+ TWITTER_ENGAGEMENT_INTERVAL_MIN: external_exports.string().default("20"),
6093
+ // minimum minutes between engagements
6094
+ TWITTER_ENGAGEMENT_INTERVAL_MAX: external_exports.string().default("40"),
6095
+ // maximum minutes between engagements
6096
+ TWITTER_DISCOVERY_INTERVAL_MIN: external_exports.string().default("15"),
6097
+ // minimum minutes between discovery cycles
6098
+ TWITTER_DISCOVERY_INTERVAL_MAX: external_exports.string().default("30"),
6099
+ // maximum minutes between discovery cycles
6085
6100
  // Limits
6086
- TWITTER_MAX_ENGAGEMENTS_PER_RUN: external_exports.string().default("10"),
6101
+ TWITTER_MAX_ENGAGEMENTS_PER_RUN: external_exports.string().default("5"),
6102
+ // Reduced from 10 to be less aggressive
6087
6103
  TWITTER_MAX_TWEET_LENGTH: external_exports.string().default("280"),
6088
6104
  // standard tweet length
6089
6105
  // Advanced
@@ -6145,16 +6161,52 @@ async function validateTwitterConfig(runtime, config = {}) {
6145
6161
  120
6146
6162
  )
6147
6163
  ),
6164
+ TWITTER_POST_INTERVAL_MIN: String(
6165
+ safeParseInt(
6166
+ config.TWITTER_POST_INTERVAL_MIN ?? getSetting(runtime, "TWITTER_POST_INTERVAL_MIN"),
6167
+ 90
6168
+ )
6169
+ ),
6170
+ TWITTER_POST_INTERVAL_MAX: String(
6171
+ safeParseInt(
6172
+ config.TWITTER_POST_INTERVAL_MAX ?? getSetting(runtime, "TWITTER_POST_INTERVAL_MAX"),
6173
+ 150
6174
+ )
6175
+ ),
6148
6176
  TWITTER_ENGAGEMENT_INTERVAL: String(
6149
6177
  safeParseInt(
6150
6178
  config.TWITTER_ENGAGEMENT_INTERVAL ?? getSetting(runtime, "TWITTER_ENGAGEMENT_INTERVAL"),
6151
6179
  30
6152
6180
  )
6153
6181
  ),
6182
+ TWITTER_ENGAGEMENT_INTERVAL_MIN: String(
6183
+ safeParseInt(
6184
+ config.TWITTER_ENGAGEMENT_INTERVAL_MIN ?? getSetting(runtime, "TWITTER_ENGAGEMENT_INTERVAL_MIN"),
6185
+ 20
6186
+ )
6187
+ ),
6188
+ TWITTER_ENGAGEMENT_INTERVAL_MAX: String(
6189
+ safeParseInt(
6190
+ config.TWITTER_ENGAGEMENT_INTERVAL_MAX ?? getSetting(runtime, "TWITTER_ENGAGEMENT_INTERVAL_MAX"),
6191
+ 40
6192
+ )
6193
+ ),
6194
+ TWITTER_DISCOVERY_INTERVAL_MIN: String(
6195
+ safeParseInt(
6196
+ config.TWITTER_DISCOVERY_INTERVAL_MIN ?? getSetting(runtime, "TWITTER_DISCOVERY_INTERVAL_MIN"),
6197
+ 15
6198
+ )
6199
+ ),
6200
+ TWITTER_DISCOVERY_INTERVAL_MAX: String(
6201
+ safeParseInt(
6202
+ config.TWITTER_DISCOVERY_INTERVAL_MAX ?? getSetting(runtime, "TWITTER_DISCOVERY_INTERVAL_MAX"),
6203
+ 30
6204
+ )
6205
+ ),
6154
6206
  TWITTER_MAX_ENGAGEMENTS_PER_RUN: String(
6155
6207
  safeParseInt(
6156
6208
  config.TWITTER_MAX_ENGAGEMENTS_PER_RUN ?? getSetting(runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN"),
6157
- 10
6209
+ 5
6158
6210
  )
6159
6211
  ),
6160
6212
  TWITTER_MAX_TWEET_LENGTH: String(
@@ -6186,6 +6238,49 @@ async function validateTwitterConfig(runtime, config = {}) {
6186
6238
  throw error;
6187
6239
  }
6188
6240
  }
6241
+ function getRandomInterval(runtime, type) {
6242
+ let minInterval;
6243
+ let maxInterval;
6244
+ let fallbackInterval;
6245
+ switch (type) {
6246
+ case "post":
6247
+ const postMin = getSetting(runtime, "TWITTER_POST_INTERVAL_MIN");
6248
+ const postMax = getSetting(runtime, "TWITTER_POST_INTERVAL_MAX");
6249
+ minInterval = postMin ? safeParseInt(postMin, 0) : void 0;
6250
+ maxInterval = postMax ? safeParseInt(postMax, 0) : void 0;
6251
+ fallbackInterval = safeParseInt(
6252
+ getSetting(runtime, "TWITTER_POST_INTERVAL"),
6253
+ 120
6254
+ );
6255
+ break;
6256
+ case "engagement":
6257
+ const engagementMin = getSetting(runtime, "TWITTER_ENGAGEMENT_INTERVAL_MIN");
6258
+ const engagementMax = getSetting(runtime, "TWITTER_ENGAGEMENT_INTERVAL_MAX");
6259
+ minInterval = engagementMin ? safeParseInt(engagementMin, 0) : void 0;
6260
+ maxInterval = engagementMax ? safeParseInt(engagementMax, 0) : void 0;
6261
+ fallbackInterval = safeParseInt(
6262
+ getSetting(runtime, "TWITTER_ENGAGEMENT_INTERVAL"),
6263
+ 30
6264
+ );
6265
+ break;
6266
+ case "discovery":
6267
+ const discoveryMin = getSetting(runtime, "TWITTER_DISCOVERY_INTERVAL_MIN");
6268
+ const discoveryMax = getSetting(runtime, "TWITTER_DISCOVERY_INTERVAL_MAX");
6269
+ minInterval = discoveryMin ? safeParseInt(discoveryMin, 0) : void 0;
6270
+ maxInterval = discoveryMax ? safeParseInt(discoveryMax, 0) : void 0;
6271
+ fallbackInterval = 20;
6272
+ break;
6273
+ default:
6274
+ throw new Error(`Unknown interval type: ${type}`);
6275
+ }
6276
+ if (minInterval !== void 0 && maxInterval !== void 0 && minInterval < maxInterval) {
6277
+ const randomInterval = Math.random() * (maxInterval - minInterval) + minInterval;
6278
+ logger3.debug(`Random ${type} interval: ${randomInterval.toFixed(1)} minutes (between ${minInterval}-${maxInterval})`);
6279
+ return randomInterval;
6280
+ }
6281
+ logger3.debug(`Using fixed ${type} interval: ${fallbackInterval} minutes`);
6282
+ return fallbackInterval;
6283
+ }
6189
6284
 
6190
6285
  // src/interactions.ts
6191
6286
  var TwitterInteractionClient = class {
@@ -6213,15 +6308,13 @@ var TwitterInteractionClient = class {
6213
6308
  this.isRunning = true;
6214
6309
  const handleTwitterInteractionsLoop = () => {
6215
6310
  if (!this.isRunning) {
6216
- logger3.info("Twitter interaction client stopped, exiting loop");
6311
+ logger4.info("Twitter interaction client stopped, exiting loop");
6217
6312
  return;
6218
6313
  }
6219
- const engagementIntervalMinutes = parseInt(
6220
- this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
6221
- );
6314
+ const engagementIntervalMinutes = getRandomInterval(this.runtime, "engagement");
6222
6315
  const interactionInterval = engagementIntervalMinutes * 60 * 1e3;
6223
- logger3.info(
6224
- `Twitter interaction client will check every ${engagementIntervalMinutes} minutes`
6316
+ logger4.info(
6317
+ `Twitter interaction client will check in ${engagementIntervalMinutes.toFixed(1)} minutes`
6225
6318
  );
6226
6319
  this.handleTwitterInteractions();
6227
6320
  if (this.isRunning) {
@@ -6234,14 +6327,14 @@ var TwitterInteractionClient = class {
6234
6327
  * Stops the Twitter interaction client
6235
6328
  */
6236
6329
  async stop() {
6237
- logger3.log("Stopping Twitter interaction client...");
6330
+ logger4.log("Stopping Twitter interaction client...");
6238
6331
  this.isRunning = false;
6239
6332
  }
6240
6333
  /**
6241
6334
  * Asynchronously handles Twitter interactions by checking for mentions and target user posts.
6242
6335
  */
6243
6336
  async handleTwitterInteractions() {
6244
- logger3.log("Checking Twitter interactions");
6337
+ logger4.log("Checking Twitter interactions");
6245
6338
  const twitterUsername = this.client.profile?.username;
6246
6339
  try {
6247
6340
  const repliesEnabled = (getSetting(this.runtime, "TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
@@ -6253,9 +6346,9 @@ var TwitterInteractionClient = class {
6253
6346
  await this.handleTargetUserPosts(targetUsersConfig);
6254
6347
  }
6255
6348
  await this.client.cacheLatestCheckedTweetId();
6256
- logger3.log("Finished checking Twitter interactions");
6349
+ logger4.log("Finished checking Twitter interactions");
6257
6350
  } catch (error) {
6258
- logger3.error("Error handling Twitter interactions:", error);
6351
+ logger4.error("Error handling Twitter interactions:", error);
6259
6352
  }
6260
6353
  }
6261
6354
  /**
@@ -6279,7 +6372,7 @@ var TwitterInteractionClient = class {
6279
6372
  }
6280
6373
  await this.processMentionTweets(mentionCandidates);
6281
6374
  } catch (error) {
6282
- logger3.error("Error handling mentions:", error);
6375
+ logger4.error("Error handling mentions:", error);
6283
6376
  }
6284
6377
  }
6285
6378
  /**
@@ -6291,7 +6384,7 @@ var TwitterInteractionClient = class {
6291
6384
  if (targetUsers.length === 0 && !targetUsersConfig.includes("*")) {
6292
6385
  return;
6293
6386
  }
6294
- logger3.info(
6387
+ logger4.info(
6295
6388
  `Checking posts from target users: ${targetUsers.join(", ") || "everyone (*)"}`
6296
6389
  );
6297
6390
  for (const targetUser of targetUsers) {
@@ -6305,7 +6398,7 @@ var TwitterInteractionClient = class {
6305
6398
  1 /* Latest */
6306
6399
  );
6307
6400
  if (searchResult.tweets.length > 0) {
6308
- logger3.info(
6401
+ logger4.info(
6309
6402
  `Found ${searchResult.tweets.length} posts from @${normalizedUsername}`
6310
6403
  );
6311
6404
  await this.processTargetUserTweets(
@@ -6314,14 +6407,14 @@ var TwitterInteractionClient = class {
6314
6407
  );
6315
6408
  }
6316
6409
  } catch (error) {
6317
- logger3.error(`Error searching posts from @${targetUser}:`, error);
6410
+ logger4.error(`Error searching posts from @${targetUser}:`, error);
6318
6411
  }
6319
6412
  }
6320
6413
  if (targetUsersConfig.includes("*")) {
6321
6414
  await this.processTimelineForEngagement();
6322
6415
  }
6323
6416
  } catch (error) {
6324
- logger3.error("Error handling target user posts:", error);
6417
+ logger4.error("Error handling target user posts:", error);
6325
6418
  }
6326
6419
  }
6327
6420
  /**
@@ -6334,7 +6427,7 @@ var TwitterInteractionClient = class {
6334
6427
  let engagementCount = 0;
6335
6428
  for (const tweet of tweets) {
6336
6429
  if (engagementCount >= maxEngagementsPerRun) {
6337
- logger3.info(`Reached max engagements limit (${maxEngagementsPerRun})`);
6430
+ logger4.info(`Reached max engagements limit (${maxEngagementsPerRun})`);
6338
6431
  break;
6339
6432
  }
6340
6433
  const tweetId = createUniqueUuid2(this.runtime, tweet.id);
@@ -6349,7 +6442,7 @@ var TwitterInteractionClient = class {
6349
6442
  }
6350
6443
  const shouldEngage = await this.shouldEngageWithTweet(tweet);
6351
6444
  if (shouldEngage) {
6352
- logger3.info(
6445
+ logger4.info(
6353
6446
  `Engaging with tweet from @${username}: ${tweet.text.substring(0, 50)}...`
6354
6447
  );
6355
6448
  await this.ensureTweetContext(tweet);
@@ -6375,13 +6468,13 @@ var TwitterInteractionClient = class {
6375
6468
  return tweetAge < 12 * 60 * 60 * 1e3;
6376
6469
  });
6377
6470
  if (relevantTweets.length > 0) {
6378
- logger3.info(
6471
+ logger4.info(
6379
6472
  `Found ${relevantTweets.length} relevant tweets from timeline`
6380
6473
  );
6381
6474
  await this.processTargetUserTweets(relevantTweets, "timeline");
6382
6475
  }
6383
6476
  } catch (error) {
6384
- logger3.error("Error processing timeline for engagement:", error);
6477
+ logger4.error("Error processing timeline for engagement:", error);
6385
6478
  }
6386
6479
  }
6387
6480
  /**
@@ -6434,7 +6527,7 @@ Response (YES/NO):`;
6434
6527
  });
6435
6528
  return response.trim().toUpperCase().includes("YES");
6436
6529
  } catch (error) {
6437
- logger3.error("Error determining engagement:", error);
6530
+ logger4.error("Error determining engagement:", error);
6438
6531
  return false;
6439
6532
  }
6440
6533
  }
@@ -6518,7 +6611,7 @@ Response (YES/NO):`;
6518
6611
  });
6519
6612
  return result.text && result.text.length > 0;
6520
6613
  } catch (error) {
6521
- logger3.error("Error engaging with tweet:", error);
6614
+ logger4.error("Error engaging with tweet:", error);
6522
6615
  return false;
6523
6616
  }
6524
6617
  }
@@ -6533,7 +6626,7 @@ Response (YES/NO):`;
6533
6626
  * Note: MENTION_RECEIVED is currently disabled (see TODO below)
6534
6627
  */
6535
6628
  async processMentionTweets(mentionCandidates) {
6536
- logger3.log(
6629
+ logger4.log(
6537
6630
  "Completed checking mentioned tweets:",
6538
6631
  mentionCandidates.length
6539
6632
  );
@@ -6547,7 +6640,7 @@ Response (YES/NO):`;
6547
6640
  targetUsersConfig
6548
6641
  );
6549
6642
  if (!shouldTarget) {
6550
- logger3.log(
6643
+ logger4.log(
6551
6644
  `Skipping tweet from @${tweet.username} - not in target users list`
6552
6645
  );
6553
6646
  }
@@ -6561,7 +6654,7 @@ Response (YES/NO):`;
6561
6654
  0,
6562
6655
  maxInteractionsPerRun
6563
6656
  );
6564
- logger3.info(
6657
+ logger4.info(
6565
6658
  `Processing ${tweetsToProcess.length} of ${uniqueTweetCandidates.length} mention tweets (max: ${maxInteractionsPerRun})`
6566
6659
  );
6567
6660
  for (const tweet of tweetsToProcess) {
@@ -6569,7 +6662,7 @@ Response (YES/NO):`;
6569
6662
  const tweetId = createUniqueUuid2(this.runtime, tweet.id);
6570
6663
  const existingResponse = await this.runtime.getMemoryById(tweetId);
6571
6664
  if (existingResponse) {
6572
- logger3.log(`Already responded to tweet ${tweet.id}, skipping`);
6665
+ logger4.log(`Already responded to tweet ${tweet.id}, skipping`);
6573
6666
  continue;
6574
6667
  }
6575
6668
  const conversationRoomId = createUniqueUuid2(
@@ -6586,22 +6679,22 @@ Response (YES/NO):`;
6586
6679
  (memory2) => memory2.content.inReplyTo === tweetId || memory2.content.inReplyTo === tweet.id
6587
6680
  );
6588
6681
  if (hasExistingReply) {
6589
- logger3.log(
6682
+ logger4.log(
6590
6683
  `Already responded to tweet ${tweet.id} (found in conversation history), skipping`
6591
6684
  );
6592
6685
  continue;
6593
6686
  }
6594
- logger3.log("New Tweet found", tweet.id);
6687
+ logger4.log("New Tweet found", tweet.id);
6595
6688
  const userId = tweet.userId;
6596
6689
  const conversationId = tweet.conversationId || tweet.id;
6597
6690
  const roomId = createUniqueUuid2(this.runtime, conversationId);
6598
6691
  const username = tweet.username;
6599
- logger3.log("----");
6600
- logger3.log(`User: ${username} (${userId})`);
6601
- logger3.log(`Tweet: ${tweet.id}`);
6602
- logger3.log(`Conversation: ${conversationId}`);
6603
- logger3.log(`Room: ${roomId}`);
6604
- logger3.log("----");
6692
+ logger4.log("----");
6693
+ logger4.log(`User: ${username} (${userId})`);
6694
+ logger4.log(`Tweet: ${tweet.id}`);
6695
+ logger4.log(`Conversation: ${conversationId}`);
6696
+ logger4.log(`Room: ${roomId}`);
6697
+ logger4.log("----");
6605
6698
  const worldId = createUniqueUuid2(this.runtime, userId);
6606
6699
  await this.runtime.ensureWorldExists({
6607
6700
  id: worldId,
@@ -6648,7 +6741,7 @@ Response (YES/NO):`;
6648
6741
  roomId,
6649
6742
  createdAt: tweet.timestamp * 1e3
6650
6743
  };
6651
- logger3.log("Saving tweet memory...");
6744
+ logger4.log("Saving tweet memory...");
6652
6745
  await this.runtime.createMemory(memory, "messages");
6653
6746
  if (tweet.thread && tweet.thread.length > 0) {
6654
6747
  const threadStartId = tweet.thread[0].id;
@@ -6831,23 +6924,23 @@ Response (YES/NO):`;
6831
6924
  thread
6832
6925
  }) {
6833
6926
  if (!message.content.text) {
6834
- logger3.log("Skipping Tweet with no text", tweet.id);
6927
+ logger4.log("Skipping Tweet with no text", tweet.id);
6835
6928
  return { text: "", actions: ["IGNORE"] };
6836
6929
  }
6837
6930
  const callback = async (response2, tweetId) => {
6838
6931
  try {
6839
6932
  if (!response2.text) {
6840
- logger3.warn("No text content in response, skipping tweet reply");
6933
+ logger4.warn("No text content in response, skipping tweet reply");
6841
6934
  return [];
6842
6935
  }
6843
6936
  const tweetToReplyTo = tweetId || tweet.id;
6844
6937
  if (this.isDryRun) {
6845
- logger3.info(
6938
+ logger4.info(
6846
6939
  `[DRY RUN] Would have replied to ${tweet.username} with: ${response2.text}`
6847
6940
  );
6848
6941
  return [];
6849
6942
  }
6850
- logger3.info(`Replying to tweet ${tweetToReplyTo}`);
6943
+ logger4.info(`Replying to tweet ${tweetToReplyTo}`);
6851
6944
  const tweetResult = await sendTweet(
6852
6945
  this.client,
6853
6946
  response2.text,
@@ -6873,7 +6966,7 @@ Response (YES/NO):`;
6873
6966
  await this.runtime.createMemory(responseMemory, "messages");
6874
6967
  return [responseMemory];
6875
6968
  } catch (error) {
6876
- logger3.error("Error in tweet reply callback:", error);
6969
+ logger4.error("Error in tweet reply callback:", error);
6877
6970
  return [];
6878
6971
  }
6879
6972
  };
@@ -6914,7 +7007,7 @@ Response (YES/NO):`;
6914
7007
  import {
6915
7008
  ChannelType as ChannelType2,
6916
7009
  createUniqueUuid as createUniqueUuid3,
6917
- logger as logger4,
7010
+ logger as logger5,
6918
7011
  ModelType as ModelType2
6919
7012
  } from "@elizaos/core";
6920
7013
  var TwitterPostClient = class {
@@ -6933,39 +7026,40 @@ var TwitterPostClient = class {
6933
7026
  this.runtime = runtime;
6934
7027
  const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6935
7028
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
6936
- logger4.log("Twitter Post Client Configuration:");
6937
- logger4.log(`- Dry Run Mode: ${this.isDryRun ? "Enabled" : "Disabled"}`);
6938
- const postIntervalMinutes = parseInt(
6939
- this.state?.TWITTER_POST_INTERVAL || getSetting(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
7029
+ logger5.log("Twitter Post Client Configuration:");
7030
+ logger5.log(`- Dry Run Mode: ${this.isDryRun ? "Enabled" : "Disabled"}`);
7031
+ const postIntervalMin = parseInt(
7032
+ this.state?.TWITTER_POST_INTERVAL_MIN || getSetting(this.runtime, "TWITTER_POST_INTERVAL_MIN") || process.env.TWITTER_POST_INTERVAL_MIN || "90"
6940
7033
  );
6941
- logger4.log(`- Post Interval: ${postIntervalMinutes} minutes`);
7034
+ const postIntervalMax = parseInt(
7035
+ this.state?.TWITTER_POST_INTERVAL_MAX || getSetting(this.runtime, "TWITTER_POST_INTERVAL_MAX") || process.env.TWITTER_POST_INTERVAL_MAX || "150"
7036
+ );
7037
+ logger5.log(`- Post Interval: ${postIntervalMin}-${postIntervalMax} minutes (randomized)`);
6942
7038
  }
6943
7039
  /**
6944
7040
  * Stops the Twitter post client
6945
7041
  */
6946
7042
  async stop() {
6947
- logger4.log("Stopping Twitter post client...");
7043
+ logger5.log("Stopping Twitter post client...");
6948
7044
  this.isRunning = false;
6949
7045
  }
6950
7046
  /**
6951
7047
  * Starts the Twitter post client, setting up a loop to periodically generate new tweets.
6952
7048
  */
6953
7049
  async start() {
6954
- logger4.log("Starting Twitter post client...");
7050
+ logger5.log("Starting Twitter post client...");
6955
7051
  this.isRunning = true;
6956
7052
  const generateNewTweetLoop = async () => {
6957
7053
  if (!this.isRunning) {
6958
- logger4.log("Twitter post client stopped, exiting loop");
7054
+ logger5.log("Twitter post client stopped, exiting loop");
6959
7055
  return;
6960
7056
  }
6961
- const postIntervalMinutes = parseInt(
6962
- this.state?.TWITTER_POST_INTERVAL || getSetting(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6963
- );
7057
+ const postIntervalMinutes = getRandomInterval(this.runtime, "post");
6964
7058
  const interval = postIntervalMinutes * 60 * 1e3;
6965
- logger4.info(`Next tweet scheduled in ${postIntervalMinutes} minutes`);
7059
+ logger5.info(`Next tweet scheduled in ${postIntervalMinutes.toFixed(1)} minutes`);
6966
7060
  await new Promise((resolve) => setTimeout(resolve, interval));
6967
7061
  if (!this.isRunning) {
6968
- logger4.log("Twitter post client stopped during wait, exiting loop");
7062
+ logger5.log("Twitter post client stopped during wait, exiting loop");
6969
7063
  return;
6970
7064
  }
6971
7065
  await this.generateNewTweet();
@@ -6976,7 +7070,7 @@ var TwitterPostClient = class {
6976
7070
  await new Promise((resolve) => setTimeout(resolve, 1e3));
6977
7071
  const postImmediately = this.state?.TWITTER_POST_IMMEDIATELY || getSetting(this.runtime, "TWITTER_POST_IMMEDIATELY") || process.env.TWITTER_POST_IMMEDIATELY;
6978
7072
  if (postImmediately === "true" || postImmediately === true) {
6979
- logger4.info(
7073
+ logger5.info(
6980
7074
  "TWITTER_POST_IMMEDIATELY is true, generating initial tweet now"
6981
7075
  );
6982
7076
  await this.generateNewTweet();
@@ -6988,19 +7082,19 @@ var TwitterPostClient = class {
6988
7082
  * This approach aligns with our platform-independent architecture.
6989
7083
  */
6990
7084
  async generateNewTweet() {
6991
- logger4.info("Attempting to generate new tweet...");
7085
+ logger5.info("Attempting to generate new tweet...");
6992
7086
  if (this.isPosting) {
6993
- logger4.info("Already posting a tweet, skipping concurrent attempt");
7087
+ logger5.info("Already posting a tweet, skipping concurrent attempt");
6994
7088
  return;
6995
7089
  }
6996
7090
  this.isPosting = true;
6997
7091
  try {
6998
7092
  const userId = this.client.profile?.id;
6999
7093
  if (!userId) {
7000
- logger4.error("Cannot generate tweet: Twitter profile not available");
7094
+ logger5.error("Cannot generate tweet: Twitter profile not available");
7001
7095
  return;
7002
7096
  }
7003
- logger4.info(
7097
+ logger5.info(
7004
7098
  `Generating tweet for user: ${this.client.profile?.username} (${userId})`
7005
7099
  );
7006
7100
  const worldId = createUniqueUuid3(this.runtime, userId);
@@ -7012,7 +7106,7 @@ var TwitterPostClient = class {
7012
7106
  content: { text: "", type: "post" },
7013
7107
  createdAt: Date.now()
7014
7108
  }).catch((error) => {
7015
- logger4.warn("Error composing state, using minimal state:", error);
7109
+ logger5.warn("Error composing state, using minimal state:", error);
7016
7110
  return {
7017
7111
  agentId: this.runtime.agentId,
7018
7112
  recentMemories: [],
@@ -7060,15 +7154,15 @@ Generate a single tweet that sounds like YOU would actually write it:`;
7060
7154
  );
7061
7155
  const tweetText = generatedContent.trim();
7062
7156
  if (!tweetText || tweetText.length === 0) {
7063
- logger4.error("Generated empty tweet content");
7157
+ logger5.error("Generated empty tweet content");
7064
7158
  return;
7065
7159
  }
7066
7160
  if (tweetText.includes("Error: Missing")) {
7067
- logger4.error("Error in generated content:", tweetText);
7161
+ logger5.error("Error in generated content:", tweetText);
7068
7162
  return;
7069
7163
  }
7070
7164
  if (tweetText.length > 280) {
7071
- logger4.warn(`Generated tweet too long (${tweetText.length} chars), truncating...`);
7165
+ logger5.warn(`Generated tweet too long (${tweetText.length} chars), truncating...`);
7072
7166
  const sentences = tweetText.match(/[^.!?]+[.!?]+/g) || [tweetText];
7073
7167
  let truncated = "";
7074
7168
  for (const sentence of sentences) {
@@ -7079,33 +7173,33 @@ Generate a single tweet that sounds like YOU would actually write it:`;
7079
7173
  }
7080
7174
  }
7081
7175
  const finalTweet = truncated.trim() || tweetText.substring(0, 277) + "...";
7082
- logger4.info(`Truncated tweet: ${finalTweet}`);
7176
+ logger5.info(`Truncated tweet: ${finalTweet}`);
7083
7177
  if (this.isDryRun) {
7084
- logger4.info(`[DRY RUN] Would post tweet: ${finalTweet}`);
7178
+ logger5.info(`[DRY RUN] Would post tweet: ${finalTweet}`);
7085
7179
  return;
7086
7180
  }
7087
7181
  const result2 = await this.postToTwitter(finalTweet, []);
7088
7182
  if (result2 === null) {
7089
- logger4.info("Skipped posting duplicate tweet");
7183
+ logger5.info("Skipped posting duplicate tweet");
7090
7184
  return;
7091
7185
  }
7092
7186
  const tweetId2 = result2.id;
7093
- logger4.info(`Tweet posted successfully! ID: ${tweetId2}`);
7094
- logger4.info("Tweet posted successfully (memory saving disabled due to room constraints)");
7187
+ logger5.info(`Tweet posted successfully! ID: ${tweetId2}`);
7188
+ logger5.info("Tweet posted successfully (memory saving disabled due to room constraints)");
7095
7189
  return;
7096
7190
  }
7097
- logger4.info(`Generated tweet: ${tweetText}`);
7191
+ logger5.info(`Generated tweet: ${tweetText}`);
7098
7192
  if (this.isDryRun) {
7099
- logger4.info(`[DRY RUN] Would post tweet: ${tweetText}`);
7193
+ logger5.info(`[DRY RUN] Would post tweet: ${tweetText}`);
7100
7194
  return;
7101
7195
  }
7102
7196
  const result = await this.postToTwitter(tweetText, []);
7103
7197
  if (result === null) {
7104
- logger4.info("Skipped posting duplicate tweet");
7198
+ logger5.info("Skipped posting duplicate tweet");
7105
7199
  return;
7106
7200
  }
7107
7201
  const tweetId = result.id;
7108
- logger4.info(`Tweet posted successfully! ID: ${tweetId}`);
7202
+ logger5.info(`Tweet posted successfully! ID: ${tweetId}`);
7109
7203
  if (result) {
7110
7204
  const postedTweetId = createUniqueUuid3(this.runtime, tweetId);
7111
7205
  await this.runtime.ensureWorldExists({
@@ -7141,10 +7235,10 @@ Generate a single tweet that sounds like YOU would actually write it:`;
7141
7235
  createdAt: Date.now()
7142
7236
  };
7143
7237
  await this.runtime.createMemory(postedMemory, "messages");
7144
- logger4.info("Tweet posted and saved to memory successfully");
7238
+ logger5.info("Tweet posted and saved to memory successfully");
7145
7239
  }
7146
7240
  } catch (error) {
7147
- logger4.error("Error generating tweet:", error);
7241
+ logger5.error("Error generating tweet:", error);
7148
7242
  } finally {
7149
7243
  this.isPosting = false;
7150
7244
  }
@@ -7163,7 +7257,7 @@ Generate a single tweet that sounds like YOU would actually write it:`;
7163
7257
  if (lastPost) {
7164
7258
  const lastTweet = await this.client.getTweet(lastPost.id);
7165
7259
  if (lastTweet && lastTweet.text === text) {
7166
- logger4.warn(
7260
+ logger5.warn(
7167
7261
  "Tweet is a duplicate of the last post. Skipping to avoid duplicate."
7168
7262
  );
7169
7263
  return null;
@@ -7173,11 +7267,11 @@ Generate a single tweet that sounds like YOU would actually write it:`;
7173
7267
  if (mediaData && mediaData.length > 0) {
7174
7268
  for (const media of mediaData) {
7175
7269
  try {
7176
- logger4.warn(
7270
+ logger5.warn(
7177
7271
  "Media upload not currently supported with the modern Twitter API"
7178
7272
  );
7179
7273
  } catch (error) {
7180
- logger4.error("Error uploading media:", error);
7274
+ logger5.error("Error uploading media:", error);
7181
7275
  }
7182
7276
  }
7183
7277
  }
@@ -7192,7 +7286,7 @@ Generate a single tweet that sounds like YOU would actually write it:`;
7192
7286
  );
7193
7287
  return result;
7194
7288
  } catch (error) {
7195
- logger4.error("Error posting to Twitter:", error);
7289
+ logger5.error("Error posting to Twitter:", error);
7196
7290
  throw error;
7197
7291
  }
7198
7292
  }
@@ -7206,7 +7300,7 @@ import {
7206
7300
  ModelType as ModelType3,
7207
7301
  parseKeyValueXml
7208
7302
  } from "@elizaos/core";
7209
- import { logger as logger5 } from "@elizaos/core";
7303
+ import { logger as logger6 } from "@elizaos/core";
7210
7304
 
7211
7305
  // src/templates.ts
7212
7306
  var twitterActionTemplate = `
@@ -7286,18 +7380,18 @@ var TwitterTimelineClient = class {
7286
7380
  this.timelineType = timelineMode === "following" /* Following */ ? "following" /* Following */ : "foryou" /* ForYou */;
7287
7381
  }
7288
7382
  async start() {
7289
- logger5.info("Starting Twitter timeline client...");
7383
+ logger6.info("Starting Twitter timeline client...");
7290
7384
  this.isRunning = true;
7291
7385
  const handleTwitterTimelineLoop = () => {
7292
7386
  if (!this.isRunning) {
7293
- logger5.info("Twitter timeline client stopped, exiting loop");
7387
+ logger6.info("Twitter timeline client stopped, exiting loop");
7294
7388
  return;
7295
7389
  }
7296
7390
  const engagementIntervalMinutes = parseInt(
7297
7391
  this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
7298
7392
  );
7299
7393
  const actionInterval = engagementIntervalMinutes * 60 * 1e3;
7300
- logger5.info(
7394
+ logger6.info(
7301
7395
  `Timeline client will check every ${engagementIntervalMinutes} minutes`
7302
7396
  );
7303
7397
  this.handleTimeline();
@@ -7308,7 +7402,7 @@ var TwitterTimelineClient = class {
7308
7402
  handleTwitterTimelineLoop();
7309
7403
  }
7310
7404
  async stop() {
7311
- logger5.info("Stopping Twitter timeline client...");
7405
+ logger6.info("Stopping Twitter timeline client...");
7312
7406
  this.isRunning = false;
7313
7407
  }
7314
7408
  async getTimeline(count) {
@@ -7338,9 +7432,9 @@ var TwitterTimelineClient = class {
7338
7432
  };
7339
7433
  }
7340
7434
  async handleTimeline() {
7341
- logger5.info("Starting Twitter timeline processing...");
7435
+ logger6.info("Starting Twitter timeline processing...");
7342
7436
  const tweets = await this.getTimeline(20);
7343
- logger5.info(`Fetched ${tweets.length} tweets from timeline`);
7437
+ logger6.info(`Fetched ${tweets.length} tweets from timeline`);
7344
7438
  const maxActionsPerCycle = parseInt(
7345
7439
  getSetting(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7346
7440
  );
@@ -7350,7 +7444,7 @@ var TwitterTimelineClient = class {
7350
7444
  const tweetId = this.createTweetId(this.runtime, tweet);
7351
7445
  const memory = await this.runtime.getMemoryById(tweetId);
7352
7446
  if (memory) {
7353
- logger5.log(`Already processed tweet ID: ${tweet.id}`);
7447
+ logger6.log(`Already processed tweet ID: ${tweet.id}`);
7354
7448
  continue;
7355
7449
  }
7356
7450
  const roomId = createUniqueUuid4(this.runtime, tweet.conversationId);
@@ -7374,7 +7468,7 @@ Choose any combination of [LIKE], [RETWEET], [QUOTE], and [REPLY] that are appro
7374
7468
  );
7375
7469
  const parsedResponse = parseActionResponseFromText(actionResponse);
7376
7470
  if (!parsedResponse) {
7377
- logger5.debug(`No action response generated for tweet ${tweet.id}`);
7471
+ logger6.debug(`No action response generated for tweet ${tweet.id}`);
7378
7472
  continue;
7379
7473
  }
7380
7474
  tweetDecisions.push({
@@ -7385,7 +7479,7 @@ Choose any combination of [LIKE], [RETWEET], [QUOTE], and [REPLY] that are appro
7385
7479
  });
7386
7480
  if (tweetDecisions.length >= maxActionsPerCycle) break;
7387
7481
  } catch (error) {
7388
- logger5.error(`Error processing tweet ${tweet.id}:`, error);
7482
+ logger6.error(`Error processing tweet ${tweet.id}:`, error);
7389
7483
  }
7390
7484
  }
7391
7485
  const rankByActionRelevance = (arr) => {
@@ -7403,7 +7497,7 @@ Choose any combination of [LIKE], [RETWEET], [QUOTE], and [REPLY] that are appro
7403
7497
  });
7404
7498
  };
7405
7499
  const prioritizedTweets = rankByActionRelevance(tweetDecisions);
7406
- logger5.info(`Processing ${prioritizedTweets.length} tweets with actions`);
7500
+ logger6.info(`Processing ${prioritizedTweets.length} tweets with actions`);
7407
7501
  if (prioritizedTweets.length > 0) {
7408
7502
  const actionSummary = prioritizedTweets.map((td) => {
7409
7503
  const actions = [];
@@ -7413,11 +7507,11 @@ Choose any combination of [LIKE], [RETWEET], [QUOTE], and [REPLY] that are appro
7413
7507
  if (td.actionResponse.reply) actions.push("REPLY");
7414
7508
  return `Tweet ${td.tweet.id}: ${actions.join(", ")}`;
7415
7509
  });
7416
- logger5.info(`Actions to execute:
7510
+ logger6.info(`Actions to execute:
7417
7511
  ${actionSummary.join("\n")}`);
7418
7512
  }
7419
7513
  await this.processTimelineActions(prioritizedTweets);
7420
- logger5.info("Timeline processing complete");
7514
+ logger6.info("Timeline processing complete");
7421
7515
  }
7422
7516
  async processTimelineActions(tweetDecisions) {
7423
7517
  const results = [];
@@ -7478,7 +7572,7 @@ ${actionSummary.join("\n")}`);
7478
7572
  }
7479
7573
  results.push({ tweetId: tweet.id, actionResponse, executedActions });
7480
7574
  } catch (error) {
7481
- logger5.error(`Error processing actions for tweet ${tweet.id}:`, error);
7575
+ logger6.error(`Error processing actions for tweet ${tweet.id}:`, error);
7482
7576
  }
7483
7577
  }
7484
7578
  return results;
@@ -7522,25 +7616,25 @@ ${actionSummary.join("\n")}`);
7522
7616
  async handleLikeAction(tweet) {
7523
7617
  try {
7524
7618
  if (this.isDryRun) {
7525
- logger5.log(`[DRY RUN] Would have liked tweet ${tweet.id}`);
7619
+ logger6.log(`[DRY RUN] Would have liked tweet ${tweet.id}`);
7526
7620
  return;
7527
7621
  }
7528
7622
  await this.twitterClient.likeTweet(tweet.id);
7529
- logger5.log(`Liked tweet ${tweet.id}`);
7623
+ logger6.log(`Liked tweet ${tweet.id}`);
7530
7624
  } catch (error) {
7531
- logger5.error(`Error liking tweet ${tweet.id}:`, error);
7625
+ logger6.error(`Error liking tweet ${tweet.id}:`, error);
7532
7626
  }
7533
7627
  }
7534
7628
  async handleRetweetAction(tweet) {
7535
7629
  try {
7536
7630
  if (this.isDryRun) {
7537
- logger5.log(`[DRY RUN] Would have retweeted tweet ${tweet.id}`);
7631
+ logger6.log(`[DRY RUN] Would have retweeted tweet ${tweet.id}`);
7538
7632
  return;
7539
7633
  }
7540
7634
  await this.twitterClient.retweet(tweet.id);
7541
- logger5.log(`Retweeted tweet ${tweet.id}`);
7635
+ logger6.log(`Retweeted tweet ${tweet.id}`);
7542
7636
  } catch (error) {
7543
- logger5.error(`Error retweeting tweet ${tweet.id}:`, error);
7637
+ logger6.error(`Error retweeting tweet ${tweet.id}:`, error);
7544
7638
  }
7545
7639
  }
7546
7640
  async handleQuoteAction(tweet) {
@@ -7559,7 +7653,7 @@ ${tweet.text}`;
7559
7653
  const responseObject = parseKeyValueXml(quoteResponse);
7560
7654
  if (responseObject.post) {
7561
7655
  if (this.isDryRun) {
7562
- logger5.log(
7656
+ logger6.log(
7563
7657
  `[DRY RUN] Would have quoted tweet ${tweet.id} with: ${responseObject.post}`
7564
7658
  );
7565
7659
  return;
@@ -7573,9 +7667,9 @@ ${tweet.text}`;
7573
7667
  const body = await result.json();
7574
7668
  const tweetResult = body?.data?.create_tweet?.tweet_results?.result || body?.data || body;
7575
7669
  if (tweetResult) {
7576
- logger5.log("Successfully posted quote tweet");
7670
+ logger6.log("Successfully posted quote tweet");
7577
7671
  } else {
7578
- logger5.error("Quote tweet creation failed:", body);
7672
+ logger6.error("Quote tweet creation failed:", body);
7579
7673
  }
7580
7674
  const tweetId = tweetResult?.id || Date.now().toString();
7581
7675
  const responseId = createUniqueUuid4(this.runtime, tweetId);
@@ -7593,7 +7687,7 @@ ${tweet.text}`;
7593
7687
  await this.runtime.createMemory(responseMemory, "messages");
7594
7688
  }
7595
7689
  } catch (error) {
7596
- logger5.error("Error in quote tweet generation:", error);
7690
+ logger6.error("Error in quote tweet generation:", error);
7597
7691
  }
7598
7692
  }
7599
7693
  async handleReplyAction(tweet) {
@@ -7612,7 +7706,7 @@ ${tweet.text}`;
7612
7706
  const responseObject = parseKeyValueXml(replyResponse);
7613
7707
  if (responseObject.post) {
7614
7708
  if (this.isDryRun) {
7615
- logger5.log(
7709
+ logger6.log(
7616
7710
  `[DRY RUN] Would have replied to tweet ${tweet.id} with: ${responseObject.post}`
7617
7711
  );
7618
7712
  return;
@@ -7624,7 +7718,7 @@ ${tweet.text}`;
7624
7718
  tweet.id
7625
7719
  );
7626
7720
  if (result) {
7627
- logger5.log("Successfully posted reply tweet");
7721
+ logger6.log("Successfully posted reply tweet");
7628
7722
  const responseId = createUniqueUuid4(this.runtime, result.id);
7629
7723
  const responseMemory = {
7630
7724
  id: responseId,
@@ -7641,7 +7735,7 @@ ${tweet.text}`;
7641
7735
  }
7642
7736
  }
7643
7737
  } catch (error) {
7644
- logger5.error("Error in reply tweet generation:", error);
7738
+ logger6.error("Error in reply tweet generation:", error);
7645
7739
  }
7646
7740
  }
7647
7741
  };
@@ -7649,7 +7743,7 @@ ${tweet.text}`;
7649
7743
  // src/discovery.ts
7650
7744
  import {
7651
7745
  createUniqueUuid as createUniqueUuid5,
7652
- logger as logger6,
7746
+ logger as logger7,
7653
7747
  ModelType as ModelType4
7654
7748
  } from "@elizaos/core";
7655
7749
  var TwitterDiscoveryClient = class {
@@ -7663,7 +7757,7 @@ var TwitterDiscoveryClient = class {
7663
7757
  const dryRunSetting = state?.TWITTER_DRY_RUN ?? getSetting(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7664
7758
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
7665
7759
  this.config = this.buildDiscoveryConfig();
7666
- logger6.info("Twitter Discovery Config:", {
7760
+ logger7.info("Twitter Discovery Config:", {
7667
7761
  topics: this.config.topics,
7668
7762
  isDryRun: this.isDryRun,
7669
7763
  minFollowerCount: this.config.minFollowerCount,
@@ -7701,7 +7795,7 @@ var TwitterDiscoveryClient = class {
7701
7795
  topics = this.extractTopicsFromBio(character.bio);
7702
7796
  }
7703
7797
  } else {
7704
- logger6.warn(
7798
+ logger7.warn(
7705
7799
  "Character not available in runtime, using default topics for discovery"
7706
7800
  );
7707
7801
  }
@@ -7717,14 +7811,15 @@ var TwitterDiscoveryClient = class {
7717
7811
  getSetting(
7718
7812
  this.runtime,
7719
7813
  "TWITTER_MAX_ENGAGEMENTS_PER_RUN"
7720
- ) || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7814
+ ) || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "5"
7815
+ // Reduced from 10 to 5
7721
7816
  ),
7722
- likeThreshold: 0.3,
7723
- // Lowered from 0.6
7724
- replyThreshold: 0.5,
7725
- // Lowered from 0.8
7726
- quoteThreshold: 0.7
7727
- // Lowered from 0.85
7817
+ likeThreshold: 0.5,
7818
+ // Increased from 0.3 (be more selective)
7819
+ replyThreshold: 0.7,
7820
+ // Increased from 0.5 (be more selective)
7821
+ quoteThreshold: 0.85
7822
+ // Increased from 0.7 (be more selective)
7728
7823
  };
7729
7824
  }
7730
7825
  extractTopicsFromBio(bio) {
@@ -7745,46 +7840,41 @@ var TwitterDiscoveryClient = class {
7745
7840
  return [...new Set(words)].slice(0, 5);
7746
7841
  }
7747
7842
  async start() {
7748
- logger6.info("Starting Twitter Discovery Client...");
7843
+ logger7.info("Starting Twitter Discovery Client...");
7749
7844
  this.isRunning = true;
7750
7845
  const discoveryLoop = async () => {
7751
7846
  if (!this.isRunning) {
7752
- logger6.info("Discovery client stopped, exiting loop");
7847
+ logger7.info("Discovery client stopped, exiting loop");
7753
7848
  return;
7754
7849
  }
7755
7850
  try {
7756
7851
  await this.runDiscoveryCycle();
7757
7852
  } catch (error) {
7758
- logger6.error("Discovery cycle error:", error);
7853
+ logger7.error("Discovery cycle error:", error);
7759
7854
  }
7760
- const baseInterval = parseInt(
7761
- getSetting(this.runtime, "TWITTER_DISCOVERY_INTERVAL") || process.env.TWITTER_DISCOVERY_INTERVAL || "30"
7762
- );
7763
- const variance = Math.random() * 20 - 10;
7764
- const nextInterval = (baseInterval + variance) * 60 * 1e3;
7765
- logger6.info(
7766
- `Next discovery cycle in ${(baseInterval + variance).toFixed(1)} minutes`
7855
+ const discoveryIntervalMinutes = getRandomInterval(this.runtime, "discovery");
7856
+ const nextInterval = discoveryIntervalMinutes * 60 * 1e3;
7857
+ logger7.log(
7858
+ `Next discovery cycle in ${discoveryIntervalMinutes.toFixed(1)} minutes`
7767
7859
  );
7768
- if (this.isRunning) {
7769
- setTimeout(discoveryLoop, nextInterval);
7770
- }
7860
+ setTimeout(discoveryLoop, nextInterval);
7771
7861
  };
7772
7862
  setTimeout(discoveryLoop, 5e3);
7773
7863
  }
7774
7864
  async stop() {
7775
- logger6.info("Stopping Twitter Discovery Client...");
7865
+ logger7.info("Stopping Twitter Discovery Client...");
7776
7866
  this.isRunning = false;
7777
7867
  }
7778
7868
  async runDiscoveryCycle() {
7779
- logger6.info("Starting Twitter discovery cycle...");
7869
+ logger7.info("Starting Twitter discovery cycle...");
7780
7870
  const discoveries = await this.discoverContent();
7781
7871
  const { tweets, accounts } = discoveries;
7782
- logger6.info(
7872
+ logger7.info(
7783
7873
  `Discovered ${tweets.length} tweets and ${accounts.length} accounts`
7784
7874
  );
7785
7875
  const followedCount = await this.processAccounts(accounts);
7786
7876
  const engagementCount = await this.processTweets(tweets);
7787
- logger6.info(
7877
+ logger7.info(
7788
7878
  `Discovery cycle complete: ${followedCount} follows, ${engagementCount} engagements`
7789
7879
  );
7790
7880
  }
@@ -7796,7 +7886,7 @@ var TwitterDiscoveryClient = class {
7796
7886
  allTweets.push(...topicContent.tweets);
7797
7887
  topicContent.accounts.forEach((acc) => allAccounts.set(acc.user.id, acc));
7798
7888
  } catch (error) {
7799
- logger6.error("Failed to discover from topics:", error);
7889
+ logger7.error("Failed to discover from topics:", error);
7800
7890
  }
7801
7891
  try {
7802
7892
  const threadContent = await this.discoverFromThreads();
@@ -7805,7 +7895,7 @@ var TwitterDiscoveryClient = class {
7805
7895
  (acc) => allAccounts.set(acc.user.id, acc)
7806
7896
  );
7807
7897
  } catch (error) {
7808
- logger6.error("Failed to discover from threads:", error);
7898
+ logger7.error("Failed to discover from threads:", error);
7809
7899
  }
7810
7900
  try {
7811
7901
  const popularContent = await this.discoverFromPopularAccounts();
@@ -7814,7 +7904,7 @@ var TwitterDiscoveryClient = class {
7814
7904
  (acc) => allAccounts.set(acc.user.id, acc)
7815
7905
  );
7816
7906
  } catch (error) {
7817
- logger6.error("Failed to discover from popular accounts:", error);
7907
+ logger7.error("Failed to discover from popular accounts:", error);
7818
7908
  }
7819
7909
  const sortedTweets = allTweets.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, 50);
7820
7910
  const sortedAccounts = Array.from(allAccounts.values()).sort(
@@ -7823,14 +7913,14 @@ var TwitterDiscoveryClient = class {
7823
7913
  return { tweets: sortedTweets, accounts: sortedAccounts };
7824
7914
  }
7825
7915
  async discoverFromTopics() {
7826
- logger6.debug("Discovering from character topics...");
7916
+ logger7.debug("Discovering from character topics...");
7827
7917
  const tweets = [];
7828
7918
  const accounts = /* @__PURE__ */ new Map();
7829
7919
  for (const topic of this.config.topics.slice(0, 5)) {
7830
7920
  try {
7831
7921
  const searchTopic = this.sanitizeTopic(topic);
7832
7922
  const popularQuery = `${searchTopic} -is:retweet -is:reply lang:en`;
7833
- logger6.debug(`Searching popular tweets for topic: ${topic}`);
7923
+ logger7.debug(`Searching popular tweets for topic: ${topic}`);
7834
7924
  const popularResults = await this.twitterClient.fetchSearchTweets(
7835
7925
  popularQuery,
7836
7926
  20,
@@ -7840,44 +7930,66 @@ var TwitterDiscoveryClient = class {
7840
7930
  if ((tweet.likes || 0) < 10) continue;
7841
7931
  const scored = this.scoreTweet(tweet, "topic");
7842
7932
  tweets.push(scored);
7933
+ const authorUsername = tweet.username;
7934
+ const authorName = tweet.name || tweet.username;
7935
+ const estimatedFollowers = Math.max(
7936
+ 1e3,
7937
+ // minimum estimate
7938
+ (tweet.likes || 0) * 100
7939
+ // rough estimate: 100 followers per like
7940
+ );
7941
+ const account = this.scoreAccount({
7942
+ id: tweet.userId,
7943
+ username: authorUsername,
7944
+ name: authorName,
7945
+ followersCount: estimatedFollowers
7946
+ });
7947
+ if (account.qualityScore > 0.3) {
7948
+ accounts.set(tweet.userId, account);
7949
+ }
7843
7950
  }
7844
- const verifiedQuery = `${searchTopic} -is:retweet lang:en is:verified`;
7845
- logger6.debug(`Searching verified accounts for topic: ${topic}`);
7846
- const verifiedResults = await this.twitterClient.fetchSearchTweets(
7847
- verifiedQuery,
7848
- 10,
7951
+ const engagedQuery = `${searchTopic} -is:retweet lang:en`;
7952
+ logger7.debug(`Searching engaged tweets for topic: ${topic}`);
7953
+ const engagedResults = await this.twitterClient.fetchSearchTweets(
7954
+ engagedQuery,
7955
+ 15,
7849
7956
  1 /* Latest */
7850
7957
  );
7851
- for (const tweet of verifiedResults.tweets) {
7958
+ for (const tweet of engagedResults.tweets) {
7959
+ if ((tweet.likes || 0) < 5) continue;
7852
7960
  const scored = this.scoreTweet(tweet, "topic");
7853
7961
  tweets.push(scored);
7854
7962
  const authorUsername = tweet.username;
7855
7963
  const authorName = tweet.name || tweet.username;
7964
+ const estimatedFollowers = Math.max(
7965
+ 500,
7966
+ // minimum for engaged tweets
7967
+ (tweet.likes || 0) * 50
7968
+ );
7856
7969
  const account = this.scoreAccount({
7857
7970
  id: tweet.userId,
7858
7971
  username: authorUsername,
7859
7972
  name: authorName,
7860
- followersCount: 1e3
7861
- // Default estimate for verified accounts
7973
+ followersCount: estimatedFollowers
7862
7974
  });
7863
- if (account.qualityScore > 0.5) {
7975
+ if (account.qualityScore > 0.2) {
7864
7976
  accounts.set(tweet.userId, account);
7865
7977
  }
7866
7978
  }
7867
7979
  } catch (error) {
7868
- logger6.error(`Failed to search topic ${topic}:`, error);
7980
+ logger7.error(`Failed to search topic ${topic}:`, error);
7869
7981
  }
7870
7982
  }
7871
7983
  return { tweets, accounts: Array.from(accounts.values()) };
7872
7984
  }
7873
7985
  async discoverFromThreads() {
7874
- logger6.debug("Discovering from conversation threads...");
7986
+ logger7.debug("Discovering from conversation threads...");
7875
7987
  const tweets = [];
7876
7988
  const accounts = /* @__PURE__ */ new Map();
7877
7989
  const topicQuery = this.config.topics.slice(0, 3).map((t) => this.sanitizeTopic(t)).join(" OR ");
7878
7990
  try {
7879
7991
  const viralQuery = `(${topicQuery}) -is:retweet has:mentions`;
7880
- logger6.debug(`Searching viral threads with query: ${viralQuery}`);
7992
+ logger7.debug(`Searching viral threads with query: ${viralQuery}`);
7881
7993
  const searchResults = await this.twitterClient.fetchSearchTweets(
7882
7994
  viralQuery,
7883
7995
  15,
@@ -7900,19 +8012,19 @@ var TwitterDiscoveryClient = class {
7900
8012
  }
7901
8013
  }
7902
8014
  } catch (error) {
7903
- logger6.error("Failed to discover threads:", error);
8015
+ logger7.error("Failed to discover threads:", error);
7904
8016
  }
7905
8017
  return { tweets, accounts: Array.from(accounts.values()) };
7906
8018
  }
7907
8019
  async discoverFromPopularAccounts() {
7908
- logger6.debug("Discovering from popular accounts in topics...");
8020
+ logger7.debug("Discovering from popular accounts in topics...");
7909
8021
  const tweets = [];
7910
8022
  const accounts = /* @__PURE__ */ new Map();
7911
8023
  for (const topic of this.config.topics.slice(0, 3)) {
7912
8024
  try {
7913
8025
  const searchTopic = this.sanitizeTopic(topic);
7914
8026
  const influencerQuery = `${searchTopic} -is:retweet lang:en`;
7915
- logger6.debug(`Searching for influencers in topic: ${topic}`);
8027
+ logger7.debug(`Searching for influencers in topic: ${topic}`);
7916
8028
  const results = await this.twitterClient.fetchSearchTweets(
7917
8029
  influencerQuery,
7918
8030
  10,
@@ -7939,7 +8051,7 @@ var TwitterDiscoveryClient = class {
7939
8051
  }
7940
8052
  }
7941
8053
  } catch (error) {
7942
- logger6.error(
8054
+ logger7.error(
7943
8055
  `Failed to discover popular accounts for ${topic}:`,
7944
8056
  error
7945
8057
  );
@@ -8003,18 +8115,35 @@ var TwitterDiscoveryClient = class {
8003
8115
  }
8004
8116
  async processAccounts(accounts) {
8005
8117
  let followedCount = 0;
8006
- for (const scoredAccount of accounts) {
8118
+ const sortedAccounts = accounts.sort((a, b) => {
8119
+ const scoreA = a.qualityScore + a.relevanceScore;
8120
+ const scoreB = b.qualityScore + b.relevanceScore;
8121
+ return scoreB - scoreA;
8122
+ });
8123
+ for (const scoredAccount of sortedAccounts) {
8007
8124
  if (followedCount >= this.config.maxFollowsPerCycle) break;
8125
+ if (scoredAccount.user.followersCount < this.config.minFollowerCount) {
8126
+ logger7.debug(
8127
+ `Skipping @${scoredAccount.user.username} - below minimum follower count (${scoredAccount.user.followersCount} < ${this.config.minFollowerCount})`
8128
+ );
8129
+ continue;
8130
+ }
8131
+ if (scoredAccount.qualityScore < 0.2) {
8132
+ logger7.debug(
8133
+ `Skipping @${scoredAccount.user.username} - quality score too low (${scoredAccount.qualityScore.toFixed(2)})`
8134
+ );
8135
+ continue;
8136
+ }
8008
8137
  try {
8009
8138
  const isFollowing = await this.checkIfFollowing(scoredAccount.user.id);
8010
8139
  if (isFollowing) continue;
8011
8140
  if (this.isDryRun) {
8012
- logger6.info(
8141
+ logger7.info(
8013
8142
  `[DRY RUN] Would follow @${scoredAccount.user.username} (quality: ${scoredAccount.qualityScore.toFixed(2)}, relevance: ${scoredAccount.relevanceScore.toFixed(2)})`
8014
8143
  );
8015
8144
  } else {
8016
8145
  await this.twitterClient.followUser(scoredAccount.user.id);
8017
- logger6.info(
8146
+ logger7.info(
8018
8147
  `Followed @${scoredAccount.user.username} (quality: ${scoredAccount.qualityScore.toFixed(2)}, relevance: ${scoredAccount.relevanceScore.toFixed(2)})`
8019
8148
  );
8020
8149
  await this.saveFollowMemory(scoredAccount.user);
@@ -8022,7 +8151,7 @@ var TwitterDiscoveryClient = class {
8022
8151
  followedCount++;
8023
8152
  await this.delay(2e3 + Math.random() * 3e3);
8024
8153
  } catch (error) {
8025
- logger6.error(
8154
+ logger7.error(
8026
8155
  `Failed to follow @${scoredAccount.user.username}:`,
8027
8156
  error
8028
8157
  );
@@ -8042,7 +8171,7 @@ var TwitterDiscoveryClient = class {
8042
8171
  );
8043
8172
  const existingMemory = await this.runtime.getMemoryById(tweetMemoryId);
8044
8173
  if (existingMemory) {
8045
- logger6.debug(
8174
+ logger7.debug(
8046
8175
  `Already engaged with tweet ${scoredTweet.tweet.id}, skipping`
8047
8176
  );
8048
8177
  continue;
@@ -8050,12 +8179,12 @@ var TwitterDiscoveryClient = class {
8050
8179
  switch (scoredTweet.engagementType) {
8051
8180
  case "like":
8052
8181
  if (this.isDryRun) {
8053
- logger6.info(
8182
+ logger7.info(
8054
8183
  `[DRY RUN] Would like tweet: ${scoredTweet.tweet.id} (score: ${scoredTweet.relevanceScore.toFixed(2)})`
8055
8184
  );
8056
8185
  } else {
8057
8186
  await this.twitterClient.likeTweet(scoredTweet.tweet.id);
8058
- logger6.info(
8187
+ logger7.info(
8059
8188
  `Liked tweet: ${scoredTweet.tweet.id} (score: ${scoredTweet.relevanceScore.toFixed(2)})`
8060
8189
  );
8061
8190
  }
@@ -8063,7 +8192,7 @@ var TwitterDiscoveryClient = class {
8063
8192
  case "reply":
8064
8193
  const replyText = await this.generateReply(scoredTweet.tweet);
8065
8194
  if (this.isDryRun) {
8066
- logger6.info(
8195
+ logger7.info(
8067
8196
  `[DRY RUN] Would reply to tweet ${scoredTweet.tweet.id} with: "${replyText}"`
8068
8197
  );
8069
8198
  } else {
@@ -8071,13 +8200,13 @@ var TwitterDiscoveryClient = class {
8071
8200
  replyText,
8072
8201
  scoredTweet.tweet.id
8073
8202
  );
8074
- logger6.info(`Replied to tweet: ${scoredTweet.tweet.id}`);
8203
+ logger7.info(`Replied to tweet: ${scoredTweet.tweet.id}`);
8075
8204
  }
8076
8205
  break;
8077
8206
  case "quote":
8078
8207
  const quoteText = await this.generateQuote(scoredTweet.tweet);
8079
8208
  if (this.isDryRun) {
8080
- logger6.info(
8209
+ logger7.info(
8081
8210
  `[DRY RUN] Would quote tweet ${scoredTweet.tweet.id} with: "${quoteText}"`
8082
8211
  );
8083
8212
  } else {
@@ -8085,7 +8214,7 @@ var TwitterDiscoveryClient = class {
8085
8214
  quoteText,
8086
8215
  scoredTweet.tweet.id
8087
8216
  );
8088
- logger6.info(`Quoted tweet: ${scoredTweet.tweet.id}`);
8217
+ logger7.info(`Quoted tweet: ${scoredTweet.tweet.id}`);
8089
8218
  }
8090
8219
  break;
8091
8220
  }
@@ -8096,7 +8225,7 @@ var TwitterDiscoveryClient = class {
8096
8225
  engagementCount++;
8097
8226
  await this.delay(3e3 + Math.random() * 5e3);
8098
8227
  } catch (error) {
8099
- logger6.error(
8228
+ logger7.error(
8100
8229
  `Failed to engage with tweet ${scoredTweet.tweet.id}:`,
8101
8230
  error
8102
8231
  );
@@ -8181,11 +8310,11 @@ Quote tweet:`;
8181
8310
  return response.trim();
8182
8311
  }
8183
8312
  async saveEngagementMemory(tweet, engagementType) {
8184
- logger6.debug(`[Discovery] Would save engagement memory for ${engagementType} on tweet ${tweet.id}`);
8313
+ logger7.debug(`[Discovery] Would save engagement memory for ${engagementType} on tweet ${tweet.id}`);
8185
8314
  return;
8186
8315
  }
8187
8316
  async saveFollowMemory(user) {
8188
- logger6.debug(`[Discovery] Would save follow memory for @${user.username}`);
8317
+ logger7.debug(`[Discovery] Would save follow memory for @${user.username}`);
8189
8318
  return;
8190
8319
  }
8191
8320
  delay(ms) {
@@ -8197,7 +8326,7 @@ Quote tweet:`;
8197
8326
  import {
8198
8327
  ChannelType as ChannelType4,
8199
8328
  createUniqueUuid as createUniqueUuid6,
8200
- logger as logger7
8329
+ logger as logger8
8201
8330
  } from "@elizaos/core";
8202
8331
  var RequestQueue = class {
8203
8332
  constructor() {
@@ -8242,7 +8371,7 @@ var RequestQueue = class {
8242
8371
  await request();
8243
8372
  this.retryAttempts.delete(request);
8244
8373
  } catch (error) {
8245
- logger7.error("Error processing request:", error);
8374
+ logger8.error("Error processing request:", error);
8246
8375
  const retryCount = (this.retryAttempts.get(request) || 0) + 1;
8247
8376
  if (retryCount < this.maxRetries) {
8248
8377
  this.retryAttempts.set(request, retryCount);
@@ -8250,7 +8379,7 @@ var RequestQueue = class {
8250
8379
  await this.exponentialBackoff(retryCount);
8251
8380
  break;
8252
8381
  } else {
8253
- logger7.error(
8382
+ logger8.error(
8254
8383
  `Max retries (${this.maxRetries}) exceeded for request, skipping`
8255
8384
  );
8256
8385
  this.retryAttempts.delete(request);
@@ -8308,7 +8437,7 @@ var _ClientBase = class _ClientBase {
8308
8437
  */
8309
8438
  async cacheTweet(tweet) {
8310
8439
  if (!tweet) {
8311
- logger7.warn("Tweet is undefined, skipping cache");
8440
+ logger8.warn("Tweet is undefined, skipping cache");
8312
8441
  return;
8313
8442
  }
8314
8443
  this.runtime.setCache(`twitter/tweets/${tweet.id}`, tweet);
@@ -8373,7 +8502,7 @@ var _ClientBase = class _ClientBase {
8373
8502
  let lastError = null;
8374
8503
  while (retryCount < maxRetries) {
8375
8504
  try {
8376
- logger7.log("Initializing Twitter API v2 client");
8505
+ logger8.log("Initializing Twitter API v2 client");
8377
8506
  await this.twitterClient.login(
8378
8507
  "",
8379
8508
  // username not needed for API v2
@@ -8389,18 +8518,18 @@ var _ClientBase = class _ClientBase {
8389
8518
  accessTokenSecret
8390
8519
  );
8391
8520
  if (await this.twitterClient.isLoggedIn()) {
8392
- logger7.info("Successfully authenticated with Twitter API v2");
8521
+ logger8.info("Successfully authenticated with Twitter API v2");
8393
8522
  break;
8394
8523
  }
8395
8524
  } catch (error) {
8396
8525
  lastError = error instanceof Error ? error : new Error(String(error));
8397
- logger7.error(
8526
+ logger8.error(
8398
8527
  `Authentication attempt ${retryCount + 1} failed: ${lastError.message}`
8399
8528
  );
8400
8529
  retryCount++;
8401
8530
  if (retryCount < maxRetries) {
8402
8531
  const delay = 2 ** retryCount * 1e3;
8403
- logger7.info(`Retrying in ${delay / 1e3} seconds...`);
8532
+ logger8.info(`Retrying in ${delay / 1e3} seconds...`);
8404
8533
  await new Promise((resolve) => setTimeout(resolve, delay));
8405
8534
  }
8406
8535
  }
@@ -8412,13 +8541,13 @@ var _ClientBase = class _ClientBase {
8412
8541
  }
8413
8542
  const profile = await this.twitterClient.me();
8414
8543
  if (profile) {
8415
- logger7.log("Twitter user ID:", profile.userId);
8416
- logger7.log("Twitter loaded:", JSON.stringify(profile, null, 10));
8544
+ logger8.log("Twitter user ID:", profile.userId);
8545
+ logger8.log("Twitter loaded:", JSON.stringify(profile, null, 10));
8417
8546
  const agentId = this.runtime.agentId;
8418
8547
  const entity = await this.runtime.getEntityById(agentId);
8419
8548
  const entityMetadata = entity?.metadata;
8420
8549
  if (entityMetadata?.twitter?.userName !== profile.username) {
8421
- logger7.log(
8550
+ logger8.log(
8422
8551
  "Updating Agents known X/twitter handle",
8423
8552
  profile.username,
8424
8553
  "was",
@@ -8457,7 +8586,7 @@ var _ClientBase = class _ClientBase {
8457
8586
  await this.populateTimeline();
8458
8587
  }
8459
8588
  async fetchOwnPosts(count) {
8460
- logger7.debug("fetching own posts");
8589
+ logger8.debug("fetching own posts");
8461
8590
  const homeTimeline = await this.twitterClient.getUserTweets(
8462
8591
  this.profile.id,
8463
8592
  count
@@ -8468,7 +8597,7 @@ var _ClientBase = class _ClientBase {
8468
8597
  * Fetch timeline for twitter account, optionally only from followed accounts
8469
8598
  */
8470
8599
  async fetchHomeTimeline(count, following) {
8471
- logger7.debug("fetching home timeline");
8600
+ logger8.debug("fetching home timeline");
8472
8601
  const homeTimeline = following ? await this.twitterClient.fetchFollowingTimeline(count, []) : await this.twitterClient.fetchHomeTimeline(count, []);
8473
8602
  return homeTimeline;
8474
8603
  }
@@ -8491,16 +8620,16 @@ var _ClientBase = class _ClientBase {
8491
8620
  );
8492
8621
  return result ?? { tweets: [] };
8493
8622
  } catch (error) {
8494
- logger7.error("Error fetching search tweets:", error);
8623
+ logger8.error("Error fetching search tweets:", error);
8495
8624
  return { tweets: [] };
8496
8625
  }
8497
8626
  } catch (error) {
8498
- logger7.error("Error fetching search tweets:", error);
8627
+ logger8.error("Error fetching search tweets:", error);
8499
8628
  return { tweets: [] };
8500
8629
  }
8501
8630
  }
8502
8631
  async populateTimeline() {
8503
- logger7.debug("populating timeline...");
8632
+ logger8.debug("populating timeline...");
8504
8633
  const cachedTimeline = await this.getCachedTimeline();
8505
8634
  if (cachedTimeline) {
8506
8635
  const existingMemories2 = await this.runtime.getMemoriesByRoomIds({
@@ -8520,7 +8649,7 @@ var _ClientBase = class _ClientBase {
8520
8649
  (tweet) => tweet.userId !== this.profile.id && !existingMemoryIds2.has(createUniqueUuid6(this.runtime, tweet.id))
8521
8650
  );
8522
8651
  for (const tweet of tweetsToSave2) {
8523
- logger7.log("Saving Tweet", tweet.id);
8652
+ logger8.log("Saving Tweet", tweet.id);
8524
8653
  if (tweet.userId === this.profile.id) {
8525
8654
  continue;
8526
8655
  }
@@ -8568,7 +8697,7 @@ var _ClientBase = class _ClientBase {
8568
8697
  );
8569
8698
  await this.cacheTweet(tweet);
8570
8699
  }
8571
- logger7.log(
8700
+ logger8.log(
8572
8701
  `Populated ${tweetsToSave2.length} missing tweets from the cache.`
8573
8702
  );
8574
8703
  return;
@@ -8597,11 +8726,11 @@ var _ClientBase = class _ClientBase {
8597
8726
  const tweetsToSave = allTweets.filter(
8598
8727
  (tweet) => tweet.userId !== this.profile.id && !existingMemoryIds.has(createUniqueUuid6(this.runtime, tweet.id))
8599
8728
  );
8600
- logger7.debug({
8729
+ logger8.debug({
8601
8730
  processingTweets: tweetsToSave.map((tweet) => tweet.id).join(",")
8602
8731
  });
8603
8732
  for (const tweet of tweetsToSave) {
8604
- logger7.log("Saving Tweet", tweet.id);
8733
+ logger8.log("Saving Tweet", tweet.id);
8605
8734
  if (tweet.userId === this.profile.id) {
8606
8735
  continue;
8607
8736
  }
@@ -8661,7 +8790,7 @@ var _ClientBase = class _ClientBase {
8661
8790
  unique: false
8662
8791
  });
8663
8792
  if (recentMessage.length > 0 && recentMessage[0].content === message.content) {
8664
- logger7.debug("Message already saved", recentMessage[0].id);
8793
+ logger8.debug("Message already saved", recentMessage[0].id);
8665
8794
  } else {
8666
8795
  await this.runtime.createMemory(message, "messages");
8667
8796
  }
@@ -8734,7 +8863,7 @@ var _ClientBase = class _ClientBase {
8734
8863
  });
8735
8864
  return profile;
8736
8865
  } catch (error) {
8737
- logger7.error("Error fetching Twitter profile:", error);
8866
+ logger8.error("Error fetching Twitter profile:", error);
8738
8867
  throw error;
8739
8868
  }
8740
8869
  }
@@ -8755,7 +8884,7 @@ var _ClientBase = class _ClientBase {
8755
8884
  (tweet) => this.formatTweetToInteraction(tweet)
8756
8885
  );
8757
8886
  } catch (error) {
8758
- logger7.error("Error fetching Twitter interactions:", error);
8887
+ logger8.error("Error fetching Twitter interactions:", error);
8759
8888
  return [];
8760
8889
  }
8761
8890
  }
@@ -8785,42 +8914,42 @@ var TwitterClientInstance = class {
8785
8914
  constructor(runtime, state) {
8786
8915
  this.client = new ClientBase(runtime, state);
8787
8916
  const postEnabledSetting = getSetting(runtime, "TWITTER_ENABLE_POST") ?? process.env.TWITTER_ENABLE_POST;
8788
- logger8.debug(
8917
+ logger9.debug(
8789
8918
  `TWITTER_ENABLE_POST setting value: ${JSON.stringify(postEnabledSetting)}, type: ${typeof postEnabledSetting}`
8790
8919
  );
8791
8920
  const postEnabled = postEnabledSetting === "true" || postEnabledSetting === true;
8792
8921
  if (postEnabled) {
8793
- logger8.info("Twitter posting is ENABLED - creating post client");
8922
+ logger9.info("Twitter posting is ENABLED - creating post client");
8794
8923
  this.post = new TwitterPostClient(this.client, runtime, state);
8795
8924
  } else {
8796
- logger8.info(
8925
+ logger9.info(
8797
8926
  "Twitter posting is DISABLED - set TWITTER_ENABLE_POST=true to enable automatic posting"
8798
8927
  );
8799
8928
  }
8800
8929
  const repliesEnabled = (getSetting(runtime, "TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
8801
8930
  if (repliesEnabled) {
8802
- logger8.info("Twitter replies/interactions are ENABLED");
8931
+ logger9.info("Twitter replies/interactions are ENABLED");
8803
8932
  this.interaction = new TwitterInteractionClient(
8804
8933
  this.client,
8805
8934
  runtime,
8806
8935
  state
8807
8936
  );
8808
8937
  } else {
8809
- logger8.info("Twitter replies/interactions are DISABLED");
8938
+ logger9.info("Twitter replies/interactions are DISABLED");
8810
8939
  }
8811
8940
  const actionsEnabled = (getSetting(runtime, "TWITTER_ENABLE_ACTIONS") ?? process.env.TWITTER_ENABLE_ACTIONS) === "true";
8812
8941
  if (actionsEnabled) {
8813
- logger8.info("Twitter timeline actions are ENABLED");
8942
+ logger9.info("Twitter timeline actions are ENABLED");
8814
8943
  this.timeline = new TwitterTimelineClient(this.client, runtime, state);
8815
8944
  } else {
8816
- logger8.info("Twitter timeline actions are DISABLED");
8945
+ logger9.info("Twitter timeline actions are DISABLED");
8817
8946
  }
8818
8947
  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";
8819
8948
  if (discoveryEnabled) {
8820
- logger8.info("Twitter discovery service is ENABLED");
8949
+ logger9.info("Twitter discovery service is ENABLED");
8821
8950
  this.discovery = new TwitterDiscoveryClient(this.client, runtime, state);
8822
8951
  } else {
8823
- logger8.info(
8952
+ logger9.info(
8824
8953
  "Twitter discovery service is DISABLED - set TWITTER_ENABLE_DISCOVERY=true to enable"
8825
8954
  );
8826
8955
  }
@@ -8837,28 +8966,28 @@ var _TwitterService = class _TwitterService extends Service {
8837
8966
  service.runtime = runtime;
8838
8967
  try {
8839
8968
  await validateTwitterConfig(runtime);
8840
- logger8.log("\u2705 Twitter configuration validated successfully");
8969
+ logger9.log("\u2705 Twitter configuration validated successfully");
8841
8970
  service.twitterClient = new TwitterClientInstance(runtime, {});
8842
8971
  await service.twitterClient.client.init();
8843
8972
  if (service.twitterClient.post) {
8844
- logger8.log("\u{1F4EE} Starting Twitter post client...");
8973
+ logger9.log("\u{1F4EE} Starting Twitter post client...");
8845
8974
  await service.twitterClient.post.start();
8846
8975
  }
8847
8976
  if (service.twitterClient.interaction) {
8848
- logger8.log("\u{1F4AC} Starting Twitter interaction client...");
8977
+ logger9.log("\u{1F4AC} Starting Twitter interaction client...");
8849
8978
  await service.twitterClient.interaction.start();
8850
8979
  }
8851
8980
  if (service.twitterClient.timeline) {
8852
- logger8.log("\u{1F4CA} Starting Twitter timeline client...");
8981
+ logger9.log("\u{1F4CA} Starting Twitter timeline client...");
8853
8982
  await service.twitterClient.timeline.start();
8854
8983
  }
8855
8984
  if (service.twitterClient.discovery) {
8856
- logger8.log("\u{1F50D} Starting Twitter discovery client...");
8985
+ logger9.log("\u{1F50D} Starting Twitter discovery client...");
8857
8986
  await service.twitterClient.discovery.start();
8858
8987
  }
8859
- logger8.log("\u2705 Twitter service started successfully");
8988
+ logger9.log("\u2705 Twitter service started successfully");
8860
8989
  } catch (error) {
8861
- logger8.error("\u{1F6A8} Failed to start Twitter service:", error);
8990
+ logger9.error("\u{1F6A8} Failed to start Twitter service:", error);
8862
8991
  throw error;
8863
8992
  }
8864
8993
  return service;
@@ -8876,7 +9005,7 @@ var _TwitterService = class _TwitterService extends Service {
8876
9005
  if (this.twitterClient?.discovery) {
8877
9006
  await this.twitterClient.discovery.stop();
8878
9007
  }
8879
- logger8.log("Twitter service stopped");
9008
+ logger9.log("Twitter service stopped");
8880
9009
  }
8881
9010
  };
8882
9011
  _TwitterService.serviceType = "twitter";
@@ -8884,7 +9013,7 @@ var TwitterService = _TwitterService;
8884
9013
 
8885
9014
  // src/actions/postTweet.ts
8886
9015
  import {
8887
- logger as logger9,
9016
+ logger as logger10,
8888
9017
  ModelType as ModelType5
8889
9018
  } from "@elizaos/core";
8890
9019
  var postTweetAction = {
@@ -8897,8 +9026,8 @@ var postTweetAction = {
8897
9026
  "SHARE_ON_TWITTER"
8898
9027
  ],
8899
9028
  validate: async (runtime, message) => {
8900
- logger9.debug("Validating POST_TWEET action");
8901
- logger9.debug("Message details:", {
9029
+ logger10.debug("Validating POST_TWEET action");
9030
+ logger10.debug("Message details:", {
8902
9031
  hasContent: !!message.content,
8903
9032
  contentType: message.content?.type,
8904
9033
  hasText: !!message.content?.text,
@@ -8908,23 +9037,23 @@ var postTweetAction = {
8908
9037
  entityId: message.entityId
8909
9038
  });
8910
9039
  if (message.content?.type === "post" && !message.content?.text) {
8911
- logger9.debug("Skipping validation for provider context (empty post type)");
9040
+ logger10.debug("Skipping validation for provider context (empty post type)");
8912
9041
  return false;
8913
9042
  }
8914
9043
  const text = message.content?.text?.trim();
8915
9044
  if (!text || text.length === 0) {
8916
- logger9.error("No text content for tweet");
8917
- logger9.debug("Stack trace:", new Error().stack);
9045
+ logger10.error("No text content for tweet");
9046
+ logger10.debug("Stack trace:", new Error().stack);
8918
9047
  return false;
8919
9048
  }
8920
9049
  if (text.length > 280) {
8921
- logger9.warn(`Tweet too long: ${text.length} characters`);
9050
+ logger10.warn(`Tweet too long: ${text.length} characters`);
8922
9051
  }
8923
9052
  return true;
8924
9053
  },
8925
9054
  description: "Post a tweet on Twitter",
8926
9055
  handler: async (runtime, message, state, _options, callback) => {
8927
- logger9.info("Executing POST_TWEET action");
9056
+ logger10.info("Executing POST_TWEET action");
8928
9057
  try {
8929
9058
  const client = new ClientBase(runtime, {});
8930
9059
  if (!client.twitterClient) {
@@ -8932,7 +9061,7 @@ var postTweetAction = {
8932
9061
  }
8933
9062
  let text = message.content?.text?.trim();
8934
9063
  if (!text) {
8935
- logger9.error("No text content for tweet");
9064
+ logger10.error("No text content for tweet");
8936
9065
  if (callback) {
8937
9066
  callback({
8938
9067
  text: "I need something to tweet! Please provide the text.",
@@ -8942,7 +9071,7 @@ var postTweetAction = {
8942
9071
  return;
8943
9072
  }
8944
9073
  if (text.length > 280) {
8945
- logger9.info(`Truncating tweet from ${text.length} to 280 characters`);
9074
+ logger10.info(`Truncating tweet from ${text.length} to 280 characters`);
8946
9075
  const sentences = text.match(/[^.!?]+[.!?]+/g) || [text];
8947
9076
  let truncated = "";
8948
9077
  for (const sentence of sentences) {
@@ -8953,7 +9082,7 @@ var postTweetAction = {
8953
9082
  }
8954
9083
  }
8955
9084
  text = truncated.trim() || text.substring(0, 277) + "...";
8956
- logger9.info(`Truncated tweet: ${text}`);
9085
+ logger10.info(`Truncated tweet: ${text}`);
8957
9086
  }
8958
9087
  if (!client.profile) {
8959
9088
  throw new Error(
@@ -9009,7 +9138,7 @@ Tweet:`;
9009
9138
  tweetId = Date.now().toString();
9010
9139
  }
9011
9140
  const tweetUrl = `https://twitter.com/${client.profile.username}/status/${tweetId}`;
9012
- logger9.info(`Successfully posted tweet: ${tweetId}`);
9141
+ logger10.info(`Successfully posted tweet: ${tweetId}`);
9013
9142
  await runtime.createMemory(
9014
9143
  {
9015
9144
  entityId: runtime.agentId,
@@ -9039,7 +9168,7 @@ View it here: ${tweetUrl}`,
9039
9168
  throw new Error("Failed to post tweet - no response data");
9040
9169
  }
9041
9170
  } catch (error) {
9042
- logger9.error("Error posting tweet:", error);
9171
+ logger10.error("Error posting tweet:", error);
9043
9172
  if (callback) {
9044
9173
  await callback({
9045
9174
  text: `Sorry, I couldn't post the tweet. Error: ${error.message}`,
@@ -9105,7 +9234,7 @@ var TwitterPlugin = {
9105
9234
  actions: [postTweetAction],
9106
9235
  services: [TwitterService],
9107
9236
  init: async (_config, runtime) => {
9108
- logger10.log("\u{1F527} Initializing Twitter plugin...");
9237
+ logger11.log("\u{1F527} Initializing Twitter plugin...");
9109
9238
  const hasGetSetting = runtime && typeof runtime.getSetting === "function";
9110
9239
  const apiKey = hasGetSetting ? runtime.getSetting("TWITTER_API_KEY") : process.env.TWITTER_API_KEY;
9111
9240
  const apiSecretKey = hasGetSetting ? runtime.getSetting("TWITTER_API_SECRET_KEY") : process.env.TWITTER_API_SECRET_KEY;
@@ -9117,14 +9246,14 @@ var TwitterPlugin = {
9117
9246
  if (!apiSecretKey) missing.push("TWITTER_API_SECRET_KEY");
9118
9247
  if (!accessToken) missing.push("TWITTER_ACCESS_TOKEN");
9119
9248
  if (!accessTokenSecret) missing.push("TWITTER_ACCESS_TOKEN_SECRET");
9120
- logger10.warn(
9249
+ logger11.warn(
9121
9250
  `Twitter API credentials not configured - Twitter functionality will be limited. Missing: ${missing.join(", ")}`
9122
9251
  );
9123
- logger10.warn(
9252
+ logger11.warn(
9124
9253
  "To enable Twitter functionality, please provide the missing credentials in your .env file"
9125
9254
  );
9126
9255
  } else {
9127
- logger10.log("\u2705 Twitter credentials found");
9256
+ logger11.log("\u2705 Twitter credentials found");
9128
9257
  }
9129
9258
  }
9130
9259
  };