@elizaos/plugin-twitter 1.2.15 → 1.2.17

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/README.md CHANGED
@@ -304,7 +304,33 @@ TWITTER_ENABLE_POST=true
304
304
  TWITTER_POST_IMMEDIATELY=true
305
305
  ```
306
306
 
307
- ## 🔧 Troubleshooting
307
+ ## 🚨 Troubleshooting
308
+
309
+ ### 403 Errors When Engaging with Tweets
310
+
311
+ If you see errors like "Failed to create tweet: Request failed with code 403", this usually means:
312
+
313
+ 1. **Missing Write Permissions**: Make sure your Twitter app has "Read and write" permissions
314
+ - Go to your app settings in the Twitter Developer Portal
315
+ - Check that App permissions shows "Read and write" ✅
316
+ - If not, change it and regenerate your Access Token & Secret
317
+
318
+ 2. **Protected Accounts**: The bot may be trying to engage with protected/private accounts
319
+ - The plugin now automatically skips these with a warning
320
+
321
+ 3. **Self-Engagement**: Trying to reply to or quote your own tweets
322
+ - Twitter API doesn't allow this and returns 403
323
+
324
+ 4. **Account Restrictions**: Your account may have restrictions
325
+ - Check if your account is in good standing
326
+ - Ensure you're not violating Twitter's automation rules
327
+
328
+ The plugin will now:
329
+ - Automatically detect and skip 403 errors with a warning
330
+ - Continue processing other tweets
331
+ - Mark failed tweets as "skip" to avoid retrying
332
+
333
+ ### Other Common Issues
308
334
 
309
335
  ### "403 Forbidden" When Posting
310
336
 
package/dist/index.js CHANGED
@@ -6282,6 +6282,25 @@ function getRandomInterval(runtime, type) {
6282
6282
  return fallbackInterval;
6283
6283
  }
6284
6284
 
6285
+ // src/utils/time.ts
6286
+ function getEpochMs(ts) {
6287
+ if (!ts) return Date.now();
6288
+ const digits = Math.floor(Math.log10(ts)) + 1;
6289
+ if (digits <= 12) {
6290
+ return ts * 1e3;
6291
+ }
6292
+ if (digits === 13) {
6293
+ return ts;
6294
+ }
6295
+ if (digits === 16) {
6296
+ return Math.floor(ts / 1e3);
6297
+ }
6298
+ while (ts > 9999999999999) {
6299
+ ts = Math.floor(ts / 1e3);
6300
+ }
6301
+ return ts;
6302
+ }
6303
+
6285
6304
  // src/interactions.ts
6286
6305
  var TwitterInteractionClient = class {
6287
6306
  /**
@@ -6435,7 +6454,7 @@ var TwitterInteractionClient = class {
6435
6454
  if (existingMemory) {
6436
6455
  continue;
6437
6456
  }
6438
- const tweetAge = Date.now() - tweet.timestamp * 1e3;
6457
+ const tweetAge = Date.now() - getEpochMs(tweet.timestamp);
6439
6458
  const maxAge = 24 * 60 * 60 * 1e3;
6440
6459
  if (tweetAge > maxAge) {
6441
6460
  continue;
@@ -6464,7 +6483,7 @@ var TwitterInteractionClient = class {
6464
6483
  1 /* Latest */
6465
6484
  );
6466
6485
  const relevantTweets = searchResult.tweets.filter((tweet) => {
6467
- const tweetAge = Date.now() - tweet.timestamp * 1e3;
6486
+ const tweetAge = Date.now() - getEpochMs(tweet.timestamp);
6468
6487
  return tweetAge < 12 * 60 * 60 * 1e3;
6469
6488
  });
6470
6489
  if (relevantTweets.length > 0) {
@@ -6583,7 +6602,7 @@ Response (YES/NO):`;
6583
6602
  },
6584
6603
  agentId: this.runtime.agentId,
6585
6604
  roomId,
6586
- createdAt: tweet.timestamp * 1e3
6605
+ createdAt: getEpochMs(tweet.timestamp)
6587
6606
  };
6588
6607
  await this.runtime.createMemory(tweetMemory, "messages");
6589
6608
  }
