memorisdk 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of memorisdk might be problematic. Click here for more details.
- memoriai/__init__.py +140 -0
- memoriai/agents/__init__.py +7 -0
- memoriai/agents/conscious_agent.py +506 -0
- memoriai/agents/memory_agent.py +322 -0
- memoriai/agents/retrieval_agent.py +579 -0
- memoriai/config/__init__.py +14 -0
- memoriai/config/manager.py +281 -0
- memoriai/config/settings.py +287 -0
- memoriai/core/__init__.py +6 -0
- memoriai/core/database.py +966 -0
- memoriai/core/memory.py +1349 -0
- memoriai/database/__init__.py +5 -0
- memoriai/database/connectors/__init__.py +9 -0
- memoriai/database/connectors/mysql_connector.py +159 -0
- memoriai/database/connectors/postgres_connector.py +158 -0
- memoriai/database/connectors/sqlite_connector.py +148 -0
- memoriai/database/queries/__init__.py +15 -0
- memoriai/database/queries/base_queries.py +204 -0
- memoriai/database/queries/chat_queries.py +157 -0
- memoriai/database/queries/entity_queries.py +236 -0
- memoriai/database/queries/memory_queries.py +178 -0
- memoriai/database/templates/__init__.py +0 -0
- memoriai/database/templates/basic_template.py +0 -0
- memoriai/database/templates/schemas/__init__.py +0 -0
- memoriai/integrations/__init__.py +68 -0
- memoriai/integrations/anthropic_integration.py +194 -0
- memoriai/integrations/litellm_integration.py +11 -0
- memoriai/integrations/openai_integration.py +273 -0
- memoriai/scripts/llm_text.py +50 -0
- memoriai/tools/__init__.py +5 -0
- memoriai/tools/memory_tool.py +544 -0
- memoriai/utils/__init__.py +89 -0
- memoriai/utils/exceptions.py +418 -0
- memoriai/utils/helpers.py +433 -0
- memoriai/utils/logging.py +204 -0
- memoriai/utils/pydantic_models.py +258 -0
- memoriai/utils/schemas.py +0 -0
- memoriai/utils/validators.py +339 -0
- memorisdk-1.0.0.dist-info/METADATA +386 -0
- memorisdk-1.0.0.dist-info/RECORD +44 -0
- memorisdk-1.0.0.dist-info/WHEEL +5 -0
- memorisdk-1.0.0.dist-info/entry_points.txt +2 -0
- memorisdk-1.0.0.dist-info/licenses/LICENSE +203 -0
- memorisdk-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom exceptions for Memoriai with comprehensive error handling
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import traceback
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Any, Dict, Optional, Union
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MemoriError(Exception):
|
|
11
|
+
"""Base exception for Memoriai with enhanced error context"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
message: str,
|
|
16
|
+
error_code: Optional[str] = None,
|
|
17
|
+
context: Optional[Dict[str, Any]] = None,
|
|
18
|
+
cause: Optional[Exception] = None,
|
|
19
|
+
):
|
|
20
|
+
super().__init__(message)
|
|
21
|
+
self.message = message
|
|
22
|
+
self.error_code = error_code or self.__class__.__name__.upper()
|
|
23
|
+
self.context = context or {}
|
|
24
|
+
self.cause = cause
|
|
25
|
+
self.timestamp = datetime.now()
|
|
26
|
+
self.traceback = traceback.format_exc() if cause else None
|
|
27
|
+
|
|
28
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
29
|
+
"""Convert exception to dictionary for logging/serialization"""
|
|
30
|
+
return {
|
|
31
|
+
"error_type": self.__class__.__name__,
|
|
32
|
+
"error_code": self.error_code,
|
|
33
|
+
"message": self.message,
|
|
34
|
+
"context": self.context,
|
|
35
|
+
"timestamp": self.timestamp.isoformat(),
|
|
36
|
+
"cause": str(self.cause) if self.cause else None,
|
|
37
|
+
"traceback": self.traceback,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
def __str__(self) -> str:
|
|
41
|
+
base_msg = f"[{self.error_code}] {self.message}"
|
|
42
|
+
if self.context:
|
|
43
|
+
base_msg += f" | Context: {self.context}"
|
|
44
|
+
if self.cause:
|
|
45
|
+
base_msg += f" | Caused by: {self.cause}"
|
|
46
|
+
return base_msg
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DatabaseError(MemoriError):
|
|
50
|
+
"""Database-related errors with connection and query context"""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
message: str,
|
|
55
|
+
query: Optional[str] = None,
|
|
56
|
+
connection_string: Optional[str] = None,
|
|
57
|
+
error_code: Optional[str] = None,
|
|
58
|
+
cause: Optional[Exception] = None,
|
|
59
|
+
):
|
|
60
|
+
context = {}
|
|
61
|
+
if query:
|
|
62
|
+
context["query"] = query
|
|
63
|
+
if connection_string:
|
|
64
|
+
# Sanitize connection string (remove credentials)
|
|
65
|
+
sanitized = self._sanitize_connection_string(connection_string)
|
|
66
|
+
context["connection"] = sanitized
|
|
67
|
+
|
|
68
|
+
super().__init__(
|
|
69
|
+
message=message,
|
|
70
|
+
error_code=error_code or "DB_ERROR",
|
|
71
|
+
context=context,
|
|
72
|
+
cause=cause,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def _sanitize_connection_string(conn_str: str) -> str:
|
|
77
|
+
"""Remove credentials from connection string for safe logging"""
|
|
78
|
+
import re
|
|
79
|
+
|
|
80
|
+
# Remove password from connection strings
|
|
81
|
+
sanitized = re.sub(r"://[^:]+:[^@]+@", "://***:***@", conn_str)
|
|
82
|
+
return sanitized
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class AgentError(MemoriError):
|
|
86
|
+
"""Memory agent-related errors with API and processing context"""
|
|
87
|
+
|
|
88
|
+
def __init__(
|
|
89
|
+
self,
|
|
90
|
+
message: str,
|
|
91
|
+
agent_type: Optional[str] = None,
|
|
92
|
+
model: Optional[str] = None,
|
|
93
|
+
api_endpoint: Optional[str] = None,
|
|
94
|
+
tokens_used: Optional[int] = None,
|
|
95
|
+
error_code: Optional[str] = None,
|
|
96
|
+
cause: Optional[Exception] = None,
|
|
97
|
+
):
|
|
98
|
+
context = {}
|
|
99
|
+
if agent_type:
|
|
100
|
+
context["agent_type"] = agent_type
|
|
101
|
+
if model:
|
|
102
|
+
context["model"] = model
|
|
103
|
+
if api_endpoint:
|
|
104
|
+
context["api_endpoint"] = api_endpoint
|
|
105
|
+
if tokens_used:
|
|
106
|
+
context["tokens_used"] = tokens_used
|
|
107
|
+
|
|
108
|
+
super().__init__(
|
|
109
|
+
message=message,
|
|
110
|
+
error_code=error_code or "AGENT_ERROR",
|
|
111
|
+
context=context,
|
|
112
|
+
cause=cause,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ConfigurationError(MemoriError):
|
|
117
|
+
"""Configuration-related errors with setting context"""
|
|
118
|
+
|
|
119
|
+
def __init__(
|
|
120
|
+
self,
|
|
121
|
+
message: str,
|
|
122
|
+
setting_path: Optional[str] = None,
|
|
123
|
+
config_file: Optional[str] = None,
|
|
124
|
+
error_code: Optional[str] = None,
|
|
125
|
+
cause: Optional[Exception] = None,
|
|
126
|
+
):
|
|
127
|
+
context = {}
|
|
128
|
+
if setting_path:
|
|
129
|
+
context["setting_path"] = setting_path
|
|
130
|
+
if config_file:
|
|
131
|
+
context["config_file"] = config_file
|
|
132
|
+
|
|
133
|
+
super().__init__(
|
|
134
|
+
message=message,
|
|
135
|
+
error_code=error_code or "CONFIG_ERROR",
|
|
136
|
+
context=context,
|
|
137
|
+
cause=cause,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class ValidationError(MemoriError):
|
|
142
|
+
"""Data validation errors with field context"""
|
|
143
|
+
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
message: str,
|
|
147
|
+
field_name: Optional[str] = None,
|
|
148
|
+
field_value: Optional[Any] = None,
|
|
149
|
+
expected_type: Optional[str] = None,
|
|
150
|
+
error_code: Optional[str] = None,
|
|
151
|
+
cause: Optional[Exception] = None,
|
|
152
|
+
):
|
|
153
|
+
context = {}
|
|
154
|
+
if field_name:
|
|
155
|
+
context["field_name"] = field_name
|
|
156
|
+
if field_value is not None:
|
|
157
|
+
context["field_value"] = str(field_value)
|
|
158
|
+
if expected_type:
|
|
159
|
+
context["expected_type"] = expected_type
|
|
160
|
+
|
|
161
|
+
super().__init__(
|
|
162
|
+
message=message,
|
|
163
|
+
error_code=error_code or "VALIDATION_ERROR",
|
|
164
|
+
context=context,
|
|
165
|
+
cause=cause,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class IntegrationError(MemoriError):
|
|
170
|
+
"""Integration-related errors with provider context"""
|
|
171
|
+
|
|
172
|
+
def __init__(
|
|
173
|
+
self,
|
|
174
|
+
message: str,
|
|
175
|
+
provider: Optional[str] = None,
|
|
176
|
+
integration_type: Optional[str] = None,
|
|
177
|
+
error_code: Optional[str] = None,
|
|
178
|
+
cause: Optional[Exception] = None,
|
|
179
|
+
):
|
|
180
|
+
context = {}
|
|
181
|
+
if provider:
|
|
182
|
+
context["provider"] = provider
|
|
183
|
+
if integration_type:
|
|
184
|
+
context["integration_type"] = integration_type
|
|
185
|
+
|
|
186
|
+
super().__init__(
|
|
187
|
+
message=message,
|
|
188
|
+
error_code=error_code or "INTEGRATION_ERROR",
|
|
189
|
+
context=context,
|
|
190
|
+
cause=cause,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class AuthenticationError(MemoriError):
|
|
195
|
+
"""Authentication and authorization errors"""
|
|
196
|
+
|
|
197
|
+
def __init__(
|
|
198
|
+
self,
|
|
199
|
+
message: str,
|
|
200
|
+
auth_type: Optional[str] = None,
|
|
201
|
+
endpoint: Optional[str] = None,
|
|
202
|
+
error_code: Optional[str] = None,
|
|
203
|
+
cause: Optional[Exception] = None,
|
|
204
|
+
):
|
|
205
|
+
context = {}
|
|
206
|
+
if auth_type:
|
|
207
|
+
context["auth_type"] = auth_type
|
|
208
|
+
if endpoint:
|
|
209
|
+
context["endpoint"] = endpoint
|
|
210
|
+
|
|
211
|
+
super().__init__(
|
|
212
|
+
message=message,
|
|
213
|
+
error_code=error_code or "AUTH_ERROR",
|
|
214
|
+
context=context,
|
|
215
|
+
cause=cause,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class RateLimitError(MemoriError):
|
|
220
|
+
"""Rate limiting errors with quota context"""
|
|
221
|
+
|
|
222
|
+
def __init__(
|
|
223
|
+
self,
|
|
224
|
+
message: str,
|
|
225
|
+
provider: Optional[str] = None,
|
|
226
|
+
limit_type: Optional[str] = None,
|
|
227
|
+
retry_after: Optional[int] = None,
|
|
228
|
+
error_code: Optional[str] = None,
|
|
229
|
+
cause: Optional[Exception] = None,
|
|
230
|
+
):
|
|
231
|
+
context = {}
|
|
232
|
+
if provider:
|
|
233
|
+
context["provider"] = provider
|
|
234
|
+
if limit_type:
|
|
235
|
+
context["limit_type"] = limit_type
|
|
236
|
+
if retry_after:
|
|
237
|
+
context["retry_after"] = retry_after
|
|
238
|
+
|
|
239
|
+
super().__init__(
|
|
240
|
+
message=message,
|
|
241
|
+
error_code=error_code or "RATE_LIMIT_ERROR",
|
|
242
|
+
context=context,
|
|
243
|
+
cause=cause,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class MemoryNotFoundError(MemoriError):
|
|
248
|
+
"""Memory not found errors with search context"""
|
|
249
|
+
|
|
250
|
+
def __init__(
|
|
251
|
+
self,
|
|
252
|
+
message: str,
|
|
253
|
+
memory_id: Optional[str] = None,
|
|
254
|
+
namespace: Optional[str] = None,
|
|
255
|
+
search_criteria: Optional[Dict[str, Any]] = None,
|
|
256
|
+
error_code: Optional[str] = None,
|
|
257
|
+
cause: Optional[Exception] = None,
|
|
258
|
+
):
|
|
259
|
+
context = {}
|
|
260
|
+
if memory_id:
|
|
261
|
+
context["memory_id"] = memory_id
|
|
262
|
+
if namespace:
|
|
263
|
+
context["namespace"] = namespace
|
|
264
|
+
if search_criteria:
|
|
265
|
+
context["search_criteria"] = search_criteria
|
|
266
|
+
|
|
267
|
+
super().__init__(
|
|
268
|
+
message=message,
|
|
269
|
+
error_code=error_code or "MEMORY_NOT_FOUND",
|
|
270
|
+
context=context,
|
|
271
|
+
cause=cause,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class ProcessingError(MemoriError):
|
|
276
|
+
"""Memory processing errors with processing context"""
|
|
277
|
+
|
|
278
|
+
def __init__(
|
|
279
|
+
self,
|
|
280
|
+
message: str,
|
|
281
|
+
processing_stage: Optional[str] = None,
|
|
282
|
+
input_data: Optional[Dict[str, Any]] = None,
|
|
283
|
+
error_code: Optional[str] = None,
|
|
284
|
+
cause: Optional[Exception] = None,
|
|
285
|
+
):
|
|
286
|
+
context = {}
|
|
287
|
+
if processing_stage:
|
|
288
|
+
context["processing_stage"] = processing_stage
|
|
289
|
+
if input_data:
|
|
290
|
+
# Sanitize potentially sensitive data
|
|
291
|
+
sanitized_data = {
|
|
292
|
+
k: (v if k not in ["api_key", "password", "secret"] else "***")
|
|
293
|
+
for k, v in input_data.items()
|
|
294
|
+
}
|
|
295
|
+
context["input_data"] = sanitized_data
|
|
296
|
+
|
|
297
|
+
super().__init__(
|
|
298
|
+
message=message,
|
|
299
|
+
error_code=error_code or "PROCESSING_ERROR",
|
|
300
|
+
context=context,
|
|
301
|
+
cause=cause,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class TimeoutError(MemoriError):
|
|
306
|
+
"""Timeout errors with operation context"""
|
|
307
|
+
|
|
308
|
+
def __init__(
|
|
309
|
+
self,
|
|
310
|
+
message: str,
|
|
311
|
+
operation: Optional[str] = None,
|
|
312
|
+
timeout_seconds: Optional[float] = None,
|
|
313
|
+
error_code: Optional[str] = None,
|
|
314
|
+
cause: Optional[Exception] = None,
|
|
315
|
+
):
|
|
316
|
+
context = {}
|
|
317
|
+
if operation:
|
|
318
|
+
context["operation"] = operation
|
|
319
|
+
if timeout_seconds:
|
|
320
|
+
context["timeout_seconds"] = timeout_seconds
|
|
321
|
+
|
|
322
|
+
super().__init__(
|
|
323
|
+
message=message,
|
|
324
|
+
error_code=error_code or "TIMEOUT_ERROR",
|
|
325
|
+
context=context,
|
|
326
|
+
cause=cause,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class ResourceExhaustedError(MemoriError):
|
|
331
|
+
"""Resource exhaustion errors with resource context"""
|
|
332
|
+
|
|
333
|
+
def __init__(
|
|
334
|
+
self,
|
|
335
|
+
message: str,
|
|
336
|
+
resource_type: Optional[str] = None,
|
|
337
|
+
current_usage: Optional[Union[int, float]] = None,
|
|
338
|
+
limit: Optional[Union[int, float]] = None,
|
|
339
|
+
error_code: Optional[str] = None,
|
|
340
|
+
cause: Optional[Exception] = None,
|
|
341
|
+
):
|
|
342
|
+
context = {}
|
|
343
|
+
if resource_type:
|
|
344
|
+
context["resource_type"] = resource_type
|
|
345
|
+
if current_usage is not None:
|
|
346
|
+
context["current_usage"] = current_usage
|
|
347
|
+
if limit is not None:
|
|
348
|
+
context["limit"] = limit
|
|
349
|
+
|
|
350
|
+
super().__init__(
|
|
351
|
+
message=message,
|
|
352
|
+
error_code=error_code or "RESOURCE_EXHAUSTED",
|
|
353
|
+
context=context,
|
|
354
|
+
cause=cause,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
# Exception utilities
|
|
359
|
+
class ExceptionHandler:
|
|
360
|
+
"""Centralized exception handling utilities"""
|
|
361
|
+
|
|
362
|
+
@staticmethod
|
|
363
|
+
def handle_database_exception(
|
|
364
|
+
e: Exception, query: Optional[str] = None
|
|
365
|
+
) -> DatabaseError:
|
|
366
|
+
"""Convert generic exception to DatabaseError with context"""
|
|
367
|
+
if isinstance(e, DatabaseError):
|
|
368
|
+
return e
|
|
369
|
+
|
|
370
|
+
return DatabaseError(
|
|
371
|
+
message=f"Database operation failed: {str(e)}",
|
|
372
|
+
query=query,
|
|
373
|
+
cause=e,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
@staticmethod
|
|
377
|
+
def handle_agent_exception(
|
|
378
|
+
e: Exception, agent_type: Optional[str] = None
|
|
379
|
+
) -> AgentError:
|
|
380
|
+
"""Convert generic exception to AgentError with context"""
|
|
381
|
+
if isinstance(e, AgentError):
|
|
382
|
+
return e
|
|
383
|
+
|
|
384
|
+
return AgentError(
|
|
385
|
+
message=f"Agent operation failed: {str(e)}",
|
|
386
|
+
agent_type=agent_type,
|
|
387
|
+
cause=e,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
@staticmethod
|
|
391
|
+
def handle_validation_exception(
|
|
392
|
+
e: Exception, field_name: Optional[str] = None
|
|
393
|
+
) -> ValidationError:
|
|
394
|
+
"""Convert generic exception to ValidationError with context"""
|
|
395
|
+
if isinstance(e, ValidationError):
|
|
396
|
+
return e
|
|
397
|
+
|
|
398
|
+
return ValidationError(
|
|
399
|
+
message=f"Validation failed: {str(e)}",
|
|
400
|
+
field_name=field_name,
|
|
401
|
+
cause=e,
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
@staticmethod
|
|
405
|
+
def log_exception(exception: MemoriError, logger=None) -> None:
|
|
406
|
+
"""Log exception with full context"""
|
|
407
|
+
if logger is None:
|
|
408
|
+
from .logging import get_logger
|
|
409
|
+
|
|
410
|
+
logger = get_logger("exceptions")
|
|
411
|
+
|
|
412
|
+
logger.error(
|
|
413
|
+
f"Exception occurred: {exception.error_code}",
|
|
414
|
+
extra={
|
|
415
|
+
"exception_data": exception.to_dict(),
|
|
416
|
+
"error_type": exception.__class__.__name__,
|
|
417
|
+
},
|
|
418
|
+
)
|