""" Configuration management for ARF Demo Updated for Pydantic v2 with pydantic-settings """ from typing import Optional, Dict, Any, List from enum import Enum import os import logging logger = logging.getLogger(__name__) # Try to import from pydantic-settings, fallback to pydantic try: from pydantic_settings import BaseSettings from pydantic import Field, validator PYDANTIC_V2 = True logger.info("Using pydantic-settings for BaseSettings") except ImportError: try: from pydantic import BaseSettings, Field, validator PYDANTIC_V2 = False logger.info("Using pydantic.BaseSettings (older version)") except ImportError as e: logger.error(f"Failed to import pydantic: {e}") # Create minimal fallback class BaseSettings: def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) class Field: @staticmethod def default(value): return value def validator(*args, **kwargs): def decorator(func): return func return decorator PYDANTIC_V2 = False class ARFMode(str, Enum): """ARF operation modes""" DEMO = "demo" OSS = "oss" ENTERPRISE = "enterprise" class SafetyMode(str, Enum): """Safety modes for execution""" ADVISORY = "advisory" APPROVAL = "approval" AUTONOMOUS = "autonomous" class Settings(BaseSettings): """ Application settings with environment variable support """ # ===== System Mode ===== arf_mode: ARFMode = Field( default=ARFMode.DEMO, description="ARF operation mode" ) use_mock_arf: bool = Field( default=True, description="Use mock ARF implementation (for demo mode)" ) # ===== ARF Configuration ===== arf_api_key: Optional[str] = Field( default=None, description="ARF API key for real integration" ) arf_base_url: str = Field( default="https://api.arf.dev", description="ARF API base URL" ) # ===== Business Configuration ===== engineer_hourly_rate: float = Field( default=150.0, description="Engineer hourly rate in USD" ) engineer_annual_cost: float = Field( default=125000.0, description="Engineer annual cost in USD" ) default_savings_rate: float = Field( default=0.82, description="Default savings rate with ARF" ) # ===== UI Configuration ===== auto_refresh_seconds: int = Field( default=30, description="Auto-refresh interval in seconds" ) max_history_items: int = Field( default=100, description="Maximum history items to display" ) # ===== Demo Configuration ===== default_scenario: str = Field( default="Cache Miss Storm", description="Default incident scenario" ) scenario_config_path: str = Field( default="config/scenarios", description="Path to scenario configuration files" ) # ===== Safety Configuration ===== default_safety_mode: SafetyMode = Field( default=SafetyMode.ADVISORY, description="Default safety mode" ) require_approval: bool = Field( default=True, description="Require human approval for execution" ) # ===== Validation ===== @validator("arf_api_key") def validate_api_key(cls, v: Optional[str], values: Dict[str, Any]) -> Optional[str]: if values.get("arf_mode") == ARFMode.ENTERPRISE and not v: raise ValueError("ARF API key required for Enterprise mode") return v @validator("use_mock_arf") def validate_mock_mode(cls, v: bool, values: Dict[str, Any]) -> bool: if values.get("arf_mode") == ARFMode.DEMO: return True return v class Config: env_file = ".env" env_file_encoding = "utf-8" case_sensitive = False use_enum_values = True # Global settings instance with fallback try: settings = Settings() except Exception as e: logger.warning(f"Failed to load settings from .env: {e}, using defaults") settings = Settings( arf_mode=ARFMode.DEMO, use_mock_arf=True, engineer_hourly_rate=150.0, engineer_annual_cost=125000.0, default_savings_rate=0.82, auto_refresh_seconds=30, max_history_items=100, default_scenario="Cache Miss Storm", scenario_config_path="config/scenarios", default_safety_mode=SafetyMode.ADVISORY, require_approval=True ) def get_settings() -> Settings: """Get settings instance (singleton pattern)""" return settings