krinya's picture
chore: commit all local changes
1b8e582
Raw
History Blame Contribute Delete
3.57 kB
"""
Tools node using state-of-the-art patterns with Pydantic validation.
"""
import os
from typing import List, Optional
from langchain_core.tools import BaseTool
from langgraph.prebuilt import ToolNode
from pydantic import BaseModel, Field, validator
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Import tools with proper schemas
from ..agent_tools.execute_sql_query import execute_sql_query
from ..agent_tools.get_exchange_rates import exchange_converter
from ..agent_tools.create_quote import create_quote
from ..agent_tools.tavily_search_tool import tavily_search_product_specs
from ..agent_tools.tavily_web_extract_tool import tavily_extract_product_content
class ToolConfig(BaseModel):
"""Configuration for tools with validation."""
enable_advanced_tools: bool = Field(default=False, description="Enable advanced database tools")
max_tools: int = Field(default=10, ge=1, le=50, description="Maximum number of tools to load")
model_name: str = Field(default_factory=lambda: os.getenv("MODEL_NAME", "gpt-4o-mini"), description="Model optimized for these tools")
@validator('model_name')
def validate_model_name(cls, v):
allowed_models = ["gpt-5-mini", "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo"]
if v not in allowed_models:
raise ValueError(f"Model must be one of {allowed_models}")
return v
class ToolRegistry(BaseModel):
"""Registry for validated tools."""
tools: List[BaseTool] = Field(description="List of validated tools")
config: ToolConfig = Field(description="Tool configuration")
class Config:
arbitrary_types_allowed = True
@validator('tools')
def validate_tools(cls, v):
"""Validate that all tools have proper schemas."""
for tool in v:
if not hasattr(tool, 'args_schema'):
raise ValueError(f"Tool {tool.name} missing args_schema for validation")
if not hasattr(tool, 'name') or not tool.name:
raise ValueError("Tool missing required name attribute")
return v
def get_all_tools(config: Optional[ToolConfig] = None) -> List[BaseTool]:
"""
Get gpt-5-mini optimized tools with proper validation.
Args:
config: Optional tool configuration with validation
Returns:
List of validated tools
"""
if config is None:
config = ToolConfig()
# Core tools with Pydantic schemas for LangGraph
core_tools = [
execute_sql_query,
exchange_converter,
create_quote,
tavily_search_product_specs,
tavily_extract_product_content
]
# Create registry with validation
registry = ToolRegistry(tools=core_tools, config=config)
return registry.tools[:config.max_tools]
def create_tool_node(config: Optional[ToolConfig] = None) -> ToolNode:
"""Create a validated tool node with LangGraph built-in error handling."""
tools = get_all_tools(config)
# LangGraph ToolNode handles validation, execution, and error handling automatically
return ToolNode(tools)
# Factory function with LangGraph best practices
def create_optimized_tool_node() -> ToolNode:
"""Create tool node optimized for the configured model from environment."""
config = ToolConfig(
enable_advanced_tools=True,
max_tools=20,
model_name=os.getenv("MODEL_NAME", "gpt-5-mini")
)
return create_tool_node(config)
# Use the optimized factory for production
tool_node = create_optimized_tool_node()