From 0544001fa04c6761d35f01eb101964504bc30d90 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 25 Apr 2026 11:29:17 +0000 Subject: [PATCH] feat(config): add GRAPH_BACKEND + NEO4J_* + LLM_PROVIDER config vars --- backend/app/config.py | 29 +++++++++++++++++++--- backend/tests/test_graph_factory.py | 37 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/backend/app/config.py b/backend/app/config.py index 7dfa8246..8b06c4a4 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -33,9 +33,20 @@ class Config: LLM_BASE_URL = os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1') LLM_MODEL_NAME = os.environ.get('LLM_MODEL_NAME', 'gpt-4o-mini') - # Zep settings + # Graph backend: "zep" (default, cloud) o "graphiti" (Neo4j local) + GRAPH_BACKEND = os.environ.get('GRAPH_BACKEND', 'zep') + + # Zep Cloud ZEP_API_KEY = os.environ.get('ZEP_API_KEY') + # Graphiti + Neo4j + NEO4J_URI = os.environ.get('NEO4J_URI', 'bolt://localhost:7687') + NEO4J_USER = os.environ.get('NEO4J_USER', 'neo4j') + NEO4J_PASSWORD = os.environ.get('NEO4J_PASSWORD') + + # LLM provider ("" = OpenAI-compatible per defecte, "gemini" = Google AI Studio) + LLM_PROVIDER = os.environ.get('LLM_PROVIDER', '') + # File upload settings MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), '../uploads') @@ -64,13 +75,25 @@ class Config: REPORT_AGENT_MAX_REFLECTION_ROUNDS = int(os.environ.get('REPORT_AGENT_MAX_REFLECTION_ROUNDS', '2')) REPORT_AGENT_TEMPERATURE = float(os.environ.get('REPORT_AGENT_TEMPERATURE', '0.5')) + @classmethod + def get_graph_config_errors(cls) -> list: + errors = [] + if cls.GRAPH_BACKEND == 'zep': + if not cls.ZEP_API_KEY: + errors.append("ZEP_API_KEY is not configured (required when GRAPH_BACKEND=zep)") + elif cls.GRAPH_BACKEND == 'graphiti': + if not cls.NEO4J_PASSWORD: + errors.append("NEO4J_PASSWORD is not configured (required when GRAPH_BACKEND=graphiti)") + else: + errors.append(f"Unknown GRAPH_BACKEND value: '{cls.GRAPH_BACKEND}'. Use 'zep' or 'graphiti'.") + return errors + @classmethod def validate(cls): """Validate required configuration""" errors = [] if not cls.LLM_API_KEY: errors.append("LLM_API_KEY is not configured") - if not cls.ZEP_API_KEY: - errors.append("ZEP_API_KEY is not configured") + errors.extend(cls.get_graph_config_errors()) return errors diff --git a/backend/tests/test_graph_factory.py b/backend/tests/test_graph_factory.py index 64b6b261..eb4f0976 100644 --- a/backend/tests/test_graph_factory.py +++ b/backend/tests/test_graph_factory.py @@ -11,3 +11,40 @@ def test_graph_backend_has_required_methods(): ] for method in required: assert hasattr(GraphBackend, method), f"GraphBackend missing: {method}" + + +def test_config_graph_backend_default(): + import os + os.environ.pop("GRAPH_BACKEND", None) + import importlib + import backend.app.config as cfg_mod + importlib.reload(cfg_mod) + assert cfg_mod.Config.GRAPH_BACKEND == "zep" + + +def test_config_zep_errors_when_key_missing(): + import backend.app.config as cfg_mod + orig_backend = cfg_mod.Config.GRAPH_BACKEND + orig_key = cfg_mod.Config.ZEP_API_KEY + try: + cfg_mod.Config.GRAPH_BACKEND = "zep" + cfg_mod.Config.ZEP_API_KEY = None + errors = cfg_mod.Config.get_graph_config_errors() + assert any("ZEP_API_KEY" in e for e in errors) + finally: + cfg_mod.Config.GRAPH_BACKEND = orig_backend + cfg_mod.Config.ZEP_API_KEY = orig_key + + +def test_config_graphiti_errors_when_missing(): + import backend.app.config as cfg_mod + orig_backend = cfg_mod.Config.GRAPH_BACKEND + orig_pw = cfg_mod.Config.NEO4J_PASSWORD + try: + cfg_mod.Config.GRAPH_BACKEND = "graphiti" + cfg_mod.Config.NEO4J_PASSWORD = None + errors = cfg_mod.Config.get_graph_config_errors() + assert len(errors) >= 1 + finally: + cfg_mod.Config.GRAPH_BACKEND = orig_backend + cfg_mod.Config.NEO4J_PASSWORD = orig_pw