superlocalmemory 2.8.5 → 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 (434) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +9 -1
  3. package/NOTICE +63 -0
  4. package/README.md +165 -480
  5. package/bin/slm +17 -449
  6. package/bin/slm-npm +2 -2
  7. package/bin/slm.bat +4 -2
  8. package/conftest.py +5 -0
  9. package/docs/api-reference.md +284 -0
  10. package/docs/architecture.md +149 -0
  11. package/docs/auto-memory.md +150 -0
  12. package/docs/cli-reference.md +276 -0
  13. package/docs/compliance.md +191 -0
  14. package/docs/configuration.md +182 -0
  15. package/docs/getting-started.md +102 -0
  16. package/docs/ide-setup.md +261 -0
  17. package/docs/mcp-tools.md +220 -0
  18. package/docs/migration-from-v2.md +170 -0
  19. package/docs/profiles.md +173 -0
  20. package/docs/troubleshooting.md +310 -0
  21. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  22. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  23. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  24. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  25. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  26. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  27. package/ide/configs/cursor-mcp.json +15 -0
  28. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  29. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  30. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  31. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  32. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  33. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  34. package/{configs → ide/configs}/zed-mcp.json +2 -2
  35. package/{hooks → ide/hooks}/context-hook.js +9 -20
  36. package/ide/hooks/memory-list-skill.js +70 -0
  37. package/ide/hooks/memory-profile-skill.js +101 -0
  38. package/ide/hooks/memory-recall-skill.js +62 -0
  39. package/ide/hooks/memory-remember-skill.js +68 -0
  40. package/ide/hooks/memory-reset-skill.js +160 -0
  41. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  42. package/ide/integrations/langchain/README.md +106 -0
  43. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  44. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  45. package/ide/integrations/langchain/pyproject.toml +38 -0
  46. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  47. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  48. package/ide/integrations/langchain/tests/test_security.py +117 -0
  49. package/ide/integrations/llamaindex/README.md +81 -0
  50. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  51. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  52. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  53. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  54. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  55. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  56. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  57. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  58. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  59. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  60. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  61. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  62. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  63. package/package.json +13 -22
  64. package/pyproject.toml +85 -0
  65. package/scripts/build-dmg.sh +417 -0
  66. package/scripts/install-skills.ps1 +334 -0
  67. package/{install.ps1 → scripts/install.ps1} +36 -4
  68. package/{install.sh → scripts/install.sh} +14 -13
  69. package/scripts/postinstall.js +2 -2
  70. package/scripts/start-dashboard.ps1 +52 -0
  71. package/scripts/start-dashboard.sh +41 -0
  72. package/scripts/sync-wiki.ps1 +127 -0
  73. package/scripts/sync-wiki.sh +82 -0
  74. package/scripts/test-dmg.sh +161 -0
  75. package/scripts/test-npm-package.ps1 +252 -0
  76. package/scripts/test-npm-package.sh +207 -0
  77. package/scripts/verify-install.ps1 +294 -0
  78. package/scripts/verify-install.sh +266 -0
  79. package/src/superlocalmemory/__init__.py +0 -0
  80. package/src/superlocalmemory/attribution/__init__.py +9 -0
  81. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  82. package/src/superlocalmemory/attribution/signer.py +153 -0
  83. package/src/superlocalmemory/attribution/watermark.py +189 -0
  84. package/src/superlocalmemory/cli/__init__.py +5 -0
  85. package/src/superlocalmemory/cli/commands.py +245 -0
  86. package/src/superlocalmemory/cli/main.py +89 -0
  87. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  88. package/src/superlocalmemory/cli/post_install.py +99 -0
  89. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  90. package/src/superlocalmemory/compliance/__init__.py +0 -0
  91. package/src/superlocalmemory/compliance/abac.py +204 -0
  92. package/src/superlocalmemory/compliance/audit.py +314 -0
  93. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  94. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  95. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  96. package/src/superlocalmemory/compliance/retention.py +232 -0
  97. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  98. package/src/superlocalmemory/core/__init__.py +0 -0
  99. package/src/superlocalmemory/core/config.py +391 -0
  100. package/src/superlocalmemory/core/embeddings.py +293 -0
  101. package/src/superlocalmemory/core/engine.py +701 -0
  102. package/src/superlocalmemory/core/hooks.py +65 -0
  103. package/src/superlocalmemory/core/maintenance.py +172 -0
  104. package/src/superlocalmemory/core/modes.py +140 -0
  105. package/src/superlocalmemory/core/profiles.py +234 -0
  106. package/src/superlocalmemory/core/registry.py +117 -0
  107. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  108. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  109. package/src/superlocalmemory/encoding/__init__.py +0 -0
  110. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  111. package/src/superlocalmemory/encoding/emotional.py +125 -0
  112. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  113. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  114. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  115. package/src/superlocalmemory/encoding/foresight.py +91 -0
  116. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  117. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  118. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  119. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  120. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  121. package/src/superlocalmemory/encoding/type_router.py +235 -0
  122. package/src/superlocalmemory/hooks/__init__.py +3 -0
  123. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  124. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  125. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  126. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  127. package/src/superlocalmemory/infra/__init__.py +3 -0
  128. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  129. package/src/superlocalmemory/infra/backup.py +317 -0
  130. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  131. package/src/superlocalmemory/infra/event_bus.py +381 -0
  132. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  133. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  134. package/src/superlocalmemory/learning/__init__.py +0 -0
  135. package/src/superlocalmemory/learning/adaptive.py +172 -0
  136. package/src/superlocalmemory/learning/behavioral.py +490 -0
  137. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  138. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  139. package/src/superlocalmemory/learning/cross_project.py +399 -0
  140. package/src/superlocalmemory/learning/database.py +376 -0
  141. package/src/superlocalmemory/learning/engagement.py +323 -0
  142. package/src/superlocalmemory/learning/features.py +138 -0
  143. package/src/superlocalmemory/learning/feedback.py +316 -0
  144. package/src/superlocalmemory/learning/outcomes.py +255 -0
  145. package/src/superlocalmemory/learning/project_context.py +366 -0
  146. package/src/superlocalmemory/learning/ranker.py +155 -0
  147. package/src/superlocalmemory/learning/source_quality.py +303 -0
  148. package/src/superlocalmemory/learning/workflows.py +309 -0
  149. package/src/superlocalmemory/llm/__init__.py +0 -0
  150. package/src/superlocalmemory/llm/backbone.py +316 -0
  151. package/src/superlocalmemory/math/__init__.py +0 -0
  152. package/src/superlocalmemory/math/fisher.py +356 -0
  153. package/src/superlocalmemory/math/langevin.py +398 -0
  154. package/src/superlocalmemory/math/sheaf.py +257 -0
  155. package/src/superlocalmemory/mcp/__init__.py +0 -0
  156. package/src/superlocalmemory/mcp/resources.py +245 -0
  157. package/src/superlocalmemory/mcp/server.py +61 -0
  158. package/src/superlocalmemory/mcp/tools.py +18 -0
  159. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  160. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  161. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  162. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  163. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  164. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  165. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  166. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  167. package/src/superlocalmemory/retrieval/engine.py +390 -0
  168. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  169. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  170. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  171. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  172. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  173. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  174. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  175. package/src/superlocalmemory/server/__init__.py +1 -0
  176. package/src/superlocalmemory/server/api.py +248 -0
  177. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  178. package/src/superlocalmemory/server/routes/agents.py +107 -0
  179. package/src/superlocalmemory/server/routes/backup.py +91 -0
  180. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  181. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  182. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  183. package/src/superlocalmemory/server/routes/events.py +183 -0
  184. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  185. package/src/superlocalmemory/server/routes/learning.py +273 -0
  186. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  187. package/src/superlocalmemory/server/routes/memories.py +399 -0
  188. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  189. package/src/superlocalmemory/server/routes/stats.py +346 -0
  190. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  191. package/src/superlocalmemory/server/routes/ws.py +82 -0
  192. package/src/superlocalmemory/server/security_middleware.py +57 -0
  193. package/src/superlocalmemory/server/ui.py +245 -0
  194. package/src/superlocalmemory/storage/__init__.py +0 -0
  195. package/src/superlocalmemory/storage/access_control.py +182 -0
  196. package/src/superlocalmemory/storage/database.py +594 -0
  197. package/src/superlocalmemory/storage/migrations.py +303 -0
  198. package/src/superlocalmemory/storage/models.py +406 -0
  199. package/src/superlocalmemory/storage/schema.py +726 -0
  200. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  201. package/src/superlocalmemory/trust/__init__.py +0 -0
  202. package/src/superlocalmemory/trust/gate.py +130 -0
  203. package/src/superlocalmemory/trust/provenance.py +124 -0
  204. package/src/superlocalmemory/trust/scorer.py +347 -0
  205. package/src/superlocalmemory/trust/signals.py +153 -0
  206. package/ui/index.html +278 -5
  207. package/ui/js/auto-settings.js +70 -0
  208. package/ui/js/dashboard.js +90 -0
  209. package/ui/js/fact-detail.js +92 -0
  210. package/ui/js/feedback.js +2 -2
  211. package/ui/js/ide-status.js +102 -0
  212. package/ui/js/math-health.js +98 -0
  213. package/ui/js/recall-lab.js +127 -0
  214. package/ui/js/settings.js +2 -2
  215. package/ui/js/trust-dashboard.js +73 -0
  216. package/api_server.py +0 -724
  217. package/bin/aider-smart +0 -72
  218. package/bin/superlocalmemoryv2-learning +0 -4
  219. package/bin/superlocalmemoryv2-list +0 -3
  220. package/bin/superlocalmemoryv2-patterns +0 -4
  221. package/bin/superlocalmemoryv2-profile +0 -3
  222. package/bin/superlocalmemoryv2-recall +0 -3
  223. package/bin/superlocalmemoryv2-remember +0 -3
  224. package/bin/superlocalmemoryv2-reset +0 -3
  225. package/bin/superlocalmemoryv2-status +0 -3
  226. package/configs/chatgpt-desktop-mcp.json +0 -16
  227. package/configs/cursor-mcp.json +0 -15
  228. package/docs/SECURITY-QUICK-REFERENCE.md +0 -214
  229. package/hooks/memory-list-skill.js +0 -139
  230. package/hooks/memory-profile-skill.js +0 -273
  231. package/hooks/memory-recall-skill.js +0 -114
  232. package/hooks/memory-remember-skill.js +0 -127
  233. package/hooks/memory-reset-skill.js +0 -274
  234. package/mcp_server.py +0 -1800
  235. package/requirements-core.txt +0 -22
  236. package/requirements-learning.txt +0 -12
  237. package/requirements.txt +0 -12
  238. package/src/agent_registry.py +0 -411
  239. package/src/auth_middleware.py +0 -61
  240. package/src/auto_backup.py +0 -459
  241. package/src/behavioral/__init__.py +0 -49
  242. package/src/behavioral/behavioral_listener.py +0 -203
  243. package/src/behavioral/behavioral_patterns.py +0 -275
  244. package/src/behavioral/cross_project_transfer.py +0 -206
  245. package/src/behavioral/outcome_inference.py +0 -194
  246. package/src/behavioral/outcome_tracker.py +0 -193
  247. package/src/behavioral/tests/__init__.py +0 -4
  248. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  249. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  250. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  251. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  252. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  253. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  254. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  255. package/src/cache_manager.py +0 -518
  256. package/src/compliance/__init__.py +0 -48
  257. package/src/compliance/abac_engine.py +0 -149
  258. package/src/compliance/abac_middleware.py +0 -116
  259. package/src/compliance/audit_db.py +0 -215
  260. package/src/compliance/audit_logger.py +0 -148
  261. package/src/compliance/retention_manager.py +0 -289
  262. package/src/compliance/retention_scheduler.py +0 -186
  263. package/src/compliance/tests/__init__.py +0 -4
  264. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  265. package/src/compliance/tests/test_abac_engine.py +0 -124
  266. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  267. package/src/compliance/tests/test_audit_db.py +0 -123
  268. package/src/compliance/tests/test_audit_logger.py +0 -98
  269. package/src/compliance/tests/test_mcp_audit.py +0 -128
  270. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  271. package/src/compliance/tests/test_retention_manager.py +0 -131
  272. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  273. package/src/compression/__init__.py +0 -25
  274. package/src/compression/cli.py +0 -150
  275. package/src/compression/cold_storage.py +0 -217
  276. package/src/compression/config.py +0 -72
  277. package/src/compression/orchestrator.py +0 -133
  278. package/src/compression/tier2_compressor.py +0 -228
  279. package/src/compression/tier3_compressor.py +0 -153
  280. package/src/compression/tier_classifier.py +0 -148
  281. package/src/db_connection_manager.py +0 -536
  282. package/src/embedding_engine.py +0 -63
  283. package/src/embeddings/__init__.py +0 -47
  284. package/src/embeddings/cache.py +0 -70
  285. package/src/embeddings/cli.py +0 -113
  286. package/src/embeddings/constants.py +0 -47
  287. package/src/embeddings/database.py +0 -91
  288. package/src/embeddings/engine.py +0 -247
  289. package/src/embeddings/model_loader.py +0 -145
  290. package/src/event_bus.py +0 -562
  291. package/src/graph/__init__.py +0 -36
  292. package/src/graph/build_helpers.py +0 -74
  293. package/src/graph/cli.py +0 -87
  294. package/src/graph/cluster_builder.py +0 -188
  295. package/src/graph/cluster_summary.py +0 -148
  296. package/src/graph/constants.py +0 -47
  297. package/src/graph/edge_builder.py +0 -162
  298. package/src/graph/entity_extractor.py +0 -95
  299. package/src/graph/graph_core.py +0 -226
  300. package/src/graph/graph_search.py +0 -231
  301. package/src/graph/hierarchical.py +0 -207
  302. package/src/graph/schema.py +0 -99
  303. package/src/graph_engine.py +0 -52
  304. package/src/hnsw_index.py +0 -628
  305. package/src/hybrid_search.py +0 -46
  306. package/src/learning/__init__.py +0 -217
  307. package/src/learning/adaptive_ranker.py +0 -682
  308. package/src/learning/bootstrap/__init__.py +0 -69
  309. package/src/learning/bootstrap/constants.py +0 -93
  310. package/src/learning/bootstrap/db_queries.py +0 -316
  311. package/src/learning/bootstrap/sampling.py +0 -82
  312. package/src/learning/bootstrap/text_utils.py +0 -71
  313. package/src/learning/cross_project_aggregator.py +0 -857
  314. package/src/learning/db/__init__.py +0 -40
  315. package/src/learning/db/constants.py +0 -44
  316. package/src/learning/db/schema.py +0 -279
  317. package/src/learning/engagement_tracker.py +0 -628
  318. package/src/learning/feature_extractor.py +0 -708
  319. package/src/learning/feedback_collector.py +0 -806
  320. package/src/learning/learning_db.py +0 -915
  321. package/src/learning/project_context_manager.py +0 -572
  322. package/src/learning/ranking/__init__.py +0 -33
  323. package/src/learning/ranking/constants.py +0 -84
  324. package/src/learning/ranking/helpers.py +0 -278
  325. package/src/learning/source_quality_scorer.py +0 -676
  326. package/src/learning/synthetic_bootstrap.py +0 -755
  327. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  328. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  329. package/src/learning/tests/test_aggregator.py +0 -306
  330. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  331. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  332. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  333. package/src/learning/tests/test_feedback_collector.py +0 -294
  334. package/src/learning/tests/test_learning_db.py +0 -602
  335. package/src/learning/tests/test_learning_db_v28.py +0 -110
  336. package/src/learning/tests/test_learning_init_v28.py +0 -48
  337. package/src/learning/tests/test_outcome_signals.py +0 -48
  338. package/src/learning/tests/test_project_context.py +0 -292
  339. package/src/learning/tests/test_schema_migration.py +0 -319
  340. package/src/learning/tests/test_signal_inference.py +0 -397
  341. package/src/learning/tests/test_source_quality.py +0 -351
  342. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  343. package/src/learning/tests/test_workflow_miner.py +0 -318
  344. package/src/learning/workflow_pattern_miner.py +0 -655
  345. package/src/lifecycle/__init__.py +0 -54
  346. package/src/lifecycle/bounded_growth.py +0 -239
  347. package/src/lifecycle/compaction_engine.py +0 -226
  348. package/src/lifecycle/lifecycle_engine.py +0 -355
  349. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  350. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  351. package/src/lifecycle/retention_policy.py +0 -285
  352. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  353. package/src/lifecycle/tests/test_compaction.py +0 -179
  354. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  355. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  356. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  357. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  358. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  359. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  360. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  361. package/src/mcp_tools_v28.py +0 -281
  362. package/src/memory/__init__.py +0 -36
  363. package/src/memory/cli.py +0 -205
  364. package/src/memory/constants.py +0 -39
  365. package/src/memory/helpers.py +0 -28
  366. package/src/memory/schema.py +0 -166
  367. package/src/memory-profiles.py +0 -595
  368. package/src/memory-reset.py +0 -491
  369. package/src/memory_compression.py +0 -989
  370. package/src/memory_store_v2.py +0 -1155
  371. package/src/migrate_v1_to_v2.py +0 -629
  372. package/src/pattern_learner.py +0 -34
  373. package/src/patterns/__init__.py +0 -24
  374. package/src/patterns/analyzers.py +0 -251
  375. package/src/patterns/learner.py +0 -271
  376. package/src/patterns/scoring.py +0 -171
  377. package/src/patterns/store.py +0 -225
  378. package/src/patterns/terminology.py +0 -140
  379. package/src/provenance_tracker.py +0 -312
  380. package/src/qualixar_attribution.py +0 -139
  381. package/src/qualixar_watermark.py +0 -78
  382. package/src/query_optimizer.py +0 -511
  383. package/src/rate_limiter.py +0 -83
  384. package/src/search/__init__.py +0 -20
  385. package/src/search/cli.py +0 -77
  386. package/src/search/constants.py +0 -26
  387. package/src/search/engine.py +0 -241
  388. package/src/search/fusion.py +0 -122
  389. package/src/search/index_loader.py +0 -114
  390. package/src/search/methods.py +0 -162
  391. package/src/search_engine_v2.py +0 -401
  392. package/src/setup_validator.py +0 -482
  393. package/src/subscription_manager.py +0 -391
  394. package/src/tree/__init__.py +0 -59
  395. package/src/tree/builder.py +0 -185
  396. package/src/tree/nodes.py +0 -202
  397. package/src/tree/queries.py +0 -257
  398. package/src/tree/schema.py +0 -80
  399. package/src/tree_manager.py +0 -19
  400. package/src/trust/__init__.py +0 -45
  401. package/src/trust/constants.py +0 -66
  402. package/src/trust/queries.py +0 -157
  403. package/src/trust/schema.py +0 -95
  404. package/src/trust/scorer.py +0 -299
  405. package/src/trust/signals.py +0 -95
  406. package/src/trust_scorer.py +0 -44
  407. package/ui/app.js +0 -1588
  408. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  409. package/ui/js/graph-cytoscape.js +0 -1168
  410. package/ui/js/graph-d3-backup.js +0 -32
  411. package/ui/js/graph.js +0 -32
  412. package/ui_server.py +0 -266
  413. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  414. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  415. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  416. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  417. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  418. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  419. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  420. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  421. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  422. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  423. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  424. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  425. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  426. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  427. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  428. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  429. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  430. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  431. /package/{completions → ide/completions}/slm.bash +0 -0
  432. /package/{completions → ide/completions}/slm.zsh +0 -0
  433. /package/{configs → ide/configs}/cody-commands.json +0 -0
  434. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
