@@ -99,6 +99,35 @@ export class TwitterPostClient {
99
99
private isProcessing : boolean = false ;
100
100
private lastProcessTime : number = 0 ;
101
101
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
+ }
102
131
103
132
async start ( postImmediately : boolean = false ) {
104
133
if ( ! this . client . profile ) {
@@ -171,31 +200,39 @@ export class TwitterPostClient {
171
200
if ( postImmediately ) {
172
201
await this . generateNewTweet ( ) ;
173
202
}
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
+ }
175
211
176
212
// 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
+ ) ;
179
216
180
- if ( enableActionProcessing ) {
217
+ if ( enableActionProcessing && ! this . isDryRun ) {
181
218
processActionsLoop ( ) . catch ( ( error ) => {
182
219
elizaLogger . error (
183
220
"Fatal error in process actions loop:" ,
184
221
error
185
222
) ;
186
223
} ) ;
187
224
} 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
+ }
189
230
}
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" ) ;
197
231
}
198
232
233
+ /**
234
+ * Generates and posts a new tweet. If isDryRun is true, only logs what would have been posted.
235
+ */
199
236
private async generateNewTweet ( ) {
200
237
elizaLogger . log ( "Generating new tweet" ) ;
201
238
@@ -292,7 +329,7 @@ export class TwitterPostClient {
292
329
// Final cleaning
293
330
cleanedContent = removeQuotes ( fixNewLines ( content ) ) ;
294
331
295
- if ( this . runtime . getSetting ( "TWITTER_DRY_RUN" ) === "true" ) {
332
+ if ( this . isDryRun ) {
296
333
elizaLogger . info (
297
334
`Dry run: would have posted tweet: ${ cleanedContent } `
298
335
) ;
@@ -447,6 +484,10 @@ export class TwitterPostClient {
447
484
) ;
448
485
}
449
486
487
+ /**
488
+ * Processes tweet actions (likes, retweets, quotes, replies). If isDryRun is true,
489
+ * only simulates and logs actions without making API calls.
490
+ */
450
491
private async processTweetActions ( ) {
451
492
if ( this . isProcessing ) {
452
493
elizaLogger . log ( "Already processing tweet actions, skipping" ) ;
@@ -459,6 +500,11 @@ export class TwitterPostClient {
459
500
460
501
elizaLogger . log ( "Processing tweet actions" ) ;
461
502
503
+ if ( this . isDryRun ) {
504
+ elizaLogger . log ( "Dry run mode: simulating tweet actions" ) ;
505
+ return [ ] ;
506
+ }
507
+
462
508
await this . runtime . ensureUserExists (
463
509
this . runtime . agentId ,
464
510
this . twitterUsername ,
@@ -526,9 +572,14 @@ export class TwitterPostClient {
526
572
// Execute actions
527
573
if ( actionResponse . like ) {
528
574
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
+ }
532
583
} catch ( error ) {
533
584
elizaLogger . error (
534
585
`Error liking tweet ${ tweet . id } :` ,
@@ -539,9 +590,14 @@ export class TwitterPostClient {
539
590
540
591
if ( actionResponse . retweet ) {
541
592
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
+ }
545
601
} catch ( error ) {
546
602
elizaLogger . error (
547
603
`Error retweeting tweet ${ tweet . id } :` ,
@@ -552,6 +608,15 @@ export class TwitterPostClient {
552
608
553
609
if ( actionResponse . quote ) {
554
610
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
+
555
620
// Build conversation thread for context
556
621
const thread = await buildConversationThread (
557
622
tweet ,
@@ -752,11 +817,21 @@ export class TwitterPostClient {
752
817
}
753
818
}
754
819
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
+ */
755
824
private async handleTextOnlyReply (
756
825
tweet : Tweet ,
757
826
tweetState : any ,
758
827
executedActions : string [ ]
759
828
) {
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
+
760
835
try {
761
836
// Build conversation thread for context
762
837
const thread = await buildConversationThread ( tweet , this . client ) ;
@@ -832,6 +907,13 @@ export class TwitterPostClient {
832
907
return ;
833
908
}
834
909
910
+ if ( this . isDryRun ) {
911
+ elizaLogger . info (
912
+ `Dry run: would have posted reply: ${ replyText } `
913
+ ) ;
914
+ return ;
915
+ }
916
+
835
917
elizaLogger . debug ( "Final reply text to be sent:" , replyText ) ;
836
918
837
919
// Send the tweet through request queue
0 commit comments