Repository: griptape-ai/griptape (language: python)

Issue:
400 error from Cohere if there is no documents in `TextChunksRerankRagModule` using `CohereRerankDriver`
 - [x] I have read and agree to the [contributing guidelines](https://github.com/griptape-ai/griptape#contributing).

**Describe the bug**
`CohereRerankDriver` throws a 400 if there is no documents getting sent.

**To Reproduce**
```
            engine = RagEngine(
                retrieval_stage=RetrievalRagStage(
                    retrieval_modules=[
                        self.KnowledgeBaseSearchRetrievalRagModule(
                            query=query,
                            count=count,
                            include_vectors=include_vectors,
                            distance_metric=distance_metric,
                            filter=filter,
                            knowledge_base=knowledge_base,
                        ),
                    ],
                    rerank_module=TextChunksRerankRagModule(
                        rerank_driver=rerank_driver
                    ),
                ),
                response_stage=ResponseRagStage(
                    response_modules=[
                        PromptResponseRagModule(
                            prompt_driver=prompt_driver
                        )
                    ]
                ),
            )
```

**Expected behavior**
The `RagEngine` should be able to handle the fact that there is nothing returned to get reranked.

**Screenshots**
```
| Traceback (most recent call last):
|   File "/opt/webapp/api/griptapecloud/components/knowledge_bases/views.py", line 171, in post
|     context = engine.process_query(query)
|               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/webapp/api/.venv/lib/python3.11/site-packages/griptape/engines/rag/rag_engine.py", line 37, in process_query
|     return self.process(RagContext(query=query))
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/webapp/api/.venv/lib/python3.11/site-packages/griptape/engines/rag/rag_engine.py", line 44, in process
|     context = self.retrieval_stage.run(context)
|               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/webapp/api/.venv/lib/python3.11/site-packages/griptape/engines/rag/stages/retrieval_rag_stage.py", line 62, in run
|     context.text_chunks = [a for a in self.rerank_module.run(context) if isinstance(a, TextArtifact)]
|                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/webapp/api/.venv/lib/python3.11/site-packages/griptape/engines/rag/modules/retrieval/text_chunks_rerank_rag_module.py", line 13, in run
|     return self.rerank_driver.run(context.query, context.text_chunks)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/webapp/api/.venv/lib/python3.11/site-packages/griptape/drivers/rerank/cohere_rerank_driver.py", line 28, in run
|     response = self.client.rerank(
|                ^^^^^^^^^^^^^^^^^^^
|   File "/opt/webapp/api/.venv/lib/python3.11/site-packages/cohere/base_client.py", line 1595, in rerank
|     raise BadRequestError(
| cohere.errors.bad_request_error.BadRequestError: status_code: 400, body: {'message': 'invalid request: list of documents must not be empty'}
```

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Version [e.g. 0.5.1]

**Additional context**
Add any other context about the problem here.



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e7d833612..6801ccf3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Missing `maxTokens` inference parameter in `AmazonBedrockPromptDriver`.
 - Incorrect model in `OpenAiDriverConfig`'s `text_to_speech_driver`.
 - Crash when using `CohereRerankDriver` with `CsvRowArtifact`s.
+- Crash when passing "empty" Artifacts or no Artifacts to `CohereRerankDriver`.
 
 
 ## [0.30.2] - 2024-08-26
diff --git a/griptape/drivers/rerank/cohere_rerank_driver.py b/griptape/drivers/rerank/cohere_rerank_driver.py
index 5ca03cf63..b6c1d1477 100644
--- a/griptape/drivers/rerank/cohere_rerank_driver.py
+++ b/griptape/drivers/rerank/cohere_rerank_driver.py
@@ -24,13 +24,17 @@ class CohereRerankDriver(BaseRerankDriver):
     )
 
     def run(self, query: str, artifacts: list[TextArtifact]) -> list[TextArtifact]:
-        artifacts_dict = {str(hash(a.to_text())): a for a in artifacts}
-        response = self.client.rerank(
-            model=self.model,
-            query=query,
-            documents=[a.to_text() for a in artifacts_dict.values()],
-            return_documents=True,
-            top_n=self.top_n,
-        )
-
-        return [artifacts_dict[str(hash(r.document.text))] for r in response.results]
+        # Cohere errors out if passed "empty" documents or no documents at all
+        artifacts_dict = {str(hash(a.to_text())): a for a in artifacts if a}
+
+        if artifacts_dict:
+            response = self.client.rerank(
+                model=self.model,
+                query=query,
+                documents=[a.to_text() for a in artifacts_dict.values()],
+                return_documents=True,
+                top_n=self.top_n,
+            )
+            return [artifacts_dict[str(hash(r.document.text))] for r in response.results]
+        else:
+            return []


Test patch:
diff --git a/tests/unit/drivers/rerank/test_cohere_rerank_driver.py b/tests/unit/drivers/rerank/test_cohere_rerank_driver.py
index 87a727269..d6f77f552 100644
--- a/tests/unit/drivers/rerank/test_cohere_rerank_driver.py
+++ b/tests/unit/drivers/rerank/test_cohere_rerank_driver.py
@@ -20,8 +20,24 @@ def mock_client(self, mocker):
 
         return mock_client
 
+    @pytest.fixture()
+    def mock_empty_client(self, mocker):
+        mock_client = mocker.patch("cohere.Client").return_value
+        mock_client.rerank.side_effect = Exception("Client should not be called")
+
+        return mock_client
+
     def test_run(self, mock_client):
         driver = CohereRerankDriver(api_key="api-key")
         result = driver.run("hello", artifacts=[TextArtifact("foo"), TextArtifact("bar")])
 
         assert len(result) == 2
+
+    def test_run_empty_artifacts(self, mock_empty_client):
+        driver = CohereRerankDriver(api_key="api-key")
+        result = driver.run("hello", artifacts=[TextArtifact(""), TextArtifact("  ")])
+
+        assert len(result) == 0
+
+        result = driver.run("hello", artifacts=[])
+        assert len(result) == 0