@elizaos/plugin-twitter 1.2.4 → 1.2.6

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _elizaos_core from '@elizaos/core';
2
- import { Service, IAgentRuntime, Memory, UUID, State, ChannelType } from '@elizaos/core';
2
+ import { IAgentRuntime, Memory, UUID, State, ChannelType, Service } from '@elizaos/core';
3
3
  import * as twitter_api_v2 from 'twitter-api-v2';
4
4
  import { TwitterApi, PollV2, TTweetv2Expansion, TTweetv2TweetField, TTweetv2PollField, TTweetv2MediaField, TTweetv2UserField, TTweetv2PlaceField } from 'twitter-api-v2';
5
5
 
@@ -762,16 +762,6 @@ declare class Client {
762
762
  fetchQuotedTweetsPage(tweetId: string, maxQuotes?: number, cursor?: string): Promise<QueryTweetsResponse>;
763
763
  }
764
764
 
765
- declare class TwitterService extends Service {
766
- static serviceType: string;
767
- capabilityDescription: string;
768
- private static instance;
769
- constructor(runtime?: IAgentRuntime);
770
- static getInstance(): TwitterService;
771
- static start(runtime: IAgentRuntime): Promise<TwitterService>;
772
- stop(): Promise<void>;
773
- }
774
-
775
765
  /**
776
766
  * Class representing a Twitter post client for generating and posting tweets.
777
767
  */
