Merge pull request #469 from ggozad/fix/minor-issues

Minor config and FTS-index fixes
This commit is contained in:
Yiorgis Gozadinos 2026-06-25 13:21:00 +03:00 committed by GitHub
commit 6bbf12e794
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 55 additions and 5 deletions

View file

@ -1,6 +1,14 @@
# Changelog
## [Unreleased]
### Fixed
- A failed FTS index build is logged at `WARNING` instead of `DEBUG`, so silent full-text search degradation is visible.
### Changed
- A bare `${VAR}` in YAML config now raises `MissingEnvVarError` when the variable is set but empty, matching the unset case. Use `${VAR:-default}` to allow an empty/absent value.
## [0.61.2] - 2026-06-24
### Fixed

View file

@ -12,7 +12,7 @@ _ENV_VAR_PATTERN = re.compile(r"\$\$|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\
class MissingEnvVarError(ValueError):
"""A ${VAR} in the config references an unset environment variable."""
"""A ${VAR} in the config references an unset or empty environment variable."""
def _expand_str(value: str) -> str:
@ -20,12 +20,12 @@ def _expand_str(value: str) -> str:
if match.group(0) == "$$":
return "$"
name, default = match.group(1), match.group(2)
if name in os.environ and (default is None or os.environ[name] != ""):
if os.environ.get(name, "") != "":
return os.environ[name]
if default is not None:
return default
raise MissingEnvVarError(
f"Config references unset environment variable ${{{name}}}. "
f"Config references unset or empty environment variable ${{{name}}}. "
f"Set it, or use ${{{name}:-default}} to provide a fallback."
)

View file

@ -33,8 +33,7 @@ class ChunkRepository:
replace=True,
)
except Exception as e:
# Log the error but don't fail - FTS might already exist
logger.debug(f"FTS index creation skipped: {e}")
logger.warning(f"FTS index build failed; full-text search degraded: {e}")
def _contextualize_content(self, chunk: Chunk) -> str:
"""Generate contextualized content for FTS by prepending headings."""

View file

@ -510,3 +510,34 @@ async def test_chunk_content_fts_without_headings(temp_db_path):
# Both should be the same when no headings
assert record["content"] == "Plain content without headings."
assert record["content_fts"] == "Plain content without headings."
async def test_ensure_fts_index_warns_on_failure(temp_db_path):
"""A failed FTS index build is surfaced at WARNING, not swallowed silently."""
import logging
from haiku.rag.store.repositories import chunk as chunk_module
async with HaikuRAG(db_path=temp_db_path, config=Config, create=True) as client:
repo = client.chunk_repository
async def _boom(*_args, **_kwargs):
raise RuntimeError("index build failed")
repo.store.chunks_table.create_index = _boom
records: list[logging.LogRecord] = []
class _Capture(logging.Handler):
def emit(self, record: logging.LogRecord) -> None:
records.append(record)
handler = _Capture(level=logging.WARNING)
chunk_module.logger.addHandler(handler)
try:
await repo._ensure_fts_index()
finally:
chunk_module.logger.removeHandler(handler)
assert [r for r in records if r.levelno == logging.WARNING]
assert any("index build failed" in r.getMessage() for r in records)

View file

@ -419,6 +419,18 @@ def test_expand_env_var_unset_raises(tmp_path, monkeypatch):
load_yaml_config(config_file)
def test_expand_env_var_empty_raises(tmp_path, monkeypatch):
"""A bare ${VAR} set to an empty string is treated as unset and raises."""
from haiku.rag.config.loader import MissingEnvVarError
monkeypatch.setenv("HAIKU_TEST_EMPTY", "")
config_file = tmp_path / "test.yaml"
config_file.write_text("api_key: ${HAIKU_TEST_EMPTY}")
with pytest.raises(MissingEnvVarError, match="HAIKU_TEST_EMPTY"):
load_yaml_config(config_file)
def test_expand_env_var_default_when_unset(tmp_path, monkeypatch):
"""${VAR:-default} falls back to the default when VAR is unset."""
monkeypatch.delenv("HAIKU_TEST_MISSING", raising=False)