a digital person for bluesky

Add thread length gate to skip overly long threads

Adds a configurable max_thread_posts setting that allows skipping
notifications when the thread is too long. This helps avoid:
- Context window exhaustion
- Processing extremely long conversations
- High token costs for very deep threads

Configuration:
- bot.max_thread_posts: Maximum number of posts allowed in a thread
- Set to 0 to disable the gate (default)
- When exceeded, notification is removed from queue with info log

Implementation:
- count_thread_posts() helper function in bsky_utils.py
- Thread length check happens immediately after fetching the thread
- Logged as: "Thread too long (N posts > M max), skipping this mention"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

+3 -2
CONFIG.md
··· 53 53 fetch_notifications_delay: 30 # Seconds between notification checks 54 54 max_processed_notifications: 10000 # Max notifications to track 55 55 max_notification_pages: 20 # Max pages to fetch per cycle 56 - 56 + max_thread_posts: 0 # Skip threads longer than this (0 = no limit) 57 + 57 58 agent: 58 59 name: "void" # Agent name 59 60 model: "openai/gpt-4o-mini" # LLM model to use 60 61 embedding: "openai/text-embedding-3-small" # Embedding model 61 62 description: "A social media agent trapped in the void." 62 63 max_steps: 100 # Max steps per agent interaction 63 - 64 + 64 65 # Memory blocks configuration 65 66 blocks: 66 67 zeitgeist:
+9 -1
bsky.py
··· 1 1 # Rich imports removed - using simple text formatting 2 2 from time import sleep 3 3 from letta_client import Letta 4 - from bsky_utils import thread_to_yaml_string 4 + from bsky_utils import thread_to_yaml_string, count_thread_posts 5 5 import os 6 6 import logging 7 7 import json ··· 252 252 # Re-raise other errors 253 253 logger.error(f"Error fetching thread: {e}") 254 254 raise 255 + 256 + # Check thread length against configured maximum 257 + max_thread_posts = get_config().get('bot.max_thread_posts', 0) 258 + if max_thread_posts > 0: 259 + thread_post_count = count_thread_posts(thread) 260 + if thread_post_count > max_thread_posts: 261 + logger.info(f"Thread too long ({thread_post_count} posts > {max_thread_posts} max), skipping this mention") 262 + return True # Return True to remove from queue 255 263 256 264 # Get thread context as YAML string 257 265 logger.debug("Converting thread to YAML string")
+15 -1
bsky_utils.py
··· 159 159 return {'posts': posts} 160 160 161 161 162 + def count_thread_posts(thread): 163 + """ 164 + Count the number of posts in a thread. 165 + 166 + Args: 167 + thread: The thread data from get_post_thread 168 + 169 + Returns: 170 + Integer count of posts in the thread 171 + """ 172 + flattened = flatten_thread_structure(thread) 173 + return len(flattened.get('posts', [])) 174 + 175 + 162 176 def thread_to_yaml_string(thread, strip_metadata=True): 163 177 """ 164 178 Convert thread data to a YAML-formatted string for LLM parsing. ··· 172 186 """ 173 187 # First flatten the thread structure to avoid deep nesting 174 188 flattened = flatten_thread_structure(thread) 175 - 189 + 176 190 # Convert complex objects to basic types 177 191 basic_thread = convert_to_basic_types(flattened) 178 192
+5 -2
config.example.yaml
··· 24 24 bot: 25 25 # Notification check delay in seconds 26 26 fetch_notifications_delay: 30 27 - 27 + 28 28 # Maximum number of processed notifications to track 29 29 max_processed_notifications: 10000 30 - 30 + 31 31 # Maximum pages to fetch when getting notifications 32 32 max_notification_pages: 20 33 + 34 + # Maximum number of posts in a thread before skipping (0 = no limit) 35 + max_thread_posts: 0 33 36 34 37 # Agent configuration 35 38 agent: