feat: implement structured exception classes with error codes and sug… (#3279)
This commit is contained in:
+181
-30
@@ -9,6 +9,7 @@ import requests
|
||||
|
||||
from mem0.client.project import AsyncProject, Project
|
||||
from mem0.client.utils import api_error_handler
|
||||
# Exception classes are referenced in docstrings only
|
||||
from mem0.memory.setup import get_user_id, setup_config
|
||||
from mem0.memory.telemetry import capture_client_event
|
||||
|
||||
@@ -139,7 +140,12 @@ class MemoryClient:
|
||||
A dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
kwargs = self._prepare_params(kwargs)
|
||||
if kwargs.get("output_format") != "v1.1":
|
||||
@@ -173,7 +179,12 @@ class MemoryClient:
|
||||
A dictionary containing the memory data.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params()
|
||||
response = self.client.get(f"/v1/memories/{memory_id}/", params=params)
|
||||
@@ -194,7 +205,12 @@ class MemoryClient:
|
||||
A list of dictionaries containing memories.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params(kwargs)
|
||||
if version == "v1":
|
||||
@@ -236,7 +252,12 @@ class MemoryClient:
|
||||
A list of dictionaries containing search results.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
payload = {"query": query}
|
||||
params = self._prepare_params(kwargs)
|
||||
@@ -303,7 +324,12 @@ class MemoryClient:
|
||||
A dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params()
|
||||
response = self.client.delete(f"/v1/memories/{memory_id}/", params=params)
|
||||
@@ -323,7 +349,12 @@ class MemoryClient:
|
||||
A dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params(kwargs)
|
||||
response = self.client.delete("/v1/memories/", params=params)
|
||||
@@ -346,7 +377,12 @@ class MemoryClient:
|
||||
A list of dictionaries containing the memory history.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params()
|
||||
response = self.client.get(f"/v1/memories/{memory_id}/history/", params=params)
|
||||
@@ -384,7 +420,10 @@ class MemoryClient:
|
||||
|
||||
Raises:
|
||||
ValueError: If specified entity not found
|
||||
APIError: If deletion fails
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
MemoryNotFoundError: If the entity doesn't exist.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
"""
|
||||
|
||||
if user_id:
|
||||
@@ -438,10 +477,13 @@ class MemoryClient:
|
||||
Dict[str, str]: Message client reset successful.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
# Delete all users, agents, and sessions
|
||||
# This will also delete the memories
|
||||
self.delete_users()
|
||||
|
||||
capture_client_event("client.reset", self, {"sync_type": "sync"})
|
||||
@@ -459,6 +501,14 @@ class MemoryClient:
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: The response from the server.
|
||||
|
||||
Raises:
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
response = self.client.put("/v1/batch/", json={"memories": memories})
|
||||
response.raise_for_status()
|
||||
@@ -479,7 +529,12 @@ class MemoryClient:
|
||||
str: Message indicating the success of the batch deletion.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
response = self.client.request("DELETE", "/v1/batch/", json={"memories": memories})
|
||||
response.raise_for_status()
|
||||
@@ -560,7 +615,12 @@ class MemoryClient:
|
||||
Dictionary containing the requested fields.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
logger.warning(
|
||||
@@ -604,7 +664,12 @@ class MemoryClient:
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
logger.warning(
|
||||
@@ -673,7 +738,12 @@ class MemoryClient:
|
||||
Dictionary containing webhook details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If project_id is not set.
|
||||
"""
|
||||
|
||||
@@ -695,7 +765,12 @@ class MemoryClient:
|
||||
Dictionary containing the created webhook details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If project_id is not set.
|
||||
"""
|
||||
|
||||
@@ -725,7 +800,12 @@ class MemoryClient:
|
||||
Dictionary containing the updated webhook details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
|
||||
payload = {k: v for k, v in {"name": name, "url": url, "event_types": event_types}.items() if v is not None}
|
||||
@@ -745,7 +825,12 @@ class MemoryClient:
|
||||
Dictionary containing success message.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
|
||||
response = self.client.delete(f"api/v1/webhooks/{webhook_id}/")
|
||||
@@ -1098,7 +1183,12 @@ class AsyncMemoryClient:
|
||||
A dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params()
|
||||
response = await self.async_client.delete(f"/v1/memories/{memory_id}/", params=params)
|
||||
@@ -1117,7 +1207,12 @@ class AsyncMemoryClient:
|
||||
A dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params(kwargs)
|
||||
response = await self.async_client.delete("/v1/memories/", params=params)
|
||||
@@ -1136,7 +1231,12 @@ class AsyncMemoryClient:
|
||||
A list of dictionaries containing the memory history.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
params = self._prepare_params()
|
||||
response = await self.async_client.get(f"/v1/memories/{memory_id}/history/", params=params)
|
||||
@@ -1174,7 +1274,10 @@ class AsyncMemoryClient:
|
||||
|
||||
Raises:
|
||||
ValueError: If specified entity not found
|
||||
APIError: If deletion fails
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
MemoryNotFoundError: If the entity doesn't exist.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
"""
|
||||
|
||||
if user_id:
|
||||
@@ -1228,7 +1331,12 @@ class AsyncMemoryClient:
|
||||
Dict[str, str]: Message client reset successful.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
await self.delete_users()
|
||||
capture_client_event("client.reset", self, {"sync_type": "async"})
|
||||
@@ -1246,6 +1354,14 @@ class AsyncMemoryClient:
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: The response from the server.
|
||||
|
||||
Raises:
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
response = await self.async_client.put("/v1/batch/", json={"memories": memories})
|
||||
response.raise_for_status()
|
||||
@@ -1266,7 +1382,12 @@ class AsyncMemoryClient:
|
||||
str: Message indicating the success of the batch deletion.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
response = await self.async_client.request("DELETE", "/v1/batch/", json={"memories": memories})
|
||||
response.raise_for_status()
|
||||
@@ -1334,7 +1455,12 @@ class AsyncMemoryClient:
|
||||
Dictionary containing the requested fields.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
logger.warning(
|
||||
@@ -1374,7 +1500,12 @@ class AsyncMemoryClient:
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
logger.warning(
|
||||
@@ -1441,7 +1572,12 @@ class AsyncMemoryClient:
|
||||
Dictionary containing webhook details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If project_id is not set.
|
||||
"""
|
||||
|
||||
@@ -1463,7 +1599,12 @@ class AsyncMemoryClient:
|
||||
Dictionary containing the created webhook details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
ValueError: If project_id is not set.
|
||||
"""
|
||||
|
||||
@@ -1493,7 +1634,12 @@ class AsyncMemoryClient:
|
||||
Dictionary containing the updated webhook details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
|
||||
payload = {k: v for k, v in {"name": name, "url": url, "event_types": event_types}.items() if v is not None}
|
||||
@@ -1513,7 +1659,12 @@ class AsyncMemoryClient:
|
||||
Dictionary containing success message.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
MemoryQuotaExceededError: If memory quota is exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
MemoryNotFoundError: If the memory doesn't exist (for updates/deletes).
|
||||
"""
|
||||
|
||||
response = await self.async_client.delete(f"api/v1/webhooks/{webhook_id}/")
|
||||
|
||||
+97
-24
@@ -7,6 +7,7 @@ from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from mem0.client.utils import api_error_handler
|
||||
from mem0.memory.telemetry import capture_client_event
|
||||
# Exception classes are referenced in docstrings only
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -141,7 +142,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the requested project fields.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -159,7 +163,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the created project details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id is not set.
|
||||
"""
|
||||
pass
|
||||
@@ -185,7 +192,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -199,7 +209,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -213,7 +226,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the list of project members.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -231,7 +247,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -249,7 +268,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -266,7 +288,10 @@ class BaseProject(ABC):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
pass
|
||||
@@ -310,7 +335,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the requested project fields.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
params = self._prepare_params({"fields": fields})
|
||||
@@ -339,7 +367,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the created project details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id is not set.
|
||||
"""
|
||||
if not self.config.org_id:
|
||||
@@ -382,7 +413,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
if (
|
||||
@@ -432,7 +466,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
response = self._client.delete(
|
||||
@@ -455,7 +492,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the list of project members.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
response = self._client.get(
|
||||
@@ -482,7 +522,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
if role not in ["READER", "OWNER"]:
|
||||
@@ -515,7 +558,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
if role not in ["READER", "OWNER"]:
|
||||
@@ -547,7 +593,10 @@ class Project(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
params = {"email": email}
|
||||
@@ -603,7 +652,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the requested project fields.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
params = self._prepare_params({"fields": fields})
|
||||
@@ -632,7 +684,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the created project details.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id is not set.
|
||||
"""
|
||||
if not self.config.org_id:
|
||||
@@ -675,7 +730,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
if (
|
||||
@@ -725,7 +783,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
response = await self._client.delete(
|
||||
@@ -748,7 +809,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the list of project members.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
response = await self._client.get(
|
||||
@@ -775,7 +839,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
if role not in ["READER", "OWNER"]:
|
||||
@@ -808,7 +875,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
if role not in ["READER", "OWNER"]:
|
||||
@@ -840,7 +910,10 @@ class AsyncProject(BaseProject):
|
||||
Dictionary containing the API response.
|
||||
|
||||
Raises:
|
||||
APIError: If the API request fails.
|
||||
ValidationError: If the input data is invalid.
|
||||
AuthenticationError: If authentication fails.
|
||||
RateLimitError: If rate limits are exceeded.
|
||||
NetworkError: If network connectivity issues occur.
|
||||
ValueError: If org_id or project_id are not set.
|
||||
"""
|
||||
params = {"email": email}
|
||||
|
||||
+91
-5
@@ -1,18 +1,35 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
import httpx
|
||||
|
||||
from mem0.exceptions import (
|
||||
NetworkError,
|
||||
create_exception_from_response,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class APIError(Exception):
|
||||
"""Exception raised for errors in the API."""
|
||||
"""Exception raised for errors in the API.
|
||||
|
||||
Deprecated: Use specific exception classes from mem0.exceptions instead.
|
||||
This class is maintained for backward compatibility.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def api_error_handler(func):
|
||||
"""Decorator to handle API errors consistently."""
|
||||
"""Decorator to handle API errors consistently.
|
||||
|
||||
This decorator catches HTTP and request errors and converts them to
|
||||
appropriate structured exception classes with detailed error information.
|
||||
|
||||
The decorator analyzes HTTP status codes and response content to create
|
||||
the most specific exception type with helpful error messages, suggestions,
|
||||
and debug information.
|
||||
"""
|
||||
from functools import wraps
|
||||
|
||||
@wraps(func)
|
||||
@@ -21,9 +38,78 @@ def api_error_handler(func):
|
||||
return func(*args, **kwargs)
|
||||
except httpx.HTTPStatusError as e:
|
||||
logger.error(f"HTTP error occurred: {e}")
|
||||
raise APIError(f"API request failed: {e.response.text}")
|
||||
|
||||
# Extract error details from response
|
||||
response_text = ""
|
||||
error_details = {}
|
||||
debug_info = {
|
||||
"status_code": e.response.status_code,
|
||||
"url": str(e.request.url),
|
||||
"method": e.request.method,
|
||||
}
|
||||
|
||||
try:
|
||||
response_text = e.response.text
|
||||
# Try to parse JSON response for additional error details
|
||||
if e.response.headers.get("content-type", "").startswith("application/json"):
|
||||
error_data = json.loads(response_text)
|
||||
if isinstance(error_data, dict):
|
||||
error_details = error_data
|
||||
response_text = error_data.get("detail", response_text)
|
||||
except (json.JSONDecodeError, AttributeError):
|
||||
# Fallback to plain text response
|
||||
pass
|
||||
|
||||
# Add rate limit information if available
|
||||
if e.response.status_code == 429:
|
||||
retry_after = e.response.headers.get("Retry-After")
|
||||
if retry_after:
|
||||
try:
|
||||
debug_info["retry_after"] = int(retry_after)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Add rate limit headers if available
|
||||
for header in ["X-RateLimit-Limit", "X-RateLimit-Remaining", "X-RateLimit-Reset"]:
|
||||
value = e.response.headers.get(header)
|
||||
if value:
|
||||
debug_info[header.lower().replace("-", "_")] = value
|
||||
|
||||
# Create specific exception based on status code
|
||||
exception = create_exception_from_response(
|
||||
status_code=e.response.status_code,
|
||||
response_text=response_text,
|
||||
details=error_details,
|
||||
debug_info=debug_info,
|
||||
)
|
||||
|
||||
raise exception
|
||||
|
||||
except httpx.RequestError as e:
|
||||
logger.error(f"Request error occurred: {e}")
|
||||
raise APIError(f"Request failed: {str(e)}")
|
||||
|
||||
# Determine the appropriate exception type based on error type
|
||||
if isinstance(e, httpx.TimeoutException):
|
||||
raise NetworkError(
|
||||
message=f"Request timed out: {str(e)}",
|
||||
error_code="NET_TIMEOUT",
|
||||
suggestion="Please check your internet connection and try again",
|
||||
debug_info={"error_type": "timeout", "original_error": str(e)},
|
||||
)
|
||||
elif isinstance(e, httpx.ConnectError):
|
||||
raise NetworkError(
|
||||
message=f"Connection failed: {str(e)}",
|
||||
error_code="NET_CONNECT",
|
||||
suggestion="Please check your internet connection and try again",
|
||||
debug_info={"error_type": "connection", "original_error": str(e)},
|
||||
)
|
||||
else:
|
||||
# Generic network error for other request errors
|
||||
raise NetworkError(
|
||||
message=f"Network request failed: {str(e)}",
|
||||
error_code="NET_GENERIC",
|
||||
suggestion="Please check your internet connection and try again",
|
||||
debug_info={"error_type": "request", "original_error": str(e)},
|
||||
)
|
||||
|
||||
return wrapper
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
"""Structured exception classes for Mem0 with error codes, suggestions, and debug information.
|
||||
|
||||
This module provides a comprehensive set of exception classes that replace the generic
|
||||
APIError with specific, actionable exceptions. Each exception includes error codes,
|
||||
user-friendly suggestions, and debug information to enable better error handling
|
||||
and recovery in applications using Mem0.
|
||||
|
||||
Example:
|
||||
Basic usage:
|
||||
try:
|
||||
memory.add(content, user_id=user_id)
|
||||
except RateLimitError as e:
|
||||
# Implement exponential backoff
|
||||
time.sleep(e.debug_info.get('retry_after', 60))
|
||||
except MemoryQuotaExceededError as e:
|
||||
# Trigger quota upgrade flow
|
||||
logger.error(f"Quota exceeded: {e.error_code}")
|
||||
except ValidationError as e:
|
||||
# Return user-friendly error
|
||||
raise HTTPException(400, detail=e.suggestion)
|
||||
|
||||
Advanced usage with error context:
|
||||
try:
|
||||
memory.update(memory_id, content=new_content)
|
||||
except MemoryNotFoundError as e:
|
||||
logger.warning(f"Memory {memory_id} not found: {e.message}")
|
||||
if e.suggestion:
|
||||
logger.info(f"Suggestion: {e.suggestion}")
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
|
||||
class MemoryError(Exception):
|
||||
"""Base exception for all memory-related errors.
|
||||
|
||||
This is the base class for all Mem0-specific exceptions. It provides a structured
|
||||
approach to error handling with error codes, contextual details, suggestions for
|
||||
resolution, and debug information.
|
||||
|
||||
Attributes:
|
||||
message (str): Human-readable error message.
|
||||
error_code (str): Unique error identifier for programmatic handling.
|
||||
details (dict): Additional context about the error.
|
||||
suggestion (str): User-friendly suggestion for resolving the error.
|
||||
debug_info (dict): Technical debugging information.
|
||||
|
||||
Example:
|
||||
raise MemoryError(
|
||||
message="Memory operation failed",
|
||||
error_code="MEM_001",
|
||||
details={"operation": "add", "user_id": "user123"},
|
||||
suggestion="Please check your API key and try again",
|
||||
debug_info={"request_id": "req_456", "timestamp": "2024-01-01T00:00:00Z"}
|
||||
)
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
error_code: str,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
suggestion: Optional[str] = None,
|
||||
debug_info: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize a MemoryError.
|
||||
|
||||
Args:
|
||||
message: Human-readable error message.
|
||||
error_code: Unique error identifier.
|
||||
details: Additional context about the error.
|
||||
suggestion: User-friendly suggestion for resolving the error.
|
||||
debug_info: Technical debugging information.
|
||||
"""
|
||||
self.message = message
|
||||
self.error_code = error_code
|
||||
self.details = details or {}
|
||||
self.suggestion = suggestion
|
||||
self.debug_info = debug_info or {}
|
||||
super().__init__(self.message)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"{self.__class__.__name__}("
|
||||
f"message={self.message!r}, "
|
||||
f"error_code={self.error_code!r}, "
|
||||
f"details={self.details!r}, "
|
||||
f"suggestion={self.suggestion!r}, "
|
||||
f"debug_info={self.debug_info!r})"
|
||||
)
|
||||
|
||||
|
||||
class AuthenticationError(MemoryError):
|
||||
"""Raised when authentication fails.
|
||||
|
||||
This exception is raised when API key validation fails, tokens are invalid,
|
||||
or authentication credentials are missing or expired.
|
||||
|
||||
Common scenarios:
|
||||
- Invalid API key
|
||||
- Expired authentication token
|
||||
- Missing authentication headers
|
||||
- Insufficient permissions
|
||||
|
||||
Example:
|
||||
raise AuthenticationError(
|
||||
message="Invalid API key provided",
|
||||
error_code="AUTH_001",
|
||||
suggestion="Please check your API key in the Mem0 dashboard"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class RateLimitError(MemoryError):
|
||||
"""Raised when rate limits are exceeded.
|
||||
|
||||
This exception is raised when the API rate limit has been exceeded.
|
||||
It includes information about retry timing and current rate limit status.
|
||||
|
||||
The debug_info typically contains:
|
||||
- retry_after: Seconds to wait before retrying
|
||||
- limit: Current rate limit
|
||||
- remaining: Remaining requests in current window
|
||||
- reset_time: When the rate limit window resets
|
||||
|
||||
Example:
|
||||
raise RateLimitError(
|
||||
message="Rate limit exceeded",
|
||||
error_code="RATE_001",
|
||||
suggestion="Please wait before making more requests",
|
||||
debug_info={"retry_after": 60, "limit": 100, "remaining": 0}
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ValidationError(MemoryError):
|
||||
"""Raised when input validation fails.
|
||||
|
||||
This exception is raised when request parameters, memory content,
|
||||
or configuration values fail validation checks.
|
||||
|
||||
Common scenarios:
|
||||
- Invalid user_id format
|
||||
- Missing required fields
|
||||
- Content too long or too short
|
||||
- Invalid metadata format
|
||||
- Malformed filters
|
||||
|
||||
Example:
|
||||
raise ValidationError(
|
||||
message="Invalid user_id format",
|
||||
error_code="VAL_001",
|
||||
details={"field": "user_id", "value": "123", "expected": "string"},
|
||||
suggestion="User ID must be a non-empty string"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MemoryNotFoundError(MemoryError):
|
||||
"""Raised when a memory is not found.
|
||||
|
||||
This exception is raised when attempting to access, update, or delete
|
||||
a memory that doesn't exist or is not accessible to the current user.
|
||||
|
||||
Example:
|
||||
raise MemoryNotFoundError(
|
||||
message="Memory not found",
|
||||
error_code="MEM_404",
|
||||
details={"memory_id": "mem_123", "user_id": "user_456"},
|
||||
suggestion="Please check the memory ID and ensure it exists"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class NetworkError(MemoryError):
|
||||
"""Raised when network connectivity issues occur.
|
||||
|
||||
This exception is raised for network-related problems such as
|
||||
connection timeouts, DNS resolution failures, or service unavailability.
|
||||
|
||||
Common scenarios:
|
||||
- Connection timeout
|
||||
- DNS resolution failure
|
||||
- Service temporarily unavailable
|
||||
- Network connectivity issues
|
||||
|
||||
Example:
|
||||
raise NetworkError(
|
||||
message="Connection timeout",
|
||||
error_code="NET_001",
|
||||
suggestion="Please check your internet connection and try again",
|
||||
debug_info={"timeout": 30, "endpoint": "api.mem0.ai"}
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ConfigurationError(MemoryError):
|
||||
"""Raised when client configuration is invalid.
|
||||
|
||||
This exception is raised when the client is improperly configured,
|
||||
such as missing required settings or invalid configuration values.
|
||||
|
||||
Common scenarios:
|
||||
- Missing API key
|
||||
- Invalid host URL
|
||||
- Incompatible configuration options
|
||||
- Missing required environment variables
|
||||
|
||||
Example:
|
||||
raise ConfigurationError(
|
||||
message="API key not configured",
|
||||
error_code="CFG_001",
|
||||
suggestion="Set MEM0_API_KEY environment variable or pass api_key parameter"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MemoryQuotaExceededError(MemoryError):
|
||||
"""Raised when user's memory quota is exceeded.
|
||||
|
||||
This exception is raised when the user has reached their memory
|
||||
storage or usage limits.
|
||||
|
||||
The debug_info typically contains:
|
||||
- current_usage: Current memory usage
|
||||
- quota_limit: Maximum allowed usage
|
||||
- usage_type: Type of quota (storage, requests, etc.)
|
||||
|
||||
Example:
|
||||
raise MemoryQuotaExceededError(
|
||||
message="Memory quota exceeded",
|
||||
error_code="QUOTA_001",
|
||||
suggestion="Please upgrade your plan or delete unused memories",
|
||||
debug_info={"current_usage": 1000, "quota_limit": 1000, "usage_type": "memories"}
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MemoryCorruptionError(MemoryError):
|
||||
"""Raised when memory data is corrupted.
|
||||
|
||||
This exception is raised when stored memory data is found to be
|
||||
corrupted, malformed, or otherwise unreadable.
|
||||
|
||||
Example:
|
||||
raise MemoryCorruptionError(
|
||||
message="Memory data is corrupted",
|
||||
error_code="CORRUPT_001",
|
||||
details={"memory_id": "mem_123"},
|
||||
suggestion="Please contact support for data recovery assistance"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class VectorSearchError(MemoryError):
|
||||
"""Raised when vector search operations fail.
|
||||
|
||||
This exception is raised when vector database operations fail,
|
||||
such as search queries, embedding generation, or index operations.
|
||||
|
||||
Common scenarios:
|
||||
- Embedding model unavailable
|
||||
- Vector index corruption
|
||||
- Search query timeout
|
||||
- Incompatible vector dimensions
|
||||
|
||||
Example:
|
||||
raise VectorSearchError(
|
||||
message="Vector search failed",
|
||||
error_code="VEC_001",
|
||||
details={"query": "find similar memories", "vector_dim": 1536},
|
||||
suggestion="Please try a simpler search query"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class CacheError(MemoryError):
|
||||
"""Raised when caching operations fail.
|
||||
|
||||
This exception is raised when cache-related operations fail,
|
||||
such as cache misses, cache invalidation errors, or cache corruption.
|
||||
|
||||
Example:
|
||||
raise CacheError(
|
||||
message="Cache operation failed",
|
||||
error_code="CACHE_001",
|
||||
details={"operation": "get", "key": "user_memories_123"},
|
||||
suggestion="Cache will be refreshed automatically"
|
||||
)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# OSS-specific exception classes
|
||||
class VectorStoreError(MemoryError):
|
||||
"""Raised when vector store operations fail.
|
||||
|
||||
This exception is raised when vector store operations fail,
|
||||
such as embedding storage, similarity search, or vector operations.
|
||||
|
||||
Example:
|
||||
raise VectorStoreError(
|
||||
message="Vector store operation failed",
|
||||
error_code="VECTOR_001",
|
||||
details={"operation": "search", "collection": "memories"},
|
||||
suggestion="Please check your vector store configuration and connection"
|
||||
)
|
||||
"""
|
||||
def __init__(self, message: str, error_code: str = "VECTOR_001", details: dict = None,
|
||||
suggestion: str = "Please check your vector store configuration and connection",
|
||||
debug_info: dict = None):
|
||||
super().__init__(message, error_code, details, suggestion, debug_info)
|
||||
|
||||
|
||||
class GraphStoreError(MemoryError):
|
||||
"""Raised when graph store operations fail.
|
||||
|
||||
This exception is raised when graph store operations fail,
|
||||
such as relationship creation, entity management, or graph queries.
|
||||
|
||||
Example:
|
||||
raise GraphStoreError(
|
||||
message="Graph store operation failed",
|
||||
error_code="GRAPH_001",
|
||||
details={"operation": "create_relationship", "entity": "user_123"},
|
||||
suggestion="Please check your graph store configuration and connection"
|
||||
)
|
||||
"""
|
||||
def __init__(self, message: str, error_code: str = "GRAPH_001", details: dict = None,
|
||||
suggestion: str = "Please check your graph store configuration and connection",
|
||||
debug_info: dict = None):
|
||||
super().__init__(message, error_code, details, suggestion, debug_info)
|
||||
|
||||
|
||||
class EmbeddingError(MemoryError):
|
||||
"""Raised when embedding operations fail.
|
||||
|
||||
This exception is raised when embedding operations fail,
|
||||
such as text embedding generation or embedding model errors.
|
||||
|
||||
Example:
|
||||
raise EmbeddingError(
|
||||
message="Embedding generation failed",
|
||||
error_code="EMBED_001",
|
||||
details={"text_length": 1000, "model": "openai"},
|
||||
suggestion="Please check your embedding model configuration"
|
||||
)
|
||||
"""
|
||||
def __init__(self, message: str, error_code: str = "EMBED_001", details: dict = None,
|
||||
suggestion: str = "Please check your embedding model configuration",
|
||||
debug_info: dict = None):
|
||||
super().__init__(message, error_code, details, suggestion, debug_info)
|
||||
|
||||
|
||||
class LLMError(MemoryError):
|
||||
"""Raised when LLM operations fail.
|
||||
|
||||
This exception is raised when LLM operations fail,
|
||||
such as text generation, completion, or model inference errors.
|
||||
|
||||
Example:
|
||||
raise LLMError(
|
||||
message="LLM operation failed",
|
||||
error_code="LLM_001",
|
||||
details={"model": "gpt-4", "prompt_length": 500},
|
||||
suggestion="Please check your LLM configuration and API key"
|
||||
)
|
||||
"""
|
||||
def __init__(self, message: str, error_code: str = "LLM_001", details: dict = None,
|
||||
suggestion: str = "Please check your LLM configuration and API key",
|
||||
debug_info: dict = None):
|
||||
super().__init__(message, error_code, details, suggestion, debug_info)
|
||||
|
||||
|
||||
class DatabaseError(MemoryError):
|
||||
"""Raised when database operations fail.
|
||||
|
||||
This exception is raised when database operations fail,
|
||||
such as SQLite operations, connection issues, or data corruption.
|
||||
|
||||
Example:
|
||||
raise DatabaseError(
|
||||
message="Database operation failed",
|
||||
error_code="DB_001",
|
||||
details={"operation": "insert", "table": "memories"},
|
||||
suggestion="Please check your database configuration and connection"
|
||||
)
|
||||
"""
|
||||
def __init__(self, message: str, error_code: str = "DB_001", details: dict = None,
|
||||
suggestion: str = "Please check your database configuration and connection",
|
||||
debug_info: dict = None):
|
||||
super().__init__(message, error_code, details, suggestion, debug_info)
|
||||
|
||||
|
||||
class DependencyError(MemoryError):
|
||||
"""Raised when required dependencies are missing.
|
||||
|
||||
This exception is raised when required dependencies are missing,
|
||||
such as optional packages for specific providers or features.
|
||||
|
||||
Example:
|
||||
raise DependencyError(
|
||||
message="Required dependency missing",
|
||||
error_code="DEPS_001",
|
||||
details={"package": "kuzu", "feature": "graph_store"},
|
||||
suggestion="Please install the required dependencies: pip install kuzu"
|
||||
)
|
||||
"""
|
||||
def __init__(self, message: str, error_code: str = "DEPS_001", details: dict = None,
|
||||
suggestion: str = "Please install the required dependencies",
|
||||
debug_info: dict = None):
|
||||
super().__init__(message, error_code, details, suggestion, debug_info)
|
||||
|
||||
|
||||
# Mapping of HTTP status codes to specific exception classes
|
||||
HTTP_STATUS_TO_EXCEPTION = {
|
||||
400: ValidationError,
|
||||
401: AuthenticationError,
|
||||
403: AuthenticationError,
|
||||
404: MemoryNotFoundError,
|
||||
408: NetworkError,
|
||||
409: ValidationError,
|
||||
413: MemoryQuotaExceededError,
|
||||
422: ValidationError,
|
||||
429: RateLimitError,
|
||||
500: MemoryError,
|
||||
502: NetworkError,
|
||||
503: NetworkError,
|
||||
504: NetworkError,
|
||||
}
|
||||
|
||||
|
||||
def create_exception_from_response(
|
||||
status_code: int,
|
||||
response_text: str,
|
||||
error_code: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
debug_info: Optional[Dict[str, Any]] = None,
|
||||
) -> MemoryError:
|
||||
"""Create an appropriate exception based on HTTP response.
|
||||
|
||||
This function analyzes the HTTP status code and response to create
|
||||
the most appropriate exception type with relevant error information.
|
||||
|
||||
Args:
|
||||
status_code: HTTP status code from the response.
|
||||
response_text: Response body text.
|
||||
error_code: Optional specific error code.
|
||||
details: Additional error context.
|
||||
debug_info: Debug information.
|
||||
|
||||
Returns:
|
||||
An instance of the appropriate MemoryError subclass.
|
||||
|
||||
Example:
|
||||
exception = create_exception_from_response(
|
||||
status_code=429,
|
||||
response_text="Rate limit exceeded",
|
||||
debug_info={"retry_after": 60}
|
||||
)
|
||||
# Returns a RateLimitError instance
|
||||
"""
|
||||
exception_class = HTTP_STATUS_TO_EXCEPTION.get(status_code, MemoryError)
|
||||
|
||||
# Generate error code if not provided
|
||||
if not error_code:
|
||||
error_code = f"HTTP_{status_code}"
|
||||
|
||||
# Create appropriate suggestion based on status code
|
||||
suggestions = {
|
||||
400: "Please check your request parameters and try again",
|
||||
401: "Please check your API key and authentication credentials",
|
||||
403: "You don't have permission to perform this operation",
|
||||
404: "The requested resource was not found",
|
||||
408: "Request timed out. Please try again",
|
||||
409: "Resource conflict. Please check your request",
|
||||
413: "Request too large. Please reduce the size of your request",
|
||||
422: "Invalid request data. Please check your input",
|
||||
429: "Rate limit exceeded. Please wait before making more requests",
|
||||
500: "Internal server error. Please try again later",
|
||||
502: "Service temporarily unavailable. Please try again later",
|
||||
503: "Service unavailable. Please try again later",
|
||||
504: "Gateway timeout. Please try again later",
|
||||
}
|
||||
|
||||
suggestion = suggestions.get(status_code, "Please try again later")
|
||||
|
||||
return exception_class(
|
||||
message=response_text or f"HTTP {status_code} error",
|
||||
error_code=error_code,
|
||||
details=details or {},
|
||||
suggestion=suggestion,
|
||||
debug_info=debug_info or {},
|
||||
)
|
||||
+32
-6
@@ -7,7 +7,6 @@ import logging
|
||||
import os
|
||||
import uuid
|
||||
import warnings
|
||||
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
@@ -21,6 +20,7 @@ from mem0.configs.prompts import (
|
||||
PROCEDURAL_MEMORY_SYSTEM_PROMPT,
|
||||
get_update_memory_messages,
|
||||
)
|
||||
from mem0.exceptions import ValidationError as Mem0ValidationError
|
||||
from mem0.memory.base import MemoryBase
|
||||
from mem0.memory.setup import mem0_dir, setup_config
|
||||
from mem0.memory.storage import SQLiteManager
|
||||
@@ -109,7 +109,12 @@ def _build_filters_and_metadata(
|
||||
session_ids_provided.append("run_id")
|
||||
|
||||
if not session_ids_provided:
|
||||
raise ValueError("At least one of 'user_id', 'agent_id', or 'run_id' must be provided.")
|
||||
raise Mem0ValidationError(
|
||||
message="At least one of 'user_id', 'agent_id', or 'run_id' must be provided.",
|
||||
error_code="VALIDATION_001",
|
||||
details={"provided_ids": {"user_id": user_id, "agent_id": agent_id, "run_id": run_id}},
|
||||
suggestion="Please provide at least one identifier to scope the memory operation."
|
||||
)
|
||||
|
||||
# ---------- optional actor filter ----------
|
||||
resolved_actor_id = actor_id or effective_query_filters.get("actor_id")
|
||||
@@ -227,6 +232,14 @@ class Memory(MemoryBase):
|
||||
including a list of memory items affected (added, updated) under a "results" key,
|
||||
and potentially "relations" if graph store is enabled.
|
||||
Example for v1.1+: `{"results": [{"id": "...", "memory": "...", "event": "ADD"}]}`
|
||||
|
||||
Raises:
|
||||
Mem0ValidationError: If input validation fails (invalid memory_type, messages format, etc.).
|
||||
VectorStoreError: If vector store operations fail.
|
||||
GraphStoreError: If graph store operations fail.
|
||||
EmbeddingError: If embedding generation fails.
|
||||
LLMError: If LLM operations fail.
|
||||
DatabaseError: If database operations fail.
|
||||
"""
|
||||
|
||||
processed_metadata, effective_filters = _build_filters_and_metadata(
|
||||
@@ -237,8 +250,11 @@ class Memory(MemoryBase):
|
||||
)
|
||||
|
||||
if memory_type is not None and memory_type != MemoryType.PROCEDURAL.value:
|
||||
raise ValueError(
|
||||
f"Invalid 'memory_type'. Please pass {MemoryType.PROCEDURAL.value} to create procedural memories."
|
||||
raise Mem0ValidationError(
|
||||
message=f"Invalid 'memory_type'. Please pass {MemoryType.PROCEDURAL.value} to create procedural memories.",
|
||||
error_code="VALIDATION_002",
|
||||
details={"provided_type": memory_type, "valid_type": MemoryType.PROCEDURAL.value},
|
||||
suggestion=f"Use '{MemoryType.PROCEDURAL.value}' to create procedural memories."
|
||||
)
|
||||
|
||||
if isinstance(messages, str):
|
||||
@@ -248,7 +264,12 @@ class Memory(MemoryBase):
|
||||
messages = [messages]
|
||||
|
||||
elif not isinstance(messages, list):
|
||||
raise ValueError("messages must be str, dict, or list[dict]")
|
||||
raise Mem0ValidationError(
|
||||
message="messages must be str, dict, or list[dict]",
|
||||
error_code="VALIDATION_003",
|
||||
details={"provided_type": type(messages).__name__, "valid_types": ["str", "dict", "list[dict]"]},
|
||||
suggestion="Convert your input to a string, dictionary, or list of dictionaries."
|
||||
)
|
||||
|
||||
if agent_id is not None and memory_type == MemoryType.PROCEDURAL.value:
|
||||
results = self._create_procedural_memory(messages, metadata=processed_metadata, prompt=prompt)
|
||||
@@ -1090,7 +1111,12 @@ class AsyncMemory(MemoryBase):
|
||||
messages = [messages]
|
||||
|
||||
elif not isinstance(messages, list):
|
||||
raise ValueError("messages must be str, dict, or list[dict]")
|
||||
raise Mem0ValidationError(
|
||||
message="messages must be str, dict, or list[dict]",
|
||||
error_code="VALIDATION_003",
|
||||
details={"provided_type": type(messages).__name__, "valid_types": ["str", "dict", "list[dict]"]},
|
||||
suggestion="Convert your input to a string, dictionary, or list of dictionaries."
|
||||
)
|
||||
|
||||
if agent_id is not None and memory_type == MemoryType.PROCEDURAL.value:
|
||||
results = await self._create_procedural_memory(
|
||||
|
||||
Reference in New Issue
Block a user