@@ -817,13 +807,11 @@ declare class TwitterPostClient {
817
807
  * @property {ClientBase} client - The base client for Twitter operations.
818
808
  * @property {TwitterPostClient} post - The client for managing Twitter posts.
819
809
  * @property {TwitterInteractionClient} interaction - The client for managing Twitter interactions.
820
- * @property {TwitterService} service - The main Twitter service instance.
821
810
  */
822
811
  interface ITwitterClient {
823
812
  client: ClientBase;
824
813
  post: TwitterPostClient;
825
814
  interaction: TwitterInteractionClient;
826
- service: TwitterService;
827
815
  }
828
816
  /**
829
817
  * Twitter-specific tweet type
@@ -1200,6 +1188,14 @@ declare class TwitterDiscoveryClient {
1200
1188
  private delay;
1201
1189
  }
1202
1190
 
1191
+ declare class TwitterService extends Service {
1192
+ static serviceType: string;
1193
+ capabilityDescription: string;
1194
+ constructor();
1195
+ static start(runtime: IAgentRuntime): Promise<TwitterService>;
1196
+ stop(): Promise<void>;
1197
+ }
1198
+
1203
1199
  /**
1204
1200
  * A manager that orchestrates all specialized Twitter logic:
1205
1201
  * - client: base operations (login, timeline caching, etc.)
@@ -1214,7 +1210,6 @@ declare class TwitterClientInstance implements ITwitterClient {
1214
1210
  interaction: TwitterInteractionClient;
1215
1211
  timeline?: TwitterTimelineClient;
1216
1212
  discovery?: TwitterDiscoveryClient;
1217
- service: TwitterService;
1218
1213
  constructor(runtime: IAgentRuntime, state: any);
1219
1214
  }
1220
1215
  declare function startTwitterClient(runtime: IAgentRuntime): Promise<void>;
package/dist/index.js CHANGED
@@ -6078,7 +6078,13 @@ function getTargetUsers(targetUsersConfig) {
6078
6078
  return users.filter((u) => u !== "*");
6079
6079
  }
6080
6080
  function getSetting(runtime, key, defaultValue) {
6081
- return runtime.getSetting(key) ?? process.env[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;
6082
6088
  }
6083
6089
  async function validateTwitterConfig(runtime, config = {}) {
6084
6090
  try {
@@ -6117,6 +6123,17 @@ async function validateTwitterConfig(runtime, config = {}) {
6117
6123
  }
6118
6124
  }
6119
6125
 
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
+
6120
6137
  // src/interactions.ts
6121
6138
  var TwitterInteractionClient = class {
6122
6139
  /**
@@ -6132,7 +6149,7 @@ var TwitterInteractionClient = class {
6132
6149
  this.client = client;
6133
6150
  this.runtime = runtime;
6134
6151
  this.state = state;
6135
- const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? this.runtime.getSetting("TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6152
+ const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6136
6153
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
6137
6154
  }
6138
6155
  /**
@@ -6147,7 +6164,7 @@ var TwitterInteractionClient = class {
6147
6164
  return;
6148
6165
  }
6149
6166
  const engagementIntervalMinutes = parseInt(
6150
- this.state?.TWITTER_ENGAGEMENT_INTERVAL || this.runtime.getSetting("TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
6167
+ this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting2(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
6151
6168
  );
6152
6169
  const interactionInterval = engagementIntervalMinutes * 60 * 1e3;
6153
6170
  logger3.info(`Twitter interaction client will check every ${engagementIntervalMinutes} minutes`);
@@ -6172,11 +6189,11 @@ var TwitterInteractionClient = class {
6172
6189
  logger3.log("Checking Twitter interactions");
6173
6190
  const twitterUsername = this.client.profile?.username;
6174
6191
  try {
6175
- const repliesEnabled = (this.runtime.getSetting("TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
6192
+ const repliesEnabled = (getSetting2(this.runtime, "TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
6176
6193
  if (repliesEnabled) {
6177
6194
  await this.handleMentions(twitterUsername);
6178
6195
  }
6179
- const targetUsersConfig = (this.runtime.getSetting("TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6196
+ const targetUsersConfig = (getSetting2(this.runtime, "TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6180
6197
  if (targetUsersConfig?.trim()) {
6181
6198
  await this.handleTargetUserPosts(targetUsersConfig);
6182
6199
  }
@@ -6250,7 +6267,7 @@ var TwitterInteractionClient = class {
6250
6267
  */
6251
6268
  async processTargetUserTweets(tweets, username) {
6252
6269
  const maxEngagementsPerRun = parseInt(
6253
- this.runtime.getSetting("TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6270
+ getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6254
6271
  );
6255
6272
  let engagementCount = 0;
6256
6273
  for (const tweet of tweets) {
@@ -6327,7 +6344,8 @@ var TwitterInteractionClient = class {
6327
6344
  createdAt: Date.now()
6328
6345
  };
6329
6346
  const state = await this.runtime.composeState(shouldEngageMemory);
6330
- const context = `You are ${this.runtime.character.name}. Should you reply to this tweet based on your interests and expertise?
6347
+ const characterName = this.runtime?.character?.name || "AI Assistant";
6348
+ const context = `You are ${characterName}. Should you reply to this tweet based on your interests and expertise?
6331
6349
 
6332
6350
  Tweet by @${tweet.username}: "${tweet.text}"
6333
6351
 
@@ -6446,7 +6464,7 @@ Response (YES/NO):`;
6446
6464
  );
6447
6465
  let uniqueTweetCandidates = [...mentionCandidates];
6448
6466
  uniqueTweetCandidates = uniqueTweetCandidates.sort((a, b) => a.id.localeCompare(b.id)).filter((tweet) => tweet.userId !== this.client.profile.id);
6449
- const targetUsersConfig = (this.runtime.getSetting("TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6467
+ const targetUsersConfig = (getSetting2(this.runtime, "TWITTER_TARGET_USERS") ?? process.env.TWITTER_TARGET_USERS) || "";
6450
6468
  if (targetUsersConfig?.trim()) {
6451
6469
  uniqueTweetCandidates = uniqueTweetCandidates.filter((tweet) => {
6452
6470
  const shouldTarget = shouldTargetUser(
@@ -6462,7 +6480,7 @@ Response (YES/NO):`;
6462
6480
  });
6463
6481
  }
6464
6482
  const maxInteractionsPerRun = parseInt(
6465
- this.runtime.getSetting("TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6483
+ getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
6466
6484
  );
6467
6485
  const tweetsToProcess = uniqueTweetCandidates.slice(0, maxInteractionsPerRun);
6468
6486
  logger3.info(`Processing ${tweetsToProcess.length} of ${uniqueTweetCandidates.length} mention tweets (max: ${maxInteractionsPerRun})`);
@@ -6821,14 +6839,14 @@ var TwitterPostClient = class {
6821
6839
  this.client = client;
6822
6840
  this.state = state;
6823
6841
  this.runtime = runtime;
6824
- const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? this.runtime.getSetting("TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6842
+ const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
6825
6843
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
6826
6844
  logger4.log("Twitter Post Client Configuration:");
6827
6845
  logger4.log(`- Dry Run Mode: ${this.isDryRun ? "Enabled" : "Disabled"}`);
6828
- const postInterval = parseInt(
6829
- this.state?.TWITTER_POST_INTERVAL || this.runtime.getSetting("TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6846
+ const postIntervalMinutes = parseInt(
6847
+ this.state?.TWITTER_POST_INTERVAL || getSetting2(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6830
6848
  );
6831
- logger4.log(`- Post Interval: ${postInterval} minutes`);
6849
+ logger4.log(`- Post Interval: ${postIntervalMinutes} minutes`);
6832
6850
  }
6833
6851
  /**
6834
6852
  * Stops the Twitter post client
@@ -6849,7 +6867,7 @@ var TwitterPostClient = class {
6849
6867
  return;
6850
6868
  }
6851
6869
  const postIntervalMinutes = parseInt(
6852
- this.state?.TWITTER_POST_INTERVAL || this.runtime.getSetting("TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6870
+ this.state?.TWITTER_POST_INTERVAL || getSetting2(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6853
6871
  );
6854
6872
  const interval = postIntervalMinutes * 60 * 1e3;
6855
6873
  logger4.info(`Next tweet scheduled in ${postIntervalMinutes} minutes`);
@@ -6860,7 +6878,7 @@ var TwitterPostClient = class {
6860
6878
  };
6861
6879
  await new Promise((resolve) => setTimeout(resolve, 1e3));
6862
6880
  const postImmediately = parseInt(
6863
- this.state?.TWITTER_POST_INTERVAL || this.runtime.getSetting("TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6881
+ this.state?.TWITTER_POST_INTERVAL || getSetting2(this.runtime, "TWITTER_POST_INTERVAL") || process.env.TWITTER_POST_INTERVAL || "120"
6864
6882
  ) === 0;
6865
6883
  if (postImmediately) {
6866
6884
  logger4.info("TWITTER_POST_IMMEDIATELY is true, generating initial tweet now");
@@ -7076,9 +7094,10 @@ var TwitterTimelineClient = class {
7076
7094
  this.twitterClient = client.twitterClient;
7077
7095
  this.runtime = runtime;
7078
7096
  this.state = state;
7079
- const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? this.runtime.getSetting("TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7097
+ const dryRunSetting = this.state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7080
7098
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
7081
- this.timelineType = (this.runtime.getSetting("TWITTER_TIMELINE_MODE") ?? process.env.TWITTER_TIMELINE_MODE) || "foryou" /* ForYou */;
7099
+ const timelineMode = getSetting2(this.runtime, "TWITTER_TIMELINE_MODE") ?? process.env.TWITTER_TIMELINE_MODE;
7100
+ this.timelineType = timelineMode === "following" /* Following */ ? "following" /* Following */ : "foryou" /* ForYou */;
7082
7101
  }
7083
7102
  async start() {
7084
7103
  logger5.info("Starting Twitter timeline client...");
@@ -7089,7 +7108,7 @@ var TwitterTimelineClient = class {
7089
7108
  return;
7090
7109
  }
7091
7110
  const engagementIntervalMinutes = parseInt(
7092
- this.state?.TWITTER_ENGAGEMENT_INTERVAL || this.runtime.getSetting("TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
7111
+ this.state?.TWITTER_ENGAGEMENT_INTERVAL || getSetting2(this.runtime, "TWITTER_ENGAGEMENT_INTERVAL") || process.env.TWITTER_ENGAGEMENT_INTERVAL || "30"
7093
7112
  );
7094
7113
  const actionInterval = engagementIntervalMinutes * 60 * 1e3;
7095
7114
  logger5.info(`Timeline client will check every ${engagementIntervalMinutes} minutes`);
@@ -7135,7 +7154,7 @@ var TwitterTimelineClient = class {
7135
7154
  const tweets = await this.getTimeline(20);
7136
7155
  logger5.info(`Fetched ${tweets.length} tweets from timeline`);
7137
7156
  const maxActionsPerCycle = parseInt(
7138
- this.runtime.getSetting("TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7157
+ getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7139
7158
  );
7140
7159
  const tweetDecisions = [];
7141
7160
  for (const tweet of tweets) {
@@ -7433,7 +7452,7 @@ var TwitterDiscoveryClient = class {
7433
7452
  this.client = client;
7434
7453
  this.twitterClient = client.twitterClient;
7435
7454
  this.runtime = runtime;
7436
- const dryRunSetting = state?.TWITTER_DRY_RUN ?? this.runtime.getSetting("TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7455
+ const dryRunSetting = state?.TWITTER_DRY_RUN ?? getSetting2(this.runtime, "TWITTER_DRY_RUN") ?? process.env.TWITTER_DRY_RUN;
7437
7456
  this.isDryRun = dryRunSetting === true || dryRunSetting === "true" || typeof dryRunSetting === "string" && dryRunSetting.toLowerCase() === "true";
7438
7457
  this.config = this.buildDiscoveryConfig();
7439
7458
  logger6.info("Twitter Discovery Config:", {
@@ -7445,18 +7464,36 @@ var TwitterDiscoveryClient = class {
7445
7464
  });
7446
7465
  }
7447
7466
  buildDiscoveryConfig() {
7448
- const character = this.runtime.character;
7449
- const topics = character.topics || this.extractTopicsFromBio(character.bio);
7467
+ const character = this.runtime?.character;
7468
+ const defaultTopics = [
7469
+ "ai",
7470
+ "technology",
7471
+ "blockchain",
7472
+ "web3",
7473
+ "crypto",
7474
+ "programming",
7475
+ "innovation"
7476
+ ];
7477
+ let topics = defaultTopics;
7478
+ if (character) {
7479
+ if (character.topics && Array.isArray(character.topics) && character.topics.length > 0) {
7480
+ topics = character.topics;
7481
+ } else if (character.bio) {
7482
+ topics = this.extractTopicsFromBio(character.bio);
7483
+ }
7484
+ } else {
7485
+ logger6.warn("Character not available in runtime, using default topics for discovery");
7486
+ }
7450
7487
  return {
7451
7488
  topics,
7452
7489
  minFollowerCount: parseInt(
7453
- this.runtime.getSetting("TWITTER_MIN_FOLLOWER_COUNT") || process.env.TWITTER_MIN_FOLLOWER_COUNT || "100"
7490
+ getSetting2(this.runtime, "TWITTER_MIN_FOLLOWER_COUNT") || process.env.TWITTER_MIN_FOLLOWER_COUNT || "100"
7454
7491
  ),
7455
7492
  maxFollowsPerCycle: parseInt(
7456
- this.runtime.getSetting("TWITTER_MAX_FOLLOWS_PER_CYCLE") || process.env.TWITTER_MAX_FOLLOWS_PER_CYCLE || "5"
7493
+ getSetting2(this.runtime, "TWITTER_MAX_FOLLOWS_PER_CYCLE") || process.env.TWITTER_MAX_FOLLOWS_PER_CYCLE || "5"
7457
7494
  ),
7458
7495
  maxEngagementsPerCycle: parseInt(
7459
- this.runtime.getSetting("TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7496
+ getSetting2(this.runtime, "TWITTER_MAX_ENGAGEMENTS_PER_RUN") || process.env.TWITTER_MAX_ENGAGEMENTS_PER_RUN || "10"
7460
7497
  ),
7461
7498
  likeThreshold: 0.6,
7462
7499
  replyThreshold: 0.8,
@@ -7464,6 +7501,9 @@ var TwitterDiscoveryClient = class {
7464
7501
  };
7465
7502
  }
7466
7503
  extractTopicsFromBio(bio) {
7504
+ if (!bio) {
7505
+ return [];
7506
+ }
7467
7507
  const bioText = Array.isArray(bio) ? bio.join(" ") : bio;
7468
7508
  const words = bioText.toLowerCase().split(/\s+/).filter((word) => word.length > 4).filter((word) => !["about", "helping", "working", "people", "making", "building"].includes(word));
7469
7509
  return [...new Set(words)].slice(0, 5);
@@ -7482,7 +7522,7 @@ var TwitterDiscoveryClient = class {
7482
7522
  logger6.error("Discovery cycle error:", error);
7483
7523
  }
7484
7524
  const baseInterval = parseInt(
7485
- this.runtime.getSetting("TWITTER_DISCOVERY_INTERVAL") || process.env.TWITTER_DISCOVERY_INTERVAL || "30"
7525
+ getSetting2(this.runtime, "TWITTER_DISCOVERY_INTERVAL") || process.env.TWITTER_DISCOVERY_INTERVAL || "30"
7486
7526
  );
7487
7527
  const variance = Math.random() * 20 - 10;
7488
7528
  const nextInterval = (baseInterval + variance) * 60 * 1e3;
@@ -7796,12 +7836,21 @@ var TwitterDiscoveryClient = class {
7796
7836
  return followMemories.length > 0;
7797
7837
  }
7798
7838
  async generateReply(tweet) {
7799
- const prompt = `You are ${this.runtime.character.name}. Generate a thoughtful reply to this tweet:
7839
+ const characterName = this.runtime?.character?.name || "AI Assistant";
7840
+ let characterBio = "";
7841
+ if (this.runtime?.character?.bio) {
7842
+ if (Array.isArray(this.runtime.character.bio)) {
7843
+ characterBio = this.runtime.character.bio.join(" ");
7844
+ } else {
7845
+ characterBio = this.runtime.character.bio;
7846
+ }
7847
+ }
7848
+ const prompt = `You are ${characterName}. Generate a thoughtful reply to this tweet:
7800
7849
 
7801
7850
  Tweet by @${tweet.username}: "${tweet.text}"
7802
7851
 
7803
7852
  Your interests: ${this.config.topics.join(", ")}
7804
- Character bio: ${Array.isArray(this.runtime.character.bio) ? this.runtime.character.bio.join(" ") : this.runtime.character.bio}
7853
+ Character bio: ${characterBio}
7805
7854
 
7806
7855
  Keep the reply:
7807
7856
  - Relevant and adding value to the conversation
@@ -7819,12 +7868,21 @@ Reply:`;
7819
7868
  return response.trim();
7820
7869
  }
7821
7870
  async generateQuote(tweet) {
7822
- const prompt = `You are ${this.runtime.character.name}. Add your perspective to this tweet with a quote tweet:
7871
+ const characterName = this.runtime?.character?.name || "AI Assistant";
7872
+ let characterBio = "";
7873
+ if (this.runtime?.character?.bio) {
7874
+ if (Array.isArray(this.runtime.character.bio)) {
7875
+ characterBio = this.runtime.character.bio.join(" ");
7876
+ } else {
7877
+ characterBio = this.runtime.character.bio;
7878
+ }
7879
+ }
7880
+ const prompt = `You are ${characterName}. Add your perspective to this tweet with a quote tweet:
7823
7881
 
7824
7882
  Original tweet by @${tweet.username}: "${tweet.text}"
7825
7883
 
7826
7884
  Your interests: ${this.config.topics.join(", ")}
7827
- Character bio: ${Array.isArray(this.runtime.character.bio) ? this.runtime.character.bio.join(" ") : this.runtime.character.bio}
7885
+ Character bio: ${characterBio}
7828
7886
 
7829
7887
  Create a quote tweet that:
7830
7888
  - Adds unique insight or perspective
@@ -7974,7 +8032,7 @@ var _ClientBase = class _ClientBase {
7974
8032
  this.callback = null;
7975
8033
  this.runtime = runtime;
7976
8034
  this.state = state;
7977
- const apiKey = state?.TWITTER_API_KEY || runtime.getSetting("TWITTER_API_KEY") || process.env.TWITTER_API_KEY;
8035
+ const apiKey = state?.TWITTER_API_KEY || (runtime && typeof runtime.getSetting === "function" ? runtime.getSetting("TWITTER_API_KEY") : null) || process.env.TWITTER_API_KEY;
7978
8036
  if (apiKey && _ClientBase._twitterClients[apiKey]) {
7979
8037
  this.twitterClient = _ClientBase._twitterClients[apiKey];
7980
8038
  } else {
@@ -8038,10 +8096,10 @@ var _ClientBase = class _ClientBase {
8038
8096
  throw new Error("Not implemented in base class, please call from subclass");
8039
8097
  }
8040
8098
  async init() {
8041
- const apiKey = this.state?.TWITTER_API_KEY || this.runtime.getSetting("TWITTER_API_KEY") || process.env.TWITTER_API_KEY;
8042
- const apiSecretKey = this.state?.TWITTER_API_SECRET_KEY || this.runtime.getSetting("TWITTER_API_SECRET_KEY") || process.env.TWITTER_API_SECRET_KEY;
8043
- const accessToken = this.state?.TWITTER_ACCESS_TOKEN || this.runtime.getSetting("TWITTER_ACCESS_TOKEN") || process.env.TWITTER_ACCESS_TOKEN;
8044
- const accessTokenSecret = this.state?.TWITTER_ACCESS_TOKEN_SECRET || this.runtime.getSetting("TWITTER_ACCESS_TOKEN_SECRET") || process.env.TWITTER_ACCESS_TOKEN_SECRET;
8099
+ const apiKey = this.state?.TWITTER_API_KEY || (this.runtime && typeof this.runtime.getSetting === "function" ? this.runtime.getSetting("TWITTER_API_KEY") : null) || process.env.TWITTER_API_KEY;
8100
+ const apiSecretKey = this.state?.TWITTER_API_SECRET_KEY || (this.runtime && typeof this.runtime.getSetting === "function" ? this.runtime.getSetting("TWITTER_API_SECRET_KEY") : null) || process.env.TWITTER_API_SECRET_KEY;
8101
+ const accessToken = this.state?.TWITTER_ACCESS_TOKEN || (this.runtime && typeof this.runtime.getSetting === "function" ? this.runtime.getSetting("TWITTER_ACCESS_TOKEN") : null) || process.env.TWITTER_ACCESS_TOKEN;
8102
+ const accessTokenSecret = this.state?.TWITTER_ACCESS_TOKEN_SECRET || (this.runtime && typeof this.runtime.getSetting === "function" ? this.runtime.getSetting("TWITTER_ACCESS_TOKEN_SECRET") : null) || process.env.TWITTER_ACCESS_TOKEN_SECRET;
8045
8103
  if (!apiKey || !apiSecretKey || !accessToken || !accessTokenSecret) {
8046
8104
  const missing = [];
8047
8105
  if (!apiKey) missing.push("TWITTER_API_KEY");
@@ -8396,11 +8454,23 @@ var _ClientBase = class _ClientBase {
8396
8454
  try {
8397
8455
  const profile = await this.requestQueue.add(async () => {
8398
8456
  const profile2 = await this.twitterClient.getProfile(username);
8457
+ const defaultName = "AI Assistant";
8458
+ const defaultBio = "";
8459
+ let characterName = defaultName;
8460
+ let characterBio = defaultBio;
8461
+ if (this.runtime?.character) {
8462
+ characterName = this.runtime.character.name || defaultName;
8463
+ if (typeof this.runtime.character.bio === "string") {
8464
+ characterBio = this.runtime.character.bio;
8465
+ } else if (Array.isArray(this.runtime.character.bio) && this.runtime.character.bio.length > 0) {
8466
+ characterBio = this.runtime.character.bio[0];
8467
+ }
8468
+ }
8399
8469
  return {
8400
8470
  id: profile2.userId,
8401
8471
  username,
8402
- screenName: profile2.name || this.runtime.character.name,
8403
- bio: profile2.biography || typeof this.runtime.character.bio === "string" ? this.runtime.character.bio : this.runtime.character.bio.length > 0 ? this.runtime.character.bio[0] : "",
8472
+ screenName: profile2.name || characterName,
8473
+ bio: profile2.biography || characterBio,
8404
8474
  nicknames: this.profile?.nicknames || []
8405
8475
  };
8406
8476
  });
@@ -8455,21 +8525,15 @@ var ClientBase = _ClientBase;
8455
8525
  // src/services/twitter.service.ts
8456
8526
  import { Service } from "@elizaos/core";
8457
8527
  var _TwitterService = class _TwitterService extends Service {
8458
- constructor(runtime) {
8459
- super(runtime);
8528
+ constructor() {
8529
+ super();
8460
8530
  // Add the required abstract property
8461
8531
  this.capabilityDescription = "The agent is able to send and receive messages on Twitter";
8462
8532
  }
8463
- static getInstance() {
8464
- if (!_TwitterService.instance) {
8465
- _TwitterService.instance = new _TwitterService();
8466
- }
8467
- return _TwitterService.instance;
8468
- }
8469
8533
  static async start(runtime) {
8470
- const instance = _TwitterService.getInstance();
8471
- instance.runtime = runtime;
8472
- return instance;
8534
+ const service = new _TwitterService();
8535
+ service.runtime = runtime;
8536
+ return service;
8473
8537
  }
8474
8538
  async stop() {
8475
8539
  }
@@ -8636,7 +8700,13 @@ View it here: ${tweetUrl}`,
8636
8700
  var TwitterClientInstance = class {
8637
8701
  constructor(runtime, state) {
8638
8702
  this.client = new ClientBase(runtime, state);
8639
- const postEnabledSetting = runtime.getSetting("TWITTER_ENABLE_POST") ?? process.env.TWITTER_ENABLE_POST;
8703
+ const getSetting3 = (key) => {
8704
+ if (runtime && typeof runtime.getSetting === "function") {
8705
+ return runtime.getSetting(key);
8706
+ }
8707
+ return void 0;
8708
+ };
8709
+ const postEnabledSetting = getSetting3("TWITTER_ENABLE_POST") ?? process.env.TWITTER_ENABLE_POST;
8640
8710
  logger9.debug(`TWITTER_ENABLE_POST setting value: ${JSON.stringify(postEnabledSetting)}, type: ${typeof postEnabledSetting}`);
8641
8711
  const postEnabled = postEnabledSetting === "true" || postEnabledSetting === true;
8642
8712
  if (postEnabled) {
@@ -8645,7 +8715,7 @@ var TwitterClientInstance = class {
8645
8715
  } else {
8646
8716
  logger9.info("Twitter posting is DISABLED - set TWITTER_ENABLE_POST=true to enable automatic posting");
8647
8717
  }
8648
- const repliesEnabled = (runtime.getSetting("TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
8718
+ const repliesEnabled = (getSetting3("TWITTER_ENABLE_REPLIES") ?? process.env.TWITTER_ENABLE_REPLIES) !== "false";
8649
8719
  if (repliesEnabled) {
8650
8720
  logger9.info("Twitter replies/interactions are ENABLED");
8651
8721
  this.interaction = new TwitterInteractionClient(
@@ -8656,21 +8726,20 @@ var TwitterClientInstance = class {
8656
8726
  } else {
8657
8727
  logger9.info("Twitter replies/interactions are DISABLED");
8658
8728
  }
8659
- const actionsEnabled = (runtime.getSetting("TWITTER_ENABLE_ACTIONS") ?? process.env.TWITTER_ENABLE_ACTIONS) === "true";
8729
+ const actionsEnabled = (getSetting3("TWITTER_ENABLE_ACTIONS") ?? process.env.TWITTER_ENABLE_ACTIONS) === "true";
8660
8730
  if (actionsEnabled) {
8661
8731
  logger9.info("Twitter timeline actions are ENABLED");
8662
8732
  this.timeline = new TwitterTimelineClient(this.client, runtime, state);
8663
8733
  } else {
8664
8734
  logger9.info("Twitter timeline actions are DISABLED");
8665
8735
  }
8666
- const discoveryEnabled = (runtime.getSetting("TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) === "true" || actionsEnabled && (runtime.getSetting("TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) !== "false";
8736
+ const discoveryEnabled = (getSetting3("TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) === "true" || actionsEnabled && (getSetting3("TWITTER_ENABLE_DISCOVERY") ?? process.env.TWITTER_ENABLE_DISCOVERY) !== "false";
8667
8737
  if (discoveryEnabled) {
8668
8738
  logger9.info("Twitter discovery service is ENABLED");
8669
8739
  this.discovery = new TwitterDiscoveryClient(this.client, runtime, state);
8670
8740
  } else {
8671
8741
  logger9.info("Twitter discovery service is DISABLED - set TWITTER_ENABLE_DISCOVERY=true to enable");
8672
8742
  }
8673
- this.service = TwitterService.getInstance();
8674
8743
  }
8675
8744
  };
8676
8745
  async function startTwitterClient(runtime) {
@@ -8680,7 +8749,7 @@ async function startTwitterClient(runtime) {
8680
8749
  logger9.log("\u2705 Twitter configuration validated successfully");
8681
8750
  const twitterClient = new TwitterClientInstance(runtime, {});
8682
8751
  await twitterClient.client.init();
8683
- runtime.registerService(TwitterService);
8752
+ await runtime.registerService(TwitterService);
8684
8753
  if (twitterClient.post) {
8685
8754
  logger9.log("\u{1F4EE} Starting Twitter post client...");
8686
8755
  await twitterClient.post.start();