Skip to content

Commit 97c52a9

Browse files
committed
Add ConfigManager for unified configuration management
- Introduced a new `config_manager.py` module to handle reading and writing configurations from `config.yml` and `.env` files, ensuring backward compatibility. - Refactored `ChronicleSetup` in `backends/advanced/init.py` to utilize `ConfigManager` for loading and updating configurations, simplifying the setup process. - Removed redundant methods for loading and saving `config.yml` directly in `ChronicleSetup`, as these are now managed by `ConfigManager`. - Enhanced user feedback during configuration updates, including success messages for changes made to configuration files.
1 parent dafe563 commit 97c52a9

File tree

2 files changed

+383
-67
lines changed

2 files changed

+383
-67
lines changed

backends/advanced/init.py

Lines changed: 35 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,27 @@ def __init__(self, args=None):
2828
self.console = Console()
2929
self.config: Dict[str, Any] = {}
3030
self.args = args or argparse.Namespace()
31-
self.config_yml_path = Path("../../config.yml") # Repo root config.yml
32-
self.config_yml_data = None
3331

3432
# Check if we're in the right directory
3533
if not Path("pyproject.toml").exists() or not Path("src").exists():
3634
self.console.print("[red][ERROR][/red] Please run this script from the backends/advanced directory")
3735
sys.exit(1)
3836

39-
# Load config.yml if it exists
40-
self.load_config_yml()
37+
# Initialize ConfigManager
38+
repo_root = Path.cwd().parent.parent # backends/advanced -> repo root
39+
if str(repo_root) not in sys.path:
40+
sys.path.insert(0, str(repo_root))
41+
42+
from config_manager import ConfigManager
43+
44+
self.config_manager = ConfigManager(service_path="backends/advanced")
45+
self.console.print(f"[blue][INFO][/blue] Using config.yml at: {self.config_manager.config_yml_path}")
46+
47+
# Load existing config or create default structure
48+
self.config_yml_data = self.config_manager.get_full_config()
49+
if not self.config_yml_data:
50+
self.console.print("[yellow][WARNING][/yellow] config.yml not found, will create default structure")
51+
self.config_yml_data = self._get_default_config_structure()
4152

4253
def print_header(self, title: str):
4354
"""Print a colorful header"""
@@ -126,21 +137,6 @@ def mask_api_key(self, key: str, show_chars: int = 5) -> str:
126137

127138
return f"{key_clean[:show_chars]}{'*' * min(15, len(key_clean) - show_chars * 2)}{key_clean[-show_chars:]}"
128139

129-
def load_config_yml(self):
130-
"""Load config.yml from repository root"""
131-
if not self.config_yml_path.exists():
132-
self.console.print(f"[yellow][WARNING][/yellow] config.yml not found at {self.config_yml_path}")
133-
self.console.print("[yellow]Will create a new config.yml during setup[/yellow]")
134-
self.config_yml_data = self._get_default_config_structure()
135-
return
136-
137-
try:
138-
with open(self.config_yml_path, 'r') as f:
139-
self.config_yml_data = yaml.safe_load(f)
140-
self.console.print(f"[blue][INFO][/blue] Loaded existing config.yml")
141-
except Exception as e:
142-
self.console.print(f"[red][ERROR][/red] Failed to load config.yml: {e}")
143-
self.config_yml_data = self._get_default_config_structure()
144140

145141
def _get_default_config_structure(self) -> Dict[str, Any]:
146142
"""Return default config.yml structure if file doesn't exist"""
@@ -163,36 +159,6 @@ def _get_default_config_structure(self) -> Dict[str, Any]:
163159
}
164160
}
165161

166-
def save_config_yml(self):
167-
"""Save config.yml back to repository root"""
168-
try:
169-
# Backup existing config.yml if it exists
170-
if self.config_yml_path.exists():
171-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
172-
backup_path = self.config_yml_path.parent / f"config.yml.backup.{timestamp}"
173-
shutil.copy2(self.config_yml_path, backup_path)
174-
self.console.print(f"[blue][INFO][/blue] Backed up config.yml to {backup_path.name}")
175-
176-
# Write updated config
177-
with open(self.config_yml_path, 'w') as f:
178-
yaml.dump(self.config_yml_data, f, default_flow_style=False, sort_keys=False)
179-
180-
self.console.print("[green][SUCCESS][/green] config.yml updated successfully")
181-
except Exception as e:
182-
self.console.print(f"[red][ERROR][/red] Failed to save config.yml: {e}")
183-
raise
184-
185-
def update_config_default(self, key: str, value: str):
186-
"""Update a default value in config.yml"""
187-
if "defaults" not in self.config_yml_data:
188-
self.config_yml_data["defaults"] = {}
189-
self.config_yml_data["defaults"][key] = value
190-
191-
def update_memory_config(self, updates: Dict[str, Any]):
192-
"""Update memory configuration in config.yml"""
193-
if "memory" not in self.config_yml_data:
194-
self.config_yml_data["memory"] = {}
195-
self.config_yml_data["memory"].update(updates)
196162

