diff --git a/core/src/agentforge_core/config.py b/core/src/agentforge_core/config.py new file mode 100644 index 0000000..996bf5b --- /dev/null +++ b/core/src/agentforge_core/config.py @@ -0,0 +1,50 @@ +"""Configuración global del core. Se carga desde variables de entorno (.env).""" + +from __future__ import annotations + +from pathlib import Path +from typing import Literal + +from pydantic import Field +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + """Settings tipadas. Pydantic falla en arranque si una requerida no está.""" + + model_config = SettingsConfigDict( + env_file=".env", + env_file_encoding="utf-8", + case_sensitive=False, + extra="ignore", + ) + + # LLM + llm_provider: Literal["mock", "azure", "openai"] = "mock" + llm_fallback_provider: Literal["mock", "azure", "openai", ""] = "" + + # Azure OpenAI + azure_openai_endpoint: str = "" + azure_openai_api_key: str = "" + azure_openai_deployment: str = "" + azure_openai_api_version: str = "2024-08-01-preview" + + # OpenAI + openai_api_key: str = "" + openai_model: str = "gpt-4o" + + # Guardrails + guardrails_nemo_enabled: bool = False + + # Observabilidad + log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO" + + # Persistencia + data_dir: Path = Field(default=Path("./data")) + agents_dir: Path = Field(default=Path("./agents")) + policies_dir: Path = Field(default=Path("./policies")) + + +def get_settings() -> Settings: + """Helper para inyección por dependencia en FastAPI.""" + return Settings() diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py new file mode 100644 index 0000000..03e270d --- /dev/null +++ b/tests/unit/test_config.py @@ -0,0 +1,21 @@ +"""Tests de configuración.""" + +import os +from pathlib import Path +from unittest.mock import patch + +from agentforge_core.config import Settings + + +def test_settings_defaults_seguros() -> None: + with patch.dict(os.environ, {}, clear=True): + s = Settings(_env_file=None) # type: ignore[call-arg] + assert s.llm_provider == "mock" + assert s.guardrails_nemo_enabled is False + assert s.log_level == "INFO" + + +def test_settings_data_dir_se_resuelve() -> None: + with patch.dict(os.environ, {"DATA_DIR": "/tmp/agentforge-test"}, clear=True): + s = Settings(_env_file=None) # type: ignore[call-arg] + assert s.data_dir == Path("/tmp/agentforge-test")