Source code for tooluniverse.tool_defaults

"""
Tool Defaults Configuration

This module provides structured default configurations for tool metadata,
including MCP annotations and future extensible fields.

Design Principles:
- Python code for efficiency (no runtime file I/O)
- Structured dataclass for type safety and extensibility
- Multi-level override system (default → type → category → tool)
- Same level as default_config.py in the module hierarchy
"""

from dataclasses import dataclass, field
from typing import Dict, Optional
import os

# =============================================================================
# MCP Tool Annotations Defaults
# =============================================================================


[docs] @dataclass class ToolAnnotations: """ Tool annotation values for MCP protocol. Attributes ---------- readOnlyHint : bool Whether the tool only reads data (default: True for database queries) destructiveHint : bool Whether the tool may modify/delete data (default: False) """ readOnlyHint: bool = True destructiveHint: bool = False
# Future extensibility: # idempotentHint: bool = True # openWorldHint: bool = False # ============================================================================= # Tool Defaults Configuration # =============================================================================
[docs] @dataclass class ToolDefaultsConfig: """ Structured configuration for tool defaults. Supports multi-level overrides: 1. default_annotations: Base defaults for all tools 2. tool_type_overrides: Override by tool class type (e.g., "AgenticTool") 3. category_overrides: Override by tool category (e.g., "agents") Tool-specific overrides are handled via tool_config fields. """ # Default annotations for all tools default_annotations: ToolAnnotations = field(default_factory=ToolAnnotations) # Override by tool type (e.g., "AgenticTool", "ComposeTool", "PackageTool") tool_type_overrides: Dict[str, ToolAnnotations] = field(default_factory=dict) # Override by category (e.g., "agents", "compose") category_overrides: Dict[str, ToolAnnotations] = field(default_factory=dict)
# ============================================================================= # Global Configuration Instance # ============================================================================= TOOL_DEFAULTS = ToolDefaultsConfig( # Base defaults: most tools are read-only database queries default_annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False), # Tool type overrides tool_type_overrides={ "ComposeTool": ToolAnnotations( readOnlyHint=False, destructiveHint=False, # Composition tools may modify state ), "PythonCodeExecutor": ToolAnnotations( readOnlyHint=False, destructiveHint=True, # Code execution may have side effects ), }, # Category overrides category_overrides={ "compose": ToolAnnotations( readOnlyHint=False, destructiveHint=False, ), "python_executor": ToolAnnotations( readOnlyHint=False, destructiveHint=True, ), }, ) # ============================================================================= # Public API Functions # =============================================================================
[docs] def get_tool_defaults() -> ToolDefaultsConfig: """ Get the tool defaults configuration. Returns ------- ToolDefaultsConfig Structured configuration with defaults and overrides """ return TOOL_DEFAULTS
[docs] def get_default_annotations() -> Dict[str, bool]: """ Get default tool annotations as a dictionary. Returns ------- dict Dictionary with readOnlyHint and destructiveHint """ default = TOOL_DEFAULTS.default_annotations return { "readOnlyHint": default.readOnlyHint, "destructiveHint": default.destructiveHint, }
[docs] def get_annotations_for_tool( tool_type: Optional[str] = None, category: Optional[str] = None, tool_config: Optional[Dict] = None, update_config: bool = False, ) -> Dict[str, bool]: """ Get annotations for a specific tool with multi-level override support. If tool_config is provided, tool_type and category will be automatically extracted from it if not explicitly provided. Category will also be derived from source_file if not present. Override priority (highest to lowest): 1. tool_config.mcp_annotations or tool_config.readOnlyHint/destructiveHint 2. category_overrides[category] 3. tool_type_overrides[tool_type] 4. default_annotations Parameters ---------- tool_type : str, optional Tool class type (e.g., "AgenticTool"). If None and tool_config provided, will be extracted from tool_config["type"] category : str, optional Tool category (e.g., "agents"). If None and tool_config provided, will be derived from tool_config tool_config : dict, optional Tool configuration with potential overrides. If provided, tool_type and category will be auto-extracted if not explicitly provided. update_config : bool, default False If True and tool_config is provided, will update tool_config["mcp_annotations"] in-place with the computed annotations. Returns ------- dict Dictionary with readOnlyHint and destructiveHint """ config = TOOL_DEFAULTS # Auto-extract from tool_config if provided if tool_config: if tool_type is None: tool_type = tool_config.get("type") if category is None: category = tool_config.get("category") or _derive_category_from_config( tool_config ) # Start with defaults annotations = { "readOnlyHint": config.default_annotations.readOnlyHint, "destructiveHint": config.default_annotations.destructiveHint, } # Apply tool type override if tool_type and tool_type in config.tool_type_overrides: override = config.tool_type_overrides[tool_type] annotations["readOnlyHint"] = override.readOnlyHint annotations["destructiveHint"] = override.destructiveHint # Apply category override (higher priority than type) if category and category in config.category_overrides: override = config.category_overrides[category] annotations["readOnlyHint"] = override.readOnlyHint annotations["destructiveHint"] = override.destructiveHint # Apply tool-specific override (highest priority) if tool_config: if "mcp_annotations" in tool_config: tool_override = tool_config["mcp_annotations"] if "readOnlyHint" in tool_override: annotations["readOnlyHint"] = tool_override["readOnlyHint"] if "destructiveHint" in tool_override: annotations["destructiveHint"] = tool_override["destructiveHint"] # Also support top-level fields if "readOnlyHint" in tool_config: annotations["readOnlyHint"] = tool_config["readOnlyHint"] if "destructiveHint" in tool_config: annotations["destructiveHint"] = tool_config["destructiveHint"] # Update config if requested if update_config and tool_config: tool_config["mcp_annotations"] = annotations return annotations
[docs] def _derive_category_from_config(tool_config: Dict) -> Optional[str]: """ Derive category from tool config by looking up in default_config. Since tools are only loaded if they exist in default_config.default_tool_files, we can directly look up the category from there by matching the source_file path. Parameters ---------- tool_config : dict Tool configuration dictionary Returns ------- str or None Category name if found in default_config, None otherwise """ # First check explicit category in config category = tool_config.get("category") if category: return category # Look up category from default_config.default_tool_files source_file = tool_config.get("source_file", "") if source_file: from .default_config import default_tool_files # Normalize the source_file path for comparison source_file_normalized = os.path.normpath(source_file) # Search for matching file path in default_tool_files for cat_name, file_path in default_tool_files.items(): file_path_normalized = os.path.normpath(file_path) # Match by full path or just filename if source_file_normalized == file_path_normalized or os.path.basename( source_file_normalized ) == os.path.basename(file_path_normalized): return cat_name return None
[docs] def add_annotations_to_tool_config(tool_config: Dict) -> Dict: """ Add MCP annotations to a tool config in-place. This is a convenience wrapper around get_annotations_for_tool with update_config=True. Parameters ---------- tool_config : dict Tool configuration dictionary (will be modified in-place) Returns ------- dict The same tool_config dictionary with annotations added """ get_annotations_for_tool(tool_config=tool_config, update_config=True) return tool_config