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
@@ -2,7 +2,7 @@
2
2
  MySQL-specific search adapter with FULLTEXT support and proper security
3
3
  """
4
4
 
5
- from typing import Any, Dict, List, Optional
5
+ from typing import Any
6
6
 
7
7
  from loguru import logger
8
8
 
@@ -25,9 +25,9 @@ class MySQLSearchAdapter(BaseSearchAdapter):
25
25
  self,
26
26
  query: str,
27
27
  namespace: str = "default",
28
- category_filter: Optional[List[str]] = None,
28
+ category_filter: list[str] | None = None,
29
29
  limit: int = 10,
30
- ) -> List[Dict[str, Any]]:
30
+ ) -> list[dict[str, Any]]:
31
31
  """Execute MySQL FULLTEXT search with proper validation"""
32
32
  try:
33
33
  # Validate all parameters
@@ -65,7 +65,7 @@ class MySQLSearchAdapter(BaseSearchAdapter):
65
65
  query, namespace, category_filter, limit
66
66
  )
67
67
 
68
- def create_search_indexes(self) -> List[str]:
68
+ def create_search_indexes(self) -> list[str]:
69
69
  """Create MySQL-specific search indexes"""
70
70
  indexes = []
71
71
 
@@ -182,9 +182,9 @@ class MySQLSearchAdapter(BaseSearchAdapter):
182
182
  self,
183
183
  query: str,
184
184
  namespace: str = "default",
185
- category_filter: Optional[List[str]] = None,
185
+ category_filter: list[str] | None = None,
186
186
  limit: int = 10,
187
- ) -> List[Dict[str, Any]]:
187
+ ) -> list[dict[str, Any]]:
188
188
  """Execute LIKE-based fallback search for MySQL"""
189
189
  try:
190
190
  return self.query_executor.execute_search(
@@ -231,7 +231,7 @@ class MySQLSearchAdapter(BaseSearchAdapter):
231
231
  current_settings = {}
232
232
  if hasattr(cursor, "description") and cursor.description:
233
233
  for row in settings:
234
- if isinstance(row, (list, tuple)) and len(row) >= 2:
234
+ if isinstance(row, list | tuple) and len(row) >= 2:
235
235
  current_settings[row[0]] = row[1]
236
236
 
237
237
  logger.debug(f"Current MySQL FULLTEXT settings: {current_settings}")
@@ -277,7 +277,7 @@ class MySQLSearchAdapter(BaseSearchAdapter):
277
277
  except Exception as e:
278
278
  logger.warning(f"FULLTEXT index repair failed: {e}")
279
279
 
280
- def get_fulltext_statistics(self) -> Dict[str, Any]:
280
+ def get_fulltext_statistics(self) -> dict[str, Any]:
281
281
  """Get statistics about FULLTEXT usage and performance"""
282
282
  stats = {}
283
283
 
@@ -2,7 +2,7 @@
2
2
  PostgreSQL-specific search adapter with tsvector support and proper security
3
3
  """
4
4
 
5
- from typing import Any, Dict, List, Optional
5
+ from typing import Any
6
6
 
7
7
  from loguru import logger
8
8
 
@@ -26,9 +26,9 @@ class PostgreSQLSearchAdapter(BaseSearchAdapter):
26
26
  self,
27
27
  query: str,
28
28
  namespace: str = "default",
29
- category_filter: Optional[List[str]] = None,
29
+ category_filter: list[str] | None = None,
30
30
  limit: int = 10,
31
- ) -> List[Dict[str, Any]]:
31
+ ) -> list[dict[str, Any]]:
32
32
  """Execute PostgreSQL full-text search with tsvector"""
33
33
  try:
34
34
  # Validate all parameters
@@ -66,7 +66,7 @@ class PostgreSQLSearchAdapter(BaseSearchAdapter):
66
66
  query, namespace, category_filter, limit
67
67
  )
68
68
 
69
- def create_search_indexes(self) -> List[str]:
69
+ def create_search_indexes(self) -> list[str]:
70
70
  """Create PostgreSQL-specific search indexes"""
71
71
  indexes = []
72
72
 
@@ -170,9 +170,9 @@ class PostgreSQLSearchAdapter(BaseSearchAdapter):
170
170
  self,
171
171
  query: str,
172
172
  namespace: str = "default",
173
- category_filter: Optional[List[str]] = None,
173
+ category_filter: list[str] | None = None,
174
174
  limit: int = 10,
175
- ) -> List[Dict[str, Any]]:
175
+ ) -> list[dict[str, Any]]:
176
176
  """Execute LIKE-based fallback search for PostgreSQL"""
177
177
  try:
178
178
  return self.query_executor.execute_search(
@@ -3,7 +3,7 @@ SQLite-specific search adapter with FTS5 support and proper security
3
3
  """
4
4
 
5
5
  import sqlite3
6
- from typing import Any, Dict, List, Optional
6
+ from typing import Any
7
7
 
8
8
  from loguru import logger
9
9
 
@@ -25,9 +25,9 @@ class SQLiteSearchAdapter(BaseSearchAdapter):
25
25
  self,
26
26
  query: str,
27
27
  namespace: str = "default",
28
- category_filter: Optional[List[str]] = None,
28
+ category_filter: list[str] | None = None,
29
29
  limit: int = 10,
30
- ) -> List[Dict[str, Any]]:
30
+ ) -> list[dict[str, Any]]:
31
31
  """Execute SQLite FTS5 search with proper validation"""
32
32
  try:
33
33
  # Validate all parameters
@@ -64,7 +64,7 @@ class SQLiteSearchAdapter(BaseSearchAdapter):
64
64
  query, namespace, category_filter, limit
65
65
  )
66
66
 
67
- def create_search_indexes(self) -> List[str]:
67
+ def create_search_indexes(self) -> list[str]:
68
68
  """Create SQLite-specific search indexes"""
69
69
  indexes = []
70
70
 
@@ -189,9 +189,9 @@ class SQLiteSearchAdapter(BaseSearchAdapter):
189
189
  self,
190
190
  query: str,
191
191
  namespace: str = "default",
192
- category_filter: Optional[List[str]] = None,
192
+ category_filter: list[str] | None = None,
193
193
  limit: int = 10,
194
- ) -> List[Dict[str, Any]]:
194
+ ) -> list[dict[str, Any]]:
195
195
  """Execute LIKE-based fallback search for SQLite"""
196
196
  try:
197
197
  return self.query_executor.execute_search(
@@ -6,7 +6,6 @@ PostgreSQL and MySQL with proper error handling and security validation.
6
6
  """
7
7
 
8
8
  import ssl
9
- from typing import Dict
10
9
  from urllib.parse import parse_qs, urlparse
11
10
 
12
11
  from loguru import logger
@@ -77,7 +76,7 @@ class DatabaseAutoCreator:
77
76
  # This allows graceful degradation if user has manual setup
78
77
  return connection_string
79
78
 
80
- def _database_exists(self, components: Dict[str, str]) -> bool:
79
+ def _database_exists(self, components: dict[str, str]) -> bool:
81
80
  """Check if target database exists."""
82
81
  try:
83
82
  engine = components["engine"]
@@ -94,7 +93,7 @@ class DatabaseAutoCreator:
94
93
  logger.error(f"Failed to check database existence: {e}")
95
94
  return False
96
95
 
97
- def _postgresql_database_exists(self, components: Dict[str, str]) -> bool:
96
+ def _postgresql_database_exists(self, components: dict[str, str]) -> bool:
98
97
  """Check if PostgreSQL database exists."""
99
98
  try:
100
99
  # Connect to postgres system database
@@ -114,7 +113,7 @@ class DatabaseAutoCreator:
114
113
  logger.error(f"PostgreSQL database existence check failed: {e}")
115
114
  return False
116
115
 
117
- def _get_mysql_connect_args(self, original_url: str) -> Dict:
116
+ def _get_mysql_connect_args(self, original_url: str) -> dict:
118
117
  """Get MySQL connection arguments with SSL support for system database connections."""
119
118
  connect_args = {"charset": "utf8mb4"}
120
119
 
@@ -146,7 +145,7 @@ class DatabaseAutoCreator:
146
145
 
147
146
  return connect_args
148
147
 
149
- def _mysql_database_exists(self, components: Dict[str, str]) -> bool:
148
+ def _mysql_database_exists(self, components: dict[str, str]) -> bool:
150
149
  """Check if MySQL database exists."""
151
150
  try:
152
151
  # Connect to mysql system database with SSL support
@@ -180,7 +179,7 @@ class DatabaseAutoCreator:
180
179
  logger.error(f"MySQL database existence check failed: {e}")
181
180
  return False
182
181
 
183
- def _create_database(self, components: Dict[str, str]) -> None:
182
+ def _create_database(self, components: dict[str, str]) -> None:
184
183
  """Create the target database."""
185
184
  engine = components["engine"]
186
185
 
@@ -191,7 +190,7 @@ class DatabaseAutoCreator:
191
190
  else:
192
191
  raise ValueError(f"Database creation not supported for {engine}")
193
192
 
194
- def _create_postgresql_database(self, components: Dict[str, str]) -> None:
193
+ def _create_postgresql_database(self, components: dict[str, str]) -> None:
195
194
  """Create PostgreSQL database."""
196
195
  try:
197
196
  logger.info(f"Creating PostgreSQL database '{components['database']}'...")
@@ -230,7 +229,7 @@ class DatabaseAutoCreator:
230
229
  except Exception as e:
231
230
  raise RuntimeError(f"Unexpected error creating PostgreSQL database: {e}")
232
231
 
233
- def _create_mysql_database(self, components: Dict[str, str]) -> None:
232
+ def _create_mysql_database(self, components: dict[str, str]) -> None:
234
233
  """Create MySQL database."""
235
234
  try:
236
235
  logger.info(f"Creating MySQL database '{components['database']}'...")
@@ -281,7 +280,7 @@ class DatabaseAutoCreator:
281
280
  except Exception as e:
282
281
  raise RuntimeError(f"Unexpected error creating MySQL database: {e}")
283
282
 
284
- def get_database_info(self, connection_string: str) -> Dict[str, str]:
283
+ def get_database_info(self, connection_string: str) -> dict[str, str]:
285
284
  """
286
285
  Get detailed information about database from connection string.
287
286
 
@@ -6,7 +6,6 @@ and managing multi-database scenarios for memori instances.
6
6
  """
7
7
 
8
8
  import re
9
- from typing import Dict, Tuple
10
9
  from urllib.parse import urlparse
11
10
 
12
11
  from loguru import logger
@@ -20,10 +19,11 @@ class DatabaseConnectionUtils:
20
19
  "postgresql": "postgres",
21
20
  "mysql": "mysql",
22
21
  "sqlite": None, # SQLite doesn't need default DB
22
+ "mongodb": None, # MongoDB doesn't need default DB for connection
23
23
  }
24
24
 
25
25
  @classmethod
26
- def parse_connection_string(cls, connection_string: str) -> Dict[str, str]:
26
+ def parse_connection_string(cls, connection_string: str) -> dict[str, str]:
27
27
  """
28
28
  Parse database connection string and extract components.
29
29
 
@@ -91,7 +91,7 @@ class DatabaseConnectionUtils:
91
91
  "default_url": default_url,
92
92
  "original_url": connection_string,
93
93
  "needs_creation": engine
94
- in ["postgresql", "mysql"], # SQLite auto-creates
94
+ in ["postgresql", "mysql"], # SQLite and MongoDB auto-create
95
95
  }
96
96
 
97
97
  except Exception as e:
@@ -100,7 +100,7 @@ class DatabaseConnectionUtils:
100
100
 
101
101
  @classmethod
102
102
  def build_connection_string(
103
- cls, components: Dict[str, str], target_database: str
103
+ cls, components: dict[str, str], target_database: str
104
104
  ) -> str:
105
105
  """
106
106
  Build connection string with specific database name.
@@ -189,7 +189,7 @@ class DatabaseConnectionUtils:
189
189
  return database_name
190
190
 
191
191
  @classmethod
192
- def extract_database_info(cls, connection_string: str) -> Tuple[str, str, bool]:
192
+ def extract_database_info(cls, connection_string: str) -> tuple[str, str, bool]:
193
193
  """
194
194
  Extract database engine, name, and creation requirement.
195
195
 
@@ -6,4 +6,15 @@ from .mysql_connector import MySQLConnector
6
6
  from .postgres_connector import PostgreSQLConnector
7
7
  from .sqlite_connector import SQLiteConnector
8
8
 
9
+ try:
10
+ from .mongodb_connector import MongoDBConnector
11
+
12
+ MONGODB_AVAILABLE = True
13
+ except ImportError:
14
+ MongoDBConnector = None # type: ignore
15
+ MONGODB_AVAILABLE = False
16
+
9
17
  __all__ = ["SQLiteConnector", "PostgreSQLConnector", "MySQLConnector"]
18
+
19
+ if MONGODB_AVAILABLE:
20
+ __all__.append("MongoDBConnector")
@@ -5,7 +5,7 @@ Provides abstraction layer for different database backends
5
5
 
6
6
  from abc import ABC, abstractmethod
7
7
  from enum import Enum
8
- from typing import Any, Dict, List, Optional, Tuple
8
+ from typing import Any
9
9
 
10
10
 
11
11
  class DatabaseType(str, Enum):
@@ -14,6 +14,7 @@ class DatabaseType(str, Enum):
14
14
  SQLITE = "sqlite"
15
15
  MYSQL = "mysql"
16
16
  POSTGRESQL = "postgresql"
17
+ MONGODB = "mongodb"
17
18
 
18
19
 
19
20
  class SearchStrategy(str, Enum):
@@ -28,7 +29,7 @@ class SearchStrategy(str, Enum):
28
29
  class BaseDatabaseConnector(ABC):
29
30
  """Abstract base class for database connectors"""
30
31
 
31
- def __init__(self, connection_config: Dict[str, Any]):
32
+ def __init__(self, connection_config: dict[str, Any]):
32
33
  self.connection_config = connection_config
33
34
  self.database_type = self._detect_database_type()
34
35
 
@@ -44,30 +45,28 @@ class BaseDatabaseConnector(ABC):
44
45
 
45
46
  @abstractmethod
46
47
  def execute_query(
47
- self, query: str, params: Optional[List[Any]] = None
48
- ) -> List[Dict[str, Any]]:
48
+ self, query: str, params: list[Any] | None = None
49
+ ) -> list[dict[str, Any]]:
49
50
  """Execute a query and return results"""
50
51
  pass
51
52
 
52
53
  @abstractmethod
53
- def execute_insert(self, query: str, params: Optional[List[Any]] = None) -> str:
54
+ def execute_insert(self, query: str, params: list[Any] | None = None) -> str:
54
55
  """Execute an insert query and return the inserted row ID"""
55
56
  pass
56
57
 
57
58
  @abstractmethod
58
- def execute_update(self, query: str, params: Optional[List[Any]] = None) -> int:
59
+ def execute_update(self, query: str, params: list[Any] | None = None) -> int:
59
60
  """Execute an update query and return number of affected rows"""
60
61
  pass
61
62
 
62
63
  @abstractmethod
63
- def execute_delete(self, query: str, params: Optional[List[Any]] = None) -> int:
64
+ def execute_delete(self, query: str, params: list[Any] | None = None) -> int:
64
65
  """Execute a delete query and return number of affected rows"""
65
66
  pass
66
67
 
67
68
  @abstractmethod
68
- def execute_transaction(
69
- self, queries: List[Tuple[str, Optional[List[Any]]]]
70
- ) -> bool:
69
+ def execute_transaction(self, queries: list[tuple[str, list[Any] | None]]) -> bool:
71
70
  """Execute multiple queries in a transaction"""
72
71
  pass
73
72
 
@@ -77,7 +76,7 @@ class BaseDatabaseConnector(ABC):
77
76
  pass
78
77
 
79
78
  @abstractmethod
80
- def initialize_schema(self, schema_sql: Optional[str] = None):
79
+ def initialize_schema(self, schema_sql: str | None = None):
81
80
  """Initialize database schema"""
82
81
  pass
83
82
 
@@ -88,13 +87,13 @@ class BaseDatabaseConnector(ABC):
88
87
 
89
88
  @abstractmethod
90
89
  def create_full_text_index(
91
- self, table: str, columns: List[str], index_name: str
90
+ self, table: str, columns: list[str], index_name: str
92
91
  ) -> str:
93
92
  """Create database-specific full-text search index"""
94
93
  pass
95
94
 
96
95
  @abstractmethod
97
- def get_database_info(self) -> Dict[str, Any]:
96
+ def get_database_info(self) -> dict[str, Any]:
98
97
  """Get database information and capabilities"""
99
98
  pass
100
99
 
@@ -111,14 +110,14 @@ class BaseSearchAdapter(ABC):
111
110
  self,
112
111
  query: str,
113
112
  namespace: str = "default",
114
- category_filter: Optional[List[str]] = None,
113
+ category_filter: list[str] | None = None,
115
114
  limit: int = 10,
116
- ) -> List[Dict[str, Any]]:
115
+ ) -> list[dict[str, Any]]:
117
116
  """Execute full-text search using database-specific methods"""
118
117
  pass
119
118
 
120
119
  @abstractmethod
121
- def create_search_indexes(self) -> List[str]:
120
+ def create_search_indexes(self) -> list[str]:
122
121
  """Create search indexes for optimal performance"""
123
122
  pass
124
123
 
@@ -131,9 +130,9 @@ class BaseSearchAdapter(ABC):
131
130
  self,
132
131
  query: str,
133
132
  namespace: str = "default",
134
- category_filter: Optional[List[str]] = None,
133
+ category_filter: list[str] | None = None,
135
134
  limit: int = 10,
136
- ) -> List[Dict[str, Any]]:
135
+ ) -> list[dict[str, Any]]:
137
136
  """Execute fallback LIKE-based search with proper parameterization"""
138
137
  try:
139
138
  # Input validation and sanitization
@@ -265,7 +264,7 @@ class BaseSchemaGenerator(ABC):
265
264
  pass
266
265
 
267
266
  @abstractmethod
268
- def get_data_type_mappings(self) -> Dict[str, str]:
267
+ def get_data_type_mappings(self) -> dict[str, str]:
269
268
  """Get database-specific data type mappings"""
270
269
  pass
271
270