@@ -6602,7 +6621,7 @@ Response (YES/NO):`;
6602
6621
  },
6603
6622
  agentId: this.runtime.agentId,
6604
6623
  roomId: createUniqueUuid2(this.runtime, tweet.conversationId),
6605
- createdAt: tweet.timestamp * 1e3
6624
+ createdAt: getEpochMs(tweet.timestamp)
6606
6625
  };
6607
6626
  const result = await this.handleTweet({
6608
6627
  tweet,
@@ -6739,7 +6758,7 @@ Response (YES/NO):`;
6739
6758
  },
6740
6759
  agentId: this.runtime.agentId,
6741
6760
  roomId,
6742
- createdAt: tweet.timestamp * 1e3
6761
+ createdAt: getEpochMs(tweet.timestamp)
6743
6762
  };
6744
6763
  logger4.log("Saving tweet memory...");
6745
6764
  await this.runtime.createMemory(memory, "messages");
@@ -7428,7 +7447,7 @@ var TwitterTimelineClient = class {
7428
7447
  },
7429
7448
  entityId: createUniqueUuid4(runtime, tweet.userId),
7430
7449
  roomId: createUniqueUuid4(runtime, tweet.conversationId),
7431
- createdAt: tweet.timestamp * 1e3
7450
+ createdAt: getEpochMs(tweet.timestamp)
7432
7451
  };
7433
7452
  }
7434
7453
  async handleTimeline() {
@@ -7545,7 +7564,7 @@ ${actionSummary.join("\n")}`);
7545
7564
  },
7546
7565
  agentId: this.runtime.agentId,
7547
7566
  roomId,
7548
- createdAt: tweet.timestamp * 1e3
7567
+ createdAt: getEpochMs(tweet.timestamp)
7549
7568
  },
7550
7569
  "messages"
7551
7570
  );
@@ -8062,6 +8081,13 @@ var TwitterDiscoveryClient = class {
8062
8081
  // Remove the discoverFromTrends method since API v2 doesn't support it
8063
8082
  // Remove the isTrendRelevant method since we're not using trends
8064
8083
  scoreTweet(tweet, source) {
8084
+ if (tweet.isRetweet) {
8085
+ return {
8086
+ tweet,
8087
+ relevanceScore: 0,
8088
+ engagementType: "skip"
8089
+ };
8090
+ }
8065
8091
  let relevanceScore = 0;
8066
8092
  const sourceScores = {
8067
8093
  topic: 0.4,
@@ -8225,10 +8251,25 @@ var TwitterDiscoveryClient = class {
8225
8251
  engagementCount++;
8226
8252
  await this.delay(3e3 + Math.random() * 5e3);
8227
8253
  } catch (error) {
8228
- logger7.error(
8229
- `Failed to engage with tweet ${scoredTweet.tweet.id}:`,
8230
- error
8231
- );
8254
+ if (error?.message?.includes("403")) {
8255
+ logger7.warn(
8256
+ `Permission denied (403) for tweet ${scoredTweet.tweet.id}. This might be a protected account or restricted tweet. Skipping.`
8257
+ );
8258
+ await this.saveEngagementMemory(
8259
+ scoredTweet.tweet,
8260
+ "skip"
8261
+ );
8262
+ } else if (error?.message?.includes("429")) {
8263
+ logger7.warn(
8264
+ `Rate limit (429) hit while engaging with tweet ${scoredTweet.tweet.id}. Pausing engagement cycle.`
8265
+ );
8266
+ break;
8267
+ } else {
8268
+ logger7.error(
8269
+ `Failed to engage with tweet ${scoredTweet.tweet.id}:`,
8270
+ error
8271
+ );
8272
+ }
8232
8273
  }
8233
8274
  }
8234
8275
  return engagementCount;
@@ -8691,7 +8732,7 @@ var _ClientBase = class _ClientBase {
8691
8732
  content,
8692
8733
  agentId: this.runtime.agentId,
8693
8734
  roomId,
8694
- createdAt: tweet.timestamp * 1e3
8735
+ createdAt: getEpochMs(tweet.timestamp)
8695
8736
  },
8696
8737
  "messages"
8697
8738
  );
@@ -8772,7 +8813,7 @@ var _ClientBase = class _ClientBase {
8772
8813
  content,
8773
8814
  agentId: this.runtime.agentId,
8774
8815
  roomId,
8775
- createdAt: tweet.timestamp * 1e3
8816
+ createdAt: getEpochMs(tweet.timestamp)
8776
8817
  },
8777
8818
  "messages"
8778
8819
  );