memorygraphMCP 0.11.7__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.
Files changed (65) hide show
  1. memorygraph/__init__.py +50 -0
  2. memorygraph/__main__.py +12 -0
  3. memorygraph/advanced_tools.py +509 -0
  4. memorygraph/analytics/__init__.py +46 -0
  5. memorygraph/analytics/advanced_queries.py +727 -0
  6. memorygraph/backends/__init__.py +21 -0
  7. memorygraph/backends/base.py +179 -0
  8. memorygraph/backends/cloud.py +75 -0
  9. memorygraph/backends/cloud_backend.py +858 -0
  10. memorygraph/backends/factory.py +577 -0
  11. memorygraph/backends/falkordb_backend.py +749 -0
  12. memorygraph/backends/falkordblite_backend.py +746 -0
  13. memorygraph/backends/ladybugdb_backend.py +242 -0
  14. memorygraph/backends/memgraph_backend.py +327 -0
  15. memorygraph/backends/neo4j_backend.py +298 -0
  16. memorygraph/backends/sqlite_fallback.py +463 -0
  17. memorygraph/backends/turso.py +448 -0
  18. memorygraph/cli.py +743 -0
  19. memorygraph/cloud_database.py +297 -0
  20. memorygraph/config.py +295 -0
  21. memorygraph/database.py +933 -0
  22. memorygraph/graph_analytics.py +631 -0
  23. memorygraph/integration/__init__.py +69 -0
  24. memorygraph/integration/context_capture.py +426 -0
  25. memorygraph/integration/project_analysis.py +583 -0
  26. memorygraph/integration/workflow_tracking.py +492 -0
  27. memorygraph/intelligence/__init__.py +59 -0
  28. memorygraph/intelligence/context_retrieval.py +447 -0
  29. memorygraph/intelligence/entity_extraction.py +386 -0
  30. memorygraph/intelligence/pattern_recognition.py +420 -0
  31. memorygraph/intelligence/temporal.py +374 -0
  32. memorygraph/migration/__init__.py +27 -0
  33. memorygraph/migration/manager.py +579 -0
  34. memorygraph/migration/models.py +142 -0
  35. memorygraph/migration/scripts/__init__.py +17 -0
  36. memorygraph/migration/scripts/bitemporal_migration.py +595 -0
  37. memorygraph/migration/scripts/multitenancy_migration.py +452 -0
  38. memorygraph/migration_tools_module.py +146 -0
  39. memorygraph/models.py +684 -0
  40. memorygraph/proactive/__init__.py +46 -0
  41. memorygraph/proactive/outcome_learning.py +444 -0
  42. memorygraph/proactive/predictive.py +410 -0
  43. memorygraph/proactive/session_briefing.py +399 -0
  44. memorygraph/relationships.py +668 -0
  45. memorygraph/server.py +883 -0
  46. memorygraph/sqlite_database.py +1876 -0
  47. memorygraph/tools/__init__.py +59 -0
  48. memorygraph/tools/activity_tools.py +262 -0
  49. memorygraph/tools/memory_tools.py +315 -0
  50. memorygraph/tools/migration_tools.py +181 -0
  51. memorygraph/tools/relationship_tools.py +147 -0
  52. memorygraph/tools/search_tools.py +406 -0
  53. memorygraph/tools/temporal_tools.py +339 -0
  54. memorygraph/utils/__init__.py +10 -0
  55. memorygraph/utils/context_extractor.py +429 -0
  56. memorygraph/utils/error_handling.py +151 -0
  57. memorygraph/utils/export_import.py +425 -0
  58. memorygraph/utils/graph_algorithms.py +200 -0
  59. memorygraph/utils/pagination.py +149 -0
  60. memorygraph/utils/project_detection.py +133 -0
  61. memorygraphmcp-0.11.7.dist-info/METADATA +970 -0
  62. memorygraphmcp-0.11.7.dist-info/RECORD +65 -0
  63. memorygraphmcp-0.11.7.dist-info/WHEEL +4 -0
  64. memorygraphmcp-0.11.7.dist-info/entry_points.txt +2 -0
  65. memorygraphmcp-0.11.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,374 @@
