Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **fix(chroma)** — GH #200: stop toggling SQLite `journal_mode=WAL` through a second `sqlite3` connection *after* `chromadb.PersistentClient` is already live. In HTTP/SSE mode the Chroma Rust binding holds a live sqlx pool, so the post-client switch left stale `-wal`/`-shm` handles and the first `Collection.add()` failed during compaction with `SQLITE_NOTADB` (error 26, "file is not a database"). WAL is now switched inside `_init_chroma_client` **before** the client opens the DB, is idempotent (a DB already in WAL is left untouched), pre-creates a fresh install's DB directly in WAL (so run #1 is already WAL, verified against chromadb 1.5.9), and is skipped on network filesystems (NFS/SMB/CIFS) where WAL is unsafe (chroma-core/chroma#7040 caveat), including UTF-8 mountpoints. Read-only startups were unaffected; only incremental writes hit the failure. Reported by @admincheg with an isolated A/B reproduction. 18 regression tests lock the ordering, idempotency, fresh-install pre-create and network-FS guard.
- **fix(config)** — the `init`-generated `config.yaml` now enables 29 formats (code + infrastructure) instead of only `.md`/`.txt`/`.pdf`/`.docx`. The bundled `mcp_server/data/config.example.yaml` template previously shipped an explicit list with the new infra/code formats commented out, so anyone who ran `init` silently opted out of Go/Rust/YAML/Proto/SQL/etc; it now mirrors the root `config.example.yaml` (the 4 office/notebook formats and MetaTrader stay opt-in, commented). Also corrects the stale "20 formats" count to 35 across `README.md` and `docs/ARCHITECTURE.md`, and `12 MCP tools` to 13 in the npm README.
- **fix(search)**: `QueryCache` never hit for the default dispatch path. In `KnowledgeOrchestrator.query()`, the per-result formatting loop reassigns the local name `search_method` (to label each result `hybrid`/`semantic`/`keyword`) after the cache lookup already ran, so the cache write stored under that clobbered value instead of the caller's actual dispatch parameter (`"auto"` by default). Every repeat of the same query missed the cache. The per-result label now uses its own variable; the parameter is untouched for the rest of the function.
- **fix(config)**: GH #208: `KNOWLEDGE_RAG_DIR` set to a relative path (e.g. `./my-data`) or tilde path (`~/rag`) now resolves correctly at startup. `BASE_DIR` applies `.expanduser().resolve()` so all derived paths (`config.yaml`, `data_dir`, `chroma_db`, `documents_dir`, `models_cache_dir`) are always absolute regardless of how the env var was written. Absolute paths are idempotent (no behavior change for existing users). Cross-platform safe — tested on Linux, Windows and macOS.
Comment thread
greptile-apps[bot] marked this conversation as resolved.

### v4.8.5 (2026-08-13) — Enterprise observability: `/health` probes + JSON structured logging (opt-in)

Expand Down
2 changes: 1 addition & 1 deletion mcp_server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def _is_project_root(path):
_venv_dir = _venv_project_dir()

if os.environ.get("KNOWLEDGE_RAG_DIR"):
BASE_DIR = Path(os.environ["KNOWLEDGE_RAG_DIR"])
BASE_DIR = Path(os.environ["KNOWLEDGE_RAG_DIR"]).expanduser().resolve()
elif _venv_dir is not None and (_venv_dir / "config.yaml").exists():
# Prefer venv parent if it has an actual config.yaml (editable installs, PyPI installs)
BASE_DIR = _venv_dir
Expand Down
23 changes: 23 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
"""Tests for configuration integrity."""

import os
from pathlib import Path

from mcp_server.config import _merge_query_expansion_sources, config


Expand Down Expand Up @@ -152,3 +155,23 @@ def test_query_expansion_groups_extend_legacy_entries():
assert merged["tb"] == ["triple barrier", "trip_barr", "legacy_alias"]
assert "tb" in merged["triple barrier"]
assert "trip_barr" in merged["triple barrier"]


class TestKnowledgeRagDirResolution:
"""Path(KNOWLEDGE_RAG_DIR).expanduser().resolve() must produce absolute paths."""

def test_relative_path_becomes_absolute(self, monkeypatch, tmp_path):
monkeypatch.chdir(tmp_path)
base = Path("." + os.sep + "my-rag-data").expanduser().resolve()
assert base.is_absolute()
assert base == (tmp_path / "my-rag-data").resolve()

def test_absolute_path_stays_absolute(self, tmp_path):
raw = str(tmp_path / "rag-store")
base = Path(raw).expanduser().resolve()
assert base == Path(raw).resolve()

def test_tilde_path_expands(self):
base = Path("~/.knowledge-rag").expanduser().resolve()
assert base.is_absolute()
assert "~" not in str(base)
Loading