memorisdk 2.0.1__py3-none-any.whl → 2.1.1__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 (62) hide show
  1. memori/__init__.py +3 -3
  2. memori/agents/conscious_agent.py +289 -77
  3. memori/agents/memory_agent.py +19 -9
  4. memori/agents/retrieval_agent.py +59 -51
  5. memori/config/manager.py +7 -7
  6. memori/config/memory_manager.py +25 -25
  7. memori/config/settings.py +13 -6
  8. memori/core/conversation.py +15 -15
  9. memori/core/database.py +14 -13
  10. memori/core/memory.py +376 -105
  11. memori/core/providers.py +25 -25
  12. memori/database/__init__.py +11 -0
  13. memori/database/adapters/__init__.py +11 -0
  14. memori/database/adapters/mongodb_adapter.py +739 -0
  15. memori/database/adapters/mysql_adapter.py +8 -8
  16. memori/database/adapters/postgresql_adapter.py +6 -6
  17. memori/database/adapters/sqlite_adapter.py +6 -6
  18. memori/database/auto_creator.py +8 -9
  19. memori/database/connection_utils.py +5 -5
  20. memori/database/connectors/__init__.py +11 -0
  21. memori/database/connectors/base_connector.py +18 -19
  22. memori/database/connectors/mongodb_connector.py +654 -0
  23. memori/database/connectors/mysql_connector.py +13 -15
  24. memori/database/connectors/postgres_connector.py +12 -12
  25. memori/database/connectors/sqlite_connector.py +11 -11
  26. memori/database/models.py +2 -2
  27. memori/database/mongodb_manager.py +1484 -0
  28. memori/database/queries/base_queries.py +3 -4
  29. memori/database/queries/chat_queries.py +3 -5
  30. memori/database/queries/entity_queries.py +3 -5
  31. memori/database/queries/memory_queries.py +3 -5
  32. memori/database/query_translator.py +11 -11
  33. memori/database/schema_generators/__init__.py +11 -0
  34. memori/database/schema_generators/mongodb_schema_generator.py +666 -0
  35. memori/database/schema_generators/mysql_schema_generator.py +2 -4
  36. memori/database/search/__init__.py +11 -0
  37. memori/database/search/mongodb_search_adapter.py +653 -0
  38. memori/database/search/mysql_search_adapter.py +8 -8
  39. memori/database/search/sqlite_search_adapter.py +6 -6
  40. memori/database/search_service.py +17 -17
  41. memori/database/sqlalchemy_manager.py +10 -12
  42. memori/integrations/__init__.py +1 -1
  43. memori/integrations/anthropic_integration.py +1 -3
  44. memori/integrations/litellm_integration.py +23 -6
  45. memori/integrations/openai_integration.py +31 -3
  46. memori/tools/memory_tool.py +10 -9
  47. memori/utils/exceptions.py +58 -58
  48. memori/utils/helpers.py +11 -12
  49. memori/utils/input_validator.py +10 -12
  50. memori/utils/logging.py +4 -4
  51. memori/utils/pydantic_models.py +57 -57
  52. memori/utils/query_builder.py +20 -20
  53. memori/utils/security_audit.py +28 -28
  54. memori/utils/security_integration.py +9 -9
  55. memori/utils/transaction_manager.py +20 -19
  56. memori/utils/validators.py +6 -6
  57. {memorisdk-2.0.1.dist-info → memorisdk-2.1.1.dist-info}/METADATA +23 -12
  58. memorisdk-2.1.1.dist-info/RECORD +71 -0
  59. memorisdk-2.0.1.dist-info/RECORD +0 -66
  60. {memorisdk-2.0.1.dist-info → memorisdk-2.1.1.dist-info}/WHEEL +0 -0
  61. {memorisdk-2.0.1.dist-info → memorisdk-2.1.1.dist-info}/licenses/LICENSE +0 -0
  62. {memorisdk-2.0.1.dist-info → memorisdk-2.1.1.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,7 @@ Custom exceptions for Memoriai with comprehensive error handling
4
4
 
5
5
  import traceback
6
6
  from datetime import datetime
7
- from typing import Any, Dict, Optional, Union
7
+ from typing import Any
8
8
 
9
9
 
10
10
  class MemoriError(Exception):
@@ -13,9 +13,9 @@ class MemoriError(Exception):
13
13
  def __init__(
14
14
  self,
15
15
  message: str,
16
- error_code: Optional[str] = None,
17
- context: Optional[Dict[str, Any]] = None,
18
- cause: Optional[Exception] = None,
16
+ error_code: str | None = None,
17
+ context: dict[str, Any] | None = None,
18
+ cause: Exception | None = None,
19
19
  ):
20
20
  super().__init__(message)
21
21
  self.message = message
@@ -25,7 +25,7 @@ class MemoriError(Exception):
25
25
  self.timestamp = datetime.now()
26
26
  self.traceback = traceback.format_exc() if cause else None
27
27
 
28
- def to_dict(self) -> Dict[str, Any]:
28
+ def to_dict(self) -> dict[str, Any]:
29
29
  """Convert exception to dictionary for logging/serialization"""
30
30
  return {
31
31
  "error_type": self.__class__.__name__,
@@ -52,10 +52,10 @@ class DatabaseError(MemoriError):
52
52
  def __init__(
53
53
  self,
54
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,
55
+ query: str | None = None,
56
+ connection_string: str | None = None,
57
+ error_code: str | None = None,
58
+ cause: Exception | None = None,
59
59
  ):
60
60
  context = {}
61
61
  if query:
@@ -88,12 +88,12 @@ class AgentError(MemoriError):
88
88
  def __init__(
89
89
  self,
90
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,
91
+ agent_type: str | None = None,
92
+ model: str | None = None,
93
+ api_endpoint: str | None = None,
94
+ tokens_used: int | None = None,
95
+ error_code: str | None = None,
96
+ cause: Exception | None = None,
97
97
  ):
98
98
  context = {}
99
99
  if agent_type:
@@ -119,10 +119,10 @@ class ConfigurationError(MemoriError):
119
119
  def __init__(
120
120
  self,
121
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,
122
+ setting_path: str | None = None,
123
+ config_file: str | None = None,
124
+ error_code: str | None = None,
125
+ cause: Exception | None = None,
126
126
  ):
127
127
  context = {}
128
128
  if setting_path:
@@ -144,11 +144,11 @@ class ValidationError(MemoriError):
144
144
  def __init__(
145
145
  self,
146
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,
147
+ field_name: str | None = None,
148
+ field_value: Any | None = None,
149
+ expected_type: str | None = None,
150
+ error_code: str | None = None,
151
+ cause: Exception | None = None,
152
152
  ):
153
153
  context = {}
154
154
  if field_name:
@@ -172,10 +172,10 @@ class IntegrationError(MemoriError):
172
172
  def __init__(
173
173
  self,
174
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,
175
+ provider: str | None = None,
176
+ integration_type: str | None = None,
177
+ error_code: str | None = None,
178
+ cause: Exception | None = None,
179
179
  ):
180
180
  context = {}
181
181
  if provider:
@@ -197,10 +197,10 @@ class AuthenticationError(MemoriError):
197
197
  def __init__(
198
198
  self,
199
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,
200
+ auth_type: str | None = None,
201
+ endpoint: str | None = None,
202
+ error_code: str | None = None,
203
+ cause: Exception | None = None,
204
204
  ):
205
205
  context = {}
206
206
  if auth_type:
@@ -222,11 +222,11 @@ class RateLimitError(MemoriError):
222
222
  def __init__(
223
223
  self,
224
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,
225
+ provider: str | None = None,
226
+ limit_type: str | None = None,
227
+ retry_after: int | None = None,
228
+ error_code: str | None = None,
229
+ cause: Exception | None = None,
230
230
  ):
231
231
  context = {}
232
232
  if provider:
@@ -250,11 +250,11 @@ class MemoryNotFoundError(MemoriError):
250
250
  def __init__(
251
251
  self,
252
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,
253
+ memory_id: str | None = None,
254
+ namespace: str | None = None,
255
+ search_criteria: dict[str, Any] | None = None,
256
+ error_code: str | None = None,
257
+ cause: Exception | None = None,
258
258
  ):
259
259
  context = {}
260
260
  if memory_id:
@@ -278,10 +278,10 @@ class ProcessingError(MemoriError):
278
278
  def __init__(
279
279
  self,
280
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,
281
+ processing_stage: str | None = None,
282
+ input_data: dict[str, Any] | None = None,
283
+ error_code: str | None = None,
284
+ cause: Exception | None = None,
285
285
  ):
286
286
  context = {}
287
287
  if processing_stage:
@@ -308,10 +308,10 @@ class TimeoutError(MemoriError):
308
308
  def __init__(
309
309
  self,
310
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,
311
+ operation: str | None = None,
312
+ timeout_seconds: float | None = None,
313
+ error_code: str | None = None,
314
+ cause: Exception | None = None,
315
315
  ):
316
316
  context = {}
317
317
  if operation:
@@ -333,11 +333,11 @@ class ResourceExhaustedError(MemoriError):
333
333
  def __init__(
334
334
  self,
335
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,
336
+ resource_type: str | None = None,
337
+ current_usage: int | float | None = None,
338
+ limit: int | float | None = None,
339
+ error_code: str | None = None,
340
+ cause: Exception | None = None,
341
341
  ):
342
342
  context = {}
343
343
  if resource_type:
@@ -361,7 +361,7 @@ class ExceptionHandler:
361
361
 
362
362
  @staticmethod
363
363
  def handle_database_exception(
364
- e: Exception, query: Optional[str] = None
364
+ e: Exception, query: str | None = None
365
365
  ) -> DatabaseError:
366
366
  """Convert generic exception to DatabaseError with context"""
367
367
  if isinstance(e, DatabaseError):
@@ -375,7 +375,7 @@ class ExceptionHandler:
375
375
 
376
376
  @staticmethod
377
377
  def handle_agent_exception(
378
- e: Exception, agent_type: Optional[str] = None
378
+ e: Exception, agent_type: str | None = None
379
379
  ) -> AgentError:
380
380
  """Convert generic exception to AgentError with context"""
381
381
  if isinstance(e, AgentError):
@@ -389,7 +389,7 @@ class ExceptionHandler:
389
389
 
390
390
  @staticmethod
391
391
  def handle_validation_exception(
392
- e: Exception, field_name: Optional[str] = None
392
+ e: Exception, field_name: str | None = None
393
393
  ) -> ValidationError:
394
394
  """Convert generic exception to ValidationError with context"""
395
395
  if isinstance(e, ValidationError):
memori/utils/helpers.py CHANGED
@@ -7,9 +7,10 @@ import functools
7
7
  import hashlib
8
8
  import json
9
9
  import uuid
10
+ from collections.abc import Awaitable, Callable
10
11
  from datetime import datetime, timedelta
11
12
  from pathlib import Path
12
- from typing import Any, Awaitable, Callable, Dict, List, Optional, TypeVar, Union
13
+ from typing import Any, TypeVar
13
14
 
14
15
  from .exceptions import MemoriError
15
16
 
@@ -52,7 +53,7 @@ class StringUtils:
52
53
  return hash_obj.hexdigest()
53
54
 
54
55
  @staticmethod
55
- def extract_keywords(text: str, max_keywords: int = 10) -> List[str]:
56
+ def extract_keywords(text: str, max_keywords: int = 10) -> list[str]:
56
57
  """Extract keywords from text (simple implementation)"""
57
58
  import re
58
59
 
@@ -201,7 +202,7 @@ class JsonUtils:
201
202
  return json.dumps(default or {}, indent=indent)
202
203
 
203
204
  @staticmethod
204
- def merge_dicts(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
205
+ def merge_dicts(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
205
206
  """Deep merge two dictionaries"""
206
207
  result = base.copy()
207
208
 
@@ -222,16 +223,14 @@ class FileUtils:
222
223
  """File handling utilities"""
223
224
 
224
225
  @staticmethod
225
- def ensure_directory(path: Union[str, Path]) -> Path:
226
+ def ensure_directory(path: str | Path) -> Path:
226
227
  """Ensure directory exists, create if not"""
227
228
  path = Path(path)
228
229
  path.mkdir(parents=True, exist_ok=True)
229
230
  return path
230
231
 
231
232
  @staticmethod
232
- def safe_read_text(
233
- file_path: Union[str, Path], encoding: str = "utf-8"
234
- ) -> Optional[str]:
233
+ def safe_read_text(file_path: str | Path, encoding: str = "utf-8") -> str | None:
235
234
  """Safely read text file"""
236
235
  try:
237
236
  return Path(file_path).read_text(encoding=encoding)
@@ -240,7 +239,7 @@ class FileUtils:
240
239
 
241
240
  @staticmethod
242
241
  def safe_write_text(
243
- file_path: Union[str, Path], content: str, encoding: str = "utf-8"
242
+ file_path: str | Path, content: str, encoding: str = "utf-8"
244
243
  ) -> bool:
245
244
  """Safely write text file"""
246
245
  try:
@@ -252,7 +251,7 @@ class FileUtils:
252
251
  return False
253
252
 
254
253
  @staticmethod
255
- def get_file_size(file_path: Union[str, Path]) -> int:
254
+ def get_file_size(file_path: str | Path) -> int:
256
255
  """Get file size in bytes"""
257
256
  try:
258
257
  return Path(file_path).stat().st_size
@@ -260,7 +259,7 @@ class FileUtils:
260
259
  return 0
261
260
 
262
261
  @staticmethod
263
- def is_file_recent(file_path: Union[str, Path], hours: int = 24) -> bool:
262
+ def is_file_recent(file_path: str | Path, hours: int = 24) -> bool:
264
263
  """Check if file was modified recently"""
265
264
  try:
266
265
  mtime = datetime.fromtimestamp(Path(file_path).stat().st_mtime)
@@ -386,7 +385,7 @@ class PerformanceUtils:
386
385
  return wrapper
387
386
 
388
387
  @staticmethod
389
- def memory_usage() -> Dict[str, float]:
388
+ def memory_usage() -> dict[str, float]:
390
389
  """Get current memory usage"""
391
390
  try:
392
391
  import psutil
@@ -417,7 +416,7 @@ class AsyncUtils:
417
416
  )
418
417
 
419
418
  @staticmethod
420
- async def gather_with_concurrency(limit: int, *tasks) -> List[Any]:
419
+ async def gather_with_concurrency(limit: int, *tasks) -> list[Any]:
421
420
  """Run tasks with concurrency limit"""
422
421
  semaphore = asyncio.Semaphore(limit)
423
422
 
@@ -7,7 +7,7 @@ import html
7
7
  import json
8
8
  import re
9
9
  from datetime import datetime
10
- from typing import Any, Dict, List, Optional, Union
10
+ from typing import Any
11
11
 
12
12
  from loguru import logger
13
13
 
@@ -40,7 +40,7 @@ class InputValidator:
40
40
  @classmethod
41
41
  def validate_and_sanitize_query(cls, query: str, max_length: int = 10000) -> str:
42
42
  """Validate and sanitize search query input"""
43
- if not isinstance(query, (str, type(None))):
43
+ if not isinstance(query, str | type(None)):
44
44
  raise ValidationError("Query must be a string or None")
45
45
 
46
46
  if query is None:
@@ -95,9 +95,7 @@ class InputValidator:
95
95
  return sanitized_namespace
96
96
 
97
97
  @classmethod
98
- def validate_category_filter(
99
- cls, category_filter: Optional[List[str]]
100
- ) -> List[str]:
98
+ def validate_category_filter(cls, category_filter: list[str] | None) -> list[str]:
101
99
  """Validate and sanitize category filter list"""
102
100
  if category_filter is None:
103
101
  return []
@@ -130,7 +128,7 @@ class InputValidator:
130
128
  return sanitized_categories
131
129
 
132
130
  @classmethod
133
- def validate_limit(cls, limit: Union[int, str]) -> int:
131
+ def validate_limit(cls, limit: int | str) -> int:
134
132
  """Validate and sanitize limit parameter"""
135
133
  try:
136
134
  int_limit = int(limit)
@@ -223,7 +221,7 @@ class InputValidator:
223
221
  return sanitized_content.strip()
224
222
 
225
223
  @classmethod
226
- def validate_timestamp(cls, timestamp: Union[datetime, str, None]) -> datetime:
224
+ def validate_timestamp(cls, timestamp: datetime | str | None) -> datetime:
227
225
  """Validate and normalize timestamp"""
228
226
  if timestamp is None:
229
227
  return datetime.now()
@@ -246,7 +244,7 @@ class InputValidator:
246
244
 
247
245
  @classmethod
248
246
  def validate_score(
249
- cls, score: Union[float, int, str], field_name: str = "score"
247
+ cls, score: float | int | str, field_name: str = "score"
250
248
  ) -> float:
251
249
  """Validate and normalize score values (0.0 to 1.0)"""
252
250
  try:
@@ -328,8 +326,8 @@ class DatabaseInputValidator:
328
326
 
329
327
  @classmethod
330
328
  def validate_insert_params(
331
- cls, table: str, params: Dict[str, Any]
332
- ) -> Dict[str, Any]:
329
+ cls, table: str, params: dict[str, Any]
330
+ ) -> dict[str, Any]:
333
331
  """Validate parameters for database insert operations"""
334
332
  sanitized_params = {}
335
333
 
@@ -383,9 +381,9 @@ class DatabaseInputValidator:
383
381
  cls,
384
382
  query: str,
385
383
  namespace: str,
386
- category_filter: Optional[List[str]],
384
+ category_filter: list[str] | None,
387
385
  limit: int,
388
- ) -> Dict[str, Any]:
386
+ ) -> dict[str, Any]:
389
387
  """Validate all search parameters together"""
