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.project import AsyncProject, Project
|
||||||
from mem0.client.utils import api_error_handler
|
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.setup import get_user_id, setup_config
|
||||||
from mem0.memory.telemetry import capture_client_event
|
from mem0.memory.telemetry import capture_client_event
|
||||||
|
|
||||||
@@ -139,7 +140,12 @@ class MemoryClient:
|
|||||||
A dictionary containing the API response.
|
A dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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)
|
kwargs = self._prepare_params(kwargs)
|
||||||
if kwargs.get("output_format") != "v1.1":
|
if kwargs.get("output_format") != "v1.1":
|
||||||
@@ -173,7 +179,12 @@ class MemoryClient:
|
|||||||
A dictionary containing the memory data.
|
A dictionary containing the memory data.
|
||||||
|
|
||||||
Raises:
|
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()
|
params = self._prepare_params()
|
||||||
response = self.client.get(f"/v1/memories/{memory_id}/", params=params)
|
response = self.client.get(f"/v1/memories/{memory_id}/", params=params)
|
||||||
@@ -194,7 +205,12 @@ class MemoryClient:
|
|||||||
A list of dictionaries containing memories.
|
A list of dictionaries containing memories.
|
||||||
|
|
||||||
Raises:
|
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)
|
params = self._prepare_params(kwargs)
|
||||||
if version == "v1":
|
if version == "v1":
|
||||||
@@ -236,7 +252,12 @@ class MemoryClient:
|
|||||||
A list of dictionaries containing search results.
|
A list of dictionaries containing search results.
|
||||||
|
|
||||||
Raises:
|
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}
|
payload = {"query": query}
|
||||||
params = self._prepare_params(kwargs)
|
params = self._prepare_params(kwargs)
|
||||||
@@ -303,7 +324,12 @@ class MemoryClient:
|
|||||||
A dictionary containing the API response.
|
A dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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()
|
params = self._prepare_params()
|
||||||
response = self.client.delete(f"/v1/memories/{memory_id}/", params=params)
|
response = self.client.delete(f"/v1/memories/{memory_id}/", params=params)
|
||||||
@@ -323,7 +349,12 @@ class MemoryClient:
|
|||||||
A dictionary containing the API response.
|
A dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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)
|
params = self._prepare_params(kwargs)
|
||||||
response = self.client.delete("/v1/memories/", params=params)
|
response = self.client.delete("/v1/memories/", params=params)
|
||||||
@@ -346,7 +377,12 @@ class MemoryClient:
|
|||||||
A list of dictionaries containing the memory history.
|
A list of dictionaries containing the memory history.
|
||||||
|
|
||||||
Raises:
|
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()
|
params = self._prepare_params()
|
||||||
response = self.client.get(f"/v1/memories/{memory_id}/history/", params=params)
|
response = self.client.get(f"/v1/memories/{memory_id}/history/", params=params)
|
||||||
@@ -384,7 +420,10 @@ class MemoryClient:
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If specified entity not found
|
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:
|
if user_id:
|
||||||
@@ -438,10 +477,13 @@ class MemoryClient:
|
|||||||
Dict[str, str]: Message client reset successful.
|
Dict[str, str]: Message client reset successful.
|
||||||
|
|
||||||
Raises:
|
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()
|
self.delete_users()
|
||||||
|
|
||||||
capture_client_event("client.reset", self, {"sync_type": "sync"})
|
capture_client_event("client.reset", self, {"sync_type": "sync"})
|
||||||
@@ -459,6 +501,14 @@ class MemoryClient:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, Any]: The response from the server.
|
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 = self.client.put("/v1/batch/", json={"memories": memories})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@@ -479,7 +529,12 @@ class MemoryClient:
|
|||||||
str: Message indicating the success of the batch deletion.
|
str: Message indicating the success of the batch deletion.
|
||||||
|
|
||||||
Raises:
|
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 = self.client.request("DELETE", "/v1/batch/", json={"memories": memories})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@@ -560,7 +615,12 @@ class MemoryClient:
|
|||||||
Dictionary containing the requested fields.
|
Dictionary containing the requested fields.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -604,7 +664,12 @@ class MemoryClient:
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -673,7 +738,12 @@ class MemoryClient:
|
|||||||
Dictionary containing webhook details.
|
Dictionary containing webhook details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If project_id is not set.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -695,7 +765,12 @@ class MemoryClient:
|
|||||||
Dictionary containing the created webhook details.
|
Dictionary containing the created webhook details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If project_id is not set.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -725,7 +800,12 @@ class MemoryClient:
|
|||||||
Dictionary containing the updated webhook details.
|
Dictionary containing the updated webhook details.
|
||||||
|
|
||||||
Raises:
|
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}
|
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.
|
Dictionary containing success message.
|
||||||
|
|
||||||
Raises:
|
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}/")
|
response = self.client.delete(f"api/v1/webhooks/{webhook_id}/")
|
||||||
@@ -1098,7 +1183,12 @@ class AsyncMemoryClient:
|
|||||||
A dictionary containing the API response.
|
A dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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()
|
params = self._prepare_params()
|
||||||
response = await self.async_client.delete(f"/v1/memories/{memory_id}/", params=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.
|
A dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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)
|
params = self._prepare_params(kwargs)
|
||||||
response = await self.async_client.delete("/v1/memories/", params=params)
|
response = await self.async_client.delete("/v1/memories/", params=params)
|
||||||
@@ -1136,7 +1231,12 @@ class AsyncMemoryClient:
|
|||||||
A list of dictionaries containing the memory history.
|
A list of dictionaries containing the memory history.
|
||||||
|
|
||||||
Raises:
|
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()
|
params = self._prepare_params()
|
||||||
response = await self.async_client.get(f"/v1/memories/{memory_id}/history/", params=params)
|
response = await self.async_client.get(f"/v1/memories/{memory_id}/history/", params=params)
|
||||||
@@ -1174,7 +1274,10 @@ class AsyncMemoryClient:
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If specified entity not found
|
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:
|
if user_id:
|
||||||
@@ -1228,7 +1331,12 @@ class AsyncMemoryClient:
|
|||||||
Dict[str, str]: Message client reset successful.
|
Dict[str, str]: Message client reset successful.
|
||||||
|
|
||||||
Raises:
|
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()
|
await self.delete_users()
|
||||||
capture_client_event("client.reset", self, {"sync_type": "async"})
|
capture_client_event("client.reset", self, {"sync_type": "async"})
|
||||||
@@ -1246,6 +1354,14 @@ class AsyncMemoryClient:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, Any]: The response from the server.
|
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 = await self.async_client.put("/v1/batch/", json={"memories": memories})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@@ -1266,7 +1382,12 @@ class AsyncMemoryClient:
|
|||||||
str: Message indicating the success of the batch deletion.
|
str: Message indicating the success of the batch deletion.
|
||||||
|
|
||||||
Raises:
|
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 = await self.async_client.request("DELETE", "/v1/batch/", json={"memories": memories})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@@ -1334,7 +1455,12 @@ class AsyncMemoryClient:
|
|||||||
Dictionary containing the requested fields.
|
Dictionary containing the requested fields.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -1374,7 +1500,12 @@ class AsyncMemoryClient:
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -1441,7 +1572,12 @@ class AsyncMemoryClient:
|
|||||||
Dictionary containing webhook details.
|
Dictionary containing webhook details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If project_id is not set.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1463,7 +1599,12 @@ class AsyncMemoryClient:
|
|||||||
Dictionary containing the created webhook details.
|
Dictionary containing the created webhook details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If project_id is not set.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1493,7 +1634,12 @@ class AsyncMemoryClient:
|
|||||||
Dictionary containing the updated webhook details.
|
Dictionary containing the updated webhook details.
|
||||||
|
|
||||||
Raises:
|
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}
|
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.
|
Dictionary containing success message.
|
||||||
|
|
||||||
Raises:
|
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}/")
|
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.client.utils import api_error_handler
|
||||||
from mem0.memory.telemetry import capture_client_event
|
from mem0.memory.telemetry import capture_client_event
|
||||||
|
# Exception classes are referenced in docstrings only
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -141,7 +142,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the requested project fields.
|
Dictionary containing the requested project fields.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -159,7 +163,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the created project details.
|
Dictionary containing the created project details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id is not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -185,7 +192,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -199,7 +209,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -213,7 +226,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the list of project members.
|
Dictionary containing the list of project members.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -231,7 +247,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -249,7 +268,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -266,7 +288,10 @@ class BaseProject(ABC):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -310,7 +335,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the requested project fields.
|
Dictionary containing the requested project fields.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
params = self._prepare_params({"fields": fields})
|
params = self._prepare_params({"fields": fields})
|
||||||
@@ -339,7 +367,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the created project details.
|
Dictionary containing the created project details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id is not set.
|
||||||
"""
|
"""
|
||||||
if not self.config.org_id:
|
if not self.config.org_id:
|
||||||
@@ -382,7 +413,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
if (
|
if (
|
||||||
@@ -432,7 +466,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
response = self._client.delete(
|
response = self._client.delete(
|
||||||
@@ -455,7 +492,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the list of project members.
|
Dictionary containing the list of project members.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
response = self._client.get(
|
response = self._client.get(
|
||||||
@@ -482,7 +522,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
if role not in ["READER", "OWNER"]:
|
if role not in ["READER", "OWNER"]:
|
||||||
@@ -515,7 +558,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
if role not in ["READER", "OWNER"]:
|
if role not in ["READER", "OWNER"]:
|
||||||
@@ -547,7 +593,10 @@ class Project(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
params = {"email": email}
|
params = {"email": email}
|
||||||
@@ -603,7 +652,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the requested project fields.
|
Dictionary containing the requested project fields.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
params = self._prepare_params({"fields": fields})
|
params = self._prepare_params({"fields": fields})
|
||||||
@@ -632,7 +684,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the created project details.
|
Dictionary containing the created project details.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id is not set.
|
||||||
"""
|
"""
|
||||||
if not self.config.org_id:
|
if not self.config.org_id:
|
||||||
@@ -675,7 +730,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
if (
|
if (
|
||||||
@@ -725,7 +783,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
response = await self._client.delete(
|
response = await self._client.delete(
|
||||||
@@ -748,7 +809,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the list of project members.
|
Dictionary containing the list of project members.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
response = await self._client.get(
|
response = await self._client.get(
|
||||||
@@ -775,7 +839,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
if role not in ["READER", "OWNER"]:
|
if role not in ["READER", "OWNER"]:
|
||||||
@@ -808,7 +875,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
if role not in ["READER", "OWNER"]:
|
if role not in ["READER", "OWNER"]:
|
||||||
@@ -840,7 +910,10 @@ class AsyncProject(BaseProject):
|
|||||||
Dictionary containing the API response.
|
Dictionary containing the API response.
|
||||||
|
|
||||||
Raises:
|
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.
|
ValueError: If org_id or project_id are not set.
|
||||||
"""
|
"""
|
||||||
params = {"email": email}
|
params = {"email": email}
|
||||||
|
|||||||
+91
-5
@@ -1,18 +1,35 @@
|
|||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
from mem0.exceptions import (
|
||||||
|
NetworkError,
|
||||||
|
create_exception_from_response,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class APIError(Exception):
|
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
|
pass
|
||||||
|
|
||||||
|
|
||||||
def api_error_handler(func):
|
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
|
from functools import wraps
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
@@ -21,9 +38,78 @@ def api_error_handler(func):
|
|||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
logger.error(f"HTTP error occurred: {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:
|
except httpx.RequestError as e:
|
||||||
logger.error(f"Request error occurred: {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
|
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 os
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
@@ -21,6 +20,7 @@ from mem0.configs.prompts import (
|
|||||||
PROCEDURAL_MEMORY_SYSTEM_PROMPT,
|
PROCEDURAL_MEMORY_SYSTEM_PROMPT,
|
||||||
get_update_memory_messages,
|
get_update_memory_messages,
|
||||||
)
|
)
|
||||||
|
from mem0.exceptions import ValidationError as Mem0ValidationError
|
||||||
from mem0.memory.base import MemoryBase
|
from mem0.memory.base import MemoryBase
|
||||||
from mem0.memory.setup import mem0_dir, setup_config
|
from mem0.memory.setup import mem0_dir, setup_config
|
||||||
from mem0.memory.storage import SQLiteManager
|
from mem0.memory.storage import SQLiteManager
|
||||||
@@ -109,7 +109,12 @@ def _build_filters_and_metadata(
|
|||||||
session_ids_provided.append("run_id")
|
session_ids_provided.append("run_id")
|
||||||
|
|
||||||
if not session_ids_provided:
|
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 ----------
|
# ---------- optional actor filter ----------
|
||||||
resolved_actor_id = actor_id or effective_query_filters.get("actor_id")
|
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,
|
including a list of memory items affected (added, updated) under a "results" key,
|
||||||
and potentially "relations" if graph store is enabled.
|
and potentially "relations" if graph store is enabled.
|
||||||
Example for v1.1+: `{"results": [{"id": "...", "memory": "...", "event": "ADD"}]}`
|
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(
|
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:
|
if memory_type is not None and memory_type != MemoryType.PROCEDURAL.value:
|
||||||
raise ValueError(
|
raise Mem0ValidationError(
|
||||||
f"Invalid 'memory_type'. Please pass {MemoryType.PROCEDURAL.value} to create procedural memories."
|
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):
|
if isinstance(messages, str):
|
||||||
@@ -248,7 +264,12 @@ class Memory(MemoryBase):
|
|||||||
messages = [messages]
|
messages = [messages]
|
||||||
|
|
||||||
elif not isinstance(messages, list):
|
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:
|
if agent_id is not None and memory_type == MemoryType.PROCEDURAL.value:
|
||||||
results = self._create_procedural_memory(messages, metadata=processed_metadata, prompt=prompt)
|
results = self._create_procedural_memory(messages, metadata=processed_metadata, prompt=prompt)
|
||||||
@@ -1090,7 +1111,12 @@ class AsyncMemory(MemoryBase):
|
|||||||
messages = [messages]
|
messages = [messages]
|
||||||
|
|
||||||
elif not isinstance(messages, list):
|
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:
|
if agent_id is not None and memory_type == MemoryType.PROCEDURAL.value:
|
||||||
results = await self._create_procedural_memory(
|
results = await self._create_procedural_memory(
|
||||||
|
|||||||
Reference in New Issue
Block a user