""" Main entry point for the Sales Assistant application. This file serves as the primary interface to run the sales assistant agent. It uses the agent runner from agent_main/agent_runner.py to create and manage the conversational agent with database exploration capabilities. """ import os import sys from typing import Optional from dotenv import load_dotenv # Add the src directory to the path so we can import from sales_assistant sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) from sales_assistant.agent_main.agent_runner import ( ConversationConfig, run_interactive_loop, create_agent_runner, run_conversation_turn ) from sales_assistant.agent_main.tools_node import get_all_tools # Load environment variables load_dotenv() def check_environment_setup() -> bool: """ Check if the environment is properly set up for the agent. Returns: True if environment is properly configured, False otherwise """ required_vars = [ "OPENAI_API_KEY", "MODEL_PROVIDER", "MODEL_NAME", "MYSQL_HOST", "MYSQL_USER", "MYSQL_PASSWORD", "MYSQL_DB" ] missing_vars = [var for var in required_vars if not os.getenv(var)] if missing_vars: print("โŒ Missing required environment variables:") for var in missing_vars: print(f" - {var}") print("\n๐Ÿ’ก Please set these variables in your .env file") return False print("โœ… Environment configuration looks good!") return True def display_available_tools() -> None: """Display available tools information.""" try: tools = get_all_tools() print("\n๐Ÿ› ๏ธ Available Tools:") print("-" * 30) for i, tool in enumerate(tools, 1): tool_name = getattr(tool, 'name', 'Unknown Tool') tool_description = getattr(tool, 'description', 'No description available') print(f"{i}. {tool_name}") print(f" ๐Ÿ“ {tool_description}") print(f"\n๐Ÿ“Š Total tools available: {len(tools)}") print("-" * 30) except Exception as e: print(f"โš ๏ธ Could not load tools information: {e}") def create_custom_config( session_id: Optional[str] = None, user_id: Optional[str] = None, enable_langsmith: bool = True, recursion_limit: int = int(os.getenv("LANGRAPH_RECURSION_LIMIT", "100")) ) -> ConversationConfig: """ Create a custom configuration for the agent. Args: session_id: Optional custom session ID user_id: Optional user identifier enable_langsmith: Whether to enable LangSmith tracing recursion_limit: Maximum recursion limit for LangGraph Returns: ConversationConfig object """ config = ConversationConfig( enable_langsmith=enable_langsmith, langsmith_project=os.getenv("LANGSMITH_PROJECT", "sales-assistant-prod"), recursion_limit=recursion_limit ) if session_id: config.session_id = session_id if user_id: config.user_id = user_id return config def run_sales_assistant( interactive: bool = True, custom_config: Optional[ConversationConfig] = None ) -> None: """ Main function to run the sales assistant. Args: interactive: Whether to run in interactive mode custom_config: Optional custom configuration """ print("๐Ÿš€ Starting Sales Assistant...") # Check environment setup if not check_environment_setup(): return # Display available tools display_available_tools() try: if interactive: print("\n๐Ÿ’ฌ Starting interactive mode...") config = custom_config or ConversationConfig() run_interactive_loop(config) else: print("\nโš™๏ธ Agent initialized and ready for programmatic use") config = custom_config or ConversationConfig() compiled_graph, checkpointer, callback_manager, thread_id = create_agent_runner(config) print(f"๐Ÿ“Š Session ID: {config.session_id}") print(f"๐Ÿงต Thread ID: {thread_id}") print("๐Ÿ’ก Use the returned objects to run conversations programmatically") return compiled_graph, checkpointer, callback_manager, thread_id except KeyboardInterrupt: print("\n๐Ÿ‘‹ Sales Assistant stopped by user") except Exception as e: print(f"โŒ Error running Sales Assistant: {str(e)}") sys.exit(1) def single_query(query: str, config: Optional[ConversationConfig] = None) -> str: """ Run a single query against the agent without interactive mode. Args: query: The question to ask the agent config: Optional configuration Returns: Agent's response """ if not check_environment_setup(): return "Environment not properly configured" try: config = config or ConversationConfig() compiled_graph, checkpointer, callback_manager, thread_id = create_agent_runner(config) response = run_conversation_turn( compiled_graph, thread_id, query, callback_manager ) return response except Exception as e: return f"Error processing query: {str(e)}" def main(): """ Main entry point when running the script directly. """ import argparse parser = argparse.ArgumentParser( description="Sales Assistant - Database-powered product inquiry agent" ) parser.add_argument( "--mode", choices=["interactive", "single"], default="interactive", help="Mode to run the assistant in" ) parser.add_argument( "--query", type=str, help="Single query to run (only for single mode)" ) parser.add_argument( "--no-langsmith", action="store_true", help="Disable LangSmith tracing" ) parser.add_argument( "--session-id", type=str, help="Custom session ID" ) parser.add_argument( "--user-id", type=str, help="User identifier" ) args = parser.parse_args() # Create configuration config = create_custom_config( session_id=args.session_id, user_id=args.user_id, enable_langsmith=not args.no_langsmith ) if args.mode == "single": if not args.query: print("โŒ --query is required for single mode") sys.exit(1) print(f"๐Ÿ” Processing query: {args.query}") response = single_query(args.query, config) print(f"๐Ÿค– Response: {response}") else: # interactive mode run_sales_assistant(interactive=True, custom_config=config) if __name__ == "__main__": main()