1
+ """
2
+ Temporal Memory - Track how information changes over time.
3
+
4
+ This module provides version tracking, memory history, and
5
+ temporal queries for understanding how knowledge evolves.
6
+ """
7
+
8
+ import logging
9
+ from typing import Optional
10
+ from datetime import datetime
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class TemporalMemory:
16
+ """Handles temporal aspects of memories, including version tracking."""
17
+
18
+ def __init__(self, backend):
19
+ """
20
+ Initialize temporal memory with database backend.
21
+
22
+ Args:
23
+ backend: Database backend instance
24
+ """
25
+ self.backend = backend
26
+
27
+ async def get_memory_history(self, memory_id: str) -> list[dict]:
28
+ """
29
+ Get complete version history for a memory by traversing PREVIOUS relationships.
30
+
31
+ Args:
32
+ memory_id: ID of the memory to get history for
33
+
34
+ Returns:
35
+ List of memory versions in chronological order (oldest to newest)
36
+ """
37
+ query = """
38
+ MATCH path = (current:Memory {id: $memory_id})-[:PREVIOUS*0..]->(older:Memory)
39
+ WITH older, length(path) as depth
40
+ ORDER BY depth DESC
41
+ RETURN older.id as id,
42
+ older.title as title,
43
+ older.content as content,
44
+ older.type as type,
45
+ older.tags as tags,
46
+ older.created_at as created_at,
47
+ older.updated_at as updated_at,
48
+ older.is_current as is_current,
49
+ older.superseded_by as superseded_by,
50
+ depth
51
+ """
52
+
53
+ params = {"memory_id": memory_id}
54
+
55
+ try:
56
+ results = await self.backend.execute_query(query, params)
57
+
58
+ history = []
59
+ for record in results:
60
+ version = {
61
+ "id": record["id"],
62
+ "title": record.get("title"),
63
+ "content": record.get("content"),
64
+ "type": record.get("type"),
65
+ "tags": record.get("tags", []),
66
+ "created_at": record.get("created_at"),
67
+ "updated_at": record.get("updated_at"),
68
+ "is_current": record.get("is_current", True),
69
+ "superseded_by": record.get("superseded_by"),
70
+ "version_depth": record["depth"],
71
+ }
72
+ history.append(version)
73
+
74
+ return history
75
+
76
+ except Exception as e:
77
+ logger.error(f"Error getting memory history for {memory_id}: {e}")
78
+ return []
79
+
80
+ async def get_state_at(
81
+ self, memory_id: str, timestamp: datetime
82
+ ) -> Optional[dict]:
83
+ """
84
+ Get the state of a memory at a specific point in time.
85
+
86
+ Args:
87
+ memory_id: ID of the memory
88
+ timestamp: Target timestamp
89
+
90
+ Returns:
91
+ Memory state at that timestamp, or None if not found
92
+ """
93
+ query = """
94
+ MATCH path = (current:Memory {id: $memory_id})-[:PREVIOUS*0..]->(older:Memory)
95
+ WHERE older.created_at <= $timestamp
96
+ WITH older, length(path) as depth
97
+ ORDER BY depth ASC, older.created_at DESC
98
+ LIMIT 1
99
+ RETURN older.id as id,
100
+ older.title as title,
101
+ older.content as content,
102
+ older.type as type,
103
+ older.tags as tags,
104
+ older.created_at as created_at,
105
+ older.updated_at as updated_at,
106
+ older.is_current as is_current
107
+ """
108
+
109
+ params = {"memory_id": memory_id, "timestamp": timestamp}
110
+
111
+ try:
112
+ results = await self.backend.execute_query(query, params)
113
+
114
+ if not results:
115
+ return None
116
+
117
+ record = results[0]
118
+ return {
119
+ "id": record["id"],
120
+ "title": record.get("title"),
121
+ "content": record.get("content"),
122
+ "type": record.get("type"),
123
+ "tags": record.get("tags", []),
124
+ "created_at": record.get("created_at"),
125
+ "updated_at": record.get("updated_at"),
126
+ "is_current": record.get("is_current", False),
127
+ "queried_at": timestamp,
128
+ }
129
+
130
+ except Exception as e:
131
+ logger.error(f"Error getting state at {timestamp} for {memory_id}: {e}")
132
+ return None
133
+
134
+ async def track_entity_changes(self, entity_id: str) -> list[dict]:
135
+ """
136
+ Track how an entity has changed over time by finding all memories that mention it.
137
+
138
+ Args:
139
+ entity_id: ID or text of the entity to track
140
+
141
+ Returns:
142
+ Timeline of changes to the entity
143
+ """
144
+ query = """
145
+ MATCH (e:Entity)
146
+ WHERE e.id = $entity_id OR e.text = $entity_id
147
+ MATCH (m:Memory)-[r:MENTIONS]->(e)
148
+ OPTIONAL MATCH (m)-[:PREVIOUS]->(prev:Memory)
149
+ WITH m, e, prev,
150
+ CASE WHEN prev IS NOT NULL
151
+ THEN exists((prev)-[:MENTIONS]->(e))
152
+ ELSE false
153
+ END as was_mentioned_before
154
+ RETURN m.id as memory_id,
155
+ m.title as title,
156
+ m.content as content,
157
+ m.type as memory_type,
158
+ m.created_at as created_at,
159
+ m.updated_at as updated_at,
160
+ r.confidence as mention_confidence,
161
+ was_mentioned_before,
162
+ CASE WHEN m.is_current = true THEN 'current'
163
+ WHEN m.superseded_by IS NOT NULL THEN 'superseded'
164
+ ELSE 'active'
165
+ END as status
166
+ ORDER BY m.created_at ASC
167
+ """
168
+
169
+ params = {"entity_id": entity_id}
170
+
171
+ try:
172
+ results = await self.backend.execute_query(query, params)
173
+
174
+ timeline = []
175
+ for record in results:
176
+ change = {
177
+ "memory_id": record["memory_id"],
178
+ "title": record.get("title"),
179
+ "content": record.get("content"),
180
+ "memory_type": record.get("memory_type"),
181
+ "created_at": record.get("created_at"),
182
+ "updated_at": record.get("updated_at"),
183
+ "mention_confidence": record.get("mention_confidence"),
184
+ "was_new_mention": not record.get("was_mentioned_before", False),
185
+ "status": record.get("status", "active"),
186
+ }
187
+ timeline.append(change)
188
+
189
+ return timeline
190
+
191
+ except Exception as e:
192
+ logger.error(f"Error tracking entity changes for {entity_id}: {e}")
193
+ return []
194
+
195
+ async def create_version(
196
+ self,
197
+ current_memory_id: str,
198
+ new_memory: dict,
199
+ ) -> str:
200
+ """
201
+ Create a new version of a memory, linking it to the previous version.
202
+
203
+ Args:
204
+ current_memory_id: ID of the current memory to supersede
205
+ new_memory: New memory data
206
+
207
+ Returns:
208
+ ID of the new memory version
209
+ """
210
+ query = """
211
+ MATCH (current:Memory {id: $current_id})
212
+ CREATE (new:Memory)
213
+ SET new = $new_props,
214
+ new.id = randomUUID(),
215
+ new.created_at = datetime(),
216
+ new.updated_at = datetime(),
217
+ new.is_current = true,
218
+ current.is_current = false,
219
+ current.superseded_by = new.id
220
+ CREATE (new)-[:PREVIOUS {superseded_at: datetime()}]->(current)
221
+ RETURN new.id as new_id
222
+ """
223
+
224
+ params = {
225
+ "current_id": current_memory_id,
226
+ "new_props": new_memory,
227
+ }
228
+
229
+ try:
230
+ results = await self.backend.execute_query(query, params)
231
+
232
+ if results:
233
+ new_id = results[0]["new_id"]
234
+ logger.info(f"Created new version {new_id} for memory {current_memory_id}")
235
+ return new_id
236
+ else:
237
+ raise Exception("Failed to create new version")
238
+
239
+ except Exception as e:
240
+ logger.error(f"Error creating version for {current_memory_id}: {e}")
241
+ raise
242
+
243
+ async def get_version_diff(
244
+ self, version1_id: str, version2_id: str
245
+ ) -> dict[str, dict]:
246
+ """
247
+ Compare two versions of a memory and return differences.
248
+
249
+ Args:
250
+ version1_id: ID of first version
251
+ version2_id: ID of second version
252
+
253
+ Returns:
254
+ Dictionary of changes between versions
255
+ """
256
+ query = """
257
+ MATCH (v1:Memory {id: $v1_id})
258
+ MATCH (v2:Memory {id: $v2_id})
259
+ RETURN v1.title as v1_title, v2.title as v2_title,
260
+ v1.content as v1_content, v2.content as v2_content,
261
+ v1.type as v1_type, v2.type as v2_type,
262
+ v1.tags as v1_tags, v2.tags as v2_tags,
263
+ v1.updated_at as v1_updated, v2.updated_at as v2_updated
264
+ """
265
+
266
+ params = {"v1_id": version1_id, "v2_id": version2_id}
267
+
268
+ try:
269
+ results = await self.backend.execute_query(query, params)
270
+
271
+ if not results:
272
+ return {}
273
+
274
+ record = results[0]
275
+ diff = {}
276
+
277
+ # Compare fields
278
+ if record.get("v1_title") != record.get("v2_title"):
279
+ diff["title"] = {
280
+ "from": record.get("v1_title"),
281
+ "to": record.get("v2_title"),
282
+ }
283
+
284
+ if record.get("v1_content") != record.get("v2_content"):
285
+ diff["content"] = {
286
+ "from": record.get("v1_content"),
287
+ "to": record.get("v2_content"),
288
+ }
289
+
290
+ if record.get("v1_type") != record.get("v2_type"):
291
+ diff["type"] = {
292
+ "from": record.get("v1_type"),
293
+ "to": record.get("v2_type"),
294
+ }
295
+
296
+ v1_tags = set(record.get("v1_tags", []))
297
+ v2_tags = set(record.get("v2_tags", []))
298
+ if v1_tags != v2_tags:
299
+ diff["tags"] = {
300
+ "added": list(v2_tags - v1_tags),
301
+ "removed": list(v1_tags - v2_tags),
302
+ }
303
+
304
+ return diff
305
+
306
+ except Exception as e:
307
+ logger.error(f"Error comparing versions {version1_id} and {version2_id}: {e}")
308
+ return {}
309
+
310
+
311
+ # Convenience functions
312
+
313
+
314
+ async def get_memory_history(backend, memory_id: str) -> list[dict]:
315
+ """
316
+ Get version history for a memory.
317
+
318
+ Args:
319
+ backend: Database backend instance
320
+ memory_id: ID of the memory
321
+
322
+ Returns:
323
+ List of memory versions in chronological order
324
+
325
+ Example:
326
+ >>> history = await get_memory_history(backend, "memory-123")
327
+ >>> for version in history:
328
+ ... print(f"Version created at {version['created_at']}")
329
+ """
330
+ temporal = TemporalMemory(backend)
331
+ return await temporal.get_memory_history(memory_id)
332
+
333
+
334
+ async def get_state_at(
335
+ backend, memory_id: str, timestamp: datetime
336
+ ) -> Optional[dict]:
337
+ """
338
+ Get memory state at a specific timestamp.
339
+
340
+ Args:
341
+ backend: Database backend instance
342
+ memory_id: ID of the memory
343
+ timestamp: Target timestamp
344
+
345
+ Returns:
346
+ Memory state at that time, or None
347
+
348
+ Example:
349
+ >>> from datetime import datetime, timedelta, timezone
350
+ >>> yesterday = datetime.now(timezone.utc) - timedelta(days=1)
351
+ >>> state = await get_state_at(backend, "memory-123", yesterday)
352
+ """
353
+ temporal = TemporalMemory(backend)
354
+ return await temporal.get_state_at(memory_id, timestamp)
355
+
356
+
357
+ async def track_entity_changes(backend, entity_id: str) -> list[dict]:
358
+ """
359
+ Track entity changes over time.
360
+
361
+ Args:
362
+ backend: Database backend instance
363
+ entity_id: ID or text of the entity
364
+
365
+ Returns:
366
+ Timeline of entity mentions and changes
367
+
368
+ Example:
369
+ >>> timeline = await track_entity_changes(backend, "React")
370
+ >>> for change in timeline:
371
+ ... print(f"{change['created_at']}: {change['title']}")
372
+ """
373
+ temporal = TemporalMemory(backend)
374
+ return await temporal.track_entity_changes(entity_id)
@@ -0,0 +1,27 @@
1
+ """
2
+ Backend migration module.
3
+
4
+ Provides utilities for migrating memories between different backend types
5
+ with validation, verification, and rollback capability.
6
+ """
7
+
8
+ from .models import (
9
+ BackendType,
10
+ BackendConfig,
11
+ MigrationOptions,
12
+ ValidationResult,
13
+ VerificationResult,
14
+ MigrationResult
15
+ )
16
+ from .manager import MigrationManager, MigrationError
17
+
18
+ __all__ = [
19
+ "BackendType",
20
+ "BackendConfig",
21
+ "MigrationOptions",
22
+ "ValidationResult",
23
+ "VerificationResult",
24
+ "MigrationResult",
25
+ "MigrationManager",
26
+ "MigrationError",
27
+ ]