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.

Files changed (44) hide show
  1. memoriai/__init__.py +140 -0
  2. memoriai/agents/__init__.py +7 -0
  3. memoriai/agents/conscious_agent.py +506 -0
  4. memoriai/agents/memory_agent.py +322 -0
  5. memoriai/agents/retrieval_agent.py +579 -0
  6. memoriai/config/__init__.py +14 -0
  7. memoriai/config/manager.py +281 -0
  8. memoriai/config/settings.py +287 -0
  9. memoriai/core/__init__.py +6 -0
  10. memoriai/core/database.py +966 -0
  11. memoriai/core/memory.py +1349 -0
  12. memoriai/database/__init__.py +5 -0
  13. memoriai/database/connectors/__init__.py +9 -0
  14. memoriai/database/connectors/mysql_connector.py +159 -0
  15. memoriai/database/connectors/postgres_connector.py +158 -0
  16. memoriai/database/connectors/sqlite_connector.py +148 -0
  17. memoriai/database/queries/__init__.py +15 -0
  18. memoriai/database/queries/base_queries.py +204 -0
  19. memoriai/database/queries/chat_queries.py +157 -0
  20. memoriai/database/queries/entity_queries.py +236 -0
  21. memoriai/database/queries/memory_queries.py +178 -0
  22. memoriai/database/templates/__init__.py +0 -0
  23. memoriai/database/templates/basic_template.py +0 -0
  24. memoriai/database/templates/schemas/__init__.py +0 -0
  25. memoriai/integrations/__init__.py +68 -0
  26. memoriai/integrations/anthropic_integration.py +194 -0
  27. memoriai/integrations/litellm_integration.py +11 -0
  28. memoriai/integrations/openai_integration.py +273 -0
  29. memoriai/scripts/llm_text.py +50 -0
  30. memoriai/tools/__init__.py +5 -0
  31. memoriai/tools/memory_tool.py +544 -0
  32. memoriai/utils/__init__.py +89 -0
  33. memoriai/utils/exceptions.py +418 -0
  34. memoriai/utils/helpers.py +433 -0
  35. memoriai/utils/logging.py +204 -0
  36. memoriai/utils/pydantic_models.py +258 -0
  37. memoriai/utils/schemas.py +0 -0
  38. memoriai/utils/validators.py +339 -0
  39. memorisdk-1.0.0.dist-info/METADATA +386 -0
  40. memorisdk-1.0.0.dist-info/RECORD +44 -0
  41. memorisdk-1.0.0.dist-info/WHEEL +5 -0
  42. memorisdk-1.0.0.dist-info/entry_points.txt +2 -0
  43. memorisdk-1.0.0.dist-info/licenses/LICENSE +203 -0
  44. 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
+ )