197163
def setup_authentication(self):
198164
"""Configure authentication settings"""
@@ -306,8 +272,8 @@ def setup_llm(self):
306272
if api_key:
307273
self.config["OPENAI_API_KEY"] = api_key
308274
# Update config.yml to use OpenAI models
309-
self.update_config_default("llm", "openai-llm")
310-
self.update_config_default("embedding", "openai-embed")
275+
self.config_manager.update_config_defaults({"llm": "openai-llm", "embedding": "openai-embed"})
276+
self.config_yml_data = self.config_manager.get_full_config() # Reload to stay in sync
311277
self.console.print("[green][SUCCESS][/green] OpenAI configured in config.yml")
312278
self.console.print("[blue][INFO][/blue] Set defaults.llm: openai-llm")
313279
self.console.print("[blue][INFO][/blue] Set defaults.embedding: openai-embed")
@@ -317,8 +283,8 @@ def setup_llm(self):
317283
elif choice == "2":
318284
self.console.print("[blue][INFO][/blue] Ollama selected")
319285
# Update config.yml to use Ollama models
320-
self.update_config_default("llm", "local-llm")
321-
self.update_config_default("embedding", "local-embed")
286+
self.config_manager.update_config_defaults({"llm": "local-llm", "embedding": "local-embed"})
287+
self.config_yml_data = self.config_manager.get_full_config() # Reload to stay in sync
322288
self.console.print("[green][SUCCESS][/green] Ollama configured in config.yml")
323289
self.console.print("[blue][INFO][/blue] Set defaults.llm: local-llm")
324290
self.console.print("[blue][INFO][/blue] Set defaults.embedding: local-embed")
@@ -327,7 +293,8 @@ def setup_llm(self):
327293
elif choice == "3":
328294
self.console.print("[blue][INFO][/blue] Skipping LLM setup - memory extraction disabled")
329295
# Disable memory extraction in config.yml
330-
self.update_memory_config({"extraction": {"enabled": False}})
296+
self.config_manager.update_memory_config({"extraction": {"enabled": False}})
297+
self.config_yml_data = self.config_manager.get_full_config() # Reload to stay in sync
331298

332299
def setup_memory(self):
333300
"""Configure memory provider - updates config.yml"""
@@ -347,9 +314,10 @@ def setup_memory(self):
347314
qdrant_url = self.prompt_value("Qdrant URL", "qdrant")
348315
self.config["QDRANT_BASE_URL"] = qdrant_url
349316

350-
# Update config.yml
351-
self.update_memory_config({"provider": "chronicle"})
352-
self.console.print("[green][SUCCESS][/green] Chronicle memory provider configured in config.yml")
317+
# Update config.yml (also updates .env automatically)
318+
self.config_manager.update_memory_config({"provider": "chronicle"})
319+
self.config_yml_data = self.config_manager.get_full_config() # Reload to stay in sync
320+
self.console.print("[green][SUCCESS][/green] Chronicle memory provider configured in config.yml and .env")
353321

354322
elif choice == "2":
355323
self.console.print("[blue][INFO][/blue] OpenMemory MCP selected")
@@ -359,8 +327,8 @@ def setup_memory(self):
359327
user_id = self.prompt_value("OpenMemory user ID", "openmemory")
360328
timeout = self.prompt_value("OpenMemory timeout (seconds)", "30")
361329

362-
# Update config.yml with OpenMemory MCP settings
363-
self.update_memory_config({
330+
# Update config.yml with OpenMemory MCP settings (also updates .env automatically)
331+
self.config_manager.update_memory_config({
364332
"provider": "openmemory_mcp",
365333
"openmemory_mcp": {
366334
"server_url": mcp_url,
@@ -369,7 +337,8 @@ def setup_memory(self):
369337
"timeout": int(timeout)
370338
}
371339
})
372-
self.console.print("[green][SUCCESS][/green] OpenMemory MCP configured in config.yml")
340+
self.config_yml_data = self.config_manager.get_full_config() # Reload to stay in sync
341+
self.console.print("[green][SUCCESS][/green] OpenMemory MCP configured in config.yml and .env")
373342
self.console.print("[yellow][WARNING][/yellow] Remember to start OpenMemory: cd ../../extras/openmemory-mcp && docker compose up -d")
374343

375344
elif choice == "3":
@@ -378,15 +347,16 @@ def setup_memory(self):
378347
mycelia_url = self.prompt_value("Mycelia API URL", "http://localhost:5173")
379348
timeout = self.prompt_value("Mycelia timeout (seconds)", "30")
380349

381-
# Update config.yml with Mycelia settings
382-
self.update_memory_config({
350+
# Update config.yml with Mycelia settings (also updates .env automatically)
351+
self.config_manager.update_memory_config({
383352
"provider": "mycelia",
384353
"mycelia": {
385354
"api_url": mycelia_url,
386355
"timeout": int(timeout)
387356
}
388357
})
389-
self.console.print("[green][SUCCESS][/green] Mycelia memory provider configured in config.yml")
358+
self.config_yml_data = self.config_manager.get_full_config() # Reload to stay in sync
359+
self.console.print("[green][SUCCESS][/green] Mycelia memory provider configured in config.yml and .env")
390360
self.console.print("[yellow][WARNING][/yellow] Make sure Mycelia is running at the configured URL")
391361

392362
def setup_optional_services(self):
@@ -559,10 +529,8 @@ def generate_env_file(self):
559529

560530
self.console.print("[green][SUCCESS][/green] .env file configured successfully with secure permissions")
561531

562-
# Save config.yml with all updates
563-
self.console.print()
564-
self.console.print("[blue][INFO][/blue] Saving configuration to config.yml...")
565-
self.save_config_yml()
532+
# Note: config.yml is automatically saved by ConfigManager when updates are made
533+
self.console.print("[blue][INFO][/blue] Configuration saved to config.yml and .env (via ConfigManager)")
566534

567535
def copy_config_templates(self):
568536
"""Copy other configuration files"""

0 commit comments

Comments
 (0)