Skip to main content
Glama
ImDPS
by ImDPS
__init__.py5.93 kB
""" Tools module for Gemini LLM Integration. Provides dynamic tool registration and discovery with enhanced error handling. """ import os import importlib import logging from typing import List, Callable, Any, Dict, Optional from dataclasses import dataclass logger = logging.getLogger(__name__) @dataclass class ToolDefinition: """Definition of a tool that can be registered.""" name: str description: str handler: Callable input_schema: Dict[str, Any] examples: Optional[List[str]] = None # Example queries for this tool def __post_init__(self): """Validate tool definition after initialization.""" if not self.name or not isinstance(self.name, str): raise ValueError("Tool name must be a non-empty string") if not self.description or not isinstance(self.description, str): raise ValueError("Tool description must be a non-empty string") if not callable(self.handler): raise ValueError("Tool handler must be callable") if not isinstance(self.input_schema, dict): raise ValueError("Tool input_schema must be a dictionary") class ToolRegistry: """Enhanced registry for managing and discovering tools with better error handling.""" def __init__(self): self.tools: List[ToolDefinition] = [] self._discovered = False def register_tool(self, tool_def: ToolDefinition): """Register a tool definition with validation.""" if not isinstance(tool_def, ToolDefinition): raise ValueError("tool_def must be a ToolDefinition instance") # Check for duplicate tool names existing_tool = self.get_tool(tool_def.name) if existing_tool: raise ValueError(f"Tool '{tool_def.name}' is already registered") self.tools.append(tool_def) logger.info(f"Registered tool: {tool_def.name} - {tool_def.description}") def discover_and_register_tools(self) -> List[ToolDefinition]: """Discover and register all available tools with enhanced error handling.""" if self._discovered: return self.tools try: # Get the tools directory tools_dir = os.path.dirname(__file__) if not os.path.exists(tools_dir): raise RuntimeError(f"Tools directory not found: {tools_dir}") # Discover all Python files in the tools directory discovered_count = 0 for filename in os.listdir(tools_dir): if filename.endswith('.py') and filename != '__init__.py': module_name = filename[:-3] # Remove .py extension try: # Import the module - try different import paths module = None import_paths = [ f'src.tools.{module_name}', f'tools.{module_name}', module_name ] for import_path in import_paths: try: module = importlib.import_module(import_path) break except ImportError: continue if module is None: logger.error(f"Could not import {filename} with any import path") continue # Look for register_tool function if hasattr(module, 'register_tool'): tool_def = module.register_tool() if tool_def: self.register_tool(tool_def) discovered_count += 1 logger.info(f"Successfully discovered tool: {tool_def.name}") else: logger.warning(f"No register_tool function found in {filename}") except Exception as e: logger.error(f"Failed to load tool from {filename}: {e}") continue self._discovered = True logger.info(f"Tool discovery completed. Found {discovered_count} tools out of {len(self.tools)} total.") if not self.tools: logger.warning("No tools were discovered. Check that tools exist and have register_tool() functions.") except Exception as e: logger.error(f"Error during tool discovery: {e}") raise RuntimeError(f"Tool discovery failed: {str(e)}") return self.tools def get_tool(self, name: str) -> Optional[ToolDefinition]: """Get a tool by name.""" for tool in self.tools: if tool.name == name: return tool return None def list_tools(self) -> List[str]: """List all registered tool names.""" return [tool.name for tool in self.tools] def get_tool_descriptions(self) -> Dict[str, str]: """Get a dictionary of tool names to descriptions.""" return {tool.name: tool.description for tool in self.tools} def validate_tool_call(self, tool_name: str, arguments: Dict[str, Any]) -> bool: """Validate that a tool call has the correct arguments.""" tool = self.get_tool(tool_name) if not tool: return False # Check required properties required_props = tool.input_schema.get("required", []) for prop in required_props: if prop not in arguments: return False return True

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ImDPS/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server