Skip to content

Commit 3053047

Browse files
committed
fix: improve Twitter client dry run mode and configuration logging
- Added proper boolean parsing for dry run configuration - Improved configuration logging on startup - Prevented tweet generation and action loops in dry run mode - Added more descriptive dry run messages - Fixed duplicate loop execution
1 parent b78fbfe commit 3053047

File tree

1 file changed

+101
-19
lines changed

1 file changed

+101
-19
lines changed

packages/client-twitter/src/post.ts

+101-19
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,35 @@ export class TwitterPostClient {
9999
private isProcessing: boolean = false;
100100
private lastProcessTime: number = 0;
101101
private stopProcessingActions: boolean = false;
102+
private isDryRun: boolean;
103+
104+
constructor(client: ClientBase, runtime: IAgentRuntime) {
105+
this.client = client;
106+
this.runtime = runtime;
107+
this.twitterUsername = runtime.getSetting("TWITTER_USERNAME");
108+
this.isDryRun = parseBooleanFromText(
109+
runtime.getSetting("TWITTER_DRY_RUN") ?? "false"
110+
);
111+
112+
// Log configuration on initialization
113+
elizaLogger.log("Twitter Client Configuration:");
114+
elizaLogger.log(`- Username: ${this.twitterUsername}`);
115+
elizaLogger.log(`- Dry Run Mode: ${this.isDryRun ? "enabled" : "disabled"}`);
116+
elizaLogger.log(`- Post Interval: ${runtime.getSetting("POST_INTERVAL_MIN") || "90"}-${runtime.getSetting("POST_INTERVAL_MAX") || "180"} minutes`);
117+
elizaLogger.log(`- Action Processing: ${parseBooleanFromText(runtime.getSetting("ENABLE_ACTION_PROCESSING") ?? "false") ? "enabled" : "disabled"}`);
118+
elizaLogger.log(`- Action Interval: ${(parseInt(runtime.getSetting("ACTION_INTERVAL") ?? "300000") / 1000).toFixed(0)} seconds`);
119+
elizaLogger.log(`- Post Immediately: ${parseBooleanFromText(runtime.getSetting("POST_IMMEDIATELY") ?? "false") ? "enabled" : "disabled"}`);
120+
elizaLogger.log(`- Search Enabled: ${parseBooleanFromText(runtime.getSetting("TWITTER_SEARCH_ENABLE") ?? "false") ? "enabled" : "disabled"}`);
121+
122+
const targetUsers = runtime.getSetting("TWITTER_TARGET_USERS");
123+
if (targetUsers) {
124+
elizaLogger.log(`- Target Users: ${targetUsers}`);
125+
}
126+
127+
if (this.isDryRun) {
128+
elizaLogger.log("Twitter client initialized in dry run mode - no actual tweets will be posted");
129+
}
130+
}
102131

103132
async start(postImmediately: boolean = false) {
104133
if (!this.client.profile) {
@@ -171,31 +200,39 @@ export class TwitterPostClient {
171200
if (postImmediately) {
172201
await this.generateNewTweet();
173202
}
174-
generateNewTweetLoop();
203+
204+
// Only start tweet generation loop if not in dry run mode
205+
if (!this.isDryRun) {
206+
generateNewTweetLoop();
207+
elizaLogger.log("Tweet generation loop started");
208+
} else {
209+
elizaLogger.log("Tweet generation loop disabled (dry run mode)");
210+
}
175211

176212
// Add check for ENABLE_ACTION_PROCESSING before starting the loop
177-
const enableActionProcessing =
178-
this.runtime.getSetting("ENABLE_ACTION_PROCESSING") ?? false;
213+
const enableActionProcessing = parseBooleanFromText(
214+
this.runtime.getSetting("ENABLE_ACTION_PROCESSING") ?? "false"
215+
);
179216

180-
if (enableActionProcessing) {
217+
if (enableActionProcessing && !this.isDryRun) {
181218
processActionsLoop().catch((error) => {
182219
elizaLogger.error(
183220
"Fatal error in process actions loop:",
184221
error
185222
);
186223
});
187224
} else {
188-
elizaLogger.log("Action processing loop disabled by configuration");
225+
if (this.isDryRun) {
226+
elizaLogger.log("Action processing loop disabled (dry run mode)");
227+
} else {
228+
elizaLogger.log("Action processing loop disabled by configuration");
229+
}
189230
}
190-
generateNewTweetLoop();
191-
}
192-
193-
constructor(client: ClientBase, runtime: IAgentRuntime) {
194-
this.client = client;
195-
this.runtime = runtime;
196-
this.twitterUsername = runtime.getSetting("TWITTER_USERNAME");
197231
}
198232

233+
/**
234+
* Generates and posts a new tweet. If isDryRun is true, only logs what would have been posted.
235+
*/
199236
private async generateNewTweet() {
200237
elizaLogger.log("Generating new tweet");
201238

@@ -292,7 +329,7 @@ export class TwitterPostClient {
292329
// Final cleaning
293330
cleanedContent = removeQuotes(fixNewLines(content));
294331

295-
if (this.runtime.getSetting("TWITTER_DRY_RUN") === "true") {
332+
if (this.isDryRun) {
296333
elizaLogger.info(
297334
`Dry run: would have posted tweet: ${cleanedContent}`
298335
);
@@ -447,6 +484,10 @@ export class TwitterPostClient {
447484
);
448485
}
449486

487+
/**
488+
* Processes tweet actions (likes, retweets, quotes, replies). If isDryRun is true,
489+
* only simulates and logs actions without making API calls.
490+
*/
450491
private async processTweetActions() {
451492
if (this.isProcessing) {
452493
elizaLogger.log("Already processing tweet actions, skipping");
@@ -459,6 +500,11 @@ export class TwitterPostClient {
459500

460501
elizaLogger.log("Processing tweet actions");
461502

503+
if (this.isDryRun) {
504+
elizaLogger.log("Dry run mode: simulating tweet actions");
505+
return [];
506+
}
507+
462508
await this.runtime.ensureUserExists(
463509
this.runtime.agentId,
464510
this.twitterUsername,
@@ -526,9 +572,14 @@ export class TwitterPostClient {
526572
// Execute actions
527573
if (actionResponse.like) {
528574
try {
529-
await this.client.twitterClient.likeTweet(tweet.id);
530-
executedActions.push("like");
531-
elizaLogger.log(`Liked tweet ${tweet.id}`);
575+
if (this.isDryRun) {
576+
elizaLogger.info(`Dry run: would have liked tweet ${tweet.id}`);
577+
executedActions.push("like (dry run)");
578+
} else {
579+
await this.client.twitterClient.likeTweet(tweet.id);
580+
executedActions.push("like");
581+
elizaLogger.log(`Liked tweet ${tweet.id}`);
582+
}
532583
} catch (error) {
533584
elizaLogger.error(
534585
`Error liking tweet ${tweet.id}:`,
@@ -539,9 +590,14 @@ export class TwitterPostClient {
539590

540591
if (actionResponse.retweet) {
541592
try {
542-
await this.client.twitterClient.retweet(tweet.id);
543-
executedActions.push("retweet");
544-
elizaLogger.log(`Retweeted tweet ${tweet.id}`);
593+
if (this.isDryRun) {
594+
elizaLogger.info(`Dry run: would have retweeted tweet ${tweet.id}`);
595+
executedActions.push("retweet (dry run)");
596+
} else {
597+
await this.client.twitterClient.retweet(tweet.id);
598+
executedActions.push("retweet");
599+
elizaLogger.log(`Retweeted tweet ${tweet.id}`);
600+
}
545601
} catch (error) {
546602
elizaLogger.error(
547603
`Error retweeting tweet ${tweet.id}:`,
@@ -552,6 +608,15 @@ export class TwitterPostClient {
552608

553609
if (actionResponse.quote) {
554610
try {
611+
// Check for dry run mode
612+
if (this.isDryRun) {
613+
elizaLogger.info(
614+
`Dry run: would have posted quote tweet for ${tweet.id}`
615+
);
616+
executedActions.push("quote (dry run)");
617+
continue;
618+
}
619+
555620
// Build conversation thread for context
556621
const thread = await buildConversationThread(
557622
tweet,
@@ -752,11 +817,21 @@ export class TwitterPostClient {
752817
}
753818
}
754819

820+
/**
821+
* Handles text-only replies to tweets. If isDryRun is true, only logs what would
822+
* have been replied without making API calls.
823+
*/
755824
private async handleTextOnlyReply(
756825
tweet: Tweet,
757826
tweetState: any,
758827
executedActions: string[]
759828
) {
829+
if (this.isDryRun) {
830+
elizaLogger.info(`Dry run: would have processed reply to tweet ${tweet.id}`);
831+
executedActions.push("reply (dry run)");
832+
return;
833+
}
834+
760835
try {
761836
// Build conversation thread for context
762837
const thread = await buildConversationThread(tweet, this.client);
@@ -832,6 +907,13 @@ export class TwitterPostClient {
832907
return;
833908
}
834909

910+
if (this.isDryRun) {
911+
elizaLogger.info(
912+
`Dry run: would have posted reply: ${replyText}`
913+
);
914+
return;
915+
}
916+
835917
elizaLogger.debug("Final reply text to be sent:", replyText);
836918

837919
// Send the tweet through request queue

0 commit comments

Comments
 (0)