a digital entity named phi that roams bsky

feat: discover thread context when phi is tagged into existing threads

- check if thread exists in SQLite before processing
- if not, fetch full thread from ATProto (get_thread with depth=100)
- recursively parse and store all previous messages
- phi now has full thread awareness even when tagged in mid-conversation
- fixes 'what is this thread about' when phi hasn't participated yet

+38 -1
+38 -1
src/bot/services/message_handler.py
··· 20 20 self.client = client 21 21 self.agent = PhiAgent() 22 22 23 + async def _store_thread_messages(self, thread_node, thread_uri: str): 24 + """Recursively extract and store all messages from a thread.""" 25 + if not thread_node or not hasattr(thread_node, "post"): 26 + return 27 + 28 + post = thread_node.post 29 + 30 + # Store this message 31 + thread_db.add_message( 32 + thread_uri=thread_uri, 33 + author_handle=post.author.handle, 34 + author_did=post.author.did, 35 + message_text=post.record.text, 36 + post_uri=post.uri, 37 + ) 38 + 39 + # Recursively store replies 40 + if hasattr(thread_node, "replies") and thread_node.replies: 41 + for reply in thread_node.replies: 42 + await self._store_thread_messages(reply, thread_uri) 43 + 44 + # Also check for parent if this is a reply 45 + if hasattr(thread_node, "parent") and thread_node.parent: 46 + await self._store_thread_messages(thread_node.parent, thread_uri) 47 + 23 48 async def handle_mention(self, notification): 24 49 """Process a mention or reply notification.""" 25 50 try: ··· 52 77 root_ref = parent_ref 53 78 thread_uri = post_uri 54 79 55 - # Store the message in thread history 80 + # Discover thread context if we haven't participated yet 81 + existing_messages = thread_db.get_thread_messages(thread_uri) 82 + if not existing_messages: 83 + # Phi is being tagged into an existing thread - fetch full context 84 + logger.debug(f"🔍 Discovering thread context for {thread_uri}") 85 + try: 86 + thread_data = await self.client.get_thread(thread_uri, depth=100) 87 + # Extract and store all messages from the thread 88 + await self._store_thread_messages(thread_data.thread, thread_uri) 89 + except Exception as e: 90 + logger.warning(f"Failed to fetch thread context: {e}") 91 + 92 + # Store the current mention in thread history 56 93 thread_db.add_message( 57 94 thread_uri=thread_uri, 58 95 author_handle=author_handle,