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.
This commit is contained in:
Yiorgis Gozadinos 2026-08-26 13:34:09 +03:00
parent 1b3334b5af
commit 4c2bfc4fc1
No known key found for this signature in database
6 changed files with 15 additions and 35 deletions

View file

@ -131,17 +131,6 @@ class EvidenceState(BaseModel):
self.searches.clear() 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: def _awaits_the_model(messages: list[ModelMessage]) -> bool:
"""Whether the history unmistakably leaves the model something to answer. """Whether the history unmistakably leaves the model something to answer.
@ -637,6 +626,5 @@ class RAGCapabilityBase[StateT: EvidenceState](AbstractCapability[Any]):
__all__ = [ __all__ = [
"CodeExecutionEntry", "CodeExecutionEntry",
"RAGCapabilityBase", "RAGCapabilityBase",
"covers_several_databases",
"resolve_scope", "resolve_scope",
] ]

View file

@ -15,7 +15,6 @@ from haiku.rag.capabilities._base import (
CodeExecutionEntry, CodeExecutionEntry,
EvidenceState, EvidenceState,
RAGCapabilityBase, RAGCapabilityBase,
covers_several_databases,
resolve_scope, resolve_scope,
) )
from haiku.rag.capabilities._tools import merge_results from haiku.rag.capabilities._tools import merge_results
@ -215,7 +214,9 @@ def create_capability(
analysis_model = config.analysis.model or config.qa.model analysis_model = config.analysis.model or config.qa.model
scope = resolve_scope(db_path, config) scope = resolve_scope(db_path, config)
instruction_text = instructions() 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() instruction_text += several_databases_instructions()
return AnalysisCapability( return AnalysisCapability(
scope=scope, scope=scope,

View file

@ -13,7 +13,6 @@ if TYPE_CHECKING:
from haiku.rag.capabilities._base import ( from haiku.rag.capabilities._base import (
EvidenceState, EvidenceState,
RAGCapabilityBase, RAGCapabilityBase,
covers_several_databases,
resolve_scope, resolve_scope,
) )
from haiku.rag.config.models import AppConfig from haiku.rag.config.models import AppConfig
@ -118,7 +117,9 @@ def create_capability(
config = get_config() config = get_config()
scope = resolve_scope(db_path, config) scope = resolve_scope(db_path, config)
instruction_text = instructions() 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() instruction_text += several_databases_instructions()
return RAGCapability( return RAGCapability(
scope=scope, scope=scope,

View file

@ -148,11 +148,7 @@ class HaikuRAG:
# single-database configuration from it, and asking again has to see the # single-database configuration from it, and asking again has to see the
# same set rather than the answer from last time. # same set rather than the answer from last time.
self._config = self._configured self._config = self._configured
self._db_path_given = db_path is not None self._requested_db_path = Path(db_path) if db_path is not None else None
if db_path is None:
db_path = self._config.storage.data_dir / "haiku.rag.lancedb"
self._db_path = db_path
self._skip_validation = skip_validation self._skip_validation = skip_validation
self._create = create self._create = create
self._read_only = read_only self._read_only = read_only
@ -285,10 +281,9 @@ class HaikuRAG:
if self._scope is not None: if self._scope is not None:
return self._scope return self._scope
scope = DatabaseScope.resolve( scope = DatabaseScope.resolve(
self._configured, self._configured, database_path=self._requested_db_path
database_path=self._db_path if self._db_path_given else None,
) )
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) scope = scope.select(self._requested_sources)
return scope return scope
@ -326,12 +321,9 @@ class HaikuRAG:
[ref] = scope.databases [ref] = scope.databases
self._config, db_path = ref.connection(self._configured) 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._session = await SingleDatabaseSession(
self._db_path, db_path if db_path is not None else default_db_path(self._config),
self._config, self._config,
skip_validation=self._skip_validation, skip_validation=self._skip_validation,
create=self._create, create=self._create,

View file

@ -117,12 +117,10 @@ SearchType = Literal["vector", "fts", "hybrid"]
def qualified_id(source: str | None, id: str | None) -> tuple[str | None, str | None]: 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 """What tells one chunk from another: an id is unique within a database only.
and says nothing across them.
For in-memory structures only. Everything serialized records the id alone For in-memory structures. Serialized ones record the id alone and reject
and rejects ambiguity instead. `id` is optional, and results built by hand ambiguity instead. Results built by hand carry no id and cannot be told apart.
carry none and cannot be told apart.
""" """
return (source, id) return (source, id)

View file

@ -53,9 +53,9 @@ def test_default_db_path_comes_from_storage_data_dir(tmp_path):
config = AppConfig() config = AppConfig()
config.storage.data_dir = tmp_path 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 @pytest.mark.asyncio