@@ -1,194 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Implicit outcome detection from recall behavior patterns.
4
-
5
- Pure logic module — no database, no I/O. Takes recall events and
6
- returns inference results. The caller (EventBus integration) passes
7
- these to OutcomeTracker for persistence.
8
-
9
- Inference rules (checked in priority order, first match wins per recall):
10
- 1. Deletion of recalled memory within 60 min -> failure, confidence 0.0
11
- 2. Usage signal "mcp_used_high" within 5 min -> success, confidence 0.8
12
- 3. Usage signal cross-tool within 5 min -> success, confidence 0.7
13
- 4. Rapid-fire: 3+ recalls in 2 min window -> failure, confidence 0.1
14
- 5. Different-query recall within 2 min -> failure, confidence 0.2
15
- 6. No re-query for 10+ min elapsed -> success, confidence 0.6
16
- 7. Otherwise -> not yet inferrable (keep)
17
- """
18
- from datetime import datetime, timedelta
19
- from typing import Dict, List, Optional
20
-
21
-
22
- # ── Thresholds (seconds) ─────────────────────────────────────────────
23
- _DELETION_WINDOW = 60 * 60 # 60 min
24
- _USAGE_WINDOW = 5 * 60 # 5 min
25
- _RAPID_FIRE_WINDOW = 2 * 60 # 2 min
26
- _RAPID_FIRE_COUNT = 3
27
- _REQUERY_WINDOW = 2 * 60 # 2 min
28
- _QUIET_WINDOW = 10 * 60 # 10 min
29
-
30
-
31
- class OutcomeInference:
32
- """Infer implicit success/failure from post-recall user behavior."""
33
-
34
- def __init__(self) -> None:
35
- self._recalls: List[Dict] = [] # {query, memory_ids, ts}
36
- self._usages: List[Dict] = [] # {query, signal, ts}
37
- self._deletions: List[Dict] = [] # {memory_id, ts}
38
-
39
- # ── Recording API ────────────────────────────────────────────────
40
-
41
- def record_recall(
42
- self,
43
- query: str,
44
- memory_ids: List[int],
45
- timestamp: Optional[datetime] = None,
46
- ) -> None:
47
- """Buffer a recall event."""
48
- self._recalls.append({
49
- "query": query,
50
- "memory_ids": list(memory_ids),
51
- "ts": timestamp or datetime.now(),
52
- })
53
-
54
- def record_usage(
55
- self,
56
- query: str,
57
- signal: str,
58
- timestamp: Optional[datetime] = None,
59
- ) -> None:
60
- """Buffer a post-recall usage signal."""
61
- self._usages.append({
62
- "query": query,
63
- "signal": signal,
64
- "ts": timestamp or datetime.now(),
65
- })
66
-
67
- def record_deletion(
68
- self,
69
- memory_id: int,
70
- timestamp: Optional[datetime] = None,
71
- ) -> None:
72
- """Buffer a memory deletion event."""
73
- self._deletions.append({
74
- "memory_id": memory_id,
75
- "ts": timestamp or datetime.now(),
76
- })
77
-
78
- # ── Inference engine ─────────────────────────────────────────────
79
-
80
- def infer_outcomes(self, now: Optional[datetime] = None) -> List[Dict]:
81
- """Process buffered events, apply rules, return inferences.
82
-
83
- Processed recall events are removed from the buffer.
84
- Events that are not yet inferrable remain for later.
85
-
86
- Returns:
87
- List of dicts with keys: outcome, confidence, memory_ids, reason
88
- """
89
- now = now or datetime.now()
90
- results: List[Dict] = []
91
- remaining: List[Dict] = []
92
-
93
- for recall in self._recalls:
94
- result = self._evaluate(recall, now)
95
- if result is not None:
96
- results.append(result)
97
- else:
98
- remaining.append(recall)
99
-
100
- # Clear processed; keep un-inferrable recalls
101
- self._recalls = remaining
102
- # Consumed usages and deletions are cleared entirely
103
- self._usages.clear()
104
- self._deletions.clear()
105
-
106
- return results
107
-
108
- # ── Private rule evaluation ──────────────────────────────────────
109
-
110
- def _evaluate(self, recall: Dict, now: datetime) -> Optional[Dict]:
111
- """Apply rules in priority order. First match wins."""
112
- query = recall["query"]
113
- mem_ids = recall["memory_ids"]
114
- ts = recall["ts"]
115
- elapsed = (now - ts).total_seconds()
116
-
117
- # Rule 1: Deletion of recalled memory within 60 min
118
- for d in self._deletions:
119
- if d["memory_id"] in mem_ids:
120
- delta = (d["ts"] - ts).total_seconds()
121
- if 0 <= delta <= _DELETION_WINDOW:
122
- return self._result(
123
- "failure", 0.0, mem_ids,
124
- "memory_deleted_after_recall",
125
- )
126
-
127
- # Rule 2: Usage signal "mcp_used_high" within 5 min
128
- for u in self._usages:
129
- if u["query"] == query and u["signal"] == "mcp_used_high":
130
- delta = (u["ts"] - ts).total_seconds()
131
- if 0 <= delta <= _USAGE_WINDOW:
132
- return self._result(
133
- "success", 0.8, mem_ids,
134
- "mcp_used_high_after_recall",
135
- )
136
-
137
- # Rule 3: Cross-tool usage within 5 min
138
- for u in self._usages:
139
- if u["query"] == query and u["signal"] == "implicit_positive_cross_tool":
140
- delta = (u["ts"] - ts).total_seconds()
141
- if 0 <= delta <= _USAGE_WINDOW:
142
- return self._result(
143
- "success", 0.7, mem_ids,
144
- "cross_tool_access_after_recall",
145
- )
146
-
147
- # Rule 4: Rapid-fire — 3+ recalls within 2 min window
148
- window_start = ts - timedelta(seconds=_RAPID_FIRE_WINDOW)
149
- nearby = [
150
- r for r in self._recalls
151
- if r is not recall and window_start <= r["ts"] <= ts + timedelta(seconds=_RAPID_FIRE_WINDOW)
152
- ]
153
- # Count total including this recall
154
- if len(nearby) + 1 >= _RAPID_FIRE_COUNT:
155
- return self._result(
156
- "failure", 0.1, mem_ids,
157
- "rapid_fire_queries",
158
- )
159
-
160
- # Rule 5: Different-query recall within 2 min
161
- for r in self._recalls:
162
- if r is recall:
163
- continue
164
- if r["query"] != query:
165
- delta = abs((r["ts"] - ts).total_seconds())
166
- if delta <= _REQUERY_WINDOW:
167
- return self._result(
168
- "failure", 0.2, mem_ids,
169
- "immediate_requery_different_terms",
170
- )
171
-
172
- # Rule 6: 10+ min elapsed with no subsequent activity
173
- if elapsed >= _QUIET_WINDOW:
174
- return self._result(
175
- "success", 0.6, mem_ids,
176
- "no_requery_after_recall",
177
- )
178
-
179
- # Rule 7: Not yet inferrable
180
- return None
181
-
182
- @staticmethod
183
- def _result(
184
- outcome: str,
185
- confidence: float,
186
- memory_ids: List[int],
187
- reason: str,
188
- ) -> Dict:
189
- return {
190
- "outcome": outcome,
191
- "confidence": confidence,
192
- "memory_ids": memory_ids,
193
- "reason": reason,
194
- }
@@ -1,193 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Explicit + implicit action outcome recording.
4
-
5
- Records what happens AFTER memories are recalled — success, failure,
6
- or partial outcomes. Self-contained: creates its own table via
7
- CREATE TABLE IF NOT EXISTS so no external migration is needed.
8
-
9
- Part of SLM v2.8 Behavioral Learning Engine.
10
- """
11
- import json
12
- import sqlite3
13
- import threading
14
- from typing import Dict, List, Optional, Any
15
-
16
-
17
- class OutcomeTracker:
18
- """Records action outcomes for behavioral learning.
19
-
20
- Each outcome links one or more memory IDs to an outcome label
21
- (success / failure / partial) with optional context metadata.
22
- Confidence defaults to 0.9 for explicit (user-reported) outcomes.
23
- """
24
-
25
- OUTCOMES = ("success", "failure", "partial")
26
-
27
- ACTION_TYPES = (
28
- "code_written",
29
- "decision_made",
30
- "debug_resolved",
31
- "architecture_chosen",
32
- "other",
33
- )
34
-
35
- _CREATE_TABLE = """
36
- CREATE TABLE IF NOT EXISTS action_outcomes (
37
- id INTEGER PRIMARY KEY AUTOINCREMENT,
38
- memory_ids TEXT NOT NULL,
39
- outcome TEXT NOT NULL,
40
- action_type TEXT DEFAULT 'other',
41
- context TEXT DEFAULT '{}',
42
- confidence REAL DEFAULT 0.9,
43
- agent_id TEXT DEFAULT 'user',
44
- project TEXT,
45
- profile TEXT DEFAULT 'default',
46
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
47
- )
48
- """
49
-
50
- def __init__(self, db_path: Optional[str] = None):
51
- self._db_path = db_path
52
- self._lock = threading.Lock()
53
- if db_path:
54
- self._ensure_table()
55
-
56
- # ------------------------------------------------------------------
57
- # Public API
58
- # ------------------------------------------------------------------
59
-
60
- def record_outcome(
61
- self,
62
- memory_ids: List[int],
63
- outcome: str,
64
- action_type: str = "other",
65
- context: Optional[Dict[str, Any]] = None,
66
- confidence: float = 0.9,
67
- agent_id: str = "user",
68
- project: Optional[str] = None,
69
- ) -> Optional[int]:
70
- """Record an action outcome against one or more memories.
71
-
72
- Args:
73
- memory_ids: List of memory IDs involved in this outcome.
74
- outcome: One of OUTCOMES ("success", "failure", "partial").
75
- action_type: Category of the action taken.
76
- context: Arbitrary metadata dict (stored as JSON).
77
- confidence: Confidence in the outcome label (default 0.9).
78
- agent_id: Identifier for the reporting agent.
79
- project: Optional project scope.
80
-
81
- Returns:
82
- The row ID of the inserted outcome, or None if validation fails.
83
- """
84
- if outcome not in self.OUTCOMES:
85
- return None
86
-
87
- context_json = json.dumps(context or {})
88
- memory_ids_json = json.dumps(memory_ids)
89
-
90
- with self._lock:
91
- conn = self._connect()
92
- try:
93
- cur = conn.execute(
94
- """INSERT INTO action_outcomes
95
- (memory_ids, outcome, action_type, context,
96
- confidence, agent_id, project)
97
- VALUES (?, ?, ?, ?, ?, ?, ?)""",
98
- (
99
- memory_ids_json,
100
- outcome,
101
- action_type,
102
- context_json,
103
- confidence,
104
- agent_id,
105
- project,
106
- ),
107
- )
108
- conn.commit()
109
- return cur.lastrowid
110
- finally:
111
- conn.close()
112
-
113
- def get_outcomes(
114
- self,
115
- memory_id: Optional[int] = None,
116
- project: Optional[str] = None,
117
- limit: int = 100,
118
- ) -> List[Dict[str, Any]]:
119
- """Query recorded outcomes with optional filters.
120
-
121
- Args:
122
- memory_id: If given, return only outcomes that include this
123
- memory ID in their memory_ids list.
124
- project: If given, filter by project scope.
125
- limit: Maximum rows to return (default 100).
126
-
127
- Returns:
128
- List of outcome dicts with deserialized memory_ids and context.
129
- """
130
- with self._lock:
131
- conn = self._connect()
132
- try:
133
- query = "SELECT * FROM action_outcomes WHERE 1=1"
134
- params: List[Any] = []
135
-
136
- if project is not None:
137
- query += " AND project = ?"
138
- params.append(project)
139
-
140
- query += " ORDER BY created_at DESC LIMIT ?"
141
- params.append(limit)
142
-
143
- rows = conn.execute(query, params).fetchall()
144
- results = [self._row_to_dict(r) for r in rows]
145
-
146
- if memory_id is not None:
147
- results = [
148
- r for r in results if memory_id in r["memory_ids"]
149
- ]
150
-
151
- return results
152
- finally:
153
- conn.close()
154
-
155
- def get_success_rate(self, memory_id: int) -> float:
156
- """Calculate success rate for a specific memory.
157
-
158
- Counts outcomes where memory_id appears in memory_ids.
159
- Returns success count / total count, or 0.0 if no outcomes.
160
- """
161
- outcomes = self.get_outcomes(memory_id=memory_id)
162
- if not outcomes:
163
- return 0.0
164
- successes = sum(1 for o in outcomes if o["outcome"] == "success")
165
- return round(successes / len(outcomes), 3)
166
-
167
- # ------------------------------------------------------------------
168
- # Internal helpers
169
- # ------------------------------------------------------------------
170
-
171
- def _connect(self) -> sqlite3.Connection:
172
- """Open a connection with row factory enabled."""
173
- conn = sqlite3.connect(self._db_path)
174
- conn.row_factory = sqlite3.Row
175
- return conn
176
-
177
- def _ensure_table(self) -> None:
178
- """Create the action_outcomes table if it doesn't exist."""
179
- conn = self._connect()
180
- try:
181
- conn.execute(self._CREATE_TABLE)
182
- conn.commit()
183
- finally:
184
- conn.close()
185
-
186
- @staticmethod
187
- def _row_to_dict(row: sqlite3.Row) -> Dict[str, Any]:
188
- """Convert a sqlite3.Row into a plain dict with parsed JSON fields."""
189
- d = dict(row)
190
- d["memory_ids"] = json.loads(d.get("memory_ids", "[]"))
191
- ctx = d.get("context", "{}")
192
- d["context"] = json.loads(ctx) if isinstance(ctx, str) else ctx
193
- return d
@@ -1,4 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for behavioral learning engine.
4
- """
@@ -1,108 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for behavioral engine EventBus integration.
4
- """
5
- import sqlite3
6
- import tempfile
7
- import os
8
- import sys
9
- from datetime import datetime
10
- from pathlib import Path
11
- from unittest.mock import MagicMock, patch
12
-
13
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
14
-
15
-
16
- class TestBehavioralIntegration:
17
- """Test behavioral engine wiring with EventBus."""
18
-
19
- def setup_method(self):
20
- self.tmp_dir = tempfile.mkdtemp()
21
- self.db_path = os.path.join(self.tmp_dir, "learning.db")
22
-
23
- def teardown_method(self):
24
- import shutil
25
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
26
-
27
- def test_create_behavioral_listener(self):
28
- """BehavioralListener can be instantiated."""
29
- from behavioral.behavioral_listener import BehavioralListener
30
- listener = BehavioralListener(self.db_path)
31
- assert listener is not None
32
-
33
- def test_listener_handles_recall_event(self):
34
- """Listener processes memory.recalled events."""
35
- from behavioral.behavioral_listener import BehavioralListener
36
- listener = BehavioralListener(self.db_path)
37
- event = {
38
- "event_type": "memory.recalled",
39
- "memory_id": 1,
40
- "payload": {"query": "test query", "memory_ids": [1, 2]},
41
- "timestamp": datetime.now().isoformat(),
42
- }
43
- # Should not raise
44
- listener.handle_event(event)
45
- assert listener.events_processed >= 1
46
-
47
- def test_listener_ignores_irrelevant_events(self):
48
- """Listener ignores non-recall events."""
49
- from behavioral.behavioral_listener import BehavioralListener
50
- listener = BehavioralListener(self.db_path)
51
- event = {
52
- "event_type": "memory.created",
53
- "memory_id": 1,
54
- "payload": {},
55
- "timestamp": datetime.now().isoformat(),
56
- }
57
- listener.handle_event(event)
58
- assert listener.recall_events_processed == 0
59
-
60
- def test_listener_handles_deletion_event(self):
61
- """Listener records deletion events for inference."""
62
- from behavioral.behavioral_listener import BehavioralListener
63
- listener = BehavioralListener(self.db_path)
64
- event = {
65
- "event_type": "memory.deleted",
66
- "memory_id": 5,
67
- "payload": {},
68
- "timestamp": datetime.now().isoformat(),
69
- }
70
- listener.handle_event(event)
71
- assert listener.deletion_events_processed >= 1
72
-
73
- def test_listener_tracks_usage_signals(self):
74
- """Listener records usage signals (memory_used) for inference."""
75
- from behavioral.behavioral_listener import BehavioralListener
76
- listener = BehavioralListener(self.db_path)
77
- event = {
78
- "event_type": "memory.recalled",
79
- "memory_id": 1,
80
- "payload": {"query": "test", "memory_ids": [1], "signal": "mcp_used_high"},
81
- "timestamp": datetime.now().isoformat(),
82
- }
83
- listener.handle_event(event)
84
- assert listener.events_processed >= 1
85
-
86
- def test_graceful_degradation_no_eventbus(self):
87
- """If EventBus unavailable, behavioral engine still works."""
88
- from behavioral.behavioral_listener import BehavioralListener
89
- listener = BehavioralListener(self.db_path)
90
- # register_with_eventbus should not crash even if EventBus fails
91
- result = listener.register_with_eventbus()
92
- # Result depends on whether EventBus is importable in test env
93
- assert isinstance(result, bool)
94
-
95
- def test_pattern_extraction_threshold(self):
96
- """Pattern extraction triggers after outcome count threshold."""
97
- from behavioral.behavioral_listener import BehavioralListener
98
- listener = BehavioralListener(self.db_path, extraction_threshold=5)
99
- assert listener.extraction_threshold == 5
100
-
101
- def test_get_status(self):
102
- """Listener reports its status."""
103
- from behavioral.behavioral_listener import BehavioralListener
104
- listener = BehavioralListener(self.db_path)
105
- status = listener.get_status()
106
- assert "events_processed" in status
107
- assert "recall_events_processed" in status
108
- assert "registered" in status
@@ -1,150 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for behavioral pattern extraction from outcomes.
4
- """
5
- import sqlite3
6
- import tempfile
7
- import os
8
- import sys
9
- import json
10
- from pathlib import Path
11
-
12
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
13
-
14
-
15
- class TestBehavioralPatterns:
16
- """Test pattern extraction from action outcomes."""
17
-
18
- def setup_method(self):
19
- self.tmp_dir = tempfile.mkdtemp()
20
- self.db_path = os.path.join(self.tmp_dir, "learning.db")
21
- conn = sqlite3.connect(self.db_path)
22
- # Create action_outcomes table (populated by OutcomeTracker)
23
- conn.execute("""
24
- CREATE TABLE IF NOT EXISTS action_outcomes (
25
- id INTEGER PRIMARY KEY AUTOINCREMENT,
26
- memory_ids TEXT NOT NULL,
27
- outcome TEXT NOT NULL,
28
- action_type TEXT DEFAULT 'other',
29
- context TEXT DEFAULT '{}',
30
- confidence REAL DEFAULT 0.9,
31
- agent_id TEXT DEFAULT 'user',
32
- project TEXT,
33
- profile TEXT DEFAULT 'default',
34
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
35
- )
36
- """)
37
- # Create behavioral_patterns table
38
- conn.execute("""
39
- CREATE TABLE IF NOT EXISTS behavioral_patterns (
40
- id INTEGER PRIMARY KEY AUTOINCREMENT,
41
- pattern_type TEXT NOT NULL,
42
- pattern_key TEXT NOT NULL,
43
- success_rate REAL DEFAULT 0.0,
44
- evidence_count INTEGER DEFAULT 0,
45
- confidence REAL DEFAULT 0.0,
46
- metadata TEXT DEFAULT '{}',
47
- project TEXT,
48
- profile TEXT DEFAULT 'default',
49
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
50
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
51
- )
52
- """)
53
- # Insert sample outcomes for pattern extraction
54
- # Project A: 8 success, 2 failure -> 80% success
55
- for i in range(8):
56
- conn.execute("INSERT INTO action_outcomes (memory_ids, outcome, project, action_type) VALUES (?, ?, ?, ?)",
57
- (json.dumps([i+1]), "success", "project_a", "code_written"))
58
- for i in range(2):
59
- conn.execute("INSERT INTO action_outcomes (memory_ids, outcome, project, action_type) VALUES (?, ?, ?, ?)",
60
- (json.dumps([i+20]), "failure", "project_a", "code_written"))
61
- # Project B: 2 success, 8 failure -> 20% success
62
- for i in range(2):
63
- conn.execute("INSERT INTO action_outcomes (memory_ids, outcome, project, action_type) VALUES (?, ?, ?, ?)",
64
- (json.dumps([i+30]), "success", "project_b", "debug_resolved"))
65
- for i in range(8):
66
- conn.execute("INSERT INTO action_outcomes (memory_ids, outcome, project, action_type) VALUES (?, ?, ?, ?)",
67
- (json.dumps([i+40]), "failure", "project_b", "debug_resolved"))
68
- conn.commit()
69
- conn.close()
70
-
71
- def teardown_method(self):
72
- import shutil
73
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
74
-
75
- def test_extract_patterns(self):
76
- """extract_patterns returns list of discovered patterns."""
77
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
78
- extractor = BehavioralPatternExtractor(self.db_path)
79
- patterns = extractor.extract_patterns()
80
- assert isinstance(patterns, list)
81
- assert len(patterns) >= 2 # At least project_a and project_b patterns
82
-
83
- def test_project_success_rate(self):
84
- """Patterns should reflect actual success rates per project."""
85
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
86
- extractor = BehavioralPatternExtractor(self.db_path)
87
- patterns = extractor.extract_patterns()
88
- proj_a = [p for p in patterns if p["pattern_key"] == "project_a" and p["pattern_type"] == "project_success"]
89
- assert len(proj_a) == 1
90
- assert abs(proj_a[0]["success_rate"] - 0.8) < 0.01
91
-
92
- def test_success_pattern_high_rate(self):
93
- """Projects with >70% success and 5+ evidence -> success pattern."""
94
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
95
- extractor = BehavioralPatternExtractor(self.db_path)
96
- patterns = extractor.extract_patterns()
97
- proj_a = [p for p in patterns if p["pattern_key"] == "project_a" and p["pattern_type"] == "project_success"]
98
- assert proj_a[0]["success_rate"] > 0.7
99
- assert proj_a[0]["evidence_count"] >= 5
100
-
101
- def test_failure_pattern_low_rate(self):
102
- """Projects with <30% success and 5+ evidence -> failure pattern."""
103
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
104
- extractor = BehavioralPatternExtractor(self.db_path)
105
- patterns = extractor.extract_patterns()
106
- proj_b = [p for p in patterns if p["pattern_key"] == "project_b" and p["pattern_type"] == "project_success"]
107
- assert proj_b[0]["success_rate"] < 0.3
108
-
109
- def test_action_type_patterns(self):
110
- """Should extract patterns grouped by action_type."""
111
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
112
- extractor = BehavioralPatternExtractor(self.db_path)
113
- patterns = extractor.extract_patterns()
114
- action_patterns = [p for p in patterns if p["pattern_type"] == "action_type_success"]
115
- assert len(action_patterns) >= 1
116
-
117
- def test_get_patterns_with_min_confidence(self):
118
- """get_patterns filters by minimum confidence."""
119
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
120
- extractor = BehavioralPatternExtractor(self.db_path)
121
- extractor.extract_patterns()
122
- # Store patterns to DB first
123
- extractor.save_patterns()
124
- high_conf = extractor.get_patterns(min_confidence=0.5)
125
- all_patterns = extractor.get_patterns(min_confidence=0.0)
126
- assert len(high_conf) <= len(all_patterns)
127
-
128
- def test_pattern_confidence_scoring(self):
129
- """Patterns with more evidence should have higher confidence."""
130
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
131
- extractor = BehavioralPatternExtractor(self.db_path)
132
- patterns = extractor.extract_patterns()
133
- for p in patterns:
134
- assert 0.0 <= p["confidence"] <= 1.0
135
- # Confidence should increase with evidence
136
- if p["evidence_count"] >= 10:
137
- assert p["confidence"] >= 0.5
138
-
139
- def test_save_patterns_to_db(self):
140
- """save_patterns stores extracted patterns in behavioral_patterns table."""
141
- from behavioral.behavioral_patterns import BehavioralPatternExtractor
142
- extractor = BehavioralPatternExtractor(self.db_path)
143
- extractor.extract_patterns()
144
- count = extractor.save_patterns()
145
- assert count >= 2
146
- # Verify in DB
147
- conn = sqlite3.connect(self.db_path)
148
- rows = conn.execute("SELECT COUNT(*) FROM behavioral_patterns").fetchone()
149
- conn.close()
150
- assert rows[0] >= 2