File size: 9,259 Bytes
c922f8b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#!/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()