this repo has no description
at 1e670142b7b57a938af8ffef24c55ea671c6b497 175 lines 6.2 kB view raw
1#!/usr/bin/env python3 2"""Register all Void tools with a Letta agent.""" 3import os 4import sys 5import logging 6from typing import List 7from dotenv import load_dotenv 8from letta_client import Letta 9from rich.console import Console 10from rich.table import Table 11 12# Import standalone functions and their schemas 13from tools.search import search_bluesky_posts, SearchArgs 14from tools.post import post_to_bluesky, PostArgs 15from tools.feed import get_bluesky_feed, FeedArgs 16from tools.blocks import attach_user_blocks, detach_user_blocks, AttachUserBlocksArgs, DetachUserBlocksArgs 17 18load_dotenv() 19logging.basicConfig(level=logging.INFO) 20logger = logging.getLogger(__name__) 21console = Console() 22 23 24# Tool configurations: function paired with its args_schema and metadata 25TOOL_CONFIGS = [ 26 { 27 "func": search_bluesky_posts, 28 "args_schema": SearchArgs, 29 "description": "Search for posts on Bluesky matching the given criteria", 30 "tags": ["bluesky", "search", "posts"] 31 }, 32 { 33 "func": post_to_bluesky, 34 "args_schema": PostArgs, 35 "description": "Post a message to Bluesky", 36 "tags": ["bluesky", "post", "create"] 37 }, 38 { 39 "func": get_bluesky_feed, 40 "args_schema": FeedArgs, 41 "description": "Retrieve a Bluesky feed (home timeline or custom feed)", 42 "tags": ["bluesky", "feed", "timeline"] 43 }, 44 { 45 "func": attach_user_blocks, 46 "args_schema": AttachUserBlocksArgs, 47 "description": "Attach user-specific memory blocks to the agent. Creates blocks if they don't exist.", 48 "tags": ["memory", "blocks", "user"] 49 }, 50 { 51 "func": detach_user_blocks, 52 "args_schema": DetachUserBlocksArgs, 53 "description": "Detach user-specific memory blocks from the agent. Blocks are preserved for later use.", 54 "tags": ["memory", "blocks", "user"] 55 }, 56 # { 57 # "func": update_user_blocks, 58 # "args_schema": UpdateUserBlockArgs, 59 # "description": "Update the content of user-specific memory blocks", 60 # "tags": ["memory", "blocks", "user"] 61 # }, 62] 63 64 65def register_tools(agent_name: str = "void", tools: List[str] = None): 66 """Register tools with a Letta agent. 67 68 Args: 69 agent_name: Name of the agent to attach tools to 70 tools: List of tool names to register. If None, registers all tools. 71 """ 72 try: 73 # Initialize Letta client with API key 74 client = Letta(token=os.environ["LETTA_API_KEY"]) 75 76 # Find the agent 77 agents = client.agents.list() 78 agent = None 79 for a in agents: 80 if a.name == agent_name: 81 agent = a 82 break 83 84 if not agent: 85 console.print(f"[red]Error: Agent '{agent_name}' not found[/red]") 86 console.print("\nAvailable agents:") 87 for a in agents: 88 console.print(f" - {a.name}") 89 return 90 91 # Filter tools if specific ones requested 92 tools_to_register = TOOL_CONFIGS 93 if tools: 94 tools_to_register = [t for t in TOOL_CONFIGS if t["func"].__name__ in tools] 95 if len(tools_to_register) != len(tools): 96 missing = set(tools) - {t["func"].__name__ for t in tools_to_register} 97 console.print(f"[yellow]Warning: Unknown tools: {missing}[/yellow]") 98 99 # Create results table 100 table = Table(title=f"Tool Registration for Agent '{agent_name}'") 101 table.add_column("Tool", style="cyan") 102 table.add_column("Status", style="green") 103 table.add_column("Description") 104 105 # Register each tool 106 for tool_config in tools_to_register: 107 func = tool_config["func"] 108 tool_name = func.__name__ 109 110 try: 111 # Create or update the tool using the standalone function 112 created_tool = client.tools.upsert_from_function( 113 func=func, 114 args_schema=tool_config["args_schema"], 115 tags=tool_config["tags"] 116 ) 117 118 # Get current agent tools 119 current_tools = client.agents.tools.list(agent_id=str(agent.id)) 120 tool_names = [t.name for t in current_tools] 121 122 # Check if already attached 123 if created_tool.name in tool_names: 124 table.add_row(tool_name, "Already Attached", tool_config["description"]) 125 else: 126 # Attach to agent 127 client.agents.tools.attach( 128 agent_id=str(agent.id), 129 tool_id=str(created_tool.id) 130 ) 131 table.add_row(tool_name, "✓ Attached", tool_config["description"]) 132 133 except Exception as e: 134 table.add_row(tool_name, f"✗ Error: {str(e)}", tool_config["description"]) 135 logger.error(f"Error registering tool {tool_name}: {e}") 136 137 console.print(table) 138 139 except Exception as e: 140 console.print(f"[red]Error: {str(e)}[/red]") 141 logger.error(f"Fatal error: {e}") 142 143 144def list_available_tools(): 145 """List all available tools.""" 146 table = Table(title="Available Void Tools") 147 table.add_column("Tool Name", style="cyan") 148 table.add_column("Description") 149 table.add_column("Tags", style="dim") 150 151 for tool_config in TOOL_CONFIGS: 152 table.add_row( 153 tool_config["func"].__name__, 154 tool_config["description"], 155 ", ".join(tool_config["tags"]) 156 ) 157 158 console.print(table) 159 160 161if __name__ == "__main__": 162 import argparse 163 164 parser = argparse.ArgumentParser(description="Register Void tools with a Letta agent") 165 parser.add_argument("agent", nargs="?", default="void", help="Agent name (default: void)") 166 parser.add_argument("--tools", nargs="+", help="Specific tools to register (default: all)") 167 parser.add_argument("--list", action="store_true", help="List available tools") 168 169 args = parser.parse_args() 170 171 if args.list: 172 list_available_tools() 173 else: 174 console.print(f"\n[bold]Registering tools for agent: {args.agent}[/bold]\n") 175 register_tools(args.agent, args.tools)