"""Semantic search service regression tests for local SQLite search.""" import pytest from basic_memory.repository.semantic_errors import ( SemanticDependenciesMissingError, SemanticSearchDisabledError, ) from basic_memory.repository.sqlite_search_repository import SQLiteSearchRepository from basic_memory.schemas.search import SearchItemType, SearchQuery, SearchRetrievalMode def _sqlite_repo(search_service) -> SQLiteSearchRepository: repository = search_service.repository if not isinstance(repository, SQLiteSearchRepository): pytest.skip("Semantic retrieval behavior is local SQLite-only in this phase.") return repository @pytest.mark.asyncio async def test_semantic_vector_search_fails_when_disabled(search_service, test_graph): """Vector mode should fail fast when semantic search is disabled.""" repository = _sqlite_repo(search_service) repository._semantic_enabled = False with pytest.raises(SemanticSearchDisabledError): await search_service.search( SearchQuery( text="Connected Entity", retrieval_mode=SearchRetrievalMode.VECTOR, ) ) @pytest.mark.asyncio async def test_semantic_hybrid_search_fails_when_disabled(search_service, test_graph): """Hybrid mode should fail fast when semantic search is disabled.""" repository = _sqlite_repo(search_service) repository._semantic_enabled = False with pytest.raises(SemanticSearchDisabledError): await search_service.search( SearchQuery( text="Root Entity", retrieval_mode=SearchRetrievalMode.HYBRID, ) ) @pytest.mark.asyncio async def test_semantic_vector_search_fails_when_provider_unavailable(search_service, test_graph): """Vector mode should fail fast when semantic provider is unavailable.""" repository = _sqlite_repo(search_service) repository._semantic_enabled = True repository._embedding_provider = None repository._vector_tables_initialized = False with pytest.raises(SemanticDependenciesMissingError): await search_service.search( SearchQuery( text="Root Entity", retrieval_mode=SearchRetrievalMode.VECTOR, ) ) @pytest.mark.asyncio async def test_semantic_vector_mode_rejects_non_text_query(search_service, test_graph): """Vector mode should not silently fall back for title-only queries.""" with pytest.raises(ValueError): await search_service.search( SearchQuery( title="Root", retrieval_mode=SearchRetrievalMode.VECTOR, entity_types=[SearchItemType.ENTITY], ) ) @pytest.mark.asyncio async def test_semantic_fts_mode_still_returns_observations(search_service, test_graph): """Explicit FTS mode should preserve existing mixed result behavior.""" results = await search_service.search( SearchQuery( text="Root note 1", retrieval_mode=SearchRetrievalMode.FTS, ) ) assert results assert any(result.type == SearchItemType.OBSERVATION.value for result in results)