#!/usr/bin/env python3 """ GAIA Environment Validation Script This script checks all environment variables used by the GAIA system and generates a comprehensive validation report. Usage: python validate_gaia_environment.py [--generate-env] [--verbose] Options: --generate-env Generate a .env file from .env.example if not exists --verbose Enable verbose output Example: python validate_gaia_environment.py --generate-env --verbose """ import os import sys import argparse import json import logging from pathlib import Path from datetime import datetime from typing import Dict, List, Any, Optional # Add the project root to the path sys.path.append('.') # Import the config validator from src.gaia.utils.config_validator import ( validate_config, generate_env_example, initialize_env_from_example, get_documentation, REQUIRED_ENV_VARS, OPTIONAL_ENV_VARS ) # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger("gaia.env_validator") def parse_args(): """Parse command line arguments.""" parser = argparse.ArgumentParser(description="Validate GAIA environment configuration") parser.add_argument("--generate-env", action="store_true", help="Generate a .env file from .env.example if not exists") parser.add_argument("--verbose", action="store_true", help="Enable verbose output") return parser.parse_args() def generate_markdown_report(validation_result: Dict[str, Any]) -> str: """ Generate a comprehensive Markdown report of the validation results. Args: validation_result: Result from validate_config() Returns: Markdown report as string """ config = validation_result["config"] errors = validation_result["errors"] warnings = validation_result["warnings"] # Start with report header report = f"# GAIA Environment Configuration Report\n\n" report += f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n" # Overall status if validation_result["valid"]: report += "## ✅ Configuration Status: VALID\n\n" else: report += "## ❌ Configuration Status: INVALID\n\n" report += f"Found {len(errors)} error(s) in configuration.\n\n" # Add errors section if there are any if errors: report += "## Errors\n\n" report += "The following errors must be fixed for the GAIA system to function properly:\n\n" for error in errors: report += f"- {error}\n" report += "\n" # Add warnings section if there are any if warnings: report += "## Warnings\n\n" report += "The following warnings should be reviewed but don't prevent the system from functioning:\n\n" for warning in warnings: report += f"- {warning}\n" report += "\n" # Required environment variables report += "## Required Environment Variables\n\n" report += "| Variable | Status | Description |\n" report += "|----------|--------|-------------|\n" for var in REQUIRED_ENV_VARS: var_name = var["name"] is_set = var_name in os.environ and os.environ[var_name] != "" var_error = None for error in errors: if var_name in error: var_error = error.split(": ", 1)[1] if ": " in error else error break status = "✅ Set" if is_set and not var_error else "❌ Missing or Invalid" if var_error: status += f" - {var_error}" # Mask sensitive values for security value = os.environ.get(var_name, "") if value and ("KEY" in var_name or "TOKEN" in var_name): value = value[:4] + "****" + value[-4:] if len(value) > 8 else "****" report += f"| {var_name} | {status} | {var['description']} |\n" # Optional environment variables report += "\n## Optional Environment Variables\n\n" report += "| Variable | Status | Description | Default |\n" report += "|----------|--------|-------------|--------|\n" for var in OPTIONAL_ENV_VARS: var_name = var["name"] is_set = var_name in os.environ and os.environ[var_name] != "" default = var["default"] var_error = None for error in errors: if var_name in error: var_error = error.split(": ", 1)[1] if ": " in error else error break if is_set: status = "✅ Custom" if not var_error else f"❌ Invalid - {var_error}" else: status = "⚠️ Using Default" # Mask sensitive values for security value = os.environ.get(var_name, default) if value and ("KEY" in var_name or "TOKEN" in var_name): value = value[:4] + "****" + value[-4:] if len(value) > 8 else "****" report += f"| {var_name} | {status} | {var['description']} | {default} |\n" # Configuration sections report += "\n## Configuration Sections\n\n" # Model settings report += "### Model Settings\n\n" report += f"- **Default Model:** {config.get('DEFAULT_MODEL', 'Not set')}\n" report += f"- **Fallback Model:** {config.get('FALLBACK_MODEL', 'Not set')}\n" report += f"- **Embedding Model:** {config.get('EMBEDDING_MODEL', 'Not set')}\n" report += f"- **Model Temperature:** {config.get('MODEL_TEMPERATURE', 'Not set')}\n" report += f"- **Model Max Tokens:** {config.get('MODEL_MAX_TOKENS', 'Not set')}\n" # Memory settings report += "\n### Memory Settings\n\n" report += f"- **Memory Enabled:** {config.get('MEMORY_ENABLED', 'Not set')}\n" report += f"- **Memory Table Name:** {config.get('MEMORY_TABLE_NAME', 'Not set')}\n" report += f"- **Memory TTL:** {config.get('MEMORY_TTL', 'Not set')} seconds\n" report += f"- **Memory Cache Size:** {config.get('MEMORY_CACHE_SIZE', 'Not set')}\n" # Web search settings report += "\n### Web Search Settings\n\n" report += f"- **Web Search Result Count:** {config.get('WEB_SEARCH_RESULT_COUNT', 'Not set')}\n" report += f"- **DuckDuckGo Timeout:** {config.get('DUCKDUCKGO_TIMEOUT', 'Not set')} seconds\n" report += f"- **DuckDuckGo Max Results:** {config.get('DUCKDUCKGO_MAX_RESULTS', 'Not set')}\n" # System settings report += "\n### System Settings\n\n" report += f"- **Max Iterations:** {config.get('MAX_ITERATIONS', 'Not set')}\n" report += f"- **Verbose:** {config.get('VERBOSE', 'Not set')}\n" report += f"- **Log Level:** {config.get('LOG_LEVEL', 'Not set')}\n" # Next steps report += "\n## Next Steps\n\n" if validation_result["valid"]: report += "Your GAIA environment configuration is valid. You can proceed with running the system.\n\n" else: report += "Please fix the errors listed above, then run this validation script again.\n\n" report += "To fix these issues:\n\n" report += "1. Edit your `.env` file and add/update the required variables\n" report += "2. Run this script again to verify your changes\n\n" report += "You can also regenerate a template `.env.example` file by running:\n\n" report += "```bash\n" report += "python -c \"from src.gaia.utils.config_validator import generate_env_example; generate_env_example()\"\n" report += "```\n" return report def save_report(report: str, output_path: str = "environment_report.md") -> str: """ Save the validation report to a file. Args: report: Markdown report to save output_path: Path to the output file Returns: Path to the saved report """ with open(output_path, "w") as f: f.write(report) logger.info(f"Saved environment validation report to {output_path}") return output_path def main(): """Main function.""" args = parse_args() if args.verbose: logger.setLevel(logging.DEBUG) logger.debug("Verbose logging enabled") logger.info("Starting GAIA environment validation") # Generate .env file if requested if args.generate_env: initialize_env_from_example() # Validate the configuration validation_result = validate_config() # Generate and save the report report = generate_markdown_report(validation_result) report_path = save_report(report) # Print summary to console if validation_result["valid"]: logger.info("✅ Environment configuration is valid!") else: logger.error(f"❌ Environment configuration has {len(validation_result['errors'])} errors!") for error in validation_result["errors"]: logger.error(f" - {error}") if validation_result["warnings"]: logger.warning(f"⚠️ Environment configuration has {len(validation_result['warnings'])} warnings:") for warning in validation_result["warnings"]: logger.warning(f" - {warning}") logger.info(f"See the full report at: {report_path}") if __name__ == "__main__": main()