+48
-13
README.md
+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
+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
+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
+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
+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
+9
x.py
···
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}")