"""Core configuration management.""" from __future__ import annotations from pathlib import Path from pydantic import Field from pydantic_settings import BaseSettings class MCPConfig(BaseSettings): """MCP server configuration.""" model_config = {"env_prefix": "MCP_", "env_file": ".env", "extra": "ignore"} host: str = "0.0.0.0" port: int = 3100 log_level: str = "info" max_connections: int = 100 tool_timeout: float = 30.0 class DatabaseConfig(BaseSettings): """Database configuration. Environment variable prefix: DB_ All fields map to DB_* env vars (e.g. DB_POSTGRES_URL). """ model_config = {"env_prefix": "DB_", "env_file": ".env", "extra": "ignore"} postgres_url: str = "" postgres_sync_url: str = "" redis_url: str = "" qdrant_url: str = "" qdrant_collection: str = "hermes_memory" # Async connection pool settings pool_size: int = 5 max_overflow: int = 10 pool_timeout: int = 30 pool_recycle: int = 1800 pool_pre_ping: bool = True echo_sql: bool = False class ModelConfig(BaseSettings): """LLM model configuration.""" model_config = {"env_prefix": "MODEL_", "env_file": ".env", "extra": "ignore"} provider: str = "openai" name: str = "gpt-4o" api_key: str = "" base_url: str = "" temperature: float = 0.1 max_tokens: int = 4096 embedding_model: str = "BAAI/bge-small-en-v1.5" embedding_dimension: int = 384 openrouter_api_key: str = "" openrouter_base_url: str = "https://openrouter.ai/api/v1" openrouter_site_url: str = "https://github.com/mysterious75/VGTC" openrouter_app_name: str = "VGTC Platform" class ObservabilityConfig(BaseSettings): """Observability configuration.""" model_config = {"env_prefix": "OBS_", "env_file": ".env", "extra": "ignore"} enabled: bool = True langsmith_api_key: str = "" langsmith_project: str = "hermes-platform" langsmith_endpoint: str = "https://api.smith.langchain.com" otel_endpoint: str = "http://localhost:4317" otel_service_name: str = "hermes-platform" trace_prompts: bool = True trace_tool_calls: bool = True class WorkflowConfig(BaseSettings): """Workflow engine configuration.""" model_config = {"env_prefix": "WORKFLOW_", "env_file": ".env", "extra": "ignore"} engine: str = "temporal" temporal_host: str = "localhost:7233" temporal_namespace: str = "default" checkpoint_interval: int = 300 max_retries: int = 3 timeout_seconds: int = 3600 airflow_username: str = "" airflow_password: str = "" class SecurityConfig(BaseSettings): """Security configuration.""" model_config = {"env_prefix": "SECURITY_", "env_file": ".env", "extra": "ignore"} secret_key: str = "" algorithm: str = "HS256" access_token_expire_minutes: int = 30 allowed_origins: list[str] = ["http://localhost:3000"] api_key: str = "" enable_auth: bool = True rate_limit_per_minute: int = 60 class ResearchConfig(BaseSettings): """Research agent configuration.""" model_config = {"env_prefix": "RESEARCH_", "env_file": ".env", "extra": "ignore"} max_search_results: int = 10 max_repos_to_analyze: int = 5 report_max_tokens: int = 8192 analysis_depth: str = "thorough" brave_api_key: str = "" class Settings(BaseSettings): """Main application settings.""" model_config = {"env_prefix": "HERMES_", "env_file": ".env", "extra": "ignore"} app_name: str = "Hermes Platform" debug: bool = False environment: str = "development" log_level: str = "INFO" base_dir: Path = Field(default_factory=lambda: Path(__file__).parent.parent.parent) mcp: MCPConfig = Field(default_factory=MCPConfig) database: DatabaseConfig = Field(default_factory=DatabaseConfig) model: ModelConfig = Field(default_factory=ModelConfig) observability: ObservabilityConfig = Field(default_factory=ObservabilityConfig) workflow: WorkflowConfig = Field(default_factory=WorkflowConfig) security: SecurityConfig = Field(default_factory=SecurityConfig) research: ResearchConfig = Field(default_factory=ResearchConfig) _settings: Settings | None = None def get_settings() -> Settings: """Get singleton settings instance.""" global _settings if _settings is None: _settings = Settings() return _settings def reset_settings() -> None: """Reset settings (useful for testing).""" global _settings _settings = None