Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion ai4rag/core/experiment/exception_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@ def __repr__(self) -> str:
)


class VectorStoreInitializationError(AI4RAGError):
"""Exception representing error during vector store creation or retrieval."""

def __init__(self, exception, embedding_model_id, vector_store_provider_id):
super().__init__(exception)
self.embedding_model_id = embedding_model_id
self.vector_store_provider_id = vector_store_provider_id

def __repr__(self) -> str:
return (
f"{self.__class__.__name__}: Unable to initialize vector store for {self.vector_store_provider_id} "
f"embedding model '{self.embedding_model_id}' due to: {repr(self.exception)}"
)


class GenerationError(AI4RAGError):
"""Exception representing error during retrieval or inference."""

Expand Down Expand Up @@ -115,4 +130,4 @@ def get_final_error_msg(self) -> str:

error_content = next((er for er in self.errors if most_common_error_type_name in er.__class__.__name__))

return f"{error_content}. " f"To find more details please see generated logs file."
return error_content
22 changes: 15 additions & 7 deletions ai4rag/core/experiment/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
AssetSaveError,
ExperimentExceptionHandler,
IndexingError,
VectorStoreInitializationError,
)
from ai4rag.core.experiment.mps import ModelsPreSelector
from ai4rag.core.experiment.results import EvaluationResult, ExperimentResults
Expand Down Expand Up @@ -366,13 +367,20 @@ def run_single_evaluation(self, rag_params: RAGParamsType) -> float:

reuse_collection_name = self._get_reusable_collection_name(indexing_params=indexing_params)

vector_store = get_vector_store(
vs_type=self.vector_store_type,
embedding_model=embedding_model,
reuse_collection_name=reuse_collection_name,
client=self.client,
ogx_vector_io_provider_id=self.ogx_vector_io_provider_id,
)
try:
vector_store = get_vector_store(
vs_type=self.vector_store_type,
embedding_model=embedding_model,
reuse_collection_name=reuse_collection_name,
client=self.client,
ogx_vector_io_provider_id=self.ogx_vector_io_provider_id,
)
except Exception as exc:
raise VectorStoreInitializationError(
exc,
embedding_model_id=embedding_model.model_id,
vector_store_provider_id=self.ogx_vector_io_provider_id or "local_chroma",
) from exc

collection_name = vector_store.collection_name

Expand Down
4 changes: 2 additions & 2 deletions scripts/format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ echo "Running formatters on: ${TARGETS[*]}"

echo ""
echo "==> isort"
uv run isort "${TARGETS[@]}"
uv run --extra code_check isort "${TARGETS[@]}"

echo ""
echo "==> black"
uv run black "${TARGETS[@]}"
uv run --extra code_check black "${TARGETS[@]}"

echo ""
echo "==> copyright_check"
Expand Down
63 changes: 51 additions & 12 deletions tests/unit/ai4rag/core/experiment/test_exception_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
ExperimentExceptionHandler,
GenerationError,
IndexingError,
VectorStoreInitializationError,
)
from ai4rag.utils.event_handler import LogLevel

Expand Down Expand Up @@ -164,6 +165,41 @@ def test_asset_save_error_is_ai4rag_error(self):
assert issubclass(AssetSaveError, AI4RAGError)


class TestVectorStoreInitializationError:
"""Test suite for VectorStoreInitializationError exception class."""

def test_creation(self):
"""Test creating VectorStoreInitializationError."""
base_exception = ConnectionError("OGX unavailable")
error = VectorStoreInitializationError(
base_exception,
embedding_model_id="embedding-model-1",
vector_store_provider_id="vs-provider-id",
)

assert error.exception == base_exception
assert error.embedding_model_id == "embedding-model-1"

def test_repr(self):
"""Test VectorStoreInitializationError __repr__."""
base_exception = ConnectionError("OGX unavailable")
error = VectorStoreInitializationError(
base_exception,
embedding_model_id="embedding-model-1",
vector_store_provider_id="vs-provider-id",
)

repr_str = repr(error)
assert "VectorStoreInitializationError" in repr_str
assert "Unable to initialize vector store" in repr_str
assert "embedding-model-1" in repr_str
assert "ConnectionError" in repr_str

def test_is_ai4rag_error(self):
"""Test that VectorStoreInitializationError inherits from AI4RAGError."""
assert issubclass(VectorStoreInitializationError, AI4RAGError)


class TestExperimentExceptionsHandlerInitialization:
"""Test suite for ExperimentExceptionsHandler initialization."""

Expand Down Expand Up @@ -284,11 +320,10 @@ def test_get_final_error_msg_single_error(self, mocker):
# Reset logger mock after handle_exception
mock_logger.reset_mock()

msg = handler.get_final_error_msg()
result = handler.get_final_error_msg()

assert isinstance(msg, str)
assert "IndexingError" in msg
assert "please see generated logs file" in msg.lower()
assert isinstance(result, IndexingError)
assert result is error
mock_logger.error.assert_called_once()

def test_get_final_error_msg_multiple_errors_same_type(self, mocker):
Expand All @@ -307,9 +342,10 @@ def test_get_final_error_msg_multiple_errors_same_type(self, mocker):

mock_logger.reset_mock()

msg = handler.get_final_error_msg()
result = handler.get_final_error_msg()

assert "IndexingError" in msg
assert isinstance(result, IndexingError)
assert result is errors[0]
mock_logger.error.assert_called_once()

def test_get_final_error_msg_multiple_error_types(self, mocker):
Expand All @@ -328,10 +364,11 @@ def test_get_final_error_msg_multiple_error_types(self, mocker):

mock_logger.reset_mock()

msg = handler.get_final_error_msg()
result = handler.get_final_error_msg()

# Most common error type is IndexingError (2 occurrences)
assert "IndexingError" in msg
assert isinstance(result, IndexingError)
assert result is errors[0]
mock_logger.error.assert_called_once()

def test_get_final_error_msg_logs_all_errors(self, mocker):
Expand Down Expand Up @@ -385,10 +422,11 @@ def test_full_workflow_with_event_handler(self, mocker):

# Get final error message
mock_logger.reset_mock()
msg = handler.get_final_error_msg()
result = handler.get_final_error_msg()

# Most common error is IndexingError
assert "IndexingError" in msg
assert isinstance(result, IndexingError)
assert result is errors[0]
mock_logger.error.assert_called_once()

def test_full_workflow_without_event_handler(self, mocker):
Expand All @@ -409,6 +447,7 @@ def test_full_workflow_without_event_handler(self, mocker):
assert len(handler.errors) == 2

mock_logger.reset_mock()
msg = handler.get_final_error_msg()
result = handler.get_final_error_msg()

assert "GenerationError" in msg
assert isinstance(result, GenerationError)
assert result is errors[0]
Loading