diff --git a/src/agent/agent_tools/twitter/twitter.py b/src/agent/agent_tools/twitter/twitter.py index a1b2bed..ddb101c 100644 --- a/src/agent/agent_tools/twitter/twitter.py +++ b/src/agent/agent_tools/twitter/twitter.py @@ -5,6 +5,7 @@ import tweepy from pprint import pformat from .twitter_config import TwitterConfig +from .twitter_utils import with_rate_limit_handling logger = logging.getLogger(__name__) logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.INFO) @@ -82,9 +83,25 @@ def __init__( def run(self): def job(): - self.respond_to_key_users() + # Only respond if RESPOND_MODE is enabled + if getattr(self.config, 'RESPOND_MODE', True): + self.respond_to_key_users() + + # Post if POST_MODE is enabled if self.config.POST_MODE: - self.post_tweet() + try: + # Generate post text + post_text = self.model.query(self.config.POST_PROMPT) + logging.info(f"[TWITTER] Generated post: {post_text}") + + # Post the tweet + result, tweet_id = self.post_tweet(post_text) + if result: + logging.info(f"[TWITTER] Successfully posted tweet with ID: {tweet_id}") + else: + logging.error("[TWITTER] Failed to post tweet") + except Exception as e: + logging.exception(f"[TWITTER] Error in posting tweet: {e}") job() @@ -115,7 +132,7 @@ def __build_search_query_ignore_quotes(self): """Returns a twitter search query that ignores quotes""" return " -is:quote" - + @with_rate_limit_handling def __search_for_relevant_conversations(self, start_time=None): """ Gets tweets from key users or from specific conversations. diff --git a/src/agent/agent_tools/twitter/twitter_config.py b/src/agent/agent_tools/twitter/twitter_config.py index 828b8d6..f347d7c 100644 --- a/src/agent/agent_tools/twitter/twitter_config.py +++ b/src/agent/agent_tools/twitter/twitter_config.py @@ -1,5 +1,9 @@ class TwitterConfig: def __init__(self): + + # Set this to False to disable responding to tweets + self.RESPOND_MODE = False + # Agent will respond to tweets from these users every time that it runs self.KEY_USERS = [] @@ -25,4 +29,4 @@ def __init__(self): self.RESPONSES_PER_RUN = 1 # Agent will run this number of times per day - self.RUNS_PER_DAY = 12 \ No newline at end of file + self.RUNS_PER_DAY = 4 \ No newline at end of file diff --git a/src/agent/agent_tools/twitter/twitter_utils.py b/src/agent/agent_tools/twitter/twitter_utils.py new file mode 100644 index 0000000..f446d90 --- /dev/null +++ b/src/agent/agent_tools/twitter/twitter_utils.py @@ -0,0 +1,34 @@ +import time +import logging +from tweepy.errors import TooManyRequests, TwitterServerError + +def with_rate_limit_handling(func): + """Decorator to handle Twitter API rate limits with exponential backoff""" + def wrapper(*args, **kwargs): + max_retries = 5 + retry_count = 0 + base_wait_time = 60 # seconds + + while True: + try: + return func(*args, **kwargs) + except TooManyRequests as e: + retry_count += 1 + if retry_count > max_retries: + logging.error(f"[TWITTER] Maximum retries exceeded. Giving up after {max_retries} attempts.") + raise e + + # Calculate wait time with exponential backoff + wait_time = base_wait_time * (2 ** (retry_count - 1)) + logging.warning(f"[TWITTER] Rate limit reached. Waiting {wait_time} seconds before retry {retry_count}/{max_retries}.") + time.sleep(wait_time) + except TwitterServerError as e: + retry_count += 1 + if retry_count > max_retries: + logging.error(f"[TWITTER] Maximum retries exceeded. Giving up after {max_retries} attempts.") + raise e + + wait_time = base_wait_time + logging.warning(f"[TWITTER] Twitter server error. Waiting {wait_time} seconds before retry {retry_count}/{max_retries}.") + time.sleep(wait_time) + return wrapper \ No newline at end of file