diff --git a/fenn/agents/rag/retriever.py b/fenn/agents/rag/retriever.py index 133b2a7..62d6bd4 100644 --- a/fenn/agents/rag/retriever.py +++ b/fenn/agents/rag/retriever.py @@ -262,6 +262,12 @@ def index(self, docs): for chunk in chunk_text(doc, mode=self.chunk_mode): self.chunks.append(chunk) + if not self.chunks: + logger.warning( + "[cofone] nothing to index: the source(s) produced no text chunks." + ) + return + if self.use_faiss: self._build_faiss() if self.persist_path: @@ -344,6 +350,8 @@ def query(self, text, top_k=5): return self._query_bm25(text, top_k) def _query_faiss(self, text, top_k): + if self._faiss_index is None or not self.chunks: + return [] faiss_mod = self._get_faiss() vec = self._embed([text], input_type="search_query") faiss_mod.normalize_L2(vec) diff --git a/tests/unit/agents/test_retrievers.py b/tests/unit/agents/test_retrievers.py index eabbf60..976756e 100644 --- a/tests/unit/agents/test_retrievers.py +++ b/tests/unit/agents/test_retrievers.py @@ -215,6 +215,31 @@ def test_build_faiss_raises_without_faiss(self): r._build_faiss() +class TestIndexWithoutChunks: + def test_faiss_index_with_no_docs_does_not_build(self): + r = Retriever(use_faiss=True) + with patch.object(r, "_build_faiss") as build: + r.index([]) + build.assert_not_called() + assert r._faiss_index is None + + def test_faiss_index_with_only_blank_docs_does_not_build(self): + r = Retriever(use_faiss=True) + with patch.object(r, "_build_faiss") as build: + r.index([" \n\n "]) + build.assert_not_called() + assert r.chunks == [] + + def test_bm25_index_with_no_docs_does_not_raise(self): + r = Retriever(use_faiss=False) + r.index([]) + assert r.query("anything") == [] + + def test_query_faiss_returns_empty_when_index_never_built(self): + r = Retriever(use_faiss=True) + assert r.query("anything", top_k=5) == [] + + # ── Embedding method ImportError paths ────────────────────────────────────────