claude-memory-agent 2.0.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/.env.example +107 -0
- package/README.md +200 -0
- package/agent_card.py +512 -0
- package/bin/cli.js +181 -0
- package/bin/postinstall.js +216 -0
- package/config.py +104 -0
- package/dashboard.html +2689 -0
- package/hooks/README.md +196 -0
- package/hooks/__pycache__/auto-detect-response.cpython-312.pyc +0 -0
- package/hooks/__pycache__/auto_capture.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
- package/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
- package/hooks/auto-detect-response.py +348 -0
- package/hooks/auto_capture.py +255 -0
- package/hooks/detect-correction.py +173 -0
- package/hooks/grounding-hook.py +348 -0
- package/hooks/log-tool-use.py +234 -0
- package/hooks/log-user-request.py +208 -0
- package/hooks/pre-tool-decision.py +218 -0
- package/hooks/problem-detector.py +343 -0
- package/hooks/session_end.py +192 -0
- package/hooks/session_start.py +227 -0
- package/install.py +887 -0
- package/main.py +2859 -0
- package/manager.py +997 -0
- package/package.json +55 -0
- package/requirements.txt +8 -0
- package/run_server.py +136 -0
- package/services/__init__.py +50 -0
- package/services/__pycache__/__init__.cpython-312.pyc +0 -0
- package/services/__pycache__/agent_registry.cpython-312.pyc +0 -0
- package/services/__pycache__/auth.cpython-312.pyc +0 -0
- package/services/__pycache__/auto_inject.cpython-312.pyc +0 -0
- package/services/__pycache__/claude_md_sync.cpython-312.pyc +0 -0
- package/services/__pycache__/cleanup.cpython-312.pyc +0 -0
- package/services/__pycache__/compaction_flush.cpython-312.pyc +0 -0
- package/services/__pycache__/confidence.cpython-312.pyc +0 -0
- package/services/__pycache__/daily_log.cpython-312.pyc +0 -0
- package/services/__pycache__/database.cpython-312.pyc +0 -0
- package/services/__pycache__/embeddings.cpython-312.pyc +0 -0
- package/services/__pycache__/insights.cpython-312.pyc +0 -0
- package/services/__pycache__/llm_analyzer.cpython-312.pyc +0 -0
- package/services/__pycache__/memory_md_sync.cpython-312.pyc +0 -0
- package/services/__pycache__/retry_queue.cpython-312.pyc +0 -0
- package/services/__pycache__/timeline.cpython-312.pyc +0 -0
- package/services/__pycache__/vector_index.cpython-312.pyc +0 -0
- package/services/__pycache__/websocket.cpython-312.pyc +0 -0
- package/services/agent_registry.py +753 -0
- package/services/auth.py +331 -0
- package/services/auto_inject.py +250 -0
- package/services/claude_md_sync.py +275 -0
- package/services/cleanup.py +667 -0
- package/services/compaction_flush.py +447 -0
- package/services/confidence.py +301 -0
- package/services/daily_log.py +333 -0
- package/services/database.py +2485 -0
- package/services/embeddings.py +358 -0
- package/services/insights.py +632 -0
- package/services/llm_analyzer.py +595 -0
- package/services/memory_md_sync.py +409 -0
- package/services/retry_queue.py +453 -0
- package/services/timeline.py +579 -0
- package/services/vector_index.py +398 -0
- package/services/websocket.py +257 -0
- package/skills/__init__.py +6 -0
- package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/__pycache__/admin.cpython-312.pyc +0 -0
- package/skills/__pycache__/checkpoint.cpython-312.pyc +0 -0
- package/skills/__pycache__/claude_md.cpython-312.pyc +0 -0
- package/skills/__pycache__/cleanup.cpython-312.pyc +0 -0
- package/skills/__pycache__/grounding.cpython-312.pyc +0 -0
- package/skills/__pycache__/insights.cpython-312.pyc +0 -0
- package/skills/__pycache__/natural_language.cpython-312.pyc +0 -0
- package/skills/__pycache__/retrieve.cpython-312.pyc +0 -0
- package/skills/__pycache__/search.cpython-312.pyc +0 -0
- package/skills/__pycache__/state.cpython-312.pyc +0 -0
- package/skills/__pycache__/store.cpython-312.pyc +0 -0
- package/skills/__pycache__/summarize.cpython-312.pyc +0 -0
- package/skills/__pycache__/timeline.cpython-312.pyc +0 -0
- package/skills/__pycache__/verification.cpython-312.pyc +0 -0
- package/skills/admin.py +469 -0
- package/skills/checkpoint.py +198 -0
- package/skills/claude_md.py +363 -0
- package/skills/cleanup.py +241 -0
- package/skills/grounding.py +801 -0
- package/skills/insights.py +231 -0
- package/skills/natural_language.py +277 -0
- package/skills/retrieve.py +67 -0
- package/skills/search.py +213 -0
- package/skills/state.py +182 -0
- package/skills/store.py +179 -0
- package/skills/summarize.py +588 -0
- package/skills/timeline.py +387 -0
- package/skills/verification.py +391 -0
- package/start_daemon.py +155 -0
- package/test_automation.py +221 -0
- package/test_complete.py +338 -0
- package/test_full.py +322 -0
- package/update_system.py +817 -0
- package/verify_db.py +134 -0
package/test_full.py
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"""Complete test suite for all memory system features."""
|
|
2
|
+
import asyncio
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
sys.path.insert(0, '.')
|
|
6
|
+
|
|
7
|
+
async def test_all():
|
|
8
|
+
print('=' * 70)
|
|
9
|
+
print('COMPLETE MEMORY SYSTEM TEST SUITE')
|
|
10
|
+
print('=' * 70)
|
|
11
|
+
|
|
12
|
+
results = []
|
|
13
|
+
|
|
14
|
+
# ===== ORIGINAL 12 FEATURES =====
|
|
15
|
+
print('\n' + '-' * 70)
|
|
16
|
+
print('SECTION A: ORIGINAL 12 FEATURES')
|
|
17
|
+
print('-' * 70)
|
|
18
|
+
|
|
19
|
+
# [1] Database with migrations
|
|
20
|
+
print('\n[A1] Database & Migrations...')
|
|
21
|
+
passed = 0
|
|
22
|
+
try:
|
|
23
|
+
from services.database import DatabaseService
|
|
24
|
+
db = DatabaseService()
|
|
25
|
+
await db.connect()
|
|
26
|
+
await db.initialize_schema()
|
|
27
|
+
|
|
28
|
+
# Check key tables exist
|
|
29
|
+
cursor = db.conn.cursor()
|
|
30
|
+
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
|
|
31
|
+
tables = [r[0] for r in cursor.fetchall()]
|
|
32
|
+
|
|
33
|
+
required = ['memories', 'patterns', 'projects', 'anchors', 'timeline']
|
|
34
|
+
for t in required:
|
|
35
|
+
if t in tables:
|
|
36
|
+
passed += 1
|
|
37
|
+
|
|
38
|
+
await db.close()
|
|
39
|
+
except Exception as e:
|
|
40
|
+
print(f' ERROR: {e}')
|
|
41
|
+
|
|
42
|
+
results.append(('A1. Database & Migrations', passed, len(required)))
|
|
43
|
+
print(f' {passed}/{len(required)} tables verified')
|
|
44
|
+
|
|
45
|
+
# [2] Embeddings Service
|
|
46
|
+
print('\n[A2] Embeddings Service...')
|
|
47
|
+
passed = 0
|
|
48
|
+
try:
|
|
49
|
+
from services.embeddings import EmbeddingsService
|
|
50
|
+
passed += 1 # Import works
|
|
51
|
+
except Exception as e:
|
|
52
|
+
print(f' ERROR: {e}')
|
|
53
|
+
results.append(('A2. Embeddings Service', passed, 1))
|
|
54
|
+
print(f' {passed}/1 import verified')
|
|
55
|
+
|
|
56
|
+
# [3] Session Management
|
|
57
|
+
print('\n[A3] Session Management...')
|
|
58
|
+
passed = 0
|
|
59
|
+
try:
|
|
60
|
+
from skills.session import create_session, get_active_session, end_session
|
|
61
|
+
passed += 3
|
|
62
|
+
except Exception as e:
|
|
63
|
+
print(f' ERROR: {e}')
|
|
64
|
+
results.append(('A3. Session Management', passed, 3))
|
|
65
|
+
print(f' {passed}/3 functions verified')
|
|
66
|
+
|
|
67
|
+
# [4] Timeline Service
|
|
68
|
+
print('\n[A4] Timeline Service...')
|
|
69
|
+
passed = 0
|
|
70
|
+
try:
|
|
71
|
+
from skills.timeline import log_event, get_recent_events, get_session_timeline
|
|
72
|
+
passed += 3
|
|
73
|
+
except Exception as e:
|
|
74
|
+
print(f' ERROR: {e}')
|
|
75
|
+
results.append(('A4. Timeline Service', passed, 3))
|
|
76
|
+
print(f' {passed}/3 functions verified')
|
|
77
|
+
|
|
78
|
+
# [5] Grounding System (Anchors)
|
|
79
|
+
print('\n[A5] Grounding System...')
|
|
80
|
+
passed = 0
|
|
81
|
+
try:
|
|
82
|
+
from services.grounding import GroundingService
|
|
83
|
+
passed += 1
|
|
84
|
+
except Exception as e:
|
|
85
|
+
print(f' ERROR: {e}')
|
|
86
|
+
results.append(('A5. Grounding System', passed, 1))
|
|
87
|
+
print(f' {passed}/1 service verified')
|
|
88
|
+
|
|
89
|
+
# [6] Insight Aggregation
|
|
90
|
+
print('\n[A6] Insight Aggregation...')
|
|
91
|
+
passed = 0
|
|
92
|
+
try:
|
|
93
|
+
from services.insight_aggregator import InsightAggregator
|
|
94
|
+
passed += 1
|
|
95
|
+
except Exception as e:
|
|
96
|
+
print(f' ERROR: {e}')
|
|
97
|
+
results.append(('A6. Insight Aggregation', passed, 1))
|
|
98
|
+
print(f' {passed}/1 service verified')
|
|
99
|
+
|
|
100
|
+
# [7] Auto-Conflict Detection
|
|
101
|
+
print('\n[A7] Auto-Conflict Detection...')
|
|
102
|
+
passed = 0
|
|
103
|
+
try:
|
|
104
|
+
from services.grounding import GroundingService
|
|
105
|
+
# Check conflict table exists
|
|
106
|
+
db = DatabaseService()
|
|
107
|
+
await db.connect()
|
|
108
|
+
cursor = db.conn.cursor()
|
|
109
|
+
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='anchor_conflicts'")
|
|
110
|
+
if cursor.fetchone():
|
|
111
|
+
passed += 1
|
|
112
|
+
await db.close()
|
|
113
|
+
except Exception as e:
|
|
114
|
+
print(f' ERROR: {e}')
|
|
115
|
+
results.append(('A7. Conflict Detection', passed, 1))
|
|
116
|
+
print(f' {passed}/1 table verified')
|
|
117
|
+
|
|
118
|
+
# [8] Memory Cleanup
|
|
119
|
+
print('\n[A8] Memory Cleanup Service...')
|
|
120
|
+
passed = 0
|
|
121
|
+
try:
|
|
122
|
+
from services.cleanup import CleanupService
|
|
123
|
+
passed += 1
|
|
124
|
+
except Exception as e:
|
|
125
|
+
print(f' ERROR: {e}')
|
|
126
|
+
results.append(('A8. Memory Cleanup', passed, 1))
|
|
127
|
+
print(f' {passed}/1 service verified')
|
|
128
|
+
|
|
129
|
+
# [9] Auth & Queue
|
|
130
|
+
print('\n[A9] Auth & Queue Services...')
|
|
131
|
+
passed = 0
|
|
132
|
+
try:
|
|
133
|
+
from services.auth import AuthService
|
|
134
|
+
from services.queue import MemoryQueue
|
|
135
|
+
passed += 2
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f' ERROR: {e}')
|
|
138
|
+
results.append(('A9. Auth & Queue', passed, 2))
|
|
139
|
+
print(f' {passed}/2 services verified')
|
|
140
|
+
|
|
141
|
+
# [10] Dashboard
|
|
142
|
+
print('\n[A10] Dashboard...')
|
|
143
|
+
passed = 0
|
|
144
|
+
if os.path.exists('templates/dashboard.html'):
|
|
145
|
+
passed += 1
|
|
146
|
+
results.append(('A10. Dashboard', passed, 1))
|
|
147
|
+
print(f' {passed}/1 file verified')
|
|
148
|
+
|
|
149
|
+
# [11] Embedding Model Switching
|
|
150
|
+
print('\n[A11] Embedding Model Switching...')
|
|
151
|
+
passed = 0
|
|
152
|
+
try:
|
|
153
|
+
from skills.admin import get_embedding_status, switch_embedding_model
|
|
154
|
+
passed += 2
|
|
155
|
+
except Exception as e:
|
|
156
|
+
print(f' ERROR: {e}')
|
|
157
|
+
results.append(('A11. Model Switching', passed, 2))
|
|
158
|
+
print(f' {passed}/2 functions verified')
|
|
159
|
+
|
|
160
|
+
# [12] WebSocket Updates
|
|
161
|
+
print('\n[A12] WebSocket Updates...')
|
|
162
|
+
passed = 0
|
|
163
|
+
try:
|
|
164
|
+
from services.websocket import WebSocketManager, broadcast_event
|
|
165
|
+
passed += 2
|
|
166
|
+
except Exception as e:
|
|
167
|
+
print(f' ERROR: {e}')
|
|
168
|
+
results.append(('A12. WebSocket', passed, 2))
|
|
169
|
+
print(f' {passed}/2 imports verified')
|
|
170
|
+
|
|
171
|
+
# ===== 6 AUTOMATION FEATURES =====
|
|
172
|
+
print('\n' + '-' * 70)
|
|
173
|
+
print('SECTION B: AUTOMATION FEATURES')
|
|
174
|
+
print('-' * 70)
|
|
175
|
+
|
|
176
|
+
# [B1] Auto-Capture Hook
|
|
177
|
+
print('\n[B1] Auto-Capture Hook...')
|
|
178
|
+
passed = 0
|
|
179
|
+
if os.path.exists('hooks/auto_capture.py'):
|
|
180
|
+
passed += 1
|
|
181
|
+
results.append(('B1. Auto-Capture Hook', passed, 1))
|
|
182
|
+
print(f' {passed}/1 file verified')
|
|
183
|
+
|
|
184
|
+
# [B2] Session Start/End Hooks
|
|
185
|
+
print('\n[B2] Session Start/End Hooks...')
|
|
186
|
+
passed = 0
|
|
187
|
+
if os.path.exists('hooks/session_start.py'):
|
|
188
|
+
passed += 1
|
|
189
|
+
if os.path.exists('hooks/session_end.py'):
|
|
190
|
+
passed += 1
|
|
191
|
+
results.append(('B2. Session Hooks', passed, 2))
|
|
192
|
+
print(f' {passed}/2 files verified')
|
|
193
|
+
|
|
194
|
+
# [B3] Auto-Injector
|
|
195
|
+
print('\n[B3] Auto-Injector Service...')
|
|
196
|
+
passed = 0
|
|
197
|
+
try:
|
|
198
|
+
from services.auto_inject import AutoInjector, get_auto_injector
|
|
199
|
+
passed += 2
|
|
200
|
+
except Exception as e:
|
|
201
|
+
print(f' ERROR: {e}')
|
|
202
|
+
results.append(('B3. Auto-Injector', passed, 2))
|
|
203
|
+
print(f' {passed}/2 imports verified')
|
|
204
|
+
|
|
205
|
+
# [B4] Natural Language Interface
|
|
206
|
+
print('\n[B4] Natural Language Interface...')
|
|
207
|
+
passed = 0
|
|
208
|
+
try:
|
|
209
|
+
from skills.natural_language import parse_intent, process_natural_command
|
|
210
|
+
# Quick test
|
|
211
|
+
intent, _ = parse_intent('remember this: test')
|
|
212
|
+
if intent == 'store':
|
|
213
|
+
passed += 1
|
|
214
|
+
intent, _ = parse_intent('show me past errors')
|
|
215
|
+
if intent == 'list_errors':
|
|
216
|
+
passed += 1
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print(f' ERROR: {e}')
|
|
219
|
+
results.append(('B4. Natural Language', passed, 2))
|
|
220
|
+
print(f' {passed}/2 patterns verified')
|
|
221
|
+
|
|
222
|
+
# [B5] CLAUDE.md Sync
|
|
223
|
+
print('\n[B5] CLAUDE.md Sync...')
|
|
224
|
+
passed = 0
|
|
225
|
+
try:
|
|
226
|
+
from services.claude_md_sync import ClaudeMdSync, get_claude_md_sync
|
|
227
|
+
passed += 2
|
|
228
|
+
except Exception as e:
|
|
229
|
+
print(f' ERROR: {e}')
|
|
230
|
+
results.append(('B5. CLAUDE.md Sync', passed, 2))
|
|
231
|
+
print(f' {passed}/2 imports verified')
|
|
232
|
+
|
|
233
|
+
# [B6] Confidence Scoring
|
|
234
|
+
print('\n[B6] Confidence Scoring...')
|
|
235
|
+
passed = 0
|
|
236
|
+
try:
|
|
237
|
+
from services.confidence import ConfidenceService, get_confidence_service
|
|
238
|
+
passed += 2
|
|
239
|
+
except Exception as e:
|
|
240
|
+
print(f' ERROR: {e}')
|
|
241
|
+
results.append(('B6. Confidence Scoring', passed, 2))
|
|
242
|
+
print(f' {passed}/2 imports verified')
|
|
243
|
+
|
|
244
|
+
# ===== MAIN.PY INTEGRATION =====
|
|
245
|
+
print('\n' + '-' * 70)
|
|
246
|
+
print('SECTION C: MAIN.PY INTEGRATION')
|
|
247
|
+
print('-' * 70)
|
|
248
|
+
|
|
249
|
+
print('\n[C1] API Endpoints...')
|
|
250
|
+
passed = 0
|
|
251
|
+
with open('main.py', 'r') as f:
|
|
252
|
+
content = f.read()
|
|
253
|
+
|
|
254
|
+
endpoints = [
|
|
255
|
+
# Original endpoints
|
|
256
|
+
'/health', '/dashboard', '/api/stats',
|
|
257
|
+
# New automation endpoints
|
|
258
|
+
'/api/inject', '/api/memory/natural',
|
|
259
|
+
'/api/memory/{memory_id}/confidence',
|
|
260
|
+
'/api/memory/{memory_id}/verify',
|
|
261
|
+
'/api/claude-md/sync',
|
|
262
|
+
'/ws',
|
|
263
|
+
]
|
|
264
|
+
for ep in endpoints:
|
|
265
|
+
if ep in content:
|
|
266
|
+
passed += 1
|
|
267
|
+
else:
|
|
268
|
+
print(f' MISSING: {ep}')
|
|
269
|
+
|
|
270
|
+
results.append(('C1. API Endpoints', passed, len(endpoints)))
|
|
271
|
+
print(f' {passed}/{len(endpoints)} endpoints verified')
|
|
272
|
+
|
|
273
|
+
# ===== SUMMARY =====
|
|
274
|
+
print('\n' + '=' * 70)
|
|
275
|
+
print('FINAL SUMMARY')
|
|
276
|
+
print('=' * 70)
|
|
277
|
+
|
|
278
|
+
total_passed = sum(r[1] for r in results)
|
|
279
|
+
total_tests = sum(r[2] for r in results)
|
|
280
|
+
|
|
281
|
+
section_a = [(n, p, t) for n, p, t in results if n.startswith('A')]
|
|
282
|
+
section_b = [(n, p, t) for n, p, t in results if n.startswith('B')]
|
|
283
|
+
section_c = [(n, p, t) for n, p, t in results if n.startswith('C')]
|
|
284
|
+
|
|
285
|
+
print('\nSection A (Original 12 Features):')
|
|
286
|
+
a_passed = sum(r[1] for r in section_a)
|
|
287
|
+
a_total = sum(r[2] for r in section_a)
|
|
288
|
+
for name, passed, total in section_a:
|
|
289
|
+
status = 'PASS' if passed == total else 'PARTIAL' if passed > 0 else 'FAIL'
|
|
290
|
+
print(f' [{status}] {name}: {passed}/{total}')
|
|
291
|
+
print(f' Subtotal: {a_passed}/{a_total}')
|
|
292
|
+
|
|
293
|
+
print('\nSection B (6 Automation Features):')
|
|
294
|
+
b_passed = sum(r[1] for r in section_b)
|
|
295
|
+
b_total = sum(r[2] for r in section_b)
|
|
296
|
+
for name, passed, total in section_b:
|
|
297
|
+
status = 'PASS' if passed == total else 'PARTIAL' if passed > 0 else 'FAIL'
|
|
298
|
+
print(f' [{status}] {name}: {passed}/{total}')
|
|
299
|
+
print(f' Subtotal: {b_passed}/{b_total}')
|
|
300
|
+
|
|
301
|
+
print('\nSection C (Integration):')
|
|
302
|
+
c_passed = sum(r[1] for r in section_c)
|
|
303
|
+
c_total = sum(r[2] for r in section_c)
|
|
304
|
+
for name, passed, total in section_c:
|
|
305
|
+
status = 'PASS' if passed == total else 'PARTIAL' if passed > 0 else 'FAIL'
|
|
306
|
+
print(f' [{status}] {name}: {passed}/{total}')
|
|
307
|
+
print(f' Subtotal: {c_passed}/{c_total}')
|
|
308
|
+
|
|
309
|
+
pct = 100 * total_passed // total_tests if total_tests > 0 else 0
|
|
310
|
+
print(f'\n{"=" * 70}')
|
|
311
|
+
print(f'TOTAL: {total_passed}/{total_tests} ({pct}%)')
|
|
312
|
+
print(f'{"=" * 70}')
|
|
313
|
+
|
|
314
|
+
if pct == 100:
|
|
315
|
+
print('\n*** ALL TESTS PASSED! MEMORY SYSTEM FULLY OPERATIONAL ***')
|
|
316
|
+
elif pct >= 90:
|
|
317
|
+
print('\n*** MEMORY SYSTEM READY FOR USE ***')
|
|
318
|
+
|
|
319
|
+
return pct
|
|
320
|
+
|
|
321
|
+
if __name__ == '__main__':
|
|
322
|
+
pct = asyncio.run(test_all())
|