390
388
  return {
391
389
  "query": InputValidator.validate_and_sanitize_query(query),
memori/utils/logging.py CHANGED
@@ -4,7 +4,7 @@ Centralized logging configuration for Memoriai
4
4
 
5
5
  import sys
6
6
  from pathlib import Path
7
- from typing import Any, Dict, Optional
7
+ from typing import Any
8
8
 
9
9
  from loguru import logger
10
10
 
@@ -16,7 +16,7 @@ class LoggingManager:
16
16
  """Centralized logging management"""
17
17
 
18
18
  _initialized = False
19
- _current_config: Optional[LoggingSettings] = None
19
+ _current_config: LoggingSettings | None = None
20
20
 
21
21
  @classmethod
22
22
  def setup_logging(cls, settings: LoggingSettings, verbose: bool = False) -> None:
@@ -107,7 +107,7 @@ class LoggingManager:
107
107
  logger.error(f"Failed to update log level: {e}")
108
108
 
109
109
  @classmethod
110
- def add_custom_handler(cls, handler_config: Dict[str, Any]) -> None:
110
+ def add_custom_handler(cls, handler_config: dict[str, Any]) -> None:
111
111
  """Add a custom logging handler"""
112
112
  try:
113
113
  logger.add(**handler_config)
@@ -121,7 +121,7 @@ class LoggingManager:
121
121
  return cls._initialized
122
122
 
123
123
  @classmethod
124
- def get_current_config(cls) -> Optional[LoggingSettings]:
124
+ def get_current_config(cls) -> LoggingSettings | None:
125
125
  """Get current logging configuration"""
126
126
  return cls._current_config
127
127