fix: address config loader review feedback

This commit is contained in:
2026-04-13 14:03:39 -04:00
parent 828f707178
commit d16656a473
2 changed files with 182 additions and 1 deletions

View File

@@ -1,6 +1,5 @@
import json
import os
from pathlib import Path
from typing import Any, Dict, List
from pydantic import BaseModel, Field

View File

@@ -140,5 +140,187 @@ def test_load_config_reads_json_and_expands_tilde():
assert config.rag.vector_store.path == os.path.expanduser(
"~/.companion/vectors.lance"
)
assert config.companion.memory.persistent_store == os.path.expanduser(
"~/mem.db"
)
finally:
os.unlink(path)
def test_tilde_expansion_in_list_values():
"""Test that tilde expansion works for list values."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
json.dump(
{
"companion": {
"name": "SAN",
"persona": {
"role": "companion",
"tone": "reflective",
"style": "questioning",
"boundaries": [],
},
"memory": {
"session_turns": 20,
"persistent_store": "~/mem.db",
"summarize_after": 10,
},
"chat": {
"streaming": True,
"max_response_tokens": 2048,
"default_temperature": 0.7,
"allow_temperature_override": True,
},
},
"vault": {
"path": "~/test-vault",
"indexing": {
"auto_sync": False,
"auto_sync_interval_minutes": 1440,
"watch_fs_events": False,
"file_patterns": ["*.md"],
"deny_dirs": ["~/secret", ".git"],
"deny_patterns": [".*"],
},
"chunking_rules": {},
},
"rag": {
"embedding": {
"provider": "ollama",
"model": "dummy",
"base_url": "http://localhost:11434",
"dimensions": 4,
"batch_size": 2,
},
"vector_store": {
"type": "lancedb",
"path": "~/.companion/vectors.lance",
},
"search": {
"default_top_k": 8,
"max_top_k": 20,
"similarity_threshold": 0.75,
"hybrid_search": {
"enabled": False,
"keyword_weight": 0.3,
"semantic_weight": 0.7,
},
"filters": {
"date_range_enabled": True,
"tag_filter_enabled": True,
"directory_filter_enabled": True,
},
},
},
"model": {
"inference": {
"backend": "llama.cpp",
"model_path": "",
"context_length": 8192,
"gpu_layers": 35,
"batch_size": 512,
"threads": 8,
},
"fine_tuning": {
"base_model": "",
"output_dir": "",
"lora_rank": 16,
"lora_alpha": 32,
"learning_rate": 0.0002,
"batch_size": 4,
"gradient_accumulation_steps": 4,
"num_epochs": 3,
"warmup_steps": 100,
"save_steps": 500,
"eval_steps": 250,
"training_data_path": "",
"validation_split": 0.1,
},
"retrain_schedule": {
"auto_reminder": True,
"default_interval_days": 90,
"reminder_channels": [],
},
},
"api": {
"host": "127.0.0.1",
"port": 7373,
"cors_origins": [],
"auth": {"enabled": False},
},
"ui": {
"web": {
"enabled": True,
"theme": "obsidian",
"features": {
"streaming": True,
"citations": True,
"source_preview": True,
},
},
"cli": {"enabled": True, "rich_output": True},
},
"logging": {
"level": "INFO",
"file": "",
"max_size_mb": 100,
"backup_count": 5,
},
"security": {
"local_only": True,
"vault_path_traversal_check": True,
"sensitive_content_detection": True,
"sensitive_patterns": [],
"require_confirmation_for_external_apis": True,
},
},
f,
)
path = f.name
try:
config = load_config(path)
# Check tilde expansion in list values
assert config.vault.indexing.deny_dirs[0] == os.path.expanduser("~/secret")
finally:
os.unlink(path)
def test_load_config_missing_file():
"""Test that loading a missing file raises FileNotFoundError."""
with tempfile.TemporaryDirectory() as tmp:
missing_path = os.path.join(tmp, "nonexistent.json")
try:
load_config(missing_path)
assert False, "Should have raised an exception"
except FileNotFoundError:
pass # Expected
def test_load_config_malformed_json():
"""Test that malformed JSON raises JSONDecodeError."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
f.write("{invalid json")
path = f.name
try:
load_config(path)
assert False, "Should have raised an exception"
except json.JSONDecodeError:
pass # Expected
finally:
os.unlink(path)
def test_load_config_missing_required_field():
"""Test that missing required field raises ValidationError."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
# Missing required fields like "companion"
json.dump({"vault": {"path": "~/test"}}, f)
path = f.name
try:
load_config(path)
assert False, "Should have raised an exception"
except Exception as e:
# Should be a Pydantic validation error
assert "companion" in str(e).lower() or "validation" in str(e).lower()
finally:
os.unlink(path)