diff --git a/meilisearch/client.py b/meilisearch/client.py index 8003f006..f6d64314 100644 --- a/meilisearch/client.py +++ b/meilisearch/client.py @@ -1360,6 +1360,82 @@ def update_chat_workspace_settings( return self.http.patch(f"chats/{workspace_uid}/settings", body=settings) + def get_chat_workspace(self, workspace_uid: str) -> dict[str, Any]: + """Get a chat workspace. + + Parameters + ---------- + workspace_uid: + Unique identifier of the chat workspace. + + Returns + ------- + workspace: + Dictionary containing the workspace uid. + + Raises + ------ + MeilisearchApiError + An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors + ValueError + If workspace_uid is empty or contains path separators or URL delimiters (? or #). + """ + self._validate_chat_workspace_uid(workspace_uid) + + return self.http.get(f"chats/{workspace_uid}") + + def delete_chat_workspace(self, workspace_uid: str) -> None: + """Delete a chat workspace and its settings. + + Parameters + ---------- + workspace_uid: + Unique identifier of the chat workspace. + + Raises + ------ + MeilisearchApiError + An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors + ValueError + If workspace_uid is empty or contains path separators or URL delimiters (? or #). + """ + self._validate_chat_workspace_uid(workspace_uid) + + self.http.delete(f"chats/{workspace_uid}") + + def reset_chat_workspace_settings(self, workspace_uid: str) -> dict[str, Any]: + """Reset the settings of a chat workspace to their default values. + + Parameters + ---------- + workspace_uid: + Unique identifier of the chat workspace. + + Returns + ------- + settings: + Dictionary containing the default workspace settings. + + Raises + ------ + MeilisearchApiError + An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors + ValueError + If workspace_uid is empty or contains path separators or URL delimiters (? or #). + """ + self._validate_chat_workspace_uid(workspace_uid) + + return self.http.delete(f"chats/{workspace_uid}/settings") + + @staticmethod + def _validate_chat_workspace_uid(workspace_uid: str) -> None: + if not workspace_uid: + raise ValueError("workspace_uid is required and cannot be empty") + if "/" in workspace_uid or "\\" in workspace_uid: + raise ValueError("Invalid workspace_uid: must not contain path separators") + if "?" in workspace_uid or "#" in workspace_uid: + raise ValueError("Invalid workspace_uid: must not contain URL delimiters") + @staticmethod def _base64url_encode(data: bytes) -> str: return base64.urlsafe_b64encode(data).decode("utf-8").replace("=", "") diff --git a/tests/client/test_chat_workspaces.py b/tests/client/test_chat_workspaces.py new file mode 100644 index 00000000..f6e41692 --- /dev/null +++ b/tests/client/test_chat_workspaces.py @@ -0,0 +1,56 @@ +import pytest + +from meilisearch.errors import MeilisearchApiError + +WORKSPACE = "test-workspace" + + +@pytest.fixture +def chat_workspace(client): + """Enable the chat completions feature and create a workspace.""" + client.update_experimental_features({"chatCompletions": True}) + client.update_chat_workspace_settings(WORKSPACE, {"source": "openAi", "apiKey": "test-key"}) + yield WORKSPACE + try: + client.delete_chat_workspace(WORKSPACE) + except MeilisearchApiError: + pass + client.update_experimental_features({"chatCompletions": False}) + + +def test_get_chat_workspace(client, chat_workspace): + """Test that an existing workspace can be fetched.""" + assert client.get_chat_workspace(chat_workspace) == {"uid": chat_workspace} + + +def test_get_chat_workspace_not_found(client, chat_workspace): + """Test that fetching an unknown workspace raises an API error.""" + with pytest.raises(MeilisearchApiError) as exc: + client.get_chat_workspace("does-not-exist") + assert exc.value.code == "chat_not_found" + + +def test_reset_chat_workspace_settings(client, chat_workspace): + """Test that resetting settings removes the stored API key.""" + result = client.reset_chat_workspace_settings(chat_workspace) + assert result["apiKey"] is None + assert client.get_chat_workspace_settings(chat_workspace)["apiKey"] is None + + +def test_delete_chat_workspace(client, chat_workspace): + """Test that a deleted workspace can no longer be fetched.""" + client.delete_chat_workspace(chat_workspace) + with pytest.raises(MeilisearchApiError) as exc: + client.get_chat_workspace(chat_workspace) + assert exc.value.code == "chat_not_found" + + +@pytest.mark.parametrize( + "method", + ["get_chat_workspace", "delete_chat_workspace", "reset_chat_workspace_settings"], +) +@pytest.mark.parametrize("uid", ["", "a/b", "a\\b", "a?b", "a#b"]) +def test_chat_workspace_methods_reject_invalid_uid(client, method, uid): + """Test that an empty uid or one with path separators or URL delimiters is rejected before any request.""" + with pytest.raises(ValueError): + getattr(client, method)(uid)