claude-memory-agent 2.0.0 → 2.1.0
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.
- package/README.md +206 -200
- package/agent_card.py +186 -0
- package/bin/cli.js +317 -181
- package/bin/postinstall.js +270 -216
- package/dashboard.html +4232 -2689
- package/hooks/__pycache__/grounding-hook.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
- package/hooks/grounding-hook.py +422 -348
- package/hooks/session_end.py +293 -192
- package/hooks/session_start.py +227 -227
- package/install.py +919 -887
- package/main.py +4496 -2859
- package/package.json +47 -55
- package/services/__init__.py +50 -50
- package/services/__pycache__/__init__.cpython-312.pyc +0 -0
- package/services/__pycache__/curator.cpython-312.pyc +0 -0
- package/services/__pycache__/database.cpython-312.pyc +0 -0
- package/services/curator.py +1606 -0
- package/services/database.py +3637 -2485
- package/skills/__init__.py +21 -1
- package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/__pycache__/confidence_tracker.cpython-312.pyc +0 -0
- package/skills/__pycache__/context.cpython-312.pyc +0 -0
- package/skills/__pycache__/curator.cpython-312.pyc +0 -0
- package/skills/__pycache__/search.cpython-312.pyc +0 -0
- package/skills/__pycache__/session_review.cpython-312.pyc +0 -0
- package/skills/__pycache__/store.cpython-312.pyc +0 -0
- package/skills/confidence_tracker.py +441 -0
- package/skills/context.py +675 -0
- package/skills/curator.py +348 -0
- package/skills/search.py +369 -213
- package/skills/session_review.py +418 -0
- package/skills/store.py +377 -179
- package/update_system.py +829 -817
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""Curator MCP Skills - Graph exploration and maintenance capabilities."""
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Dict, Any, Optional, List
|
|
4
|
+
|
|
5
|
+
from services.database import DatabaseService
|
|
6
|
+
from services.embeddings import EmbeddingService
|
|
7
|
+
from services.curator import get_curator
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def curator_explore(
|
|
13
|
+
db: DatabaseService,
|
|
14
|
+
embeddings: EmbeddingService,
|
|
15
|
+
start_node_id: int,
|
|
16
|
+
max_depth: int = 3,
|
|
17
|
+
mode: str = "bfs",
|
|
18
|
+
relationship_filter: Optional[List[str]] = None
|
|
19
|
+
) -> Dict[str, Any]:
|
|
20
|
+
"""
|
|
21
|
+
Explore the memory graph from a starting node.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
db: Database service instance
|
|
25
|
+
embeddings: Embedding service instance
|
|
26
|
+
start_node_id: ID of the memory to start from
|
|
27
|
+
max_depth: Maximum traversal depth (default 3)
|
|
28
|
+
mode: 'bfs' (breadth-first) or 'dfs' (depth-first)
|
|
29
|
+
relationship_filter: Only follow these relationship types
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Dict with explored nodes, edges, clusters, and insights
|
|
33
|
+
"""
|
|
34
|
+
curator = get_curator(db, embeddings)
|
|
35
|
+
return await curator.explore_graph(
|
|
36
|
+
start_node_id=start_node_id,
|
|
37
|
+
max_depth=max_depth,
|
|
38
|
+
mode=mode,
|
|
39
|
+
relationship_filter=relationship_filter
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def curator_find_duplicates(
|
|
44
|
+
db: DatabaseService,
|
|
45
|
+
embeddings: EmbeddingService,
|
|
46
|
+
project_path: Optional[str] = None,
|
|
47
|
+
similarity_threshold: float = 0.92,
|
|
48
|
+
limit: int = 50
|
|
49
|
+
) -> Dict[str, Any]:
|
|
50
|
+
"""
|
|
51
|
+
Find semantically similar (duplicate) memories.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
db: Database service instance
|
|
55
|
+
embeddings: Embedding service instance
|
|
56
|
+
project_path: Optional project filter
|
|
57
|
+
similarity_threshold: Minimum similarity to consider duplicates
|
|
58
|
+
limit: Maximum number of duplicate pairs to return
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Dict with duplicate clusters and merge suggestions
|
|
62
|
+
"""
|
|
63
|
+
curator = get_curator(db, embeddings)
|
|
64
|
+
return await curator.find_duplicates(
|
|
65
|
+
project_path=project_path,
|
|
66
|
+
similarity_threshold=similarity_threshold,
|
|
67
|
+
limit=limit
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def curator_suggest_links(
|
|
72
|
+
db: DatabaseService,
|
|
73
|
+
embeddings: EmbeddingService,
|
|
74
|
+
memory_id: Optional[int] = None,
|
|
75
|
+
project_path: Optional[str] = None,
|
|
76
|
+
similarity_threshold: float = 0.7,
|
|
77
|
+
limit: int = 20
|
|
78
|
+
) -> Dict[str, Any]:
|
|
79
|
+
"""
|
|
80
|
+
Suggest missing relationships between memories.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
db: Database service instance
|
|
84
|
+
embeddings: Embedding service instance
|
|
85
|
+
memory_id: Optional specific memory to find links for
|
|
86
|
+
project_path: Optional project filter
|
|
87
|
+
similarity_threshold: Minimum similarity for suggestions
|
|
88
|
+
limit: Maximum suggestions to return
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Dict with suggested relationships
|
|
92
|
+
"""
|
|
93
|
+
curator = get_curator(db, embeddings)
|
|
94
|
+
return await curator.suggest_relationships(
|
|
95
|
+
memory_id=memory_id,
|
|
96
|
+
project_path=project_path,
|
|
97
|
+
similarity_threshold=similarity_threshold,
|
|
98
|
+
limit=limit
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
async def curator_merge(
|
|
103
|
+
db: DatabaseService,
|
|
104
|
+
embeddings: EmbeddingService,
|
|
105
|
+
keep_id: int,
|
|
106
|
+
remove_ids: List[int],
|
|
107
|
+
merge_content: bool = False
|
|
108
|
+
) -> Dict[str, Any]:
|
|
109
|
+
"""
|
|
110
|
+
Merge duplicate memories into one.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
db: Database service instance
|
|
114
|
+
embeddings: Embedding service instance
|
|
115
|
+
keep_id: Memory ID to keep
|
|
116
|
+
remove_ids: Memory IDs to merge into keep_id
|
|
117
|
+
merge_content: If True, append removed content to kept memory
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Dict with merge result
|
|
121
|
+
"""
|
|
122
|
+
curator = get_curator(db, embeddings)
|
|
123
|
+
return await curator.merge_memories(
|
|
124
|
+
keep_id=keep_id,
|
|
125
|
+
remove_ids=remove_ids,
|
|
126
|
+
merge_content=merge_content
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
async def curator_get_summary(
|
|
131
|
+
db: DatabaseService,
|
|
132
|
+
embeddings: EmbeddingService,
|
|
133
|
+
query: str,
|
|
134
|
+
project_path: Optional[str] = None,
|
|
135
|
+
max_memories: int = 10,
|
|
136
|
+
include_graph: bool = True
|
|
137
|
+
) -> Dict[str, Any]:
|
|
138
|
+
"""
|
|
139
|
+
Generate curated context summary for a query.
|
|
140
|
+
|
|
141
|
+
This is what gets injected into the main Claude's context.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
db: Database service instance
|
|
145
|
+
embeddings: Embedding service instance
|
|
146
|
+
query: The topic/query to generate context for
|
|
147
|
+
project_path: Optional project filter
|
|
148
|
+
max_memories: Maximum memories to include
|
|
149
|
+
include_graph: Include relationship graph context
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dict with curated context summary
|
|
153
|
+
"""
|
|
154
|
+
curator = get_curator(db, embeddings)
|
|
155
|
+
return await curator.generate_summary(
|
|
156
|
+
query=query,
|
|
157
|
+
project_path=project_path,
|
|
158
|
+
max_memories=max_memories,
|
|
159
|
+
include_graph=include_graph
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
async def curator_run_maintenance(
|
|
164
|
+
db: DatabaseService,
|
|
165
|
+
embeddings: EmbeddingService,
|
|
166
|
+
project_path: Optional[str] = None,
|
|
167
|
+
tasks: Optional[List[str]] = None
|
|
168
|
+
) -> Dict[str, Any]:
|
|
169
|
+
"""
|
|
170
|
+
Run curator maintenance tasks.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
db: Database service instance
|
|
174
|
+
embeddings: Embedding service instance
|
|
175
|
+
project_path: Optional project filter
|
|
176
|
+
tasks: Specific tasks to run, or None for all
|
|
177
|
+
Options: dedup, orphans, links, decay, quality
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Dict with maintenance report
|
|
181
|
+
"""
|
|
182
|
+
curator = get_curator(db, embeddings)
|
|
183
|
+
return await curator.run_maintenance(
|
|
184
|
+
project_path=project_path,
|
|
185
|
+
tasks=tasks
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
async def curator_get_report(
|
|
190
|
+
db: DatabaseService,
|
|
191
|
+
embeddings: EmbeddingService,
|
|
192
|
+
project_path: Optional[str] = None
|
|
193
|
+
) -> Dict[str, Any]:
|
|
194
|
+
"""
|
|
195
|
+
Get the latest curator report.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
db: Database service instance
|
|
199
|
+
embeddings: Embedding service instance
|
|
200
|
+
project_path: Optional project filter
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Dict with latest report or None
|
|
204
|
+
"""
|
|
205
|
+
curator = get_curator(db, embeddings)
|
|
206
|
+
report = await curator.get_latest_report(project_path=project_path)
|
|
207
|
+
if report:
|
|
208
|
+
return report
|
|
209
|
+
return {"message": "No curator reports found"}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
async def curator_get_status(
|
|
213
|
+
db: DatabaseService,
|
|
214
|
+
embeddings: EmbeddingService
|
|
215
|
+
) -> Dict[str, Any]:
|
|
216
|
+
"""
|
|
217
|
+
Get current curator agent status.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
db: Database service instance
|
|
221
|
+
embeddings: Embedding service instance
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Dict with curator status
|
|
225
|
+
"""
|
|
226
|
+
curator = get_curator(db, embeddings)
|
|
227
|
+
return await curator.get_status()
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
async def curator_score_quality(
|
|
231
|
+
db: DatabaseService,
|
|
232
|
+
embeddings: EmbeddingService,
|
|
233
|
+
memory_id: Optional[int] = None,
|
|
234
|
+
project_path: Optional[str] = None,
|
|
235
|
+
limit: int = 100
|
|
236
|
+
) -> Dict[str, Any]:
|
|
237
|
+
"""
|
|
238
|
+
Calculate quality scores for memories.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
db: Database service instance
|
|
242
|
+
embeddings: Embedding service instance
|
|
243
|
+
memory_id: Optional specific memory to score
|
|
244
|
+
project_path: Optional project filter
|
|
245
|
+
limit: Maximum memories to score
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Dict with quality scores and insights
|
|
249
|
+
"""
|
|
250
|
+
curator = get_curator(db, embeddings)
|
|
251
|
+
return await curator.score_quality(
|
|
252
|
+
memory_id=memory_id,
|
|
253
|
+
project_path=project_path,
|
|
254
|
+
limit=limit
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
async def curator_find_orphans(
|
|
259
|
+
db: DatabaseService,
|
|
260
|
+
embeddings: EmbeddingService,
|
|
261
|
+
project_path: Optional[str] = None,
|
|
262
|
+
limit: int = 50
|
|
263
|
+
) -> Dict[str, Any]:
|
|
264
|
+
"""
|
|
265
|
+
Find memories with no relationships (orphans).
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
db: Database service instance
|
|
269
|
+
embeddings: Embedding service instance
|
|
270
|
+
project_path: Optional project filter
|
|
271
|
+
limit: Maximum orphans to return
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Dict with orphan memories
|
|
275
|
+
"""
|
|
276
|
+
curator = get_curator(db, embeddings)
|
|
277
|
+
orphans = await curator.find_orphan_memories(
|
|
278
|
+
project_path=project_path,
|
|
279
|
+
limit=limit
|
|
280
|
+
)
|
|
281
|
+
return {
|
|
282
|
+
"orphans": orphans,
|
|
283
|
+
"total_found": len(orphans),
|
|
284
|
+
"recommendation": "Consider linking these memories or archiving if no longer relevant"
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
async def curator_get_config(
|
|
289
|
+
db: DatabaseService,
|
|
290
|
+
embeddings: EmbeddingService,
|
|
291
|
+
project_path: Optional[str] = None
|
|
292
|
+
) -> Dict[str, Any]:
|
|
293
|
+
"""
|
|
294
|
+
Get curator configuration.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
db: Database service instance
|
|
298
|
+
embeddings: Embedding service instance
|
|
299
|
+
project_path: Optional project path
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Dict with curator configuration
|
|
303
|
+
"""
|
|
304
|
+
curator = get_curator(db, embeddings)
|
|
305
|
+
return await curator.get_config(project_path=project_path)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
async def curator_update_config(
|
|
309
|
+
db: DatabaseService,
|
|
310
|
+
embeddings: EmbeddingService,
|
|
311
|
+
project_path: str,
|
|
312
|
+
auto_dedup_enabled: Optional[bool] = None,
|
|
313
|
+
auto_link_enabled: Optional[bool] = None,
|
|
314
|
+
dedup_threshold: Optional[float] = None,
|
|
315
|
+
maintenance_interval_hours: Optional[int] = None,
|
|
316
|
+
curator_active: Optional[bool] = None
|
|
317
|
+
) -> Dict[str, Any]:
|
|
318
|
+
"""
|
|
319
|
+
Update curator configuration for a project.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
db: Database service instance
|
|
323
|
+
embeddings: Embedding service instance
|
|
324
|
+
project_path: Project path to update config for
|
|
325
|
+
auto_dedup_enabled: Enable auto-deduplication
|
|
326
|
+
auto_link_enabled: Enable auto-linking
|
|
327
|
+
dedup_threshold: Similarity threshold for duplicates
|
|
328
|
+
maintenance_interval_hours: Hours between maintenance runs
|
|
329
|
+
curator_active: Enable/disable curator
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
Dict with updated configuration
|
|
333
|
+
"""
|
|
334
|
+
curator = get_curator(db, embeddings)
|
|
335
|
+
|
|
336
|
+
config_updates = {}
|
|
337
|
+
if auto_dedup_enabled is not None:
|
|
338
|
+
config_updates["auto_dedup_enabled"] = auto_dedup_enabled
|
|
339
|
+
if auto_link_enabled is not None:
|
|
340
|
+
config_updates["auto_link_enabled"] = auto_link_enabled
|
|
341
|
+
if dedup_threshold is not None:
|
|
342
|
+
config_updates["dedup_threshold"] = dedup_threshold
|
|
343
|
+
if maintenance_interval_hours is not None:
|
|
344
|
+
config_updates["maintenance_interval_hours"] = maintenance_interval_hours
|
|
345
|
+
if curator_active is not None:
|
|
346
|
+
config_updates["curator_active"] = curator_active
|
|
347
|
+
|
|
348
|
+
return await curator.update_config(project_path=project_path, **config_updates)
|