From 4c2bfc4fc1c49cc675ae2ca6fc051632257aa6ac Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Wed, 26 Aug 2026 13:34:09 +0300 Subject: [PATCH] Drop the indirection around what a client covers `covers_several_databases` had one line of body and two call sites. `_db_path_given` guarded a default path manufactured in `__init__` and overwritten in `__aenter__`; `_requested_db_path` is what the caller asked for, and the effective path falls out of the resolved scope. --- haiku_rag_slim/haiku/rag/capabilities/_base.py | 12 ------------ .../haiku/rag/capabilities/analysis.py | 5 +++-- haiku_rag_slim/haiku/rag/capabilities/rag.py | 5 +++-- haiku_rag_slim/haiku/rag/client/__init__.py | 16 ++++------------ haiku_rag_slim/haiku/rag/store/models/chunk.py | 8 +++----- tests/test_database_autocreate.py | 4 ++-- 6 files changed, 15 insertions(+), 35 deletions(-) diff --git a/haiku_rag_slim/haiku/rag/capabilities/_base.py b/haiku_rag_slim/haiku/rag/capabilities/_base.py index ce333881..2bb04dd0 100644 --- a/haiku_rag_slim/haiku/rag/capabilities/_base.py +++ b/haiku_rag_slim/haiku/rag/capabilities/_base.py @@ -131,17 +131,6 @@ class EvidenceState(BaseModel): self.searches.clear() -def covers_several_databases(scope: DatabaseScope, rag: "HaikuRAG | None") -> bool: - """Whether the capability will read from more than one database. - - A lent client already covers what it covers; otherwise the scope says. - Instructions follow coverage, not configuration. - """ - if rag is not None: - return rag.covers_multiple - return scope.covers_multiple - - def _awaits_the_model(messages: list[ModelMessage]) -> bool: """Whether the history unmistakably leaves the model something to answer. @@ -637,6 +626,5 @@ class RAGCapabilityBase[StateT: EvidenceState](AbstractCapability[Any]): __all__ = [ "CodeExecutionEntry", "RAGCapabilityBase", - "covers_several_databases", "resolve_scope", ] diff --git a/haiku_rag_slim/haiku/rag/capabilities/analysis.py b/haiku_rag_slim/haiku/rag/capabilities/analysis.py index ec5f44e2..18cdaeb4 100644 --- a/haiku_rag_slim/haiku/rag/capabilities/analysis.py +++ b/haiku_rag_slim/haiku/rag/capabilities/analysis.py @@ -15,7 +15,6 @@ from haiku.rag.capabilities._base import ( CodeExecutionEntry, EvidenceState, RAGCapabilityBase, - covers_several_databases, resolve_scope, ) from haiku.rag.capabilities._tools import merge_results @@ -215,7 +214,9 @@ def create_capability( analysis_model = config.analysis.model or config.qa.model scope = resolve_scope(db_path, config) instruction_text = instructions() - if covers_several_databases(scope, rag): + # A lent client covers what it covers; otherwise the scope says. + several = rag.covers_multiple if rag is not None else scope.covers_multiple + if several: instruction_text += several_databases_instructions() return AnalysisCapability( scope=scope, diff --git a/haiku_rag_slim/haiku/rag/capabilities/rag.py b/haiku_rag_slim/haiku/rag/capabilities/rag.py index f452cec2..11a9520c 100644 --- a/haiku_rag_slim/haiku/rag/capabilities/rag.py +++ b/haiku_rag_slim/haiku/rag/capabilities/rag.py @@ -13,7 +13,6 @@ if TYPE_CHECKING: from haiku.rag.capabilities._base import ( EvidenceState, RAGCapabilityBase, - covers_several_databases, resolve_scope, ) from haiku.rag.config.models import AppConfig @@ -118,7 +117,9 @@ def create_capability( config = get_config() scope = resolve_scope(db_path, config) instruction_text = instructions() - if covers_several_databases(scope, rag): + # A lent client covers what it covers; otherwise the scope says. + several = rag.covers_multiple if rag is not None else scope.covers_multiple + if several: instruction_text += several_databases_instructions() return RAGCapability( scope=scope, diff --git a/haiku_rag_slim/haiku/rag/client/__init__.py b/haiku_rag_slim/haiku/rag/client/__init__.py index baf13a1b..264cd12a 100644 --- a/haiku_rag_slim/haiku/rag/client/__init__.py +++ b/haiku_rag_slim/haiku/rag/client/__init__.py @@ -148,11 +148,7 @@ class HaikuRAG: # single-database configuration from it, and asking again has to see the # same set rather than the answer from last time. self._config = self._configured - self._db_path_given = db_path is not None - if db_path is None: - db_path = self._config.storage.data_dir / "haiku.rag.lancedb" - - self._db_path = db_path + self._requested_db_path = Path(db_path) if db_path is not None else None self._skip_validation = skip_validation self._create = create self._read_only = read_only @@ -285,10 +281,9 @@ class HaikuRAG: if self._scope is not None: return self._scope scope = DatabaseScope.resolve( - self._configured, - database_path=self._db_path if self._db_path_given else None, + self._configured, database_path=self._requested_db_path ) - if self._requested_sources is not None and not self._db_path_given: + if self._requested_sources is not None and self._requested_db_path is None: scope = scope.select(self._requested_sources) return scope @@ -326,12 +321,9 @@ class HaikuRAG: [ref] = scope.databases self._config, db_path = ref.connection(self._configured) - self._db_path = ( - db_path if db_path is not None else default_db_path(self._config) - ) self._session = await SingleDatabaseSession( - self._db_path, + db_path if db_path is not None else default_db_path(self._config), self._config, skip_validation=self._skip_validation, create=self._create, diff --git a/haiku_rag_slim/haiku/rag/store/models/chunk.py b/haiku_rag_slim/haiku/rag/store/models/chunk.py index 9e28e393..9ae77f65 100644 --- a/haiku_rag_slim/haiku/rag/store/models/chunk.py +++ b/haiku_rag_slim/haiku/rag/store/models/chunk.py @@ -117,12 +117,10 @@ SearchType = Literal["vector", "fts", "hybrid"] def qualified_id(source: str | None, id: str | None) -> tuple[str | None, str | None]: - """What tells one chunk from another: a chunk id is unique within a database - and says nothing across them. + """What tells one chunk from another: an id is unique within a database only. - For in-memory structures only. Everything serialized records the id alone - and rejects ambiguity instead. `id` is optional, and results built by hand - carry none and cannot be told apart. + For in-memory structures. Serialized ones record the id alone and reject + ambiguity instead. Results built by hand carry no id and cannot be told apart. """ return (source, id) diff --git a/tests/test_database_autocreate.py b/tests/test_database_autocreate.py index 1d14c936..d34c9033 100644 --- a/tests/test_database_autocreate.py +++ b/tests/test_database_autocreate.py @@ -53,9 +53,9 @@ def test_default_db_path_comes_from_storage_data_dir(tmp_path): config = AppConfig() config.storage.data_dir = tmp_path - client = HaikuRAG(config=config) + [ref] = HaikuRAG(config=config)._resolve_scope().databases - assert client._db_path == tmp_path / "haiku.rag.lancedb" + assert ref.db_path == tmp_path / "haiku.rag.lancedb" @pytest.mark.asyncio