Skip to content
Closed
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
76 changes: 76 additions & 0 deletions meilisearch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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("=", "")
Expand Down
56 changes: 56 additions & 0 deletions tests/client/test_chat_workspaces.py
Original file line number Diff line number Diff line change
@@ -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)