# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ LangGraph-compatible tools for chatbot. Wraps connectors and external services as LangGraph tools. """ import logging import json from typing import Optional from langchain_core.tools import tool logger = logging.getLogger(__name__) @tool def send_streaming_message(message: str) -> str: """Send a streaming message to the user to provide updates during processing. Use this tool to send short status updates to the user while you are working on their request. This helps keep the user informed about what you are doing. Args: message: A short German message describing what you are currently doing. Examples: "Durchsuche Datenbank nach Lampen, LED, Leuchten, und Ähnlichem." "Suche im Internet nach Produktinformationen." "Analysiere Suchergebnisse." Returns: A confirmation that the message was sent. """ # This tool doesn't actually do anything - it's just for the AI to signal # what it's doing to the frontend via the tool call mechanism return f"Status-Update gesendet: {message}" def create_sql_tool(connector_instance): """ Create a LangGraph-compatible SQL tool using a connector instance. Args: connector_instance: PreprocessorConnector or similar connector instance Returns: LangChain tool for SQL queries """ # Store connector in closure connector = connector_instance @tool async def execute_sql_query(query: str) -> str: """Execute a SQL SELECT query on the database. This tool allows you to query the database to find articles, prices, inventory levels, and other information. Args: query: A valid SQL SELECT query. Only SELECT queries are allowed. Use double quotes for column names with spaces or special characters. Example: SELECT "Artikelnummer", "Artikelbezeichnung" FROM Artikel WHERE "Artikelbezeichnung" LIKE '%Lampe%' LIMIT 20 Returns: Query results as formatted string with data rows """ try: logger.info(f"Executing SQL query via connector: {query[:100]}...") # Ensure connector is initialized if connector is None: return "Error: Database connector not initialized" # Execute query result = await connector.executeQuery(query, return_json=True) if isinstance(result, dict): # Return formatted text result text_result = result.get("text", "Query executed successfully but returned no results.") # Also include data count if available data = result.get("data", []) if data: text_result += f"\n\nFound {len(data)} row(s)." return text_result else: # Return string result directly return str(result) except Exception as e: error_msg = f"Error executing SQL query: {str(e)}" logger.error(error_msg, exc_info=True) return error_msg # Set tool metadata for better AI understanding execute_sql_query.name = "execute_sql_query" execute_sql_query.description = """Execute a SQL SELECT query on the database. Use this tool to search for articles, check prices, inventory levels, suppliers, etc. Only SELECT queries are allowed. Use double quotes for column names with spaces. Database tables: Artikel, Einkaufspreis_neu, Lagerplatz_Artikel, Lagerplatz Example queries: - SELECT "Artikelnummer", "Artikelbezeichnung" FROM Artikel WHERE "Artikelbezeichnung" LIKE '%Lampe%' - SELECT a."Artikelnummer", e."EP_CHF" FROM Artikel a LEFT JOIN Einkaufspreis_neu e ON a."I_ID" = e."ARTIKEL" - SELECT a."Artikelnummer", l."S_IST_BESTAND" FROM Artikel a LEFT JOIN Lagerplatz_Artikel l ON a."I_ID" = l."R_ARTIKEL" """ return execute_sql_query def create_tavily_tools(tavily_api_key: Optional[str] = None, enable_web_research: bool = True): """ Create Tavily search tools for web research. Args: tavily_api_key: Tavily API key (if None, tools will return error messages) enable_web_research: Whether web research is enabled Returns: List of Tavily tools (search and extract) """ tools = [] if not enable_web_research or not tavily_api_key: # Return dummy tools that explain web research is disabled @tool def tavily_search_disabled(query: str) -> str: """Web research is disabled for this chatbot instance.""" return "Web research is not enabled for this chatbot instance." @tool def tavily_extract_disabled(urls: str) -> str: """Web research is disabled for this chatbot instance.""" return "Web research is not enabled for this chatbot instance." return [tavily_search_disabled, tavily_extract_disabled] try: from langchain_tavily import TavilySearchResults, TavilyExtract # Create Tavily search tool tavily_search = TavilySearchResults( tavily_api_key=tavily_api_key, max_results=5 ) # Create Tavily extract tool tavily_extract = TavilyExtract(tavily_api_key=tavily_api_key) return [tavily_search, tavily_extract] except ImportError: logger.warning("langchain_tavily not available, creating dummy tools") @tool def tavily_search_fallback(query: str) -> str: """Tavily search tool (not available - langchain_tavily not installed).""" return "Tavily search is not available. Please install langchain_tavily package." @tool def tavily_extract_fallback(urls: str) -> str: """Tavily extract tool (not available - langchain_tavily not installed).""" return "Tavily extract is not available. Please install langchain_tavily package." return [tavily_search_fallback, tavily_extract_fallback]