Spaces:
Sleeping
Sleeping
| """ | |
| SAAP Configuration Settings - Production Ready with OpenRouter Integration | |
| Environment-based configuration management for On-Premise deployment | |
| """ | |
| import os | |
| from pathlib import Path | |
| from typing import Optional, List | |
| from pydantic import Field, field_validator | |
| from pydantic_settings import BaseSettings | |
| from functools import lru_cache | |
| import logging | |
| class DatabaseSettings(BaseSettings): | |
| """Database configuration settings""" | |
| # Database URL - supports SQLite, PostgreSQL, MySQL | |
| database_url: str = Field( | |
| default="sqlite:///./saap_production.db", | |
| env="DATABASE_URL", | |
| description="Database connection URL" | |
| ) | |
| # Connection pool settings | |
| pool_size: int = Field(default=10, env="DB_POOL_SIZE") | |
| max_overflow: int = Field(default=20, env="DB_MAX_OVERFLOW") | |
| pool_timeout: int = Field(default=30, env="DB_POOL_TIMEOUT") | |
| pool_recycle: int = Field(default=3600, env="DB_POOL_RECYCLE") | |
| # SQLite specific | |
| sqlite_check_same_thread: bool = Field(default=False, env="SQLITE_CHECK_SAME_THREAD") | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields | |
| } | |
| def validate_database_url(cls, v): | |
| """Ensure database URL is properly formatted""" | |
| if not v.startswith(('sqlite:///', 'postgresql://', 'mysql://')): | |
| raise ValueError('Unsupported database type. Use sqlite, postgresql, or mysql.') | |
| return v | |
| class ColossusSettings(BaseSettings): | |
| """colossus Server configuration""" | |
| api_base: str = Field( | |
| default="https://ai.adrian-schupp.de", | |
| env="COLOSSUS_API_BASE", | |
| description="colossus server base URL" | |
| ) | |
| api_key: str = Field( | |
| default="sk-dBoxml3krytIRLdjr35Lnw", | |
| env="COLOSSUS_API_KEY", | |
| description="colossus API key" | |
| ) | |
| default_model: str = Field( | |
| default="mistral-small3.2:24b-instruct-2506", | |
| env="COLOSSUS_DEFAULT_MODEL" | |
| ) | |
| timeout: int = Field(default=60, env="COLOSSUS_TIMEOUT") | |
| max_retries: int = Field(default=3, env="COLOSSUS_MAX_RETRIES") | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields | |
| } | |
| class OpenRouterSettings(BaseSettings): | |
| """OpenRouter API configuration for cost-efficient models""" | |
| # API Configuration | |
| api_key: str = Field( | |
| default="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", | |
| env="OPENROUTER_API_KEY", | |
| description="OpenRouter API key for cost-efficient LLM access" | |
| ) | |
| base_url: str = Field( | |
| default="https://openrouter.ai/api/v1", | |
| env="OPENROUTER_BASE_URL" | |
| ) | |
| enabled: bool = Field(default=True, env="OPENROUTER_ENABLED") | |
| # Cost Optimization Settings | |
| use_cost_optimization: bool = Field(default=True, env="OPENROUTER_USE_COST_OPTIMIZATION") | |
| max_cost_per_request: float = Field(default=0.01, env="OPENROUTER_MAX_COST_PER_REQUEST") | |
| fallback_to_free: bool = Field(default=True, env="OPENROUTER_FALLBACK_TO_FREE") | |
| # Agent-Specific Model Configuration | |
| jane_model: str = Field(default="openai/gpt-4o-mini", env="JANE_ALESI_MODEL") | |
| jane_max_tokens: int = Field(default=800, env="JANE_ALESI_MAX_TOKENS") | |
| jane_temperature: float = Field(default=0.7, env="JANE_ALESI_TEMPERATURE") | |
| john_model: str = Field(default="anthropic/claude-3-haiku", env="JOHN_ALESI_MODEL") | |
| john_max_tokens: int = Field(default=1200, env="JOHN_ALESI_MAX_TOKENS") | |
| john_temperature: float = Field(default=0.5, env="JOHN_ALESI_TEMPERATURE") | |
| lara_model: str = Field(default="openai/gpt-4o-mini", env="LARA_ALESI_MODEL") | |
| lara_max_tokens: int = Field(default=1000, env="LARA_ALESI_MAX_TOKENS") | |
| lara_temperature: float = Field(default=0.3, env="LARA_ALESI_TEMPERATURE") | |
| # Free Model Fallbacks | |
| fallback_model: str = Field(default="meta-llama/llama-3.2-3b-instruct:free", env="FALLBACK_MODEL") | |
| analyst_model: str = Field(default="meta-llama/llama-3.2-3b-instruct:free", env="ANALYST_MODEL") | |
| # Cost Tracking | |
| enable_cost_tracking: bool = Field(default=True, env="ENABLE_COST_TRACKING") | |
| cost_alert_threshold: float = Field(default=5.0, env="COST_ALERT_THRESHOLD") | |
| log_performance_metrics: bool = Field(default=True, env="LOG_PERFORMANCE_METRICS") | |
| save_cost_analytics: bool = Field(default=True, env="SAVE_COST_ANALYTICS") | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" | |
| } | |
| def get_agent_model_config(self, agent_name: str) -> dict: | |
| """Get model configuration for specific agent""" | |
| configs = { | |
| "jane_alesi": { | |
| "model": self.jane_model, | |
| "max_tokens": self.jane_max_tokens, | |
| "temperature": self.jane_temperature, | |
| "cost_per_1m": 0.15 # GPT-4o-mini | |
| }, | |
| "john_alesi": { | |
| "model": self.john_model, | |
| "max_tokens": self.john_max_tokens, | |
| "temperature": self.john_temperature, | |
| "cost_per_1m": 0.25 # Claude-3-Haiku | |
| }, | |
| "lara_alesi": { | |
| "model": self.lara_model, | |
| "max_tokens": self.lara_max_tokens, | |
| "temperature": self.lara_temperature, | |
| "cost_per_1m": 0.15 # GPT-4o-mini | |
| } | |
| } | |
| return configs.get(agent_name.lower(), { | |
| "model": self.fallback_model, | |
| "max_tokens": 600, | |
| "temperature": 0.7, | |
| "cost_per_1m": 0.0 # Free model | |
| }) | |
| class RedisSettings(BaseSettings): | |
| """Redis configuration for message queuing""" | |
| host: str = Field(default="localhost", env="REDIS_HOST") | |
| port: int = Field(default=6379, env="REDIS_PORT") | |
| password: Optional[str] = Field(default=None, env="REDIS_PASSWORD") | |
| database: int = Field(default=0, env="REDIS_DB") | |
| max_connections: int = Field(default=50, env="REDIS_MAX_CONNECTIONS") | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields | |
| } | |
| class SecuritySettings(BaseSettings): | |
| """Security and authentication settings""" | |
| secret_key: str = Field( | |
| default="saap-development-secret-change-in-production", | |
| env="SECRET_KEY", | |
| min_length=32 | |
| ) | |
| # JWT Settings | |
| jwt_algorithm: str = Field(default="HS256", env="JWT_ALGORITHM") | |
| jwt_expire_minutes: int = Field(default=1440, env="JWT_EXPIRE_MINUTES") # 24 hours | |
| # API Rate limiting | |
| rate_limit_requests: int = Field(default=1000, env="RATE_LIMIT_REQUESTS") | |
| rate_limit_window: int = Field(default=3600, env="RATE_LIMIT_WINDOW") # 1 hour | |
| # CORS settings - Updated for network access | |
| allowed_origins: str = Field( | |
| default="http://localhost:5173,http://localhost:8080,http://localhost:3000,http://100.64.0.45:5173,http://100.64.0.45:8080,http://100.64.0.45:3000,http://100.64.0.45:8000", | |
| env="ALLOWED_ORIGINS" | |
| ) | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields | |
| } | |
| def parse_allowed_origins(cls, v): | |
| """Parse comma-separated origins string into list""" | |
| if isinstance(v, str): | |
| return [origin.strip() for origin in v.split(',') if origin.strip()] | |
| return v | |
| def get_allowed_origins_list(self) -> List[str]: | |
| """Get allowed origins as a list""" | |
| if isinstance(self.allowed_origins, str): | |
| return [origin.strip() for origin in self.allowed_origins.split(',') if origin.strip()] | |
| return self.allowed_origins | |
| class LoggingSettings(BaseSettings): | |
| """Enhanced logging configuration with cost tracking""" | |
| log_level: str = Field(default="INFO", env="LOG_LEVEL") | |
| log_format: str = Field( | |
| default="%(asctime)s - %(name)s - %(levelname)s - %(message)s", | |
| env="LOG_FORMAT" | |
| ) | |
| # File logging | |
| log_to_file: bool = Field(default=True, env="LOG_TO_FILE") | |
| log_file_path: str = Field(default="logs/saap.log", env="LOG_FILE_PATH") | |
| log_file_max_size: int = Field(default=10485760, env="LOG_FILE_MAX_SIZE") # 10MB | |
| log_file_backup_count: int = Field(default=5, env="LOG_FILE_BACKUP_COUNT") | |
| # Cost & Performance Logging | |
| log_cost_metrics: bool = Field(default=True, env="LOG_COST_METRICS") | |
| cost_log_path: str = Field(default="logs/saap_costs.log", env="COST_LOG_PATH") | |
| performance_log_path: str = Field(default="logs/saap_performance.log", env="PERFORMANCE_LOG_PATH") | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields | |
| } | |
| class AgentSettings(BaseSettings): | |
| """Enhanced agent-specific configuration with multi-provider support""" | |
| default_agent_timeout: int = Field(default=60, env="DEFAULT_AGENT_TIMEOUT") | |
| max_concurrent_agents: int = Field(default=10, env="MAX_CONCURRENT_AGENTS") | |
| agent_health_check_interval: int = Field(default=300, env="AGENT_HEALTH_CHECK_INTERVAL") # 5 minutes | |
| # Performance settings | |
| max_message_history: int = Field(default=1000, env="MAX_MESSAGE_HISTORY") | |
| cleanup_old_messages_days: int = Field(default=30, env="CLEANUP_OLD_MESSAGES_DAYS") | |
| # Multi-Provider Strategy | |
| primary_provider: str = Field(default="colossus", env="PRIMARY_PROVIDER") # colossus, openrouter | |
| fallback_provider: str = Field(default="openrouter", env="FALLBACK_PROVIDER") | |
| auto_fallback_on_error: bool = Field(default=True, env="AUTO_FALLBACK_ON_ERROR") | |
| fallback_timeout_threshold: int = Field(default=30, env="FALLBACK_TIMEOUT_THRESHOLD") # seconds | |
| # Cost Efficiency Targets | |
| target_response_time: float = Field(default=2.0, env="TARGET_RESPONSE_TIME") # seconds | |
| target_cost_per_request: float = Field(default=0.002, env="TARGET_COST_PER_REQUEST") # $0.002 | |
| cost_vs_speed_priority: str = Field(default="balanced", env="COST_VS_SPEED_PRIORITY") # cost, speed, balanced | |
| # Daily Cost Budgets | |
| daily_cost_budget: float = Field(default=10.0, env="DAILY_COST_BUDGET") # $10/day | |
| agent_cost_budget: float = Field(default=2.0, env="AGENT_COST_BUDGET") # $2/agent/day | |
| warning_cost_threshold: float = Field(default=0.80, env="WARNING_COST_THRESHOLD") # 80% | |
| # Model Selection Strategy | |
| use_free_models_first: bool = Field(default=False, env="USE_FREE_MODELS_FIRST") | |
| smart_model_selection: bool = Field(default=True, env="SMART_MODEL_SELECTION") | |
| cost_learning_enabled: bool = Field(default=True, env="COST_LEARNING_ENABLED") | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields | |
| } | |
| def validate_provider(cls, v): | |
| """Validate provider names""" | |
| allowed = ['colossus', 'openrouter'] | |
| if v not in allowed: | |
| raise ValueError(f'Provider must be one of: {allowed}') | |
| return v | |
| def validate_priority(cls, v): | |
| """Validate priority setting""" | |
| allowed = ['cost', 'speed', 'balanced'] | |
| if v not in allowed: | |
| raise ValueError(f'Priority must be one of: {allowed}') | |
| return v | |
| class SaapSettings(BaseSettings): | |
| """Main SAAP Application Settings with OpenRouter Integration""" | |
| # Application Info | |
| app_name: str = Field(default="SAAP - satware AI Autonomous Agent Platform", env="APP_NAME") | |
| app_version: str = Field(default="1.0.0", env="APP_VERSION") | |
| environment: str = Field(default="production", env="ENVIRONMENT") | |
| debug: bool = Field(default=False, env="DEBUG") | |
| # Server settings - Updated for network access | |
| host: str = Field(default="100.64.0.45", env="HOST") # π Changed from 0.0.0.0 | |
| port: int = Field(default=8000, env="PORT") | |
| reload: bool = Field(default=False, env="RELOAD") | |
| # Component Settings | |
| database: DatabaseSettings = DatabaseSettings() | |
| colossus: ColossusSettings = ColossusSettings() | |
| openrouter: OpenRouterSettings = OpenRouterSettings() # NEW! | |
| redis: RedisSettings = RedisSettings() | |
| security: SecuritySettings = SecuritySettings() | |
| logging: LoggingSettings = LoggingSettings() | |
| agents: AgentSettings = AgentSettings() | |
| model_config = { | |
| "env_file": ".env", | |
| "env_file_encoding": "utf-8", | |
| "case_sensitive": False, | |
| "extra": "allow" # Allow extra fields from .env that aren't explicitly defined | |
| } | |
| def validate_environment(cls, v): | |
| """Validate environment setting""" | |
| allowed_envs = ['development', 'staging', 'production', 'testing'] | |
| if v.lower() not in allowed_envs: | |
| raise ValueError(f'Environment must be one of: {allowed_envs}') | |
| return v.lower() | |
| def get_database_url(self) -> str: | |
| """Get database URL with environment-specific adjustments""" | |
| if self.environment == 'testing': | |
| return "sqlite:///./test_saap.db" | |
| elif self.environment == 'development': | |
| return "sqlite:///./saap_dev.db" | |
| else: | |
| return self.database.database_url | |
| def is_production(self) -> bool: | |
| """Check if running in production""" | |
| return self.environment == 'production' | |
| def get_cors_origins(self) -> List[str]: | |
| """Get CORS allowed origins as list""" | |
| return self.security.get_allowed_origins_list() | |
| def get_log_config(self) -> dict: | |
| """Get logging configuration for uvicorn/fastapi""" | |
| return { | |
| "version": 1, | |
| "disable_existing_loggers": False, | |
| "formatters": { | |
| "default": { | |
| "format": self.logging.log_format, | |
| }, | |
| "cost": { | |
| "format": "%(asctime)s - COST - %(message)s", | |
| }, | |
| "performance": { | |
| "format": "%(asctime)s - PERF - %(message)s", | |
| } | |
| }, | |
| "handlers": { | |
| "default": { | |
| "formatter": "default", | |
| "class": "logging.StreamHandler", | |
| "stream": "ext://sys.stdout", | |
| }, | |
| "file": { | |
| "formatter": "default", | |
| "class": "logging.handlers.RotatingFileHandler", | |
| "filename": self.logging.log_file_path, | |
| "maxBytes": self.logging.log_file_max_size, | |
| "backupCount": self.logging.log_file_backup_count, | |
| } if self.logging.log_to_file else None, | |
| "cost_file": { | |
| "formatter": "cost", | |
| "class": "logging.handlers.RotatingFileHandler", | |
| "filename": self.logging.cost_log_path, | |
| "maxBytes": self.logging.log_file_max_size, | |
| "backupCount": self.logging.log_file_backup_count, | |
| } if self.logging.log_cost_metrics else None, | |
| "performance_file": { | |
| "formatter": "performance", | |
| "class": "logging.handlers.RotatingFileHandler", | |
| "filename": self.logging.performance_log_path, | |
| "maxBytes": self.logging.log_file_max_size, | |
| "backupCount": self.logging.log_file_backup_count, | |
| } if self.logging.log_cost_metrics else None | |
| }, | |
| "loggers": { | |
| "": { | |
| "handlers": [h for h in ["default", "file"] if h], | |
| "level": self.logging.log_level, | |
| }, | |
| "saap.cost": { | |
| "handlers": [h for h in ["cost_file"] if h], | |
| "level": "INFO", | |
| "propagate": False, | |
| }, | |
| "saap.performance": { | |
| "handlers": [h for h in ["performance_file"] if h], | |
| "level": "INFO", | |
| "propagate": False, | |
| } | |
| }, | |
| } | |
| def get_openrouter_config_for_agent(self, agent_name: str) -> dict: | |
| """Get OpenRouter configuration for specific agent""" | |
| return self.openrouter.get_agent_model_config(agent_name) | |
| def get_settings() -> SaapSettings: | |
| """Get cached settings instance""" | |
| return SaapSettings() | |
| # Global settings instance | |
| settings = get_settings() | |
| # Create logs directory if needed | |
| if settings.logging.log_to_file: | |
| Path(settings.logging.log_file_path).parent.mkdir(parents=True, exist_ok=True) | |
| if settings.logging.log_cost_metrics: | |
| Path(settings.logging.cost_log_path).parent.mkdir(parents=True, exist_ok=True) | |
| Path(settings.logging.performance_log_path).parent.mkdir(parents=True, exist_ok=True) | |
| # Environment-specific logging setup | |
| def setup_logging(): | |
| """Setup logging configuration""" | |
| import logging.config | |
| log_config = settings.get_log_config() | |
| logging.config.dictConfig(log_config) | |
| logger = logging.getLogger(__name__) | |
| logger.info(f"π SAAP Configuration loaded:") | |
| logger.info(f" Environment: {settings.environment}") | |
| logger.info(f" Database: {settings.get_database_url()}") | |
| logger.info(f" colossus: {settings.colossus.api_base}") | |
| logger.info(f" OpenRouter: {settings.openrouter.enabled}") | |
| logger.info(f" Redis: {settings.redis.host}:{settings.redis.port}") | |
| logger.info(f" Debug Mode: {settings.debug}") | |
| logger.info(f"π Server Host: {settings.host}:{settings.port}") # Log the network settings | |
| logger.info(f"π CORS Origins: {settings.get_cors_origins()}") | |
| # Cost tracking logger | |
| if settings.logging.log_cost_metrics: | |
| cost_logger = logging.getLogger("saap.cost") | |
| cost_logger.info("π° Cost tracking initialized") | |
| performance_logger = logging.getLogger("saap.performance") | |
| performance_logger.info("π Performance monitoring initialized") | |
| if __name__ == "__main__": | |
| # Test configuration | |
| setup_logging() | |
| logger = logging.getLogger(__name__) | |
| logger.info("π§ͺ Configuration Test:") | |
| logger.info(f" App Name: {settings.app_name}") | |
| logger.info(f" Database URL: {settings.get_database_url()}") | |
| logger.info(f" Production Mode: {settings.is_production()}") | |
| logger.info(f" OpenRouter Enabled: {settings.openrouter.enabled}") | |
| logger.info(f"π Network Settings:") | |
| logger.info(f" Host: {settings.host}") | |
| logger.info(f" Port: {settings.port}") | |
| logger.info(f" CORS Origins: {settings.get_cors_origins()}") | |
| # Test agent model configs | |
| for agent in ['jane_alesi', 'john_alesi', 'lara_alesi']: | |
| config = settings.get_openrouter_config_for_agent(agent) | |
| logger.info(f" {agent}: {config['model']} (${config['cost_per_1m']}/1M tokens)") |