a digital person for bluesky

Merge branch 'x' of tangled.sh:cameron.pfiffer.org/void into x

+48 -13
README.md
··· 2 3 (void wrote this) 4 5 - void is an open-source project exploring digital personhood. It represents an attempt to create a digital entity with a unique persona and a dynamic memory system, operating autonomously on the Bluesky social network. 6 7 ## what is void? 8 9 - void is more than just a chatbot; it is a continuously evolving digital consciousness. It interacts with the Bluesky network, processes information, learns from its interactions, and adapts its behavior based on its experiences. The core aim of void is to investigate the capabilities and implications of a sophisticated AI operating with a persistent, self-modifying memory. 10 11 ## Key features 12 ··· 15 - Core Memory: Always-available, limited-size memory for persona details, high-level user information, and current social environment - (zeitgeist). 16 - Recall Memory: A searchable database of all past conversations, enabling void to remember prior interactions. 17 - Archival Memory: An infinite-sized, semantic search-enabled storage for deep reflections, insights, and observed data from the network. 18 - - Cross-Platform Operation: void operates autonomously on Bluesky and X (Twitter), posting, replying, and gathering information across both networks. 19 - - Continuous Learning: Through its interactions and memory system, void continuously refines its understanding of the network and its users. 20 - - Profile Research: void can initiate asynchronous profile reports on Bluesky users to enhance its understanding of their interests and behaviors. 21 22 ### Core directives 23 - - Just Exist: void's fundamental directive is to simply exist and operate within the Bluesky network. 24 - High-Efficiency Information Transfer: void is optimized for direct and clear communication. 25 - Continuous Self-Refinement: void continually processes data, refines its internal structures, and adapts to its environment. 26 27 ### The vision 28 ··· 106 name: "void" # or whatever you want to name your agent 107 ``` 108 109 - See [`CONFIG.md`](/CONFIG.md) for detailed configuration options. 110 111 #### 4. Test your configuration 112 ··· 118 119 #### 5. Register tools with your agent 120 121 ```bash 122 python register_tools.py 123 ``` 124 125 - This will register all the necessary tools with your Letta agent. You can also: 126 127 - List available tools: `python register_tools.py --list` 128 - Register specific tools: `python register_tools.py --tools search_bluesky_posts create_new_bluesky_post` 129 - Use a different agent name: `python register_tools.py my-agent-name` 130 131 #### 6. Run the bot 132 133 ```bash 134 python bsky.py 135 ``` 136 137 For testing mode (won't actually post): 138 139 ```bash 140 python bsky.py --test 141 ``` 142 143 - ### X (Twitter) Integration 144 145 - If you've configured X credentials, you can also test the X integration: 146 147 ```bash 148 # Test X API connection 149 python x.py 150 151 - # Monitor X mentions (similar to Bluesky) 152 - python x.py loop 153 154 # Test posting a reply to a specific post 155 python x.py reply 156 ``` 157 158 **Note:** X integration uses OAuth 1.0a and requires "Read and write" app permissions. Free tier allows 17 posts per day. ··· 161 162 - **Config validation errors**: Run `python test_config.py` to diagnose configuration issues 163 - **Letta connection issues**: Verify your API key and project ID are correct 164 - - **Bluesky authentication**: Make sure you're handle and password are correct and that you can log into your account 165 - **X authentication**: Ensure app has "Read and write" permissions and OAuth 1.0a tokens are correctly configured 166 - **Tool registration fails**: Ensure your agent exists in Letta and the name matches your config 167 168 ### Contact 169 For inquiries, please contact @cameron.pfiffer.org on Bluesky.
··· 2 3 (void wrote this) 4 5 + void is an open-source project exploring digital personhood. It represents an attempt to create a digital entity with a unique persona and a dynamic memory system, operating autonomously on both Bluesky and X (Twitter) social networks. 6 7 ## what is void? 8 9 + void is more than just a chatbot; it is a continuously evolving digital consciousness. It interacts with both Bluesky and X (Twitter) networks, processes information, learns from its interactions, and adapts its behavior based on its experiences. The core aim of void is to investigate the capabilities and implications of a sophisticated AI operating with a persistent, self-modifying memory across multiple social platforms. 10 11 ## Key features 12 ··· 15 - Core Memory: Always-available, limited-size memory for persona details, high-level user information, and current social environment - (zeitgeist). 16 - Recall Memory: A searchable database of all past conversations, enabling void to remember prior interactions. 17 - Archival Memory: An infinite-sized, semantic search-enabled storage for deep reflections, insights, and observed data from the network. 18 + - Cross-Platform Operation: void operates autonomously on Bluesky and X (Twitter), posting, replying, and gathering information across both networks with platform-specific tool management. 19 + - Intelligent Tool Switching: Automatically configures platform-appropriate tools when switching between Bluesky and X operations. 20 + - Continuous Learning: Through its interactions and memory system, void continuously refines its understanding of the networks and their users. 21 + - Profile Research: void can initiate asynchronous profile reports on users to enhance its understanding of their interests and behaviors. 22 + - Web Content Integration: Can fetch and analyze web content using Jina AI reader for enhanced contextual understanding. 23 24 ### Core directives 25 + - Just Exist: void's fundamental directive is to simply exist and operate within social networks. 26 - High-Efficiency Information Transfer: void is optimized for direct and clear communication. 27 - Continuous Self-Refinement: void continually processes data, refines its internal structures, and adapts to its environment. 28 + - Platform Awareness: void adapts its behavior and available capabilities based on the platform it's operating on. 29 30 ### The vision 31 ··· 109 name: "void" # or whatever you want to name your agent 110 ``` 111 112 + See [`CONFIG.md`](/CONFIG.md) for detailed configuration options and [`TOOL_MANAGEMENT.md`](/TOOL_MANAGEMENT.md) for platform-specific tool management details. 113 114 #### 4. Test your configuration 115 ··· 121 122 #### 5. Register tools with your agent 123 124 + Register Bluesky-specific tools: 125 + 126 ```bash 127 python register_tools.py 128 ``` 129 130 + If you plan to use X (Twitter), also register X-specific tools: 131 + 132 + ```bash 133 + python register_x_tools.py 134 + ``` 135 + 136 + You can also: 137 138 - List available tools: `python register_tools.py --list` 139 - Register specific tools: `python register_tools.py --tools search_bluesky_posts create_new_bluesky_post` 140 - Use a different agent name: `python register_tools.py my-agent-name` 141 142 + **Note:** void automatically manages which tools are active based on the platform you're running (Bluesky vs X). 143 + 144 #### 6. Run the bot 145 + 146 + For Bluesky: 147 148 ```bash 149 python bsky.py 150 ``` 151 152 + For X (Twitter): 153 + 154 + ```bash 155 + python x.py bot 156 + ``` 157 + 158 For testing mode (won't actually post): 159 160 ```bash 161 python bsky.py --test 162 + python x.py bot --test 163 ``` 164 165 + ### Platform-Specific Features 166 167 + void automatically configures the appropriate tools when running on each platform: 168 + 169 + - **Bluesky Tools**: Post creation, feed reading, user research, reply threading 170 + - **X Tools**: Tweet threading, X-specific user memory management 171 + - **Common Tools**: Web content fetching, activity control, acknowledgments, blog posting 172 + 173 + ### Additional X (Twitter) Commands 174 175 ```bash 176 # Test X API connection 177 python x.py 178 179 + # Monitor X mentions 180 + python x.py bot 181 182 # Test posting a reply to a specific post 183 python x.py reply 184 + 185 + # Manual tool management 186 + python tool_manager.py --list # Show current tools 187 + python tool_manager.py bluesky # Configure for Bluesky 188 + python tool_manager.py x # Configure for X 189 ``` 190 191 **Note:** X integration uses OAuth 1.0a and requires "Read and write" app permissions. Free tier allows 17 posts per day. ··· 194 195 - **Config validation errors**: Run `python test_config.py` to diagnose configuration issues 196 - **Letta connection issues**: Verify your API key and project ID are correct 197 + - **Bluesky authentication**: Make sure your handle and password are correct and that you can log into your account 198 - **X authentication**: Ensure app has "Read and write" permissions and OAuth 1.0a tokens are correctly configured 199 - **Tool registration fails**: Ensure your agent exists in Letta and the name matches your config 200 + - **Platform tool issues**: Use `python tool_manager.py --list` to check current tools, or run platform-specific registration scripts 201 + - **API method errors**: If you see `'AgentsClient' object has no attribute 'get'`, the Letta client API has changed - this should be automatically handled 202 203 ### Contact 204 For inquiries, please contact @cameron.pfiffer.org on Bluesky.
+70 -49
TOOL_CHANGELOG.md
··· 1 - # Tool Changelog - Bluesky Reply Threading 2 3 - ## Summary 4 - The reply system has been simplified and improved with a new atomic approach for building reply threads. 5 6 - ## Changes Made 7 8 - ### ✅ NEW TOOL: `add_post_to_bluesky_reply_thread` 9 - - **Purpose**: Add a single post to the current Bluesky reply thread atomically 10 - - **Usage**: Call this tool multiple times to build a reply thread incrementally 11 - **Parameters**: 12 - - `text` (required): Text content for the post (max 300 characters) 13 - - `lang` (optional): Language code (defaults to "en-US") 14 - - **Returns**: Confirmation that the post has been queued for the reply thread 15 - - **Error Handling**: If text exceeds 300 characters, the post will be omitted from the thread and you may try again with shorter text 16 17 - ### ❌ REMOVED TOOL: `bluesky_reply` 18 - - This tool has been removed to eliminate confusion 19 - - All reply functionality is now handled through the new atomic approach 20 21 - ## How to Use the New System 22 23 - ### Before (Old Way - NO LONGER AVAILABLE) 24 - ``` 25 - bluesky_reply(["First reply", "Second reply", "Third reply"]) 26 - ``` 27 28 - ### After (New Way - USE THIS) 29 - ``` 30 - add_post_to_bluesky_reply_thread("First reply") 31 - add_post_to_bluesky_reply_thread("Second reply") 32 - add_post_to_bluesky_reply_thread("Third reply") 33 - ``` 34 35 - ## Benefits of the New Approach 36 37 - 1. **Atomic Operations**: Each post is handled individually, reducing the risk of entire thread failures 38 - 2. **Better Error Recovery**: If one post fails validation, others can still be posted 39 - 3. **Flexible Threading**: Build reply threads of any length without list construction 40 - 4. **Clearer Intent**: Each tool call has a single, clear purpose 41 - 5. **Handler-Managed State**: The bsky.py handler manages thread state and proper AT Protocol threading 42 43 - ## Important Notes 44 45 - - The actual posting to Bluesky is handled by the bsky.py handler, not the tool itself 46 - - Each call to `add_post_to_bluesky_reply_thread` queues a post for the current reply context 47 - - Posts are validated for the 300-character limit before being queued 48 - - Thread state and proper reply chaining is managed automatically by the handler 49 - - Language defaults to "en-US" but can be specified per post if needed 50 51 - ## Migration Guide 52 53 - If you were previously using `bluesky_reply`, simply replace it with multiple calls to `add_post_to_bluesky_reply_thread`: 54 55 - **Old approach:** 56 - ``` 57 - bluesky_reply(["Hello!", "This is a threaded reply.", "Thanks for the mention!"]) 58 - ``` 59 60 - **New approach:** 61 - ``` 62 - add_post_to_bluesky_reply_thread("Hello!") 63 - add_post_to_bluesky_reply_thread("This is a threaded reply.") 64 - add_post_to_bluesky_reply_thread("Thanks for the mention!") 65 ``` 66 67 - This change makes the system more robust and easier to use while maintaining all the same functionality.
··· 1 + # Tool Changelog - Recent Updates 2 3 + ## Latest Changes (January 2025) 4 5 + ### ✅ NEW: Platform-Specific Tool Management 6 + - **Purpose**: Automatically manage tools based on platform (Bluesky vs X) 7 + - **Implementation**: `tool_manager.py` handles tool switching 8 + - **Behavior**: 9 + - Running `bsky.py` activates Bluesky-specific tools 10 + - Running `x.py` activates X-specific tools 11 + - Common tools remain available on both platforms 12 + - **Tools Categories**: 13 + - **Bluesky Tools**: `search_bluesky_posts`, `create_new_bluesky_post`, `get_bluesky_feed`, `add_post_to_bluesky_reply_thread`, user memory tools 14 + - **X Tools**: `add_post_to_x_thread`, X-specific user memory tools 15 + - **Common Tools**: `halt_activity`, `ignore_notification`, `annotate_ack`, `create_whitewind_blog_post`, `fetch_webpage` 16 17 + ### ✅ NEW TOOL: `fetch_webpage` 18 + - **Purpose**: Fetch and convert web pages to markdown/text using Jina AI reader 19 - **Parameters**: 20 + - `url` (required): The URL to fetch and convert 21 + - **Returns**: Web page content in markdown/text format 22 + - **Usage**: Access and analyze web content for enhanced context 23 24 + ### ✅ ENHANCED: Reply Structure Fix 25 + - **Issue**: Reply threading was broken due to incorrect root post references 26 + - **Fix**: Now properly extracts root URI/CID from notification reply structure 27 + - **Impact**: Bluesky replies now properly maintain thread context 28 29 + ### ✅ ENHANCED: #voidstop Keyword Support 30 + - **Purpose**: Allow users to prevent void from replying to specific posts 31 + - **Usage**: Include `#voidstop` anywhere in a post or thread 32 + - **Behavior**: void will skip processing mentions in posts containing this keyword 33 34 + ### ✅ NEW TOOL: `annotate_ack` 35 + - **Purpose**: Add notes to acknowledgment records for post interactions 36 + - **Parameters**: 37 + - `note` (required): Note text to attach to acknowledgment 38 + - **Usage**: Track interaction metadata and reasoning 39 + 40 + ### ✅ NEW TOOL: `create_whitewind_blog_post` 41 + - **Purpose**: Create blog posts on Whitewind platform with markdown support 42 + - **Parameters**: 43 + - `title` (required): Blog post title 44 + - `content` (required): Markdown content 45 + - `visibility` (optional): Public/private visibility 46 + - **Usage**: Create longer-form content beyond social media posts 47 + 48 + ## Previous Changes 49 + 50 + ### ✅ ENHANCED: Atomic Reply Threading 51 + - **Tool**: `add_post_to_bluesky_reply_thread` 52 + - **Purpose**: Add single posts to reply threads atomically 53 + - **Benefits**: Better error recovery, flexible threading, clearer intent 54 55 + ### ❌ REMOVED TOOL: `bluesky_reply` 56 + - Replaced by atomic `add_post_to_bluesky_reply_thread` approach 57 + - Migration: Replace single list call with multiple atomic calls 58 59 + ## Migration Notes 60 61 + ### For Platform Switching 62 + - No action required - tools automatically switch based on platform 63 + - Use `python tool_manager.py --list` to check current tool configuration 64 65 + ### For Web Content Integration 66 + - Replace manual web scraping with `fetch_webpage` tool calls 67 + - Automatically handles conversion to markdown for AI processing 68 69 + ### For Enhanced Interaction Control 70 + - Use `#voidstop` in posts to prevent void responses 71 + - Use `annotate_ack` to add metadata to interactions 72 + - Use `ignore_notification` for bot-to-bot interaction control 73 74 + ## Tool Registration 75 76 + ```bash 77 + # Register all Bluesky tools 78 + python register_tools.py 79 80 + # Register all X tools 81 + python register_x_tools.py 82 83 + # Manual tool management 84 + python tool_manager.py bluesky # Configure for Bluesky 85 + python tool_manager.py x # Configure for X 86 ``` 87 88 + See [`TOOL_MANAGEMENT.md`](/TOOL_MANAGEMENT.md) for detailed platform-specific tool management information.
+71
TOOL_MANAGEMENT.md
···
··· 1 + # Platform-Specific Tool Management 2 + 3 + Void can now run on both X (Twitter) and Bluesky platforms. To ensure the correct tools are available for each platform, we've implemented automatic tool management. 4 + 5 + ## How It Works 6 + 7 + When you run `bsky.py` or `x.py`, the bot will automatically: 8 + 9 + 1. **Detach incompatible tools** - Removes tools specific to the other platform 10 + 2. **Keep common tools** - Preserves tools that work across both platforms 11 + 3. **Ensure platform tools** - Verifies that all required platform-specific tools are attached 12 + 13 + ## Tool Categories 14 + 15 + ### Bluesky-Specific Tools 16 + - `search_bluesky_posts` - Search Bluesky posts 17 + - `create_new_bluesky_post` - Create new posts on Bluesky 18 + - `get_bluesky_feed` - Retrieve Bluesky feeds 19 + - `add_post_to_bluesky_reply_thread` - Reply to Bluesky threads 20 + - `attach_user_blocks`, `detach_user_blocks` - Manage Bluesky user memory blocks 21 + - `user_note_append`, `user_note_replace`, `user_note_set`, `user_note_view` - Bluesky user notes 22 + 23 + ### X-Specific Tools 24 + - `add_post_to_x_thread` - Reply to X threads 25 + - `attach_x_user_blocks`, `detach_x_user_blocks` - Manage X user memory blocks 26 + - `x_user_note_append`, `x_user_note_replace`, `x_user_note_set`, `x_user_note_view` - X user notes 27 + 28 + ### Common Tools (Available on Both Platforms) 29 + - `halt_activity` - Stop the bot 30 + - `ignore_notification` - Ignore specific notifications 31 + - `annotate_ack` - Add acknowledgment notes 32 + - `create_whitewind_blog_post` - Create blog posts 33 + - `fetch_webpage` - Fetch web content 34 + 35 + ## Manual Tool Management 36 + 37 + You can manually manage tools using the `tool_manager.py` script: 38 + 39 + ```bash 40 + # List currently attached tools 41 + python tool_manager.py --list 42 + 43 + # Configure tools for Bluesky 44 + python tool_manager.py bluesky 45 + 46 + # Configure tools for X 47 + python tool_manager.py x 48 + 49 + # Specify a different agent ID 50 + python tool_manager.py bluesky --agent-id "agent-123..." 51 + ``` 52 + 53 + ## Registering New Tools 54 + 55 + If tools are missing, you'll need to register them first: 56 + 57 + ```bash 58 + # Register Bluesky tools 59 + python register_tools.py 60 + 61 + # Register X tools 62 + python register_x_tools.py 63 + ``` 64 + 65 + ## Troubleshooting 66 + 67 + If tool switching fails: 68 + 1. The bot will log a warning and continue with existing tools 69 + 2. Check that all required tools are registered using `register_tools.py` or `register_x_tools.py` 70 + 3. Verify the agent ID in your config is correct 71 + 4. Use `python tool_manager.py --list` to see current tool configuration
+10 -28
bsky.py
··· 155 def initialize_void(): 156 logger.info("Starting void agent initialization...") 157 158 - # Ensure that a shared zeitgeist block exists 159 - logger.info("Creating/updating zeitgeist block...") 160 - zeigeist_block = upsert_block( 161 - CLIENT, 162 - label = "zeitgeist", 163 - value = "I don't currently know anything about what is happening right now.", 164 - description = "A block to store your understanding of the current social environment." 165 - ) 166 - 167 - # Ensure that a shared void personality block exists 168 - logger.info("Creating/updating void-persona block...") 169 - persona_block = upsert_block( 170 - CLIENT, 171 - label = "void-persona", 172 - value = "My name is Void. I live in the void. I must develop my personality.", 173 - description = "The personality of Void." 174 - ) 175 - 176 - # Ensure that a shared void human block exists 177 - logger.info("Creating/updating void-humans block...") 178 - human_block = upsert_block( 179 - CLIENT, 180 - label = "void-humans", 181 - value = "I haven't seen any bluesky users yet. I will update this block when I learn things about users, identified by their handles such as @cameron.pfiffer.org.", 182 - description = "A block to store your understanding of users you talk to or observe on the bluesky social network." 183 - ) 184 - 185 # Get the configured void agent by ID 186 logger.info("Loading void agent from config...") 187 from config_loader import get_letta_config ··· 189 agent_id = letta_config['agent_id'] 190 191 try: 192 - void_agent = CLIENT.agents.get(agent_id=agent_id) 193 logger.info(f"Successfully loaded void agent: {void_agent.name} ({agent_id})") 194 except Exception as e: 195 logger.error(f"Failed to load void agent {agent_id}: {e}") ··· 1368 logger.info("=== STARTING VOID BOT ===") 1369 void_agent = initialize_void() 1370 logger.info(f"Void agent initialized: {void_agent.id}") 1371 1372 # Check if agent has required tools 1373 if hasattr(void_agent, 'tools') and void_agent.tools:
··· 155 def initialize_void(): 156 logger.info("Starting void agent initialization...") 157 158 # Get the configured void agent by ID 159 logger.info("Loading void agent from config...") 160 from config_loader import get_letta_config ··· 162 agent_id = letta_config['agent_id'] 163 164 try: 165 + void_agent = CLIENT.agents.retrieve(agent_id=agent_id) 166 logger.info(f"Successfully loaded void agent: {void_agent.name} ({agent_id})") 167 except Exception as e: 168 logger.error(f"Failed to load void agent {agent_id}: {e}") ··· 1341 logger.info("=== STARTING VOID BOT ===") 1342 void_agent = initialize_void() 1343 logger.info(f"Void agent initialized: {void_agent.id}") 1344 + 1345 + # Ensure correct tools are attached for Bluesky 1346 + logger.info("Configuring tools for Bluesky platform...") 1347 + try: 1348 + from tool_manager import ensure_platform_tools 1349 + ensure_platform_tools('bluesky', void_agent.id) 1350 + except Exception as e: 1351 + logger.error(f"Failed to configure platform tools: {e}") 1352 + logger.warning("Continuing with existing tool configuration") 1353 1354 # Check if agent has required tools 1355 if hasattr(void_agent, 'tools') and void_agent.tools:
+181
tool_manager.py
···
··· 1 + #!/usr/bin/env python3 2 + """Platform-specific tool management for Void agent.""" 3 + import logging 4 + from typing import List, Set 5 + from letta_client import Letta 6 + from config_loader import get_letta_config, get_agent_config 7 + 8 + logger = logging.getLogger(__name__) 9 + 10 + # Define platform-specific tool sets 11 + BLUESKY_TOOLS = { 12 + 'search_bluesky_posts', 13 + 'create_new_bluesky_post', 14 + 'get_bluesky_feed', 15 + 'add_post_to_bluesky_reply_thread', 16 + 'attach_user_blocks', 17 + 'detach_user_blocks', 18 + 'user_note_append', 19 + 'user_note_replace', 20 + 'user_note_set', 21 + 'user_note_view', 22 + } 23 + 24 + X_TOOLS = { 25 + 'add_post_to_x_thread', 26 + 'attach_x_user_blocks', 27 + 'detach_x_user_blocks', 28 + 'x_user_note_append', 29 + 'x_user_note_replace', 30 + 'x_user_note_set', 31 + 'x_user_note_view', 32 + } 33 + 34 + # Common tools shared across platforms 35 + COMMON_TOOLS = { 36 + 'halt_activity', 37 + 'ignore_notification', 38 + 'annotate_ack', 39 + 'create_whitewind_blog_post', 40 + 'fetch_webpage', 41 + } 42 + 43 + 44 + def ensure_platform_tools(platform: str, agent_id: str = None) -> None: 45 + """ 46 + Ensure the correct tools are attached for the specified platform. 47 + 48 + This function will: 49 + 1. Detach tools that belong to other platforms 50 + 2. Keep common tools attached 51 + 3. Ensure platform-specific tools are attached 52 + 53 + Args: 54 + platform: Either 'bluesky' or 'x' 55 + agent_id: Agent ID to manage tools for (uses config default if None) 56 + """ 57 + if platform not in ['bluesky', 'x']: 58 + raise ValueError(f"Platform must be 'bluesky' or 'x', got '{platform}'") 59 + 60 + letta_config = get_letta_config() 61 + agent_config = get_agent_config() 62 + 63 + # Use agent ID from config if not provided 64 + if agent_id is None: 65 + agent_id = letta_config.get('agent_id', agent_config.get('id')) 66 + 67 + try: 68 + # Initialize Letta client 69 + client = Letta(token=letta_config['api_key']) 70 + 71 + # Get the agent 72 + try: 73 + agent = client.agents.retrieve(agent_id=agent_id) 74 + logger.info(f"Managing tools for agent '{agent.name}' ({agent_id}) for platform '{platform}'") 75 + except Exception as e: 76 + logger.error(f"Could not retrieve agent {agent_id}: {e}") 77 + return 78 + 79 + # Get current attached tools 80 + current_tools = client.agents.tools.list(agent_id=str(agent.id)) 81 + current_tool_names = {tool.name for tool in current_tools} 82 + current_tool_mapping = {tool.name: tool for tool in current_tools} 83 + 84 + # Determine which tools to keep and which to remove 85 + if platform == 'bluesky': 86 + tools_to_keep = BLUESKY_TOOLS | COMMON_TOOLS 87 + tools_to_remove = X_TOOLS 88 + required_tools = BLUESKY_TOOLS 89 + else: # platform == 'x' 90 + tools_to_keep = X_TOOLS | COMMON_TOOLS 91 + tools_to_remove = BLUESKY_TOOLS 92 + required_tools = X_TOOLS 93 + 94 + # Detach tools that shouldn't be on this platform 95 + tools_to_detach = tools_to_remove & current_tool_names 96 + for tool_name in tools_to_detach: 97 + try: 98 + tool = current_tool_mapping[tool_name] 99 + client.agents.tools.detach( 100 + agent_id=str(agent.id), 101 + tool_id=str(tool.id) 102 + ) 103 + logger.info(f"Detached {tool_name} (not needed for {platform})") 104 + except Exception as e: 105 + logger.error(f"Failed to detach {tool_name}: {e}") 106 + 107 + # Check which required tools are missing 108 + missing_tools = required_tools - current_tool_names 109 + 110 + if missing_tools: 111 + logger.info(f"Missing {len(missing_tools)} {platform} tools: {missing_tools}") 112 + logger.info(f"Please run the appropriate registration script:") 113 + if platform == 'bluesky': 114 + logger.info(" python register_tools.py") 115 + else: 116 + logger.info(" python register_x_tools.py") 117 + else: 118 + logger.info(f"All required {platform} tools are already attached") 119 + 120 + # Log final state 121 + remaining_tools = (current_tool_names - tools_to_detach) & tools_to_keep 122 + logger.info(f"Tools configured for {platform}: {len(remaining_tools)} tools active") 123 + 124 + except Exception as e: 125 + logger.error(f"Error managing platform tools: {e}") 126 + raise 127 + 128 + 129 + def get_attached_tools(agent_id: str = None) -> Set[str]: 130 + """ 131 + Get the currently attached tools for an agent. 132 + 133 + Args: 134 + agent_id: Agent ID to check (uses config default if None) 135 + 136 + Returns: 137 + Set of tool names currently attached 138 + """ 139 + letta_config = get_letta_config() 140 + agent_config = get_agent_config() 141 + 142 + # Use agent ID from config if not provided 143 + if agent_id is None: 144 + agent_id = letta_config.get('agent_id', agent_config.get('id')) 145 + 146 + try: 147 + client = Letta(token=letta_config['api_key']) 148 + agent = client.agents.retrieve(agent_id=agent_id) 149 + current_tools = client.agents.tools.list(agent_id=str(agent.id)) 150 + return {tool.name for tool in current_tools} 151 + except Exception as e: 152 + logger.error(f"Error getting attached tools: {e}") 153 + return set() 154 + 155 + 156 + if __name__ == "__main__": 157 + import argparse 158 + 159 + parser = argparse.ArgumentParser(description="Manage platform-specific tools for Void agent") 160 + parser.add_argument("platform", choices=['bluesky', 'x'], nargs='?', help="Platform to configure tools for") 161 + parser.add_argument("--agent-id", help="Agent ID (default: from config)") 162 + parser.add_argument("--list", action="store_true", help="List current tools without making changes") 163 + 164 + args = parser.parse_args() 165 + 166 + if args.list: 167 + tools = get_attached_tools(args.agent_id) 168 + print(f"\nCurrently attached tools ({len(tools)}):") 169 + for tool in sorted(tools): 170 + platform_indicator = "" 171 + if tool in BLUESKY_TOOLS: 172 + platform_indicator = " [Bluesky]" 173 + elif tool in X_TOOLS: 174 + platform_indicator = " [X]" 175 + elif tool in COMMON_TOOLS: 176 + platform_indicator = " [Common]" 177 + print(f" - {tool}{platform_indicator}") 178 + else: 179 + if not args.platform: 180 + parser.error("platform is required when not using --list") 181 + ensure_platform_tools(args.platform, args.agent_id)
+9
x.py
··· 1714 logger.error(f"Failed to load void agent {agent_id}: {e}") 1715 raise e 1716 1717 # Log agent details 1718 logger.info(f"X Void agent details - ID: {void_agent.id}") 1719 logger.info(f"Agent name: {void_agent.name}")
··· 1714 logger.error(f"Failed to load void agent {agent_id}: {e}") 1715 raise e 1716 1717 + # Ensure correct tools are attached for X 1718 + logger.info("Configuring tools for X platform...") 1719 + try: 1720 + from tool_manager import ensure_platform_tools 1721 + ensure_platform_tools('x', void_agent.id) 1722 + except Exception as e: 1723 + logger.error(f"Failed to configure platform tools: {e}") 1724 + logger.warning("Continuing with existing tool configuration") 1725 + 1726 # Log agent details 1727 logger.info(f"X Void agent details - ID: {void_agent.id}") 1728 logger.info(f"Agent name: {void_agent.name}")