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.
Files changed (34) hide show
  1. package/README.md +206 -200
  2. package/agent_card.py +186 -0
  3. package/bin/cli.js +317 -181
  4. package/bin/postinstall.js +270 -216
  5. package/dashboard.html +4232 -2689
  6. package/hooks/__pycache__/grounding-hook.cpython-312.pyc +0 -0
  7. package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
  8. package/hooks/grounding-hook.py +422 -348
  9. package/hooks/session_end.py +293 -192
  10. package/hooks/session_start.py +227 -227
  11. package/install.py +919 -887
  12. package/main.py +4496 -2859
  13. package/package.json +47 -55
  14. package/services/__init__.py +50 -50
  15. package/services/__pycache__/__init__.cpython-312.pyc +0 -0
  16. package/services/__pycache__/curator.cpython-312.pyc +0 -0
  17. package/services/__pycache__/database.cpython-312.pyc +0 -0
  18. package/services/curator.py +1606 -0
  19. package/services/database.py +3637 -2485
  20. package/skills/__init__.py +21 -1
  21. package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
  22. package/skills/__pycache__/confidence_tracker.cpython-312.pyc +0 -0
  23. package/skills/__pycache__/context.cpython-312.pyc +0 -0
  24. package/skills/__pycache__/curator.cpython-312.pyc +0 -0
  25. package/skills/__pycache__/search.cpython-312.pyc +0 -0
  26. package/skills/__pycache__/session_review.cpython-312.pyc +0 -0
  27. package/skills/__pycache__/store.cpython-312.pyc +0 -0
  28. package/skills/confidence_tracker.py +441 -0
  29. package/skills/context.py +675 -0
  30. package/skills/curator.py +348 -0
  31. package/skills/search.py +369 -213
  32. package/skills/session_review.py +418 -0
  33. package/skills/store.py +377 -179
  34. package/update_system.py +829 -817
package/skills/store.py CHANGED
@@ -1,179 +1,377 @@
1
- """Store memory skill with rich context support."""
2
- from typing import Dict, Any, Optional, List
3
- from services.database import DatabaseService
4
- from services.embeddings import EmbeddingService
5
-
6
-
7
- async def store_memory(
8
- db: DatabaseService,
9
- embeddings: EmbeddingService,
10
- content: str,
11
- memory_type: str = "chunk",
12
- metadata: Optional[Dict[str, Any]] = None,
13
- session_id: Optional[str] = None,
14
- # Project context
15
- project_path: Optional[str] = None,
16
- project_name: Optional[str] = None,
17
- project_type: Optional[str] = None,
18
- tech_stack: Optional[List[str]] = None,
19
- # Session context
20
- chat_id: Optional[str] = None,
21
- # Agent context
22
- agent_type: Optional[str] = None,
23
- skill_used: Optional[str] = None,
24
- tools_used: Optional[List[str]] = None,
25
- # Outcome
26
- outcome: Optional[str] = None,
27
- success: Optional[bool] = None,
28
- # Classification
29
- tags: Optional[List[str]] = None,
30
- importance: int = 5
31
- ) -> Dict[str, Any]:
32
- """
33
- Store a memory with semantic embedding and rich context.
34
-
35
- Args:
36
- db: Database service instance
37
- embeddings: Embedding service instance
38
- content: The text content to store
39
- memory_type: Type of memory:
40
- - 'session': Session summaries
41
- - 'decision': Architectural/design decisions
42
- - 'code': Code patterns and snippets
43
- - 'chunk': General conversation chunks
44
- - 'error': Error patterns and solutions
45
- - 'preference': User preferences
46
- metadata: Optional additional metadata
47
- session_id: Session identifier
48
- project_path: Full path to the project
49
- project_name: Human-readable project name
50
- project_type: Type (wordpress, react, python, etc.)
51
- tech_stack: List of technologies used
52
- chat_id: Specific chat/conversation ID
53
- agent_type: Agent that processed this (Explore, Plan, etc.)
54
- skill_used: Skill that was invoked
55
- tools_used: List of tools that were called
56
- outcome: Description of what happened
57
- success: Whether the operation succeeded
58
- tags: Classification tags
59
- importance: 1-10 scale of importance (default 5)
60
-
61
- Returns:
62
- Dict with stored memory ID and status
63
- """
64
- # Generate embedding for the content
65
- embedding = await embeddings.generate_embedding(content)
66
-
67
- # Store in database with full context
68
- memory_id = await db.store_memory(
69
- memory_type=memory_type,
70
- content=content,
71
- embedding=embedding,
72
- metadata=metadata,
73
- session_id=session_id,
74
- project_path=project_path,
75
- project_name=project_name,
76
- project_type=project_type,
77
- tech_stack=tech_stack,
78
- chat_id=chat_id,
79
- agent_type=agent_type,
80
- skill_used=skill_used,
81
- tools_used=tools_used,
82
- outcome=outcome,
83
- success=success,
84
- tags=tags,
85
- importance=importance
86
- )
87
-
88
- return {
89
- "success": True,
90
- "memory_id": memory_id,
91
- "type": memory_type,
92
- "importance": importance,
93
- "project": project_path,
94
- "message": f"Memory stored successfully with ID {memory_id}"
95
- }
96
-
97
-
98
- async def store_project(
99
- db: DatabaseService,
100
- path: str,
101
- name: Optional[str] = None,
102
- project_type: Optional[str] = None,
103
- tech_stack: Optional[List[str]] = None,
104
- conventions: Optional[Dict[str, Any]] = None,
105
- preferences: Optional[Dict[str, Any]] = None
106
- ) -> Dict[str, Any]:
107
- """
108
- Store or update project-level information.
109
-
110
- Args:
111
- db: Database service instance
112
- path: Full path to the project
113
- name: Human-readable project name
114
- project_type: Type (wordpress, react, python, etc.)
115
- tech_stack: List of technologies
116
- conventions: Coding conventions (naming, structure, etc.)
117
- preferences: User preferences for this project
118
-
119
- Returns:
120
- Dict with project info
121
- """
122
- project_id = await db.store_project(
123
- path=path,
124
- name=name,
125
- project_type=project_type,
126
- tech_stack=tech_stack,
127
- conventions=conventions,
128
- preferences=preferences
129
- )
130
-
131
- return {
132
- "success": True,
133
- "project_id": project_id,
134
- "path": path,
135
- "message": f"Project info stored/updated for {path}"
136
- }
137
-
138
-
139
- async def store_pattern(
140
- db: DatabaseService,
141
- embeddings: EmbeddingService,
142
- name: str,
143
- solution: str,
144
- problem_type: Optional[str] = None,
145
- tech_context: Optional[List[str]] = None,
146
- metadata: Optional[Dict[str, Any]] = None
147
- ) -> Dict[str, Any]:
148
- """
149
- Store a reusable solution pattern.
150
-
151
- Args:
152
- db: Database service instance
153
- embeddings: Embedding service instance
154
- name: Pattern name
155
- solution: The solution/approach
156
- problem_type: Category (bug_fix, feature, refactor, config, etc.)
157
- tech_context: Technologies this applies to
158
- metadata: Additional info
159
-
160
- Returns:
161
- Dict with pattern info
162
- """
163
- embedding = await embeddings.generate_embedding(f"{name}: {solution}")
164
-
165
- pattern_id = await db.store_pattern(
166
- name=name,
167
- solution=solution,
168
- embedding=embedding,
169
- problem_type=problem_type,
170
- tech_context=tech_context,
171
- metadata=metadata
172
- )
173
-
174
- return {
175
- "success": True,
176
- "pattern_id": pattern_id,
177
- "name": name,
178
- "message": f"Pattern '{name}' stored successfully"
179
- }
1
+ """Store memory skill with rich context support."""
2
+ import logging
3
+ from typing import Dict, Any, Optional, List
4
+ from services.database import DatabaseService
5
+ from services.embeddings import EmbeddingService
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ # ============================================================
11
+ # INTERNAL HELPER - Auto-infer relationships
12
+ # ============================================================
13
+
14
+ async def _auto_infer_relationships(
15
+ db: DatabaseService,
16
+ embeddings: EmbeddingService,
17
+ memory_id: int,
18
+ content: str,
19
+ memory_type: str,
20
+ outcome: str,
21
+ session_id: str,
22
+ project_path: str = None
23
+ ) -> List[str]:
24
+ """
25
+ Automatically infer and create relationships based on content analysis.
26
+ Called internally after storing a memory.
27
+
28
+ This is NOT a skill - it's an internal helper function.
29
+
30
+ Args:
31
+ db: Database service instance
32
+ embeddings: Embedding service instance
33
+ memory_id: ID of the newly stored memory
34
+ content: The content of the memory
35
+ memory_type: Type of memory (decision, code, error, etc.)
36
+ outcome: Outcome status (success, partial, failed, pending)
37
+ session_id: Current session ID
38
+ project_path: Optional project path filter
39
+
40
+ Returns:
41
+ List of relationship descriptions that were created
42
+ """
43
+ relationships_created = []
44
+ content_lower = content.lower()
45
+
46
+ # 1. Fix Detection: If this is a successful decision/code after a recent error
47
+ if outcome == 'success' and memory_type in ['decision', 'code']:
48
+ if session_id:
49
+ try:
50
+ recent_errors = await db.get_memories_by_type(
51
+ memory_type='error',
52
+ session_id=session_id,
53
+ limit=3
54
+ )
55
+ for error in recent_errors:
56
+ if error['id'] != memory_id:
57
+ result = await db.create_relationship(
58
+ memory_id, error['id'], 'fixes', strength=0.9
59
+ )
60
+ if result.get('success'):
61
+ relationships_created.append(f"fixes error #{error['id']}")
62
+ except Exception as e:
63
+ logger.debug(f"Fix detection failed: {e}")
64
+
65
+ # 2. Causal Keyword Detection
66
+ causal_keywords = ['because', 'due to', 'caused by', 'result of', 'since']
67
+ if any(kw in content_lower for kw in causal_keywords):
68
+ if embeddings:
69
+ try:
70
+ embedding = await embeddings.generate_embedding(content)
71
+ similar = await db.search_similar(
72
+ embedding, limit=3, threshold=0.7, project_path=project_path
73
+ )
74
+ for mem in similar:
75
+ if mem['id'] != memory_id:
76
+ result = await db.create_relationship(
77
+ memory_id, mem['id'], 'caused_by', strength=0.7
78
+ )
79
+ if result.get('success'):
80
+ relationships_created.append(f"caused_by #{mem['id']}")
81
+ except Exception as e:
82
+ logger.debug(f"Causal detection failed: {e}")
83
+
84
+ # 3. Support Detection
85
+ support_keywords = ['supports', 'evidence for', 'proves', 'confirms', 'validates']
86
+ if any(kw in content_lower for kw in support_keywords):
87
+ if embeddings:
88
+ try:
89
+ embedding = await embeddings.generate_embedding(content)
90
+ similar = await db.search_similar(
91
+ embedding, limit=2, threshold=0.75, project_path=project_path
92
+ )
93
+ for mem in similar:
94
+ if mem['id'] != memory_id:
95
+ result = await db.create_relationship(
96
+ memory_id, mem['id'], 'supports', strength=0.8
97
+ )
98
+ if result.get('success'):
99
+ relationships_created.append(f"supports #{mem['id']}")
100
+ except Exception as e:
101
+ logger.debug(f"Support detection failed: {e}")
102
+
103
+ # 4. Contradiction Detection
104
+ contradiction_keywords = ['but actually', 'wrong', 'incorrect', 'not true', 'instead', 'actually']
105
+ if any(kw in content_lower for kw in contradiction_keywords):
106
+ if embeddings:
107
+ try:
108
+ embedding = await embeddings.generate_embedding(content)
109
+ similar = await db.search_similar(
110
+ embedding, limit=2, threshold=0.8, project_path=project_path
111
+ )
112
+ for mem in similar:
113
+ if mem['id'] != memory_id:
114
+ result = await db.create_relationship(
115
+ memory_id, mem['id'], 'contradicts', strength=0.85
116
+ )
117
+ if result.get('success'):
118
+ relationships_created.append(f"contradicts #{mem['id']}")
119
+ except Exception as e:
120
+ logger.debug(f"Contradiction detection failed: {e}")
121
+
122
+ # 5. Temporal Proximity: Link to recent memories in same session
123
+ if session_id:
124
+ try:
125
+ # Get recent memories from same session (any type)
126
+ recent = await db.get_memories_by_type(
127
+ memory_type=memory_type, # Same type for relevance
128
+ session_id=session_id,
129
+ limit=3
130
+ )
131
+ for mem in recent:
132
+ if mem['id'] != memory_id:
133
+ result = await db.create_relationship(
134
+ memory_id, mem['id'], 'related', strength=0.5
135
+ )
136
+ if result.get('success'):
137
+ relationships_created.append(f"related to #{mem['id']}")
138
+ except Exception as e:
139
+ logger.debug(f"Temporal proximity detection failed: {e}")
140
+
141
+ # 6. High Semantic Similarity: Strong related link
142
+ if embeddings:
143
+ try:
144
+ embedding = await embeddings.generate_embedding(content)
145
+ very_similar = await db.search_similar(
146
+ embedding, limit=2, threshold=0.85, project_path=project_path
147
+ )
148
+ for mem in very_similar:
149
+ if mem['id'] != memory_id:
150
+ strength = mem.get('score', 0.85)
151
+ result = await db.create_relationship(
152
+ memory_id, mem['id'], 'related', strength=strength
153
+ )
154
+ if result.get('success'):
155
+ relationships_created.append(f"highly related to #{mem['id']}")
156
+ except Exception as e:
157
+ logger.debug(f"Semantic similarity detection failed: {e}")
158
+
159
+ return relationships_created
160
+
161
+
162
+ async def store_memory(
163
+ db: DatabaseService,
164
+ embeddings: EmbeddingService,
165
+ content: str,
166
+ memory_type: str = "chunk",
167
+ metadata: Optional[Dict[str, Any]] = None,
168
+ session_id: Optional[str] = None,
169
+ # Project context
170
+ project_path: Optional[str] = None,
171
+ project_name: Optional[str] = None,
172
+ project_type: Optional[str] = None,
173
+ tech_stack: Optional[List[str]] = None,
174
+ # Session context
175
+ chat_id: Optional[str] = None,
176
+ # Agent context
177
+ agent_type: Optional[str] = None,
178
+ skill_used: Optional[str] = None,
179
+ tools_used: Optional[List[str]] = None,
180
+ # Outcome (legacy)
181
+ outcome: Optional[str] = None,
182
+ success: Optional[bool] = None,
183
+ # Classification
184
+ tags: Optional[List[str]] = None,
185
+ importance: int = 5,
186
+ confidence: float = 0.5,
187
+ # Outcome spectrum
188
+ outcome_status: str = 'pending',
189
+ fixed: Optional[List[str]] = None,
190
+ did_not_fix: Optional[List[str]] = None,
191
+ caused: Optional[List[str]] = None
192
+ ) -> Dict[str, Any]:
193
+ """
194
+ Store a memory with semantic embedding and rich context.
195
+
196
+ Args:
197
+ db: Database service instance
198
+ embeddings: Embedding service instance
199
+ content: The text content to store
200
+ memory_type: Type of memory:
201
+ - 'session': Session summaries
202
+ - 'decision': Architectural/design decisions
203
+ - 'code': Code patterns and snippets
204
+ - 'chunk': General conversation chunks
205
+ - 'error': Error patterns and solutions
206
+ - 'preference': User preferences
207
+ metadata: Optional additional metadata
208
+ session_id: Session identifier
209
+ project_path: Full path to the project
210
+ project_name: Human-readable project name
211
+ project_type: Type (wordpress, react, python, etc.)
212
+ tech_stack: List of technologies used
213
+ chat_id: Specific chat/conversation ID
214
+ agent_type: Agent that processed this (Explore, Plan, etc.)
215
+ skill_used: Skill that was invoked
216
+ tools_used: List of tools that were called
217
+ outcome: Description of what happened (legacy field)
218
+ success: Whether the operation succeeded (legacy field)
219
+ tags: Classification tags
220
+ importance: 1-10 scale of importance (default 5)
221
+ confidence: Reliability score 0.0 (unreliable) to 1.0 (proven), default 0.5
222
+ outcome_status: Status of the solution:
223
+ - 'pending': Not yet verified (default)
224
+ - 'success': Fully worked
225
+ - 'partial': Partially worked
226
+ - 'failed': Did not work
227
+ - 'superseded': Replaced by another solution
228
+ fixed: List of what this solution fixed
229
+ did_not_fix: List of what remains unfixed
230
+ caused: List of side effects this solution caused
231
+
232
+ Returns:
233
+ Dict with stored memory ID and status
234
+ """
235
+ # Generate embedding for the content
236
+ embedding = await embeddings.generate_embedding(content)
237
+
238
+ # Store in database with full context
239
+ memory_id = await db.store_memory(
240
+ memory_type=memory_type,
241
+ content=content,
242
+ embedding=embedding,
243
+ metadata=metadata,
244
+ session_id=session_id,
245
+ project_path=project_path,
246
+ project_name=project_name,
247
+ project_type=project_type,
248
+ tech_stack=tech_stack,
249
+ chat_id=chat_id,
250
+ agent_type=agent_type,
251
+ skill_used=skill_used,
252
+ tools_used=tools_used,
253
+ outcome=outcome,
254
+ success=success,
255
+ tags=tags,
256
+ importance=importance,
257
+ confidence=confidence,
258
+ outcome_status=outcome_status,
259
+ fixed=fixed,
260
+ did_not_fix=did_not_fix,
261
+ caused=caused
262
+ )
263
+
264
+ # Auto-infer relationships (silent, internal)
265
+ relationships_created = []
266
+ try:
267
+ relationships_created = await _auto_infer_relationships(
268
+ db=db,
269
+ embeddings=embeddings,
270
+ memory_id=memory_id,
271
+ content=content,
272
+ memory_type=memory_type,
273
+ outcome=outcome_status,
274
+ session_id=session_id,
275
+ project_path=project_path
276
+ )
277
+ if relationships_created:
278
+ logger.info(f"Auto-created {len(relationships_created)} relationships for memory #{memory_id}")
279
+ except Exception as e:
280
+ logger.warning(f"Failed to auto-infer relationships: {e}")
281
+ # Don't fail the store operation if relationship inference fails
282
+
283
+ return {
284
+ "success": True,
285
+ "memory_id": memory_id,
286
+ "type": memory_type,
287
+ "importance": importance,
288
+ "confidence": confidence,
289
+ "outcome_status": outcome_status,
290
+ "project": project_path,
291
+ "relationships_created": relationships_created,
292
+ "message": f"Memory stored successfully with ID {memory_id}"
293
+ }
294
+
295
+
296
+ async def store_project(
297
+ db: DatabaseService,
298
+ path: str,
299
+ name: Optional[str] = None,
300
+ project_type: Optional[str] = None,
301
+ tech_stack: Optional[List[str]] = None,
302
+ conventions: Optional[Dict[str, Any]] = None,
303
+ preferences: Optional[Dict[str, Any]] = None
304
+ ) -> Dict[str, Any]:
305
+ """
306
+ Store or update project-level information.
307
+
308
+ Args:
309
+ db: Database service instance
310
+ path: Full path to the project
311
+ name: Human-readable project name
312
+ project_type: Type (wordpress, react, python, etc.)
313
+ tech_stack: List of technologies
314
+ conventions: Coding conventions (naming, structure, etc.)
315
+ preferences: User preferences for this project
316
+
317
+ Returns:
318
+ Dict with project info
319
+ """
320
+ project_id = await db.store_project(
321
+ path=path,
322
+ name=name,
323
+ project_type=project_type,
324
+ tech_stack=tech_stack,
325
+ conventions=conventions,
326
+ preferences=preferences
327
+ )
328
+
329
+ return {
330
+ "success": True,
331
+ "project_id": project_id,
332
+ "path": path,
333
+ "message": f"Project info stored/updated for {path}"
334
+ }
335
+
336
+
337
+ async def store_pattern(
338
+ db: DatabaseService,
339
+ embeddings: EmbeddingService,
340
+ name: str,
341
+ solution: str,
342
+ problem_type: Optional[str] = None,
343
+ tech_context: Optional[List[str]] = None,
344
+ metadata: Optional[Dict[str, Any]] = None
345
+ ) -> Dict[str, Any]:
346
+ """
347
+ Store a reusable solution pattern.
348
+
349
+ Args:
350
+ db: Database service instance
351
+ embeddings: Embedding service instance
352
+ name: Pattern name
353
+ solution: The solution/approach
354
+ problem_type: Category (bug_fix, feature, refactor, config, etc.)
355
+ tech_context: Technologies this applies to
356
+ metadata: Additional info
357
+
358
+ Returns:
359
+ Dict with pattern info
360
+ """
361
+ embedding = await embeddings.generate_embedding(f"{name}: {solution}")
362
+
363
+ pattern_id = await db.store_pattern(
364
+ name=name,
365
+ solution=solution,
366
+ embedding=embedding,
367
+ problem_type=problem_type,
368
+ tech_context=tech_context,
369
+ metadata=metadata
370
+ )
371
+
372
+ return {
373
+ "success": True,
374
+ "pattern_id": pattern_id,
375
+ "name": name,
376
+ "message": f"Pattern '{name}' stored successfully"
377
+ }