| """ |
| Configuration management for ARF Demo |
| Updated with REAL ARF installation detection - FIXED ENUM ERROR |
| """ |
| from typing import Optional, Dict, Any, List |
| from enum import Enum |
| import os |
| import logging |
|
|
| logger = logging.getLogger(__name__) |
|
|
| |
| 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}") |
| |
| 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 InstallationStatus(str, Enum): |
| """ARF package installation status""" |
| NOT_INSTALLED = "not_installed" |
| OSS_ONLY = "oss_only" |
| ENTERPRISE = "enterprise" |
| BOTH = "both" |
|
|
|
|
| class Settings(BaseSettings): |
| """ |
| Application settings with environment variable support |
| """ |
| |
| |
| arf_mode: str = Field( |
| default="demo", |
| description="ARF operation mode: demo, oss, enterprise" |
| ) |
| |
| use_true_arf: bool = Field( |
| default=True, |
| description="Use true ARF integration when available" |
| ) |
| |
| |
| arf_oss_installed: bool = Field( |
| default=False, |
| description="ARF OSS package installed" |
| ) |
| |
| arf_enterprise_installed: bool = Field( |
| default=False, |
| description="ARF Enterprise package installed" |
| ) |
| |
| arf_oss_version: Optional[str] = Field( |
| default=None, |
| description="ARF OSS version if installed" |
| ) |
| |
| arf_enterprise_version: Optional[str] = Field( |
| default=None, |
| description="ARF Enterprise version if installed" |
| ) |
| |
| |
| 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" |
| ) |
| |
| |
| 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" |
| ) |
| |
| |
| 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" |
| ) |
| |
| |
| 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" |
| ) |
| |
| |
| default_safety_mode: str = Field( |
| default="advisory", |
| description="Default safety mode: advisory, approval, autonomous" |
| ) |
| |
| require_approval: bool = Field( |
| default=True, |
| description="Require human approval for execution" |
| ) |
| |
| |
| @validator("arf_api_key") |
| def validate_api_key(cls, v: Optional[str], values: Dict[str, Any]) -> Optional[str]: |
| if values.get("arf_mode") == "enterprise" and not v: |
| raise ValueError("ARF API key required for Enterprise mode") |
| return v |
| |
| @validator("use_true_arf") |
| def validate_true_arf(cls, v: bool, values: Dict[str, Any]) -> bool: |
| if v and not values.get("arf_oss_installed"): |
| logger.warning("True ARF requested but OSS package not installed. Using mock mode.") |
| return False |
| return v |
| |
| |
| @classmethod |
| def detect_installation(cls): |
| """Detect ARF package installation""" |
| results = { |
| "oss_installed": False, |
| "enterprise_installed": False, |
| "oss_version": None, |
| "enterprise_version": None |
| } |
| |
| |
| try: |
| import agentic_reliability_framework as arf_oss |
| results["oss_installed"] = True |
| results["oss_version"] = getattr(arf_oss, '__version__', '3.3.7') |
| logger.info(f"✅ ARF OSS v{results['oss_version']} detected") |
| except ImportError: |
| logger.info("⚠️ ARF OSS not installed - will use mock mode") |
| |
| |
| try: |
| import arf_enterprise |
| results["enterprise_installed"] = True |
| results["enterprise_version"] = getattr(arf_enterprise, '__version__', '1.0.2') |
| logger.info(f"✅ ARF Enterprise v{results['enterprise_version']} detected") |
| except ImportError: |
| logger.info("⚠️ ARF Enterprise not installed - will use simulation") |
| |
| return results |
| |
| def get_installation_status(self) -> InstallationStatus: |
| """Get current installation status""" |
| if self.arf_oss_installed and self.arf_enterprise_installed: |
| return InstallationStatus.BOTH |
| elif self.arf_enterprise_installed: |
| return InstallationStatus.ENTERPRISE |
| elif self.arf_oss_installed: |
| return InstallationStatus.OSS_ONLY |
| else: |
| return InstallationStatus.NOT_INSTALLED |
| |
| def get_installation_badges(self) -> Dict[str, Any]: |
| """Get badge information for UI display""" |
| if self.arf_oss_installed: |
| oss_badge = { |
| "text": f"✅ ARF OSS v{self.arf_oss_version}", |
| "color": "#10b981", |
| "icon": "✅" |
| } |
| else: |
| oss_badge = { |
| "text": "⚠️ Mock ARF", |
| "color": "#f59e0b", |
| "icon": "⚠️" |
| } |
| |
| if self.arf_enterprise_installed: |
| enterprise_badge = { |
| "text": f"🚀 Enterprise v{self.arf_enterprise_version}", |
| "color": "#8b5cf6", |
| "icon": "🚀" |
| } |
| else: |
| enterprise_badge = { |
| "text": "🔒 Enterprise Required", |
| "color": "#64748b", |
| "icon": "🔒" |
| } |
| |
| return { |
| "oss": oss_badge, |
| "enterprise": enterprise_badge |
| } |
| |
| def get_installation_recommendations(self) -> List[str]: |
| """Get installation recommendations""" |
| recommendations = [] |
| |
| if not self.arf_oss_installed: |
| recommendations.append( |
| "Install real ARF OSS: `pip install agentic-reliability-framework==3.3.7`" |
| ) |
| |
| if not self.arf_enterprise_installed: |
| recommendations.append( |
| "Install ARF Enterprise: `pip install agentic-reliability-enterprise` (requires license)" |
| ) |
| |
| return recommendations |
| |
| class Config: |
| env_file = ".env" |
| env_file_encoding = "utf-8" |
| case_sensitive = False |
|
|
|
|
| |
| try: |
| |
| installation_info = Settings.detect_installation() |
| |
| |
| settings = Settings( |
| arf_oss_installed=installation_info["oss_installed"], |
| arf_enterprise_installed=installation_info["enterprise_installed"], |
| arf_oss_version=installation_info["oss_version"], |
| arf_enterprise_version=installation_info["enterprise_version"], |
| ) |
| |
| |
| status = settings.get_installation_status() |
| logger.info(f"ARF Installation Status: {status.value}") |
| |
| if status == InstallationStatus.NOT_INSTALLED: |
| logger.warning("No ARF packages installed. Demo will use mock mode.") |
| logger.warning("For real ARF experience, install: pip install agentic-reliability-framework==3.3.7") |
| |
| except Exception as e: |
| logger.warning(f"Failed to load settings: {e}, using defaults") |
| settings = Settings( |
| arf_mode="demo", |
| use_true_arf=False, |
| arf_oss_installed=False, |
| arf_enterprise_installed=False, |
| 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="advisory", |
| require_approval=True |
| ) |
|
|
|
|
| def get_settings() -> Settings: |
| """Get settings instance (singleton pattern)""" |
| return settings |
|
|
|
|
| def print_installation_status(): |
| """Print installation status to console - SAFE VERSION""" |
| try: |
| s = get_settings() |
| |
| print("=" * 70) |
| print("🚀 ARF Ultimate Investor Demo - Installation Status") |
| print("=" * 70) |
| |
| print(f"📦 ARF OSS: {'✅ v' + s.arf_oss_version if s.arf_oss_installed else '⚠️ Not installed'}") |
| print(f"🏢 Enterprise: {'✅ v' + s.arf_enterprise_version if s.arf_enterprise_installed else '⚠️ Not installed'}") |
| |
| |
| print(f"🎯 Mode: {s.arf_mode.upper()}") |
| print(f"🤖 Using True ARF: {'✅ Yes' if s.use_true_arf else '⚠️ Mock mode'}") |
| |
| recommendations = s.get_installation_recommendations() |
| if recommendations: |
| print("\n💡 Recommendations:") |
| for rec in recommendations: |
| print(f" • {rec}") |
| |
| print("=" * 70) |
| |
| except Exception as e: |
| print(f"⚠️ Could not print installation status: {e}") |
|
|
|
|
| def get_styles() -> str: |
| """Return CSS styles for ARF demo - ADDED THIS FUNCTION""" |
| return """ |
| /* ARF Demo Styles - Professional Dark Theme */ |
| :root { |
| --primary: #3b82f6; |
| --primary-dark: #1d4ed8; |
| --success: #10b981; |
| --danger: #ef4444; |
| --warning: #f59e0b; |
| --dark-bg: #0f172a; |
| --dark-card: #1e293b; |
| --dark-border: #334155; |
| --dark-text: #f8fafc; |
| --dark-muted: #94a3b8; |
| } |
| |
| /* Modern Glass Effect */ |
| .glass { |
| background: rgba(255, 255, 255, 0.05); |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| } |
| |
| /* Professional Card Styling */ |
| .arf-card { |
| border: 1px solid var(--dark-border); |
| border-radius: 14px; |
| padding: 20px; |
| background: var(--dark-card); |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); |
| transition: transform 0.2s ease, box-shadow 0.2s ease; |
| } |
| |
| .arf-card:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4); |
| } |
| |
| /* Tab Navigation */ |
| .tab-nav { |
| background: var(--dark-bg); |
| border-bottom: 2px solid var(--dark-border); |
| } |
| |
| .tab-nav .tab { |
| padding: 12px 24px; |
| font-weight: 600; |
| border-radius: 8px 8px 0 0; |
| border: 2px solid transparent; |
| border-bottom: none; |
| transition: all 0.2s ease; |
| } |
| |
| .tab-nav .tab.selected { |
| background: var(--dark-card); |
| border-color: var(--dark-border); |
| color: var(--primary); |
| } |
| |
| /* Button Styling */ |
| button { |
| border-radius: 10px !important; |
| font-weight: 600 !important; |
| transition: all 0.2s ease !important; |
| } |
| |
| button.primary { |
| background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%) !important; |
| border: none !important; |
| color: white !important; |
| } |
| |
| button.secondary { |
| background: var(--dark-card) !important; |
| border: 2px solid var(--dark-border) !important; |
| color: var(--dark-text) !important; |
| } |
| |
| button:hover { |
| transform: translateY(-1px); |
| box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3) !important; |
| } |
| |
| /* Header Gradient */ |
| .header-gradient { |
| background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); |
| border-radius: 16px; |
| box-shadow: 0 8px 32px rgba(59, 130, 246, 0.15); |
| } |
| |
| /* Status Indicators */ |
| .status-success { |
| background: linear-gradient(135deg, #10b981 0%, #059669 100%); |
| color: white; |
| padding: 4px 12px; |
| border-radius: 20px; |
| font-size: 12px; |
| font-weight: bold; |
| display: inline-flex; |
| align-items: center; |
| gap: 6px; |
| } |
| |
| .status-warning { |
| background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); |
| color: white; |
| padding: 4px 12px; |
| border-radius: 20px; |
| font-size: 12px; |
| font-weight: bold; |
| display: inline-flex; |
| align-items: center; |
| gap: 6px; |
| } |
| |
| .status-danger { |
| background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); |
| color: white; |
| padding: 4px 12px; |
| border-radius: 20px; |
| font-size: 12px; |
| font-weight: bold; |
| display: inline-flex; |
| align-items: center; |
| gap: 6px; |
| } |
| |
| /* Metric Cards */ |
| .metric-card { |
| border-left: 4px solid var(--primary); |
| border-radius: 12px; |
| padding: 18px; |
| background: var(--dark-card); |
| margin: 8px; |
| text-align: center; |
| flex: 1; |
| min-width: 140px; |
| } |
| |
| .metric-value { |
| font-size: 28px; |
| font-weight: bold; |
| color: var(--primary); |
| margin: 8px 0; |
| } |
| |
| /* Agent Cards */ |
| .agent-card { |
| border: 2px solid var(--dark-border); |
| border-radius: 14px; |
| padding: 18px; |
| background: var(--dark-card); |
| text-align: center; |
| min-height: 180px; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .agent-card.active { |
| border-color: var(--success); |
| background: rgba(16, 185, 129, 0.1); |
| } |
| |
| /* Responsive Design */ |
| @media (max-width: 768px) { |
| .arf-card { |
| padding: 15px; |
| } |
| |
| .metric-card { |
| min-width: 100%; |
| } |
| } |
| |
| /* Custom Scrollbar */ |
| ::-webkit-scrollbar { |
| width: 8px; |
| } |
| |
| ::-webkit-scrollbar-track { |
| background: var(--dark-bg); |
| } |
| |
| ::-webkit-scrollbar-thumb { |
| background: var(--dark-border); |
| border-radius: 4px; |
| } |
| |
| ::-webkit-scrollbar-thumb:hover { |
| background: var(--dark-muted); |
| } |
| """ |