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.
- memorygraph/__init__.py +50 -0
- memorygraph/__main__.py +12 -0
- memorygraph/advanced_tools.py +509 -0
- memorygraph/analytics/__init__.py +46 -0
- memorygraph/analytics/advanced_queries.py +727 -0
- memorygraph/backends/__init__.py +21 -0
- memorygraph/backends/base.py +179 -0
- memorygraph/backends/cloud.py +75 -0
- memorygraph/backends/cloud_backend.py +858 -0
- memorygraph/backends/factory.py +577 -0
- memorygraph/backends/falkordb_backend.py +749 -0
- memorygraph/backends/falkordblite_backend.py +746 -0
- memorygraph/backends/ladybugdb_backend.py +242 -0
- memorygraph/backends/memgraph_backend.py +327 -0
- memorygraph/backends/neo4j_backend.py +298 -0
- memorygraph/backends/sqlite_fallback.py +463 -0
- memorygraph/backends/turso.py +448 -0
- memorygraph/cli.py +743 -0
- memorygraph/cloud_database.py +297 -0
- memorygraph/config.py +295 -0
- memorygraph/database.py +933 -0
- memorygraph/graph_analytics.py +631 -0
- memorygraph/integration/__init__.py +69 -0
- memorygraph/integration/context_capture.py +426 -0
- memorygraph/integration/project_analysis.py +583 -0
- memorygraph/integration/workflow_tracking.py +492 -0
- memorygraph/intelligence/__init__.py +59 -0
- memorygraph/intelligence/context_retrieval.py +447 -0
- memorygraph/intelligence/entity_extraction.py +386 -0
- memorygraph/intelligence/pattern_recognition.py +420 -0
- memorygraph/intelligence/temporal.py +374 -0
- memorygraph/migration/__init__.py +27 -0
- memorygraph/migration/manager.py +579 -0
- memorygraph/migration/models.py +142 -0
- memorygraph/migration/scripts/__init__.py +17 -0
- memorygraph/migration/scripts/bitemporal_migration.py +595 -0
- memorygraph/migration/scripts/multitenancy_migration.py +452 -0
- memorygraph/migration_tools_module.py +146 -0
- memorygraph/models.py +684 -0
- memorygraph/proactive/__init__.py +46 -0
- memorygraph/proactive/outcome_learning.py +444 -0
- memorygraph/proactive/predictive.py +410 -0
- memorygraph/proactive/session_briefing.py +399 -0
- memorygraph/relationships.py +668 -0
- memorygraph/server.py +883 -0
- memorygraph/sqlite_database.py +1876 -0
- memorygraph/tools/__init__.py +59 -0
- memorygraph/tools/activity_tools.py +262 -0
- memorygraph/tools/memory_tools.py +315 -0
- memorygraph/tools/migration_tools.py +181 -0
- memorygraph/tools/relationship_tools.py +147 -0
- memorygraph/tools/search_tools.py +406 -0
- memorygraph/tools/temporal_tools.py +339 -0
- memorygraph/utils/__init__.py +10 -0
- memorygraph/utils/context_extractor.py +429 -0
- memorygraph/utils/error_handling.py +151 -0
- memorygraph/utils/export_import.py +425 -0
- memorygraph/utils/graph_algorithms.py +200 -0
- memorygraph/utils/pagination.py +149 -0
- memorygraph/utils/project_detection.py +133 -0
- memorygraphmcp-0.11.7.dist-info/METADATA +970 -0
- memorygraphmcp-0.11.7.dist-info/RECORD +65 -0
- memorygraphmcp-0.11.7.dist-info/WHEEL +4 -0
- memorygraphmcp-0.11.7.dist-info/entry_points.txt +2 -0
- memorygraphmcp-0.11.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pagination utilities for working with memories across different backends.
|
|
3
|
+
|
|
4
|
+
Provides reusable pagination helpers that work with both MemoryDatabase
|
|
5
|
+
and SQLiteMemoryDatabase interfaces.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import AsyncIterator, List, Callable, Optional
|
|
10
|
+
|
|
11
|
+
from ..models import Memory, SearchQuery
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def paginate_memories(
|
|
17
|
+
db, # MemoryDatabase or SQLiteMemoryDatabase
|
|
18
|
+
batch_size: int = 1000,
|
|
19
|
+
progress_callback: Optional[Callable[[int], None]] = None
|
|
20
|
+
) -> AsyncIterator[List[Memory]]:
|
|
21
|
+
"""
|
|
22
|
+
Async generator that yields batches of memories.
|
|
23
|
+
|
|
24
|
+
Works with both MemoryDatabase and SQLiteMemoryDatabase by using
|
|
25
|
+
the search_memories interface with pagination support.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
db: Database instance (any backend)
|
|
29
|
+
batch_size: Number of memories to fetch per batch
|
|
30
|
+
progress_callback: Optional callback(total_yielded) for progress reporting
|
|
31
|
+
|
|
32
|
+
Yields:
|
|
33
|
+
Batches of Memory objects
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
async for batch in paginate_memories(db, batch_size=500):
|
|
37
|
+
for memory in batch:
|
|
38
|
+
print(memory.title)
|
|
39
|
+
"""
|
|
40
|
+
offset = 0
|
|
41
|
+
total_yielded = 0
|
|
42
|
+
|
|
43
|
+
while True:
|
|
44
|
+
query = SearchQuery(
|
|
45
|
+
query="", # Empty query matches all memories
|
|
46
|
+
limit=batch_size,
|
|
47
|
+
offset=offset,
|
|
48
|
+
match_mode="any"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Use paginated search if available, fallback to regular search
|
|
52
|
+
if hasattr(db, 'search_memories_paginated'):
|
|
53
|
+
result = await db.search_memories_paginated(query)
|
|
54
|
+
memories = result.results
|
|
55
|
+
has_more = result.has_more
|
|
56
|
+
else:
|
|
57
|
+
# Fallback for backends without pagination
|
|
58
|
+
memories = await db.search_memories(query)
|
|
59
|
+
has_more = len(memories) >= batch_size
|
|
60
|
+
|
|
61
|
+
if memories:
|
|
62
|
+
yield memories
|
|
63
|
+
total_yielded += len(memories)
|
|
64
|
+
|
|
65
|
+
if progress_callback:
|
|
66
|
+
progress_callback(total_yielded)
|
|
67
|
+
|
|
68
|
+
if not has_more or not memories:
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
offset += batch_size
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
async def count_memories(db) -> int:
|
|
75
|
+
"""
|
|
76
|
+
Count total memories in database using efficient method.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
db: Database instance (any backend)
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Total number of memories
|
|
83
|
+
"""
|
|
84
|
+
query = SearchQuery(query="", limit=1, offset=0, match_mode="any")
|
|
85
|
+
|
|
86
|
+
# Use paginated search for efficient counting if available
|
|
87
|
+
if hasattr(db, 'search_memories_paginated'):
|
|
88
|
+
result = await db.search_memories_paginated(query)
|
|
89
|
+
return result.total_count
|
|
90
|
+
else:
|
|
91
|
+
# Fallback: count manually by iterating
|
|
92
|
+
count = 0
|
|
93
|
+
async for batch in paginate_memories(db, batch_size=1000):
|
|
94
|
+
count += len(batch)
|
|
95
|
+
return count
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def count_relationships(db) -> int:
|
|
99
|
+
"""
|
|
100
|
+
Count total relationships in database.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
db: Database instance (any backend)
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Total number of relationships (deduplicated)
|
|
107
|
+
"""
|
|
108
|
+
count = 0
|
|
109
|
+
seen_relationships = set()
|
|
110
|
+
|
|
111
|
+
async for batch in paginate_memories(db, batch_size=1000):
|
|
112
|
+
for memory in batch:
|
|
113
|
+
try:
|
|
114
|
+
related = await db.get_related_memories(memory.id, max_depth=1)
|
|
115
|
+
for _, relationship in related:
|
|
116
|
+
# Use tuple as key for deduplication
|
|
117
|
+
key = (
|
|
118
|
+
relationship.from_memory_id,
|
|
119
|
+
relationship.to_memory_id,
|
|
120
|
+
relationship.type.value
|
|
121
|
+
)
|
|
122
|
+
if key not in seen_relationships:
|
|
123
|
+
seen_relationships.add(key)
|
|
124
|
+
count += 1
|
|
125
|
+
except Exception as e:
|
|
126
|
+
logger.warning(f"Failed to count relationships for memory {memory.id}: {e}")
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
return count
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
async def get_all_memories(db) -> List[Memory]:
|
|
133
|
+
"""
|
|
134
|
+
Get all memories from database.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
db: Database instance (any backend)
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
List of all memories
|
|
141
|
+
|
|
142
|
+
Warning:
|
|
143
|
+
This loads all memories into memory. For large databases,
|
|
144
|
+
prefer using paginate_memories() to process in batches.
|
|
145
|
+
"""
|
|
146
|
+
all_memories = []
|
|
147
|
+
async for batch in paginate_memories(db, batch_size=1000):
|
|
148
|
+
all_memories.extend(batch)
|
|
149
|
+
return all_memories
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project context detection utilities.
|
|
3
|
+
|
|
4
|
+
Auto-detects project name and context from environment.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
from typing import Optional, Dict, Any
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def detect_project_context(cwd: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
16
|
+
"""
|
|
17
|
+
Detect project context from current working directory or git repository.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
cwd: Current working directory (defaults to os.getcwd())
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Dictionary with project information:
|
|
24
|
+
- project_name: Name of the project
|
|
25
|
+
- project_path: Absolute path to project root
|
|
26
|
+
- is_git_repo: Whether this is a git repository
|
|
27
|
+
- git_remote: Git remote URL (if available)
|
|
28
|
+
|
|
29
|
+
Returns None if project cannot be detected.
|
|
30
|
+
"""
|
|
31
|
+
if cwd is None:
|
|
32
|
+
cwd = os.getcwd()
|
|
33
|
+
|
|
34
|
+
cwd = os.path.abspath(cwd)
|
|
35
|
+
|
|
36
|
+
result = {
|
|
37
|
+
"project_path": cwd,
|
|
38
|
+
"is_git_repo": False
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Try to detect from git repository
|
|
42
|
+
git_info = _detect_from_git(cwd)
|
|
43
|
+
if git_info:
|
|
44
|
+
result.update(git_info)
|
|
45
|
+
result["is_git_repo"] = True
|
|
46
|
+
return result
|
|
47
|
+
|
|
48
|
+
# Fallback: use directory name
|
|
49
|
+
project_name = os.path.basename(cwd)
|
|
50
|
+
result["project_name"] = project_name
|
|
51
|
+
|
|
52
|
+
return result
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _detect_from_git(cwd: str) -> Optional[Dict[str, Any]]:
|
|
56
|
+
"""
|
|
57
|
+
Detect project information from git repository.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
cwd: Current working directory
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Dictionary with git-based project info, or None if not a git repo
|
|
64
|
+
"""
|
|
65
|
+
try:
|
|
66
|
+
# Check if this is a git repository
|
|
67
|
+
git_check = subprocess.run(
|
|
68
|
+
["git", "rev-parse", "--is-inside-work-tree"],
|
|
69
|
+
cwd=cwd,
|
|
70
|
+
capture_output=True,
|
|
71
|
+
text=True,
|
|
72
|
+
timeout=2
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if git_check.returncode != 0:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
# Get repository root
|
|
79
|
+
repo_root = subprocess.run(
|
|
80
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
81
|
+
cwd=cwd,
|
|
82
|
+
capture_output=True,
|
|
83
|
+
text=True,
|
|
84
|
+
timeout=2
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if repo_root.returncode != 0:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
project_path = repo_root.stdout.strip()
|
|
91
|
+
project_name = os.path.basename(project_path)
|
|
92
|
+
|
|
93
|
+
result = {
|
|
94
|
+
"project_name": project_name,
|
|
95
|
+
"project_path": project_path
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# Try to get git remote (optional)
|
|
99
|
+
try:
|
|
100
|
+
remote = subprocess.run(
|
|
101
|
+
["git", "remote", "get-url", "origin"],
|
|
102
|
+
cwd=cwd,
|
|
103
|
+
capture_output=True,
|
|
104
|
+
text=True,
|
|
105
|
+
timeout=2
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if remote.returncode == 0:
|
|
109
|
+
result["git_remote"] = remote.stdout.strip()
|
|
110
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
111
|
+
pass # Git remote is optional
|
|
112
|
+
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
|
|
116
|
+
logger.debug(f"Git detection failed: {e}")
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_project_from_memories(db, limit: int = 50) -> Optional[str]:
|
|
121
|
+
"""
|
|
122
|
+
Infer current project from frequently mentioned project paths in recent memories.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
db: Database instance
|
|
126
|
+
limit: Number of recent memories to analyze
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Most common project path, or None if cannot determine
|
|
130
|
+
"""
|
|
131
|
+
# This would require database access, which we'll implement later
|
|
132
|
+
# For now, return None
|
|
133
|
+
return None
|