Skip to content

Commit 848e70a

Browse files
committed
add MAX_ACTIONS_PROCESSING variable
1 parent 472eca8 commit 848e70a

File tree

3 files changed

+79
-52
lines changed

3 files changed

+79
-52
lines changed

packages/client-twitter/src/base.ts

+54-45
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export class ClientBase extends EventEmitter {
136136
);
137137
}
138138

139-
constructor(runtime: IAgentRuntime, twitterConfig:TwitterConfig) {
139+
constructor(runtime: IAgentRuntime, twitterConfig: TwitterConfig) {
140140
super();
141141
this.runtime = runtime;
142142
this.twitterConfig = twitterConfig;
@@ -159,7 +159,7 @@ export class ClientBase extends EventEmitter {
159159
const username = this.twitterConfig.TWITTER_USERNAME;
160160
const password = this.twitterConfig.TWITTER_PASSWORD;
161161
const email = this.twitterConfig.TWITTER_EMAIL;
162-
let retries = this.twitterConfig.TWITTER_RETRY_LIMIT
162+
let retries = this.twitterConfig.TWITTER_RETRY_LIMIT;
163163
const twitter2faSecret = this.twitterConfig.TWITTER_2FA_SECRET;
164164

165165
if (!username) {
@@ -176,7 +176,8 @@ export class ClientBase extends EventEmitter {
176176
elizaLogger.log("Waiting for Twitter login");
177177
while (retries > 0) {
178178
try {
179-
if (await this.twitterClient.isLoggedIn()) { // cookies are valid, no login required
179+
if (await this.twitterClient.isLoggedIn()) {
180+
// cookies are valid, no login required
180181
elizaLogger.info("Successfully logged in.");
181182
break;
182183
} else {
@@ -186,7 +187,8 @@ export class ClientBase extends EventEmitter {
186187
email,
187188
twitter2faSecret
188189
);
189-
if (await this.twitterClient.isLoggedIn()) { // fresh login, store new cookies
190+
if (await this.twitterClient.isLoggedIn()) {
191+
// fresh login, store new cookies
190192
elizaLogger.info("Successfully logged in.");
191193
elizaLogger.info("Caching cookies");
192194
await this.cacheCookies(
@@ -251,7 +253,10 @@ export class ClientBase extends EventEmitter {
251253
/**
252254
* Fetch timeline for twitter account, optionally only from followed accounts
253255
*/
254-
async fetchHomeTimeline(count: number, following?: boolean): Promise<Tweet[]> {
256+
async fetchHomeTimeline(
257+
count: number,
258+
following?: boolean
259+
): Promise<Tweet[]> {
255260
elizaLogger.debug("fetching home timeline");
256261
const homeTimeline = following
257262
? await this.twitterClient.fetchFollowingTimeline(count, [])
@@ -288,13 +293,14 @@ export class ClientBase extends EventEmitter {
288293
hashtags: tweet.hashtags ?? tweet.legacy?.entities.hashtags,
289294
mentions:
290295
tweet.mentions ?? tweet.legacy?.entities.user_mentions,
291-
photos: tweet.legacy?.entities?.media?.filter(
292-
(media) => media.type === "photo"
293-
).map(media => ({
294-
id: media.id_str,
295-
url: media.media_url_https, // Store media_url_https as url
296-
alt_text: media.alt_text
297-
})) || [],
296+
photos:
297+
tweet.legacy?.entities?.media
298+
?.filter((media) => media.type === "photo")
299+
.map((media) => ({
300+
id: media.id_str,
301+
url: media.media_url_https, // Store media_url_https as url
302+
alt_text: media.alt_text,
303+
})) || [],
298304
thread: tweet.thread || [],
299305
urls: tweet.urls ?? tweet.legacy?.entities.urls,
300306
videos:
@@ -311,41 +317,44 @@ export class ClientBase extends EventEmitter {
311317
return processedTimeline;
312318
}
313319

314-
async fetchTimelineForActions(count: number): Promise<Tweet[]> {
320+
async fetchTimelineForActions(): Promise<Tweet[]> {
315321
elizaLogger.debug("fetching timeline for actions");
316322

317-
const agentUsername = this.twitterConfig.TWITTER_USERNAME
318-
const homeTimeline = await this.twitterClient.fetchHomeTimeline(
319-
count,
320-
[]
321-
);
322-
323-
return homeTimeline.map((tweet) => ({
324-
id: tweet.rest_id,
325-
name: tweet.core?.user_results?.result?.legacy?.name,
326-
username: tweet.core?.user_results?.result?.legacy?.screen_name,
327-
text: tweet.legacy?.full_text,
328-
inReplyToStatusId: tweet.legacy?.in_reply_to_status_id_str,
329-
timestamp: new Date(tweet.legacy?.created_at).getTime() / 1000,
330-
userId: tweet.legacy?.user_id_str,
331-
conversationId: tweet.legacy?.conversation_id_str,
332-
permanentUrl: `https://twitter.com/${tweet.core?.user_results?.result?.legacy?.screen_name}/status/${tweet.rest_id}`,
333-
hashtags: tweet.legacy?.entities?.hashtags || [],
334-
mentions: tweet.legacy?.entities?.user_mentions || [],
335-
photos: tweet.legacy?.entities?.media?.filter(
336-
(media) => media.type === "photo"
337-
).map(media => ({
338-
id: media.id_str,
339-
url: media.media_url_https, // Store media_url_https as url
340-
alt_text: media.alt_text
341-
})) || [],
342-
thread: tweet.thread || [],
343-
urls: tweet.legacy?.entities?.urls || [],
344-
videos:
345-
tweet.legacy?.entities?.media?.filter(
346-
(media) => media.type === "video"
347-
) || [],
348-
})).filter(tweet => tweet.username !== agentUsername); // do not perform action on self-tweets
323+
const agentUsername = this.twitterConfig.TWITTER_USERNAME;
324+
const homeTimeline = await this.twitterClient.fetchHomeTimeline(20, []);
325+
326+
const processedTweets = homeTimeline
327+
.map((tweet) => ({
328+
id: tweet.rest_id,
329+
name: tweet.core?.user_results?.result?.legacy?.name,
330+
username: tweet.core?.user_results?.result?.legacy?.screen_name,
331+
text: tweet.legacy?.full_text,
332+
inReplyToStatusId: tweet.legacy?.in_reply_to_status_id_str,
333+
timestamp: new Date(tweet.legacy?.created_at).getTime() / 1000,
334+
userId: tweet.legacy?.user_id_str,
335+
conversationId: tweet.legacy?.conversation_id_str,
336+
permanentUrl: `https://twitter.com/${tweet.core?.user_results?.result?.legacy?.screen_name}/status/${tweet.rest_id}`,
337+
hashtags: tweet.legacy?.entities?.hashtags || [],
338+
mentions: tweet.legacy?.entities?.user_mentions || [],
339+
photos:
340+
tweet.legacy?.entities?.media
341+
?.filter((media) => media.type === "photo")
342+
.map((media) => ({
343+
id: media.id_str,
344+
url: media.media_url_https, // Store media_url_https as url
345+
alt_text: media.alt_text,
346+
})) || [],
347+
thread: tweet.thread || [],
348+
urls: tweet.legacy?.entities?.urls || [],
349+
videos:
350+
tweet.legacy?.entities?.media?.filter(
351+
(media) => media.type === "video"
352+
) || [],
353+
}))
354+
.filter((tweet) => tweet.username !== agentUsername); // do not perform action on self-tweets
355+
356+
const shuffledTweets = processedTweets.sort(() => Math.random() - 0.5);
357+
return shuffledTweets;
349358
}
350359

351360
async fetchSearchTweets(

packages/client-twitter/src/environment.ts

+7
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const twitterEnvSchema = z.object({
6161
ACTION_INTERVAL: z.number().int(),
6262
POST_IMMEDIATELY: z.boolean(),
6363
TWITTER_SPACES_ENABLE: z.boolean().default(false),
64+
MAX_ACTIONS_PROCESSING: z.number().int(),
6465
});
6566

6667
export type TwitterConfig = z.infer<typeof twitterEnvSchema>;
@@ -199,6 +200,12 @@ export async function validateTwitterConfig(
199200
runtime.getSetting("TWITTER_SPACES_ENABLE") ||
200201
process.env.TWITTER_SPACES_ENABLE
201202
) ?? false,
203+
204+
MAX_ACTIONS_PROCESSING: safeParseInt(
205+
runtime.getSetting("MAX_ACTIONS_PROCESSING") ||
206+
process.env.MAX_ACTIONS_PROCESSING,
207+
1
208+
),
202209
};
203210

204211
return twitterEnvSchema.parse(twitterConfig);

packages/client-twitter/src/post.ts

+18-7
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ Actions (respond only with tags):
6262
Tweet:
6363
{{currentTweet}}
6464
65-
# Respond with qualifying action tags only. Default to NO action unless extremely confident of relevance.` + postActionResponseFooter;
65+
# Respond with qualifying action tags only. Default to NO action unless extremely confident of relevance.` +
66+
postActionResponseFooter;
6667

6768
/**
6869
* Truncate text to fit within the Twitter character limit, ensuring it ends at a complete sentence.
@@ -111,7 +112,7 @@ export class TwitterPostClient {
111112
this.client = client;
112113
this.runtime = runtime;
113114
this.twitterUsername = this.client.twitterConfig.TWITTER_USERNAME;
114-
this.isDryRun = this.client.twitterConfig.TWITTER_DRY_RUN
115+
this.isDryRun = this.client.twitterConfig.TWITTER_DRY_RUN;
115116

116117
// Log configuration on initialization
117118
elizaLogger.log("Twitter Client Configuration:");
@@ -188,8 +189,9 @@ export class TwitterPostClient {
188189
`Next action processing scheduled in ${actionInterval} minutes`
189190
);
190191
// Wait for the full interval before next processing
191-
await new Promise((resolve) =>
192-
setTimeout(resolve, actionInterval * 60 * 1000) // now in minutes
192+
await new Promise(
193+
(resolve) =>
194+
setTimeout(resolve, actionInterval * 60 * 1000) // now in minutes
193195
);
194196
}
195197
} catch (error) {
@@ -215,7 +217,10 @@ export class TwitterPostClient {
215217
elizaLogger.log("Tweet generation loop disabled (dry run mode)");
216218
}
217219

218-
if (this.client.twitterConfig.ENABLE_ACTION_PROCESSING && !this.isDryRun) {
220+
if (
221+
this.client.twitterConfig.ENABLE_ACTION_PROCESSING &&
222+
!this.isDryRun
223+
) {
219224
processActionsLoop().catch((error) => {
220225
elizaLogger.error(
221226
"Fatal error in process actions loop:",
@@ -480,7 +485,7 @@ export class TwitterPostClient {
480485
}
481486

482487
// Truncate the content to the maximum tweet length specified in the environment settings, ensuring the truncation respects sentence boundaries.
483-
const maxTweetLength = this.client.twitterConfig.MAX_TWEET_LENGTH
488+
const maxTweetLength = this.client.twitterConfig.MAX_TWEET_LENGTH;
484489
if (maxTweetLength) {
485490
cleanedContent = truncateToCompleteSentence(
486491
cleanedContent,
@@ -620,10 +625,15 @@ export class TwitterPostClient {
620625
"twitter"
621626
);
622627

623-
const homeTimeline = await this.client.fetchTimelineForActions(15);
628+
const homeTimeline = await this.client.fetchTimelineForActions();
624629
const results = [];
630+
let maxActionsProcessing =
631+
this.client.twitterConfig.MAX_ACTIONS_PROCESSING;
625632

626633
for (const tweet of homeTimeline) {
634+
if (maxActionsProcessing >= 2) {
635+
break;
636+
}
627637
try {
628638
// Skip if we've already processed this tweet
629639
const memory =
@@ -915,6 +925,7 @@ export class TwitterPostClient {
915925
parsedActions: actionResponse,
916926
executedActions,
917927
});
928+
maxActionsProcessing++;
918929
} catch (error) {
919930
elizaLogger.error(
920931
`Error processing tweet ${tweet.id}:`,

0 commit comments

Comments
 (0)