memorisdk 1.0.1__py3-none-any.whl → 2.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 (46) hide show
  1. memori/__init__.py +24 -8
  2. memori/agents/conscious_agent.py +252 -414
  3. memori/agents/memory_agent.py +487 -224
  4. memori/agents/retrieval_agent.py +416 -60
  5. memori/config/memory_manager.py +323 -0
  6. memori/core/conversation.py +393 -0
  7. memori/core/database.py +386 -371
  8. memori/core/memory.py +1676 -534
  9. memori/core/providers.py +217 -0
  10. memori/database/adapters/__init__.py +10 -0
  11. memori/database/adapters/mysql_adapter.py +331 -0
  12. memori/database/adapters/postgresql_adapter.py +291 -0
  13. memori/database/adapters/sqlite_adapter.py +229 -0
  14. memori/database/auto_creator.py +320 -0
  15. memori/database/connection_utils.py +207 -0
  16. memori/database/connectors/base_connector.py +283 -0
  17. memori/database/connectors/mysql_connector.py +240 -18
  18. memori/database/connectors/postgres_connector.py +277 -4
  19. memori/database/connectors/sqlite_connector.py +178 -3
  20. memori/database/models.py +400 -0
  21. memori/database/queries/base_queries.py +1 -1
  22. memori/database/queries/memory_queries.py +91 -2
  23. memori/database/query_translator.py +222 -0
  24. memori/database/schema_generators/__init__.py +7 -0
  25. memori/database/schema_generators/mysql_schema_generator.py +215 -0
  26. memori/database/search/__init__.py +8 -0
  27. memori/database/search/mysql_search_adapter.py +255 -0
  28. memori/database/search/sqlite_search_adapter.py +180 -0
  29. memori/database/search_service.py +548 -0
  30. memori/database/sqlalchemy_manager.py +839 -0
  31. memori/integrations/__init__.py +36 -11
  32. memori/integrations/litellm_integration.py +340 -6
  33. memori/integrations/openai_integration.py +506 -240
  34. memori/utils/input_validator.py +395 -0
  35. memori/utils/pydantic_models.py +138 -36
  36. memori/utils/query_builder.py +530 -0
  37. memori/utils/security_audit.py +594 -0
  38. memori/utils/security_integration.py +339 -0
  39. memori/utils/transaction_manager.py +547 -0
  40. {memorisdk-1.0.1.dist-info → memorisdk-2.0.0.dist-info}/METADATA +144 -34
  41. memorisdk-2.0.0.dist-info/RECORD +67 -0
  42. memorisdk-1.0.1.dist-info/RECORD +0 -44
  43. memorisdk-1.0.1.dist-info/entry_points.txt +0 -2
  44. {memorisdk-1.0.1.dist-info → memorisdk-2.0.0.dist-info}/WHEEL +0 -0
  45. {memorisdk-1.0.1.dist-info → memorisdk-2.0.0.dist-info}/licenses/LICENSE +0 -0
  46. {memorisdk-1.0.1.dist-info → memorisdk-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,222 @@
1
+ """
2
+ Cross-database query parameter translator for Memori v2.0
3
+
4
+ This module provides database-agnostic parameter translation to handle
5
+ differences between SQLite, PostgreSQL, and MySQL, particularly for
6
+ boolean values and other database-specific syntax.
7
+ """
8
+
9
+ from typing import Any, Dict, Union
10
+
11
+ from loguru import logger
12
+
13
+
14
+ class QueryParameterTranslator:
15
+ """
16
+ Translates query parameters to be compatible with different database engines.
17
+
18
+ Handles cross-database compatibility issues like:
19
+ - Boolean values (SQLite: 0/1, PostgreSQL: TRUE/FALSE, MySQL: 0/1)
20
+ - Date/time formats
21
+ - Case sensitivity
22
+ - Data type constraints
23
+ """
24
+
25
+ def __init__(self, database_type: str):
26
+ """
27
+ Initialize translator for specific database type.
28
+
29
+ Args:
30
+ database_type: Database engine name ('sqlite', 'postgresql', 'mysql')
31
+ """
32
+ self.database_type = database_type.lower()
33
+ logger.debug(f"QueryParameterTranslator initialized for {self.database_type}")
34
+
35
+ def translate_parameters(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
36
+ """
37
+ Translate parameters to be compatible with the target database.
38
+
39
+ Args:
40
+ parameters: Dictionary of query parameters
41
+
42
+ Returns:
43
+ Dictionary with translated parameters
44
+ """
45
+ if not parameters:
46
+ return parameters
47
+
48
+ translated = {}
49
+
50
+ for key, value in parameters.items():
51
+ translated[key] = self._translate_value(value, key)
52
+
53
+ return translated
54
+
55
+ def _translate_value(self, value: Any, parameter_name: str = None) -> Any:
56
+ """Translate a single parameter value based on database type."""
57
+
58
+ # Handle boolean values
59
+ if isinstance(value, bool):
60
+ return self._translate_boolean(value)
61
+
62
+ # Handle integer boolean representations (0, 1)
63
+ if isinstance(value, int) and value in (0, 1):
64
+ # Check if this looks like a boolean context based on parameter name
65
+ if self._is_likely_boolean_context(value, parameter_name):
66
+ return self._translate_boolean(bool(value))
67
+
68
+ # Handle None values
69
+ if value is None:
70
+ return None
71
+
72
+ # Handle lists/arrays
73
+ if isinstance(value, (list, tuple)):
74
+ return [self._translate_value(item) for item in value]
75
+
76
+ # Handle dictionaries
77
+ if isinstance(value, dict):
78
+ return {k: self._translate_value(v, k) for k, v in value.items()}
79
+
80
+ # Return other values unchanged
81
+ return value
82
+
83
+ def _translate_boolean(self, value: bool) -> Union[bool, int]:
84
+ """
85
+ Translate boolean values for database compatibility.
86
+
87
+ Args:
88
+ value: Boolean value to translate
89
+
90
+ Returns:
91
+ Database-appropriate boolean representation
92
+ """
93
+ if self.database_type == "postgresql":
94
+ # PostgreSQL uses TRUE/FALSE
95
+ return value # SQLAlchemy handles the TRUE/FALSE conversion
96
+
97
+ elif self.database_type in ("sqlite", "mysql"):
98
+ # SQLite and MySQL use 0/1 for booleans
99
+ return int(value)
100
+
101
+ else:
102
+ # Default: return as-is and let SQLAlchemy handle it
103
+ logger.warning(
104
+ f"Unknown database type {self.database_type}, using default boolean handling"
105
+ )
106
+ return value
107
+
108
+ def _is_likely_boolean_context(
109
+ self, value: int, parameter_name: str = None
110
+ ) -> bool:
111
+ """
112
+ Heuristic to determine if an integer (0 or 1) is meant to be a boolean.
113
+
114
+ This is used to detect integer parameters that should be treated as booleans
115
+ for cross-database compatibility.
116
+
117
+ Args:
118
+ value: Integer value (should be 0 or 1)
119
+ parameter_name: Name of the parameter (for context)
120
+
121
+ Returns:
122
+ True if this looks like a boolean context
123
+ """
124
+ # Must be 0 or 1 to be considered
125
+ if value not in (0, 1):
126
+ return False
127
+
128
+ # Use parameter name patterns to identify boolean fields
129
+ if parameter_name:
130
+ boolean_patterns = [
131
+ "active",
132
+ "enabled",
133
+ "disabled",
134
+ "processed",
135
+ "eligible",
136
+ "is_",
137
+ "has_",
138
+ "can_",
139
+ "should_",
140
+ "allow_",
141
+ "visible",
142
+ "hidden",
143
+ "conscious_processed",
144
+ "processed_for_duplicates",
145
+ "promotion_eligible",
146
+ "is_user_context",
147
+ "is_preference",
148
+ "is_skill_knowledge",
149
+ "is_current_project",
150
+ "is_permanent_context",
151
+ ]
152
+
153
+ param_lower = parameter_name.lower()
154
+ for pattern in boolean_patterns:
155
+ if pattern in param_lower:
156
+ return True
157
+
158
+ # Default to treating 0/1 as potential booleans if no parameter name context
159
+ return True
160
+
161
+ def translate_query_with_parameters(
162
+ self, query: str, parameters: Dict[str, Any]
163
+ ) -> tuple[str, Dict[str, Any]]:
164
+ """
165
+ Translate both query and parameters for database compatibility.
166
+
167
+ Currently focuses on parameter translation, but could be extended
168
+ to handle query syntax differences if needed.
169
+
170
+ Args:
171
+ query: SQL query string
172
+ parameters: Query parameters
173
+
174
+ Returns:
175
+ Tuple of (translated_query, translated_parameters)
176
+ """
177
+ # For now, we only translate parameters
178
+ # Query translation could be added here if needed for other compatibility issues
179
+ translated_params = self.translate_parameters(parameters)
180
+
181
+ return query, translated_params
182
+
183
+ def get_boolean_true(self) -> Union[bool, int]:
184
+ """Get database-appropriate TRUE value."""
185
+ return self._translate_boolean(True)
186
+
187
+ def get_boolean_false(self) -> Union[bool, int]:
188
+ """Get database-appropriate FALSE value."""
189
+ return self._translate_boolean(False)
190
+
191
+
192
+ # Convenience functions for common boolean translations
193
+ def get_db_boolean(value: bool, database_type: str) -> Union[bool, int]:
194
+ """
195
+ Get database-appropriate boolean value.
196
+
197
+ Args:
198
+ value: Boolean value
199
+ database_type: Database engine name
200
+
201
+ Returns:
202
+ Database-appropriate boolean representation
203
+ """
204
+ translator = QueryParameterTranslator(database_type)
205
+ return translator._translate_boolean(value)
206
+
207
+
208
+ def translate_query_params(
209
+ parameters: Dict[str, Any], database_type: str
210
+ ) -> Dict[str, Any]:
211
+ """
212
+ Convenience function to translate query parameters.
213
+
214
+ Args:
215
+ parameters: Query parameters
216
+ database_type: Database engine name
217
+
218
+ Returns:
219
+ Translated parameters
220
+ """
221
+ translator = QueryParameterTranslator(database_type)
222
+ return translator.translate_parameters(parameters)
@@ -0,0 +1,7 @@
1
+ """
2
+ Schema generators for different database backends
3
+ """
4
+
5
+ from .mysql_schema_generator import MySQLSchemaGenerator
6
+
7
+ __all__ = ["MySQLSchemaGenerator"]
@@ -0,0 +1,215 @@
1
+ """
2
+ MySQL schema generator for Memori v2.0
3
+ Converts SQLite schema to MySQL-compatible schema with FULLTEXT search
4
+ """
5
+
6
+ from typing import Dict, List
7
+
8
+ from ..connectors.base_connector import BaseSchemaGenerator, DatabaseType
9
+
10
+
11
+ class MySQLSchemaGenerator(BaseSchemaGenerator):
12
+ """MySQL-specific schema generator"""
13
+
14
+ def __init__(self):
15
+ super().__init__(DatabaseType.MYSQL)
16
+
17
+ def get_data_type_mappings(self) -> Dict[str, str]:
18
+ """Get MySQL-specific data type mappings from SQLite"""
19
+ return {
20
+ "TEXT": "TEXT",
21
+ "INTEGER": "INT",
22
+ "REAL": "DECIMAL(10,2)",
23
+ "BOOLEAN": "BOOLEAN",
24
+ "TIMESTAMP": "TIMESTAMP",
25
+ "AUTOINCREMENT": "AUTO_INCREMENT",
26
+ }
27
+
28
+ def generate_core_schema(self) -> str:
29
+ """Generate core tables schema for MySQL"""
30
+ return """
31
+ -- Chat History Table
32
+ CREATE TABLE IF NOT EXISTS chat_history (
33
+ chat_id VARCHAR(255) PRIMARY KEY,
34
+ user_input TEXT NOT NULL,
35
+ ai_output TEXT NOT NULL,
36
+ model VARCHAR(255) NOT NULL,
37
+ timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
38
+ session_id VARCHAR(255) NOT NULL,
39
+ namespace VARCHAR(255) NOT NULL DEFAULT 'default',
40
+ tokens_used INT DEFAULT 0,
41
+ metadata JSON
42
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
43
+
44
+ -- Short-term Memory Table
45
+ CREATE TABLE IF NOT EXISTS short_term_memory (
46
+ memory_id VARCHAR(255) PRIMARY KEY,
47
+ chat_id VARCHAR(255),
48
+ processed_data JSON NOT NULL,
49
+ importance_score DECIMAL(3,2) NOT NULL DEFAULT 0.5,
50
+ category_primary VARCHAR(255) NOT NULL,
51
+ retention_type VARCHAR(50) NOT NULL DEFAULT 'short_term',
52
+ namespace VARCHAR(255) NOT NULL DEFAULT 'default',
53
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
54
+ expires_at TIMESTAMP NULL,
55
+ access_count INT DEFAULT 0,
56
+ last_accessed TIMESTAMP NULL,
57
+ searchable_content TEXT NOT NULL,
58
+ summary TEXT NOT NULL,
59
+ is_permanent_context BOOLEAN DEFAULT FALSE,
60
+ INDEX idx_chat_id (chat_id),
61
+ FOREIGN KEY (chat_id) REFERENCES chat_history (chat_id) ON DELETE SET NULL
62
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
63
+
64
+ -- Long-term Memory Table
65
+ CREATE TABLE IF NOT EXISTS long_term_memory (
66
+ memory_id VARCHAR(255) PRIMARY KEY,
67
+ original_chat_id VARCHAR(255),
68
+ processed_data JSON NOT NULL,
69
+ importance_score DECIMAL(3,2) NOT NULL DEFAULT 0.5,
70
+ category_primary VARCHAR(255) NOT NULL,
71
+ retention_type VARCHAR(50) NOT NULL DEFAULT 'long_term',
72
+ namespace VARCHAR(255) NOT NULL DEFAULT 'default',
73
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
74
+ access_count INT DEFAULT 0,
75
+ last_accessed TIMESTAMP NULL,
76
+ searchable_content TEXT NOT NULL,
77
+ summary TEXT NOT NULL,
78
+ novelty_score DECIMAL(3,2) DEFAULT 0.5,
79
+ relevance_score DECIMAL(3,2) DEFAULT 0.5,
80
+ actionability_score DECIMAL(3,2) DEFAULT 0.5,
81
+
82
+ -- Enhanced Classification Fields
83
+ classification VARCHAR(50) NOT NULL DEFAULT 'conversational',
84
+ memory_importance VARCHAR(20) NOT NULL DEFAULT 'medium',
85
+ topic VARCHAR(255),
86
+ entities_json JSON DEFAULT (JSON_ARRAY()),
87
+ keywords_json JSON DEFAULT (JSON_ARRAY()),
88
+
89
+ -- Conscious Context Flags
90
+ is_user_context BOOLEAN DEFAULT FALSE,
91
+ is_preference BOOLEAN DEFAULT FALSE,
92
+ is_skill_knowledge BOOLEAN DEFAULT FALSE,
93
+ is_current_project BOOLEAN DEFAULT FALSE,
94
+ promotion_eligible BOOLEAN DEFAULT FALSE,
95
+
96
+ -- Memory Management
97
+ duplicate_of VARCHAR(255),
98
+ supersedes_json JSON DEFAULT (JSON_ARRAY()),
99
+ related_memories_json JSON DEFAULT (JSON_ARRAY()),
100
+
101
+ -- Technical Metadata
102
+ confidence_score DECIMAL(3,2) DEFAULT 0.8,
103
+ extraction_timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
104
+ classification_reason TEXT,
105
+
106
+ -- Processing Status
107
+ processed_for_duplicates BOOLEAN DEFAULT FALSE,
108
+ conscious_processed BOOLEAN DEFAULT FALSE
109
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
110
+ """
111
+
112
+ def generate_indexes(self) -> str:
113
+ """Generate MySQL-specific indexes"""
114
+ return """
115
+ -- Chat History Indexes
116
+ CREATE INDEX idx_chat_namespace_session ON chat_history(namespace, session_id);
117
+ CREATE INDEX idx_chat_timestamp ON chat_history(timestamp);
118
+ CREATE INDEX idx_chat_model ON chat_history(model);
119
+
120
+ -- Short-term Memory Indexes
121
+ CREATE INDEX idx_short_term_namespace ON short_term_memory(namespace);
122
+ CREATE INDEX idx_short_term_category ON short_term_memory(category_primary);
123
+ CREATE INDEX idx_short_term_importance ON short_term_memory(importance_score);
124
+ CREATE INDEX idx_short_term_expires ON short_term_memory(expires_at);
125
+ CREATE INDEX idx_short_term_created ON short_term_memory(created_at);
126
+ CREATE INDEX idx_short_term_access ON short_term_memory(access_count, last_accessed);
127
+ CREATE INDEX idx_short_term_permanent ON short_term_memory(is_permanent_context);
128
+
129
+ -- Long-term Memory Indexes
130
+ CREATE INDEX idx_long_term_namespace ON long_term_memory(namespace);
131
+ CREATE INDEX idx_long_term_category ON long_term_memory(category_primary);
132
+ CREATE INDEX idx_long_term_importance ON long_term_memory(importance_score);
133
+ CREATE INDEX idx_long_term_created ON long_term_memory(created_at);
134
+ CREATE INDEX idx_long_term_access ON long_term_memory(access_count, last_accessed);
135
+ CREATE INDEX idx_long_term_scores ON long_term_memory(novelty_score, relevance_score, actionability_score);
136
+
137
+ -- Enhanced Classification Indexes
138
+ CREATE INDEX idx_long_term_classification ON long_term_memory(classification);
139
+ CREATE INDEX idx_long_term_memory_importance ON long_term_memory(memory_importance);
140
+ CREATE INDEX idx_long_term_topic ON long_term_memory(topic);
141
+ CREATE INDEX idx_long_term_conscious_flags ON long_term_memory(is_user_context, is_preference, is_skill_knowledge, promotion_eligible);
142
+ CREATE INDEX idx_long_term_conscious_processed ON long_term_memory(conscious_processed);
143
+ CREATE INDEX idx_long_term_duplicates ON long_term_memory(processed_for_duplicates);
144
+ CREATE INDEX idx_long_term_confidence ON long_term_memory(confidence_score);
145
+
146
+ -- Composite indexes for search optimization
147
+ CREATE INDEX idx_short_term_namespace_category_importance ON short_term_memory(namespace, category_primary, importance_score);
148
+ CREATE INDEX idx_long_term_namespace_category_importance ON long_term_memory(namespace, category_primary, importance_score);
149
+ """
150
+
151
+ def generate_search_setup(self) -> str:
152
+ """Generate MySQL FULLTEXT search setup"""
153
+ return """
154
+ -- MySQL FULLTEXT Search Indexes
155
+ -- These replace SQLite's FTS5 virtual table with MySQL's native FULLTEXT indexes
156
+
157
+ -- FULLTEXT index for short-term memory
158
+ ALTER TABLE short_term_memory ADD FULLTEXT INDEX ft_short_term_search (searchable_content, summary);
159
+
160
+ -- FULLTEXT index for long-term memory
161
+ ALTER TABLE long_term_memory ADD FULLTEXT INDEX ft_long_term_search (searchable_content, summary);
162
+
163
+ -- Additional FULLTEXT indexes for enhanced search capabilities
164
+ ALTER TABLE long_term_memory ADD FULLTEXT INDEX ft_long_term_topic (topic);
165
+
166
+ -- Note: MySQL FULLTEXT indexes are maintained automatically
167
+ -- No triggers needed like SQLite FTS5
168
+ """
169
+
170
+ def generate_mysql_specific_optimizations(self) -> str:
171
+ """Generate MySQL-specific optimizations"""
172
+ return """
173
+ -- MySQL-specific optimizations
174
+
175
+ -- Set InnoDB buffer pool size (if you have permission)
176
+ -- SET GLOBAL innodb_buffer_pool_size = 268435456; -- 256MB
177
+
178
+ -- Optimize FULLTEXT search settings
179
+ -- SET GLOBAL ft_min_word_len = 3;
180
+ -- SET GLOBAL ft_boolean_syntax = ' +-><()~*:""&|';
181
+
182
+ -- Enable query cache (MySQL 5.7 and below)
183
+ -- SET GLOBAL query_cache_type = ON;
184
+ -- SET GLOBAL query_cache_size = 67108864; -- 64MB
185
+ """
186
+
187
+ def generate_full_schema(self) -> str:
188
+ """Generate complete MySQL schema"""
189
+ schema_parts = [
190
+ "-- Memori v2.0 MySQL Schema",
191
+ "-- Generated schema for cross-database compatibility",
192
+ "",
193
+ "-- Set MySQL session variables for optimal performance",
194
+ "SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO';",
195
+ "SET SESSION innodb_lock_wait_timeout = 30;",
196
+ "",
197
+ self.generate_core_schema(),
198
+ "",
199
+ self.generate_indexes(),
200
+ "",
201
+ self.generate_search_setup(),
202
+ "",
203
+ "-- Schema generation completed",
204
+ ]
205
+ return "\n".join(schema_parts)
206
+
207
+ def get_migration_queries(self) -> List[str]:
208
+ """Get queries to migrate from SQLite to MySQL"""
209
+ return [
210
+ # Note: These would be used for data migration from SQLite to MySQL
211
+ # Data migration is complex and would require specialized tooling
212
+ "-- Data migration queries would go here",
213
+ "-- This requires extracting data from SQLite and inserting into MySQL",
214
+ "-- with proper data type conversions and character encoding handling",
215
+ ]
@@ -0,0 +1,8 @@
1
+ """
2
+ Search adapters for different database backends
3
+ """
4
+
5
+ from .mysql_search_adapter import MySQLSearchAdapter
6
+ from .sqlite_search_adapter import SQLiteSearchAdapter
7
+
8
+ __all__ = ["SQLiteSearchAdapter", "MySQLSearchAdapter"]