superlocalmemory 2.8.6 → 3.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.
Files changed (431) hide show
  1. package/LICENSE +9 -1
  2. package/NOTICE +63 -0
  3. package/README.md +165 -480
  4. package/bin/slm +17 -449
  5. package/bin/slm-npm +1 -1
  6. package/conftest.py +5 -0
  7. package/docs/api-reference.md +284 -0
  8. package/docs/architecture.md +149 -0
  9. package/docs/auto-memory.md +150 -0
  10. package/docs/cli-reference.md +276 -0
  11. package/docs/compliance.md +191 -0
  12. package/docs/configuration.md +182 -0
  13. package/docs/getting-started.md +102 -0
  14. package/docs/ide-setup.md +261 -0
  15. package/docs/mcp-tools.md +220 -0
  16. package/docs/migration-from-v2.md +170 -0
  17. package/docs/profiles.md +173 -0
  18. package/docs/troubleshooting.md +310 -0
  19. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  20. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  21. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  22. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  23. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  24. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  25. package/ide/configs/cursor-mcp.json +15 -0
  26. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  27. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  28. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  29. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  30. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  31. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  32. package/{configs → ide/configs}/zed-mcp.json +2 -2
  33. package/{hooks → ide/hooks}/context-hook.js +9 -20
  34. package/ide/hooks/memory-list-skill.js +70 -0
  35. package/ide/hooks/memory-profile-skill.js +101 -0
  36. package/ide/hooks/memory-recall-skill.js +62 -0
  37. package/ide/hooks/memory-remember-skill.js +68 -0
  38. package/ide/hooks/memory-reset-skill.js +160 -0
  39. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  40. package/ide/integrations/langchain/README.md +106 -0
  41. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  42. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  43. package/ide/integrations/langchain/pyproject.toml +38 -0
  44. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  45. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  46. package/ide/integrations/langchain/tests/test_security.py +117 -0
  47. package/ide/integrations/llamaindex/README.md +81 -0
  48. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  49. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  50. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  51. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  52. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  53. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  54. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  55. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  56. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  57. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  58. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  59. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  60. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  61. package/package.json +13 -22
  62. package/pyproject.toml +85 -0
  63. package/scripts/build-dmg.sh +417 -0
  64. package/scripts/install-skills.ps1 +334 -0
  65. package/scripts/postinstall.js +2 -2
  66. package/scripts/start-dashboard.ps1 +52 -0
  67. package/scripts/start-dashboard.sh +41 -0
  68. package/scripts/sync-wiki.ps1 +127 -0
  69. package/scripts/sync-wiki.sh +82 -0
  70. package/scripts/test-dmg.sh +161 -0
  71. package/scripts/test-npm-package.ps1 +252 -0
  72. package/scripts/test-npm-package.sh +207 -0
  73. package/scripts/verify-install.ps1 +294 -0
  74. package/scripts/verify-install.sh +266 -0
  75. package/src/superlocalmemory/__init__.py +0 -0
  76. package/src/superlocalmemory/attribution/__init__.py +9 -0
  77. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  78. package/src/superlocalmemory/attribution/signer.py +153 -0
  79. package/src/superlocalmemory/attribution/watermark.py +189 -0
  80. package/src/superlocalmemory/cli/__init__.py +5 -0
  81. package/src/superlocalmemory/cli/commands.py +245 -0
  82. package/src/superlocalmemory/cli/main.py +89 -0
  83. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  84. package/src/superlocalmemory/cli/post_install.py +99 -0
  85. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  86. package/src/superlocalmemory/compliance/__init__.py +0 -0
  87. package/src/superlocalmemory/compliance/abac.py +204 -0
  88. package/src/superlocalmemory/compliance/audit.py +314 -0
  89. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  90. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  91. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  92. package/src/superlocalmemory/compliance/retention.py +232 -0
  93. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  94. package/src/superlocalmemory/core/__init__.py +0 -0
  95. package/src/superlocalmemory/core/config.py +391 -0
  96. package/src/superlocalmemory/core/embeddings.py +293 -0
  97. package/src/superlocalmemory/core/engine.py +701 -0
  98. package/src/superlocalmemory/core/hooks.py +65 -0
  99. package/src/superlocalmemory/core/maintenance.py +172 -0
  100. package/src/superlocalmemory/core/modes.py +140 -0
  101. package/src/superlocalmemory/core/profiles.py +234 -0
  102. package/src/superlocalmemory/core/registry.py +117 -0
  103. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  104. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  105. package/src/superlocalmemory/encoding/__init__.py +0 -0
  106. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  107. package/src/superlocalmemory/encoding/emotional.py +125 -0
  108. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  109. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  110. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  111. package/src/superlocalmemory/encoding/foresight.py +91 -0
  112. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  113. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  114. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  115. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  116. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  117. package/src/superlocalmemory/encoding/type_router.py +235 -0
  118. package/src/superlocalmemory/hooks/__init__.py +3 -0
  119. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  120. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  121. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  122. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  123. package/src/superlocalmemory/infra/__init__.py +3 -0
  124. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  125. package/src/superlocalmemory/infra/backup.py +317 -0
  126. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  127. package/src/superlocalmemory/infra/event_bus.py +381 -0
  128. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  129. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  130. package/src/superlocalmemory/learning/__init__.py +0 -0
  131. package/src/superlocalmemory/learning/adaptive.py +172 -0
  132. package/src/superlocalmemory/learning/behavioral.py +490 -0
  133. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  134. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  135. package/src/superlocalmemory/learning/cross_project.py +399 -0
  136. package/src/superlocalmemory/learning/database.py +376 -0
  137. package/src/superlocalmemory/learning/engagement.py +323 -0
  138. package/src/superlocalmemory/learning/features.py +138 -0
  139. package/src/superlocalmemory/learning/feedback.py +316 -0
  140. package/src/superlocalmemory/learning/outcomes.py +255 -0
  141. package/src/superlocalmemory/learning/project_context.py +366 -0
  142. package/src/superlocalmemory/learning/ranker.py +155 -0
  143. package/src/superlocalmemory/learning/source_quality.py +303 -0
  144. package/src/superlocalmemory/learning/workflows.py +309 -0
  145. package/src/superlocalmemory/llm/__init__.py +0 -0
  146. package/src/superlocalmemory/llm/backbone.py +316 -0
  147. package/src/superlocalmemory/math/__init__.py +0 -0
  148. package/src/superlocalmemory/math/fisher.py +356 -0
  149. package/src/superlocalmemory/math/langevin.py +398 -0
  150. package/src/superlocalmemory/math/sheaf.py +257 -0
  151. package/src/superlocalmemory/mcp/__init__.py +0 -0
  152. package/src/superlocalmemory/mcp/resources.py +245 -0
  153. package/src/superlocalmemory/mcp/server.py +61 -0
  154. package/src/superlocalmemory/mcp/tools.py +18 -0
  155. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  156. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  157. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  158. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  159. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  160. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  161. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  162. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  163. package/src/superlocalmemory/retrieval/engine.py +390 -0
  164. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  165. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  166. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  167. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  168. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  169. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  170. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  171. package/src/superlocalmemory/server/__init__.py +1 -0
  172. package/src/superlocalmemory/server/api.py +248 -0
  173. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  174. package/src/superlocalmemory/server/routes/agents.py +107 -0
  175. package/src/superlocalmemory/server/routes/backup.py +91 -0
  176. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  177. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  178. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  179. package/src/superlocalmemory/server/routes/events.py +183 -0
  180. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  181. package/src/superlocalmemory/server/routes/learning.py +273 -0
  182. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  183. package/src/superlocalmemory/server/routes/memories.py +399 -0
  184. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  185. package/src/superlocalmemory/server/routes/stats.py +346 -0
  186. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  187. package/src/superlocalmemory/server/routes/ws.py +82 -0
  188. package/src/superlocalmemory/server/security_middleware.py +57 -0
  189. package/src/superlocalmemory/server/ui.py +245 -0
  190. package/src/superlocalmemory/storage/__init__.py +0 -0
  191. package/src/superlocalmemory/storage/access_control.py +182 -0
  192. package/src/superlocalmemory/storage/database.py +594 -0
  193. package/src/superlocalmemory/storage/migrations.py +303 -0
  194. package/src/superlocalmemory/storage/models.py +406 -0
  195. package/src/superlocalmemory/storage/schema.py +726 -0
  196. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  197. package/src/superlocalmemory/trust/__init__.py +0 -0
  198. package/src/superlocalmemory/trust/gate.py +130 -0
  199. package/src/superlocalmemory/trust/provenance.py +124 -0
  200. package/src/superlocalmemory/trust/scorer.py +347 -0
  201. package/src/superlocalmemory/trust/signals.py +153 -0
  202. package/ui/index.html +278 -5
  203. package/ui/js/auto-settings.js +70 -0
  204. package/ui/js/dashboard.js +90 -0
  205. package/ui/js/fact-detail.js +92 -0
  206. package/ui/js/feedback.js +2 -2
  207. package/ui/js/ide-status.js +102 -0
  208. package/ui/js/math-health.js +98 -0
  209. package/ui/js/recall-lab.js +127 -0
  210. package/ui/js/settings.js +2 -2
  211. package/ui/js/trust-dashboard.js +73 -0
  212. package/api_server.py +0 -724
  213. package/bin/aider-smart +0 -72
  214. package/bin/superlocalmemoryv2-learning +0 -4
  215. package/bin/superlocalmemoryv2-list +0 -3
  216. package/bin/superlocalmemoryv2-patterns +0 -4
  217. package/bin/superlocalmemoryv2-profile +0 -3
  218. package/bin/superlocalmemoryv2-recall +0 -3
  219. package/bin/superlocalmemoryv2-remember +0 -3
  220. package/bin/superlocalmemoryv2-reset +0 -3
  221. package/bin/superlocalmemoryv2-status +0 -3
  222. package/configs/chatgpt-desktop-mcp.json +0 -16
  223. package/configs/cursor-mcp.json +0 -15
  224. package/hooks/memory-list-skill.js +0 -139
  225. package/hooks/memory-profile-skill.js +0 -273
  226. package/hooks/memory-recall-skill.js +0 -114
  227. package/hooks/memory-remember-skill.js +0 -127
  228. package/hooks/memory-reset-skill.js +0 -274
  229. package/mcp_server.py +0 -1808
  230. package/requirements-core.txt +0 -22
  231. package/requirements-learning.txt +0 -12
  232. package/requirements.txt +0 -12
  233. package/src/agent_registry.py +0 -411
  234. package/src/auth_middleware.py +0 -61
  235. package/src/auto_backup.py +0 -459
  236. package/src/behavioral/__init__.py +0 -49
  237. package/src/behavioral/behavioral_listener.py +0 -203
  238. package/src/behavioral/behavioral_patterns.py +0 -275
  239. package/src/behavioral/cross_project_transfer.py +0 -206
  240. package/src/behavioral/outcome_inference.py +0 -194
  241. package/src/behavioral/outcome_tracker.py +0 -193
  242. package/src/behavioral/tests/__init__.py +0 -4
  243. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  244. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  245. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  246. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  247. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  248. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  249. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  250. package/src/cache_manager.py +0 -518
  251. package/src/compliance/__init__.py +0 -48
  252. package/src/compliance/abac_engine.py +0 -149
  253. package/src/compliance/abac_middleware.py +0 -116
  254. package/src/compliance/audit_db.py +0 -215
  255. package/src/compliance/audit_logger.py +0 -148
  256. package/src/compliance/retention_manager.py +0 -289
  257. package/src/compliance/retention_scheduler.py +0 -186
  258. package/src/compliance/tests/__init__.py +0 -4
  259. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  260. package/src/compliance/tests/test_abac_engine.py +0 -124
  261. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  262. package/src/compliance/tests/test_audit_db.py +0 -123
  263. package/src/compliance/tests/test_audit_logger.py +0 -98
  264. package/src/compliance/tests/test_mcp_audit.py +0 -128
  265. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  266. package/src/compliance/tests/test_retention_manager.py +0 -131
  267. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  268. package/src/compression/__init__.py +0 -25
  269. package/src/compression/cli.py +0 -150
  270. package/src/compression/cold_storage.py +0 -217
  271. package/src/compression/config.py +0 -72
  272. package/src/compression/orchestrator.py +0 -133
  273. package/src/compression/tier2_compressor.py +0 -228
  274. package/src/compression/tier3_compressor.py +0 -153
  275. package/src/compression/tier_classifier.py +0 -148
  276. package/src/db_connection_manager.py +0 -536
  277. package/src/embedding_engine.py +0 -63
  278. package/src/embeddings/__init__.py +0 -47
  279. package/src/embeddings/cache.py +0 -70
  280. package/src/embeddings/cli.py +0 -113
  281. package/src/embeddings/constants.py +0 -47
  282. package/src/embeddings/database.py +0 -91
  283. package/src/embeddings/engine.py +0 -247
  284. package/src/embeddings/model_loader.py +0 -145
  285. package/src/event_bus.py +0 -562
  286. package/src/graph/__init__.py +0 -36
  287. package/src/graph/build_helpers.py +0 -74
  288. package/src/graph/cli.py +0 -87
  289. package/src/graph/cluster_builder.py +0 -188
  290. package/src/graph/cluster_summary.py +0 -148
  291. package/src/graph/constants.py +0 -47
  292. package/src/graph/edge_builder.py +0 -162
  293. package/src/graph/entity_extractor.py +0 -95
  294. package/src/graph/graph_core.py +0 -226
  295. package/src/graph/graph_search.py +0 -231
  296. package/src/graph/hierarchical.py +0 -207
  297. package/src/graph/schema.py +0 -99
  298. package/src/graph_engine.py +0 -52
  299. package/src/hnsw_index.py +0 -628
  300. package/src/hybrid_search.py +0 -46
  301. package/src/learning/__init__.py +0 -217
  302. package/src/learning/adaptive_ranker.py +0 -682
  303. package/src/learning/bootstrap/__init__.py +0 -69
  304. package/src/learning/bootstrap/constants.py +0 -93
  305. package/src/learning/bootstrap/db_queries.py +0 -316
  306. package/src/learning/bootstrap/sampling.py +0 -82
  307. package/src/learning/bootstrap/text_utils.py +0 -71
  308. package/src/learning/cross_project_aggregator.py +0 -857
  309. package/src/learning/db/__init__.py +0 -40
  310. package/src/learning/db/constants.py +0 -44
  311. package/src/learning/db/schema.py +0 -279
  312. package/src/learning/engagement_tracker.py +0 -628
  313. package/src/learning/feature_extractor.py +0 -708
  314. package/src/learning/feedback_collector.py +0 -806
  315. package/src/learning/learning_db.py +0 -915
  316. package/src/learning/project_context_manager.py +0 -572
  317. package/src/learning/ranking/__init__.py +0 -33
  318. package/src/learning/ranking/constants.py +0 -84
  319. package/src/learning/ranking/helpers.py +0 -278
  320. package/src/learning/source_quality_scorer.py +0 -676
  321. package/src/learning/synthetic_bootstrap.py +0 -755
  322. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  323. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  324. package/src/learning/tests/test_aggregator.py +0 -306
  325. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  326. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  327. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  328. package/src/learning/tests/test_feedback_collector.py +0 -294
  329. package/src/learning/tests/test_learning_db.py +0 -602
  330. package/src/learning/tests/test_learning_db_v28.py +0 -110
  331. package/src/learning/tests/test_learning_init_v28.py +0 -48
  332. package/src/learning/tests/test_outcome_signals.py +0 -48
  333. package/src/learning/tests/test_project_context.py +0 -292
  334. package/src/learning/tests/test_schema_migration.py +0 -319
  335. package/src/learning/tests/test_signal_inference.py +0 -397
  336. package/src/learning/tests/test_source_quality.py +0 -351
  337. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  338. package/src/learning/tests/test_workflow_miner.py +0 -318
  339. package/src/learning/workflow_pattern_miner.py +0 -655
  340. package/src/lifecycle/__init__.py +0 -54
  341. package/src/lifecycle/bounded_growth.py +0 -239
  342. package/src/lifecycle/compaction_engine.py +0 -226
  343. package/src/lifecycle/lifecycle_engine.py +0 -355
  344. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  345. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  346. package/src/lifecycle/retention_policy.py +0 -285
  347. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  348. package/src/lifecycle/tests/test_compaction.py +0 -179
  349. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  350. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  351. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  352. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  353. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  354. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  355. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  356. package/src/mcp_tools_v28.py +0 -281
  357. package/src/memory/__init__.py +0 -36
  358. package/src/memory/cli.py +0 -205
  359. package/src/memory/constants.py +0 -39
  360. package/src/memory/helpers.py +0 -28
  361. package/src/memory/schema.py +0 -166
  362. package/src/memory-profiles.py +0 -595
  363. package/src/memory-reset.py +0 -491
  364. package/src/memory_compression.py +0 -989
  365. package/src/memory_store_v2.py +0 -1155
  366. package/src/migrate_v1_to_v2.py +0 -629
  367. package/src/pattern_learner.py +0 -34
  368. package/src/patterns/__init__.py +0 -24
  369. package/src/patterns/analyzers.py +0 -251
  370. package/src/patterns/learner.py +0 -271
  371. package/src/patterns/scoring.py +0 -171
  372. package/src/patterns/store.py +0 -225
  373. package/src/patterns/terminology.py +0 -140
  374. package/src/provenance_tracker.py +0 -312
  375. package/src/qualixar_attribution.py +0 -139
  376. package/src/qualixar_watermark.py +0 -78
  377. package/src/query_optimizer.py +0 -511
  378. package/src/rate_limiter.py +0 -83
  379. package/src/search/__init__.py +0 -20
  380. package/src/search/cli.py +0 -77
  381. package/src/search/constants.py +0 -26
  382. package/src/search/engine.py +0 -241
  383. package/src/search/fusion.py +0 -122
  384. package/src/search/index_loader.py +0 -114
  385. package/src/search/methods.py +0 -162
  386. package/src/search_engine_v2.py +0 -401
  387. package/src/setup_validator.py +0 -482
  388. package/src/subscription_manager.py +0 -391
  389. package/src/tree/__init__.py +0 -59
  390. package/src/tree/builder.py +0 -185
  391. package/src/tree/nodes.py +0 -202
  392. package/src/tree/queries.py +0 -257
  393. package/src/tree/schema.py +0 -80
  394. package/src/tree_manager.py +0 -19
  395. package/src/trust/__init__.py +0 -45
  396. package/src/trust/constants.py +0 -66
  397. package/src/trust/queries.py +0 -157
  398. package/src/trust/schema.py +0 -95
  399. package/src/trust/scorer.py +0 -299
  400. package/src/trust/signals.py +0 -95
  401. package/src/trust_scorer.py +0 -44
  402. package/ui/app.js +0 -1588
  403. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  404. package/ui/js/graph-cytoscape.js +0 -1168
  405. package/ui/js/graph-d3-backup.js +0 -32
  406. package/ui/js/graph.js +0 -32
  407. package/ui_server.py +0 -286
  408. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  409. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  410. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  411. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  412. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  413. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  414. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  415. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  416. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  417. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  418. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  419. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  420. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  421. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  422. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  423. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  424. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  425. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  426. /package/{completions → ide/completions}/slm.bash +0 -0
  427. /package/{completions → ide/completions}/slm.zsh +0 -0
  428. /package/{configs → ide/configs}/cody-commands.json +0 -0
  429. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
  430. /package/{install.ps1 → scripts/install.ps1} +0 -0
  431. /package/{install.sh → scripts/install.sh} +0 -0
@@ -1,225 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- Pattern Store - SQLite-backed pattern storage and retrieval.
6
-
7
- Handles identity_patterns and pattern_examples tables,
8
- including schema migration, CRUD operations, and profile-scoped queries.
9
- """
10
-
11
- import sqlite3
12
- import json
13
- import logging
14
- from typing import Dict, List, Optional, Any
15
- from pathlib import Path
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- class PatternStore:
21
- """Handles pattern storage and retrieval."""
22
-
23
- def __init__(self, db_path: Path):
24
- self.db_path = db_path
25
- self._init_tables()
26
-
27
- def _init_tables(self):
28
- """Initialize pattern tables if they don't exist, or recreate if schema is incomplete."""
29
- conn = sqlite3.connect(self.db_path)
30
- cursor = conn.cursor()
31
-
32
- # Check if existing tables have correct schema
33
- for table_name, required_cols in [
34
- ('identity_patterns', {'pattern_type', 'key', 'value', 'confidence'}),
35
- ('pattern_examples', {'pattern_id', 'memory_id'}),
36
- ]:
37
- cursor.execute(f"PRAGMA table_info({table_name})")
38
- existing_cols = {row[1] for row in cursor.fetchall()}
39
- if existing_cols and not required_cols.issubset(existing_cols):
40
- logger.warning(f"Dropping incomplete {table_name} table (missing: {required_cols - existing_cols})")
41
- cursor.execute(f'DROP TABLE IF EXISTS {table_name}')
42
-
43
- # Identity patterns table
44
- cursor.execute('''
45
- CREATE TABLE IF NOT EXISTS identity_patterns (
46
- id INTEGER PRIMARY KEY AUTOINCREMENT,
47
- pattern_type TEXT NOT NULL,
48
- key TEXT NOT NULL,
49
- value TEXT NOT NULL,
50
- confidence REAL DEFAULT 0.5,
51
- evidence_count INTEGER DEFAULT 1,
52
- memory_ids TEXT,
53
- category TEXT,
54
- profile TEXT DEFAULT 'default',
55
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
56
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
57
- UNIQUE(pattern_type, key, category, profile)
58
- )
59
- ''')
60
-
61
- # Add profile column if upgrading from older schema
62
- try:
63
- cursor.execute('ALTER TABLE identity_patterns ADD COLUMN profile TEXT DEFAULT "default"')
64
- except sqlite3.OperationalError:
65
- pass # Column already exists
66
-
67
- # Pattern examples table
68
- cursor.execute('''
69
- CREATE TABLE IF NOT EXISTS pattern_examples (
70
- id INTEGER PRIMARY KEY AUTOINCREMENT,
71
- pattern_id INTEGER NOT NULL,
72
- memory_id INTEGER NOT NULL,
73
- example_text TEXT,
74
- FOREIGN KEY (pattern_id) REFERENCES identity_patterns(id) ON DELETE CASCADE,
75
- FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
76
- )
77
- ''')
78
-
79
- # Indexes
80
- cursor.execute('CREATE INDEX IF NOT EXISTS idx_pattern_type ON identity_patterns(pattern_type)')
81
- cursor.execute('CREATE INDEX IF NOT EXISTS idx_pattern_confidence ON identity_patterns(confidence)')
82
- cursor.execute('CREATE INDEX IF NOT EXISTS idx_pattern_profile ON identity_patterns(profile)')
83
-
84
- conn.commit()
85
- conn.close()
86
-
87
- def save_pattern(self, pattern: Dict[str, Any]) -> int:
88
- """Save or update a pattern (scoped by profile)."""
89
- conn = sqlite3.connect(self.db_path)
90
- cursor = conn.cursor()
91
- profile = pattern.get('profile', 'default')
92
-
93
- try:
94
- # Check if pattern exists for this profile
95
- cursor.execute('''
96
- SELECT id FROM identity_patterns
97
- WHERE pattern_type = ? AND key = ? AND category = ? AND profile = ?
98
- ''', (pattern['pattern_type'], pattern['key'], pattern['category'], profile))
99
-
100
- existing = cursor.fetchone()
101
-
102
- memory_ids_json = json.dumps(pattern['memory_ids'])
103
-
104
- if existing:
105
- # Update existing pattern
106
- pattern_id = existing[0]
107
- cursor.execute('''
108
- UPDATE identity_patterns
109
- SET value = ?, confidence = ?, evidence_count = ?,
110
- memory_ids = ?, updated_at = CURRENT_TIMESTAMP
111
- WHERE id = ?
112
- ''', (
113
- pattern['value'],
114
- pattern['confidence'],
115
- pattern['evidence_count'],
116
- memory_ids_json,
117
- pattern_id
118
- ))
119
- else:
120
- # Insert new pattern
121
- cursor.execute('''
122
- INSERT INTO identity_patterns
123
- (pattern_type, key, value, confidence, evidence_count, memory_ids, category, profile)
124
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
125
- ''', (
126
- pattern['pattern_type'],
127
- pattern['key'],
128
- pattern['value'],
129
- pattern['confidence'],
130
- pattern['evidence_count'],
131
- memory_ids_json,
132
- pattern['category'],
133
- profile
134
- ))
135
- pattern_id = cursor.lastrowid
136
-
137
- # Save examples
138
- self._save_pattern_examples(cursor, pattern_id, pattern['memory_ids'], pattern['key'])
139
-
140
- conn.commit()
141
- return pattern_id
142
-
143
- finally:
144
- conn.close()
145
-
146
- def _save_pattern_examples(self, cursor, pattern_id: int, memory_ids: List[int], key: str):
147
- """Save representative examples for pattern."""
148
- # Clear old examples
149
- cursor.execute('DELETE FROM pattern_examples WHERE pattern_id = ?', (pattern_id,))
150
-
151
- # Save top 3 examples
152
- for memory_id in memory_ids[:3]:
153
- cursor.execute('SELECT content FROM memories WHERE id = ?', (memory_id,))
154
- row = cursor.fetchone()
155
-
156
- if row:
157
- content = row[0]
158
- excerpt = self._extract_relevant_excerpt(content, key)
159
-
160
- cursor.execute('''
161
- INSERT INTO pattern_examples (pattern_id, memory_id, example_text)
162
- VALUES (?, ?, ?)
163
- ''', (pattern_id, memory_id, excerpt))
164
-
165
- def _extract_relevant_excerpt(self, content: str, key: str) -> str:
166
- """Extract 150-char excerpt showing pattern."""
167
- # Find first mention of key term
168
- key_lower = key.lower().replace('_', ' ')
169
- idx = content.lower().find(key_lower)
170
-
171
- if idx >= 0:
172
- start = max(0, idx - 50)
173
- end = min(len(content), idx + 100)
174
- excerpt = content[start:end]
175
- return excerpt if len(excerpt) <= 150 else excerpt[:150] + '...'
176
-
177
- # Fallback: first 150 chars
178
- return content[:150] + ('...' if len(content) > 150 else '')
179
-
180
- def get_patterns(self, min_confidence: float = 0.7, pattern_type: Optional[str] = None,
181
- profile: Optional[str] = None) -> List[Dict[str, Any]]:
182
- """Get patterns above confidence threshold, optionally filtered by profile."""
183
- conn = sqlite3.connect(self.db_path)
184
- try:
185
- cursor = conn.cursor()
186
-
187
- # Build query with optional filters
188
- conditions = ['confidence >= ?']
189
- params = [min_confidence]
190
-
191
- if pattern_type:
192
- conditions.append('pattern_type = ?')
193
- params.append(pattern_type)
194
-
195
- if profile:
196
- conditions.append('profile = ?')
197
- params.append(profile)
198
-
199
- where_clause = ' AND '.join(conditions)
200
- cursor.execute(f'''
201
- SELECT id, pattern_type, key, value, confidence, evidence_count,
202
- updated_at, created_at, category
203
- FROM identity_patterns
204
- WHERE {where_clause}
205
- ORDER BY confidence DESC, evidence_count DESC
206
- ''', params)
207
-
208
- patterns = []
209
- for row in cursor.fetchall():
210
- patterns.append({
211
- 'id': row[0],
212
- 'pattern_type': row[1],
213
- 'key': row[2],
214
- 'value': row[3],
215
- 'confidence': row[4],
216
- 'evidence_count': row[5],
217
- 'frequency': row[5],
218
- 'last_seen': row[6],
219
- 'created_at': row[7],
220
- 'category': row[8]
221
- })
222
-
223
- finally:
224
- conn.close()
225
- return patterns
@@ -1,140 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- Terminology Learner - User-specific term definition extraction.
6
-
7
- Learns how the user defines ambiguous terms like 'optimize', 'refactor', etc.
8
- by analyzing contextual co-occurrence patterns across memories.
9
- """
10
-
11
- import sqlite3
12
- import re
13
- import logging
14
- from typing import Dict, List, Optional, Any
15
- from collections import Counter
16
- from pathlib import Path
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
-
21
- class TerminologyLearner:
22
- """Learns user-specific definitions of common terms."""
23
-
24
- def __init__(self, db_path: Path):
25
- self.db_path = db_path
26
-
27
- # Common ambiguous terms to learn
28
- self.ambiguous_terms = [
29
- 'optimize', 'refactor', 'clean', 'simple',
30
- 'mvp', 'prototype', 'scale', 'production-ready',
31
- 'fix', 'improve', 'update', 'enhance'
32
- ]
33
-
34
- def learn_terminology(self, memory_ids: List[int]) -> Dict[str, Dict[str, Any]]:
35
- """Learn user-specific term definitions."""
36
- patterns = {}
37
-
38
- conn = sqlite3.connect(self.db_path)
39
- try:
40
- cursor = conn.cursor()
41
-
42
- for term in self.ambiguous_terms:
43
- contexts = []
44
-
45
- # Find all contexts where term appears
46
- for memory_id in memory_ids:
47
- cursor.execute('SELECT content FROM memories WHERE id = ?', (memory_id,))
48
- row = cursor.fetchone()
49
-
50
- if not row:
51
- continue
52
-
53
- content = row[0]
54
-
55
- # Find term in content (case-insensitive)
56
- pattern = r'\b' + re.escape(term) + r'\b'
57
- for match in re.finditer(pattern, content, re.IGNORECASE):
58
- term_idx = match.start()
59
-
60
- # Extract 100-char window around term
61
- start = max(0, term_idx - 100)
62
- end = min(len(content), term_idx + len(term) + 100)
63
- context_window = content[start:end]
64
-
65
- contexts.append({
66
- 'memory_id': memory_id,
67
- 'context': context_window
68
- })
69
-
70
- # Analyze contexts to extract meaning (need at least 3 examples)
71
- if len(contexts) >= 3:
72
- definition = self._extract_definition(term, contexts)
73
-
74
- if definition:
75
- evidence_list = list(set([ctx['memory_id'] for ctx in contexts]))
76
-
77
- # Confidence increases with more examples, capped at 0.95
78
- confidence = min(0.95, 0.6 + (len(contexts) * 0.05))
79
-
80
- patterns[term] = {
81
- 'pattern_type': 'terminology',
82
- 'key': term,
83
- 'value': definition,
84
- 'confidence': round(confidence, 2),
85
- 'evidence_count': len(evidence_list),
86
- 'memory_ids': evidence_list,
87
- 'category': 'general'
88
- }
89
-
90
- finally:
91
- conn.close()
92
- return patterns
93
-
94
- def _extract_definition(self, term: str, contexts: List[Dict]) -> Optional[str]:
95
- """Extract definition from contexts using pattern matching."""
96
- # Collect words near the term across all contexts
97
- nearby_words = []
98
-
99
- for ctx in contexts:
100
- words = re.findall(r'\b\w+\b', ctx['context'].lower())
101
- nearby_words.extend(words)
102
-
103
- # Count word frequencies
104
- word_counts = Counter(nearby_words)
105
-
106
- # Remove the term itself and common stopwords
107
- stopwords = {'the', 'a', 'an', 'is', 'to', 'for', 'of', 'in', 'on', 'at',
108
- 'and', 'or', 'but', 'with', 'from', 'by', 'this', 'that'}
109
- word_counts = Counter({w: c for w, c in word_counts.items()
110
- if w not in stopwords and w != term.lower()})
111
-
112
- # Get top co-occurring words
113
- top_words = [w for w, _ in word_counts.most_common(8)]
114
-
115
- # Apply heuristic rules based on term and context
116
- if term == 'optimize':
117
- if any(w in top_words for w in ['performance', 'speed', 'faster', 'latency']):
118
- return "Performance optimization (speed/latency)"
119
- elif any(w in top_words for w in ['code', 'clean', 'refactor']):
120
- return "Code quality optimization"
121
-
122
- elif term == 'refactor':
123
- if any(w in top_words for w in ['architecture', 'structure', 'design']):
124
- return "Architecture change, not just renaming"
125
- elif any(w in top_words for w in ['clean', 'organize', 'simplify']):
126
- return "Code organization improvement"
127
-
128
- elif term == 'mvp':
129
- if any(w in top_words for w in ['core', 'basic', 'essential', 'minimal']):
130
- return "Core features only, no polish"
131
-
132
- elif term == 'production-ready':
133
- if any(w in top_words for w in ['test', 'error', 'monitoring', 'deploy']):
134
- return "Fully tested and monitored for deployment"
135
-
136
- # Generic definition if specific pattern not matched
137
- if len(top_words) >= 3:
138
- return f"Commonly used with: {', '.join(top_words[:3])}"
139
-
140
- return None
@@ -1,312 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: MIT
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """
5
- ProvenanceTracker — Tracks the origin and lineage of every memory.
6
-
7
- Adds provenance columns to the memories table:
8
- created_by — Agent ID that created this memory (e.g., "mcp:claude-desktop")
9
- source_protocol — Protocol used (mcp, cli, rest, python)
10
- trust_score — Trust score at time of creation (default 1.0)
11
- provenance_chain — JSON array of derivation history
12
-
13
- This enables:
14
- - "Who wrote this?" queries for the dashboard
15
- - Trust-weighted recall (v2.6 — higher trust = higher ranking)
16
- - Audit trail for enterprise compliance (v3.0)
17
- - Memory lineage tracking (if agent B derives from agent A's memory)
18
-
19
- Column migration is safe: uses ALTER TABLE ADD COLUMN with try/except.
20
- Old databases without provenance columns work fine — values default.
21
- """
22
-
23
- import json
24
- import logging
25
- import sqlite3
26
- import threading
27
- from datetime import datetime
28
- from pathlib import Path
29
- from typing import Optional, Dict, Any
30
-
31
- logger = logging.getLogger("superlocalmemory.provenance")
32
-
33
-
34
- class ProvenanceTracker:
35
- """
36
- Tracks provenance (origin) metadata for memories.
37
-
38
- Singleton per database path. Thread-safe.
39
- """
40
-
41
- _instances: Dict[str, "ProvenanceTracker"] = {}
42
- _instances_lock = threading.Lock()
43
-
44
- @classmethod
45
- def get_instance(cls, db_path: Optional[Path] = None) -> "ProvenanceTracker":
46
- """Get or create the singleton ProvenanceTracker."""
47
- if db_path is None:
48
- db_path = Path.home() / ".claude-memory" / "memory.db"
49
- key = str(db_path)
50
- with cls._instances_lock:
51
- if key not in cls._instances:
52
- cls._instances[key] = cls(db_path)
53
- return cls._instances[key]
54
-
55
- @classmethod
56
- def reset_instance(cls, db_path: Optional[Path] = None) -> None:
57
- """Remove singleton. Used for testing."""
58
- with cls._instances_lock:
59
- if db_path is None:
60
- cls._instances.clear()
61
- else:
62
- key = str(db_path)
63
- if key in cls._instances:
64
- del cls._instances[key]
65
-
66
- def __init__(self, db_path: Path):
67
- self.db_path = Path(db_path)
68
- self._init_schema()
69
- logger.info("ProvenanceTracker initialized: db=%s", self.db_path)
70
-
71
- def _init_schema(self):
72
- """
73
- Add provenance columns to memories table (safe migration).
74
-
75
- Uses ALTER TABLE ADD COLUMN wrapped in try/except — safe for:
76
- - Fresh databases (columns don't exist yet)
77
- - Existing databases (columns might already exist)
78
- - Concurrent migrations (OperationalError caught)
79
- """
80
- provenance_columns = {
81
- 'created_by': "TEXT DEFAULT 'user'",
82
- 'source_protocol': "TEXT DEFAULT 'cli'",
83
- 'trust_score': "REAL DEFAULT 1.0",
84
- 'provenance_chain': "TEXT DEFAULT '[]'",
85
- }
86
-
87
- try:
88
- from db_connection_manager import DbConnectionManager
89
- mgr = DbConnectionManager.get_instance(self.db_path)
90
-
91
- def _migrate(conn):
92
- cursor = conn.cursor()
93
-
94
- # Check existing columns
95
- cursor.execute("PRAGMA table_info(memories)")
96
- existing = {row[1] for row in cursor.fetchall()}
97
-
98
- for col_name, col_type in provenance_columns.items():
99
- if col_name not in existing:
100
- try:
101
- cursor.execute(f"ALTER TABLE memories ADD COLUMN {col_name} {col_type}")
102
- except sqlite3.OperationalError:
103
- pass # Column already exists (concurrent migration)
104
-
105
- # Index for provenance queries
106
- try:
107
- cursor.execute("CREATE INDEX IF NOT EXISTS idx_created_by ON memories(created_by)")
108
- except sqlite3.OperationalError:
109
- pass
110
-
111
- try:
112
- cursor.execute("CREATE INDEX IF NOT EXISTS idx_source_protocol ON memories(source_protocol)")
113
- except sqlite3.OperationalError:
114
- pass
115
-
116
- conn.commit()
117
-
118
- mgr.execute_write(_migrate)
119
-
120
- except ImportError:
121
- conn = sqlite3.connect(str(self.db_path))
122
- cursor = conn.cursor()
123
-
124
- cursor.execute("PRAGMA table_info(memories)")
125
- existing = {row[1] for row in cursor.fetchall()}
126
-
127
- for col_name, col_type in provenance_columns.items():
128
- if col_name not in existing:
129
- try:
130
- cursor.execute(f"ALTER TABLE memories ADD COLUMN {col_name} {col_type}")
131
- except sqlite3.OperationalError:
132
- pass
133
-
134
- try:
135
- cursor.execute("CREATE INDEX IF NOT EXISTS idx_created_by ON memories(created_by)")
136
- except sqlite3.OperationalError:
137
- pass
138
- try:
139
- cursor.execute("CREATE INDEX IF NOT EXISTS idx_source_protocol ON memories(source_protocol)")
140
- except sqlite3.OperationalError:
141
- pass
142
-
143
- conn.commit()
144
- conn.close()
145
-
146
- # =========================================================================
147
- # Record Provenance
148
- # =========================================================================
149
-
150
- def record_provenance(
151
- self,
152
- memory_id: int,
153
- created_by: str = "user",
154
- source_protocol: str = "cli",
155
- trust_score: float = 1.0,
156
- derived_from: Optional[int] = None,
157
- ) -> None:
158
- """
159
- Record provenance metadata for a memory.
160
-
161
- Called after a memory is created. Updates the provenance columns
162
- on the memories table row.
163
-
164
- Args:
165
- memory_id: ID of the memory to annotate
166
- created_by: Agent ID that created this memory
167
- source_protocol: Protocol used (mcp, cli, rest, python)
168
- trust_score: Trust score at time of creation
169
- derived_from: If this memory was derived from another, its ID
170
- """
171
- trust_score = max(0.0, min(1.0, trust_score))
172
- chain = json.dumps([derived_from] if derived_from else [])
173
-
174
- try:
175
- from db_connection_manager import DbConnectionManager
176
- mgr = DbConnectionManager.get_instance(self.db_path)
177
-
178
- def _update(conn):
179
- conn.execute('''
180
- UPDATE memories
181
- SET created_by = ?, source_protocol = ?,
182
- trust_score = ?, provenance_chain = ?
183
- WHERE id = ?
184
- ''', (created_by, source_protocol, trust_score, chain, memory_id))
185
- conn.commit()
186
-
187
- mgr.execute_write(_update)
188
-
189
- except Exception as e:
190
- # Provenance failure must never break core operations
191
- logger.error("Failed to record provenance for memory %d: %s", memory_id, e)
192
-
193
- # =========================================================================
194
- # Query Provenance
195
- # =========================================================================
196
-
197
- def get_provenance(self, memory_id: int) -> Optional[dict]:
198
- """
199
- Get provenance metadata for a specific memory.
200
-
201
- Args:
202
- memory_id: Memory ID to query
203
-
204
- Returns:
205
- Dict with created_by, source_protocol, trust_score, provenance_chain
206
- or None if memory not found
207
- """
208
- try:
209
- from db_connection_manager import DbConnectionManager
210
- mgr = DbConnectionManager.get_instance(self.db_path)
211
-
212
- with mgr.read_connection() as conn:
213
- cursor = conn.cursor()
214
- cursor.execute("""
215
- SELECT id, created_by, source_protocol, trust_score, provenance_chain
216
- FROM memories WHERE id = ?
217
- """, (memory_id,))
218
- row = cursor.fetchone()
219
-
220
- if not row:
221
- return None
222
-
223
- chain = []
224
- try:
225
- chain = json.loads(row[4]) if row[4] else []
226
- except (json.JSONDecodeError, TypeError):
227
- pass
228
-
229
- return {
230
- "memory_id": row[0],
231
- "created_by": row[1] or "user",
232
- "source_protocol": row[2] or "cli",
233
- "trust_score": row[3] if row[3] is not None else 1.0,
234
- "provenance_chain": chain,
235
- }
236
-
237
- except Exception as e:
238
- logger.error("Failed to get provenance for memory %d: %s", memory_id, e)
239
- return None
240
-
241
- def get_memories_by_agent(self, agent_id: str, limit: int = 50) -> list:
242
- """
243
- Get all memories created by a specific agent.
244
-
245
- Args:
246
- agent_id: Agent ID to query
247
- limit: Max results
248
-
249
- Returns:
250
- List of (memory_id, created_at, trust_score) tuples
251
- """
252
- try:
253
- from db_connection_manager import DbConnectionManager
254
- mgr = DbConnectionManager.get_instance(self.db_path)
255
-
256
- with mgr.read_connection() as conn:
257
- cursor = conn.cursor()
258
- cursor.execute("""
259
- SELECT id, created_at, trust_score
260
- FROM memories
261
- WHERE created_by = ?
262
- ORDER BY created_at DESC
263
- LIMIT ?
264
- """, (agent_id, limit))
265
- return [
266
- {"memory_id": r[0], "created_at": r[1], "trust_score": r[2]}
267
- for r in cursor.fetchall()
268
- ]
269
-
270
- except Exception as e:
271
- logger.error("Failed to get memories by agent %s: %s", agent_id, e)
272
- return []
273
-
274
- def get_provenance_stats(self) -> dict:
275
- """Get provenance statistics across all memories."""
276
- try:
277
- from db_connection_manager import DbConnectionManager
278
- mgr = DbConnectionManager.get_instance(self.db_path)
279
-
280
- with mgr.read_connection() as conn:
281
- cursor = conn.cursor()
282
-
283
- cursor.execute("""
284
- SELECT created_by, COUNT(*) as count
285
- FROM memories
286
- WHERE created_by IS NOT NULL
287
- GROUP BY created_by
288
- ORDER BY count DESC
289
- """)
290
- by_agent = dict(cursor.fetchall())
291
-
292
- cursor.execute("""
293
- SELECT source_protocol, COUNT(*) as count
294
- FROM memories
295
- WHERE source_protocol IS NOT NULL
296
- GROUP BY source_protocol
297
- ORDER BY count DESC
298
- """)
299
- by_protocol = dict(cursor.fetchall())
300
-
301
- cursor.execute("SELECT AVG(trust_score) FROM memories WHERE trust_score IS NOT NULL")
302
- avg_trust = cursor.fetchone()[0]
303
-
304
- return {
305
- "by_agent": by_agent,
306
- "by_protocol": by_protocol,
307
- "avg_trust_score": round(avg_trust, 3) if avg_trust else 1.0,
308
- }
309
-
310
- except Exception as e:
311
- logger.error("Failed to get provenance stats: %s", e)
312
- return {"by_agent": {}, "by_protocol": {}, "error": str(e)}