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,142 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for privacy-safe cross-project behavioral transfer.
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 TestCrossProjectTransfer:
16
- """Test cross-project behavioral pattern transfer."""
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
- conn.execute("""
23
- CREATE TABLE IF NOT EXISTS behavioral_patterns (
24
- id INTEGER PRIMARY KEY AUTOINCREMENT,
25
- pattern_type TEXT NOT NULL,
26
- pattern_key TEXT NOT NULL,
27
- success_rate REAL DEFAULT 0.0,
28
- evidence_count INTEGER DEFAULT 0,
29
- confidence REAL DEFAULT 0.0,
30
- metadata TEXT DEFAULT '{}',
31
- project TEXT,
32
- profile TEXT DEFAULT 'default',
33
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
34
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
35
- )
36
- """)
37
- conn.execute("""
38
- CREATE TABLE IF NOT EXISTS cross_project_behaviors (
39
- id INTEGER PRIMARY KEY AUTOINCREMENT,
40
- source_project TEXT NOT NULL,
41
- target_project TEXT NOT NULL,
42
- pattern_id INTEGER NOT NULL,
43
- transfer_type TEXT DEFAULT 'metadata',
44
- confidence REAL DEFAULT 0.0,
45
- profile TEXT DEFAULT 'default',
46
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
47
- FOREIGN KEY (pattern_id) REFERENCES behavioral_patterns(id)
48
- )
49
- """)
50
- # Insert patterns: high-confidence pattern in project_a
51
- conn.execute(
52
- "INSERT INTO behavioral_patterns (pattern_type, pattern_key, success_rate, evidence_count, confidence, project) VALUES (?, ?, ?, ?, ?, ?)",
53
- ("action_type_success", "code_written", 0.85, 12, 0.9, "project_a"),
54
- )
55
- # Low-confidence pattern (should NOT transfer)
56
- conn.execute(
57
- "INSERT INTO behavioral_patterns (pattern_type, pattern_key, success_rate, evidence_count, confidence, project) VALUES (?, ?, ?, ?, ?, ?)",
58
- ("action_type_success", "debug_resolved", 0.4, 3, 0.2, "project_a"),
59
- )
60
- # High-confidence pattern for project_b
61
- conn.execute(
62
- "INSERT INTO behavioral_patterns (pattern_type, pattern_key, success_rate, evidence_count, confidence, project) VALUES (?, ?, ?, ?, ?, ?)",
63
- ("project_success", "project_b", 0.9, 15, 0.95, "project_b"),
64
- )
65
- conn.commit()
66
- conn.close()
67
-
68
- def teardown_method(self):
69
- import shutil
70
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
71
-
72
- def test_evaluate_transfers(self):
73
- """evaluate_transfers returns eligible patterns."""
74
- from behavioral.cross_project_transfer import CrossProjectTransfer
75
- transfer = CrossProjectTransfer(self.db_path)
76
- eligible = transfer.evaluate_transfers(target_project="project_c")
77
- assert isinstance(eligible, list)
78
- assert len(eligible) >= 1 # At least the high-confidence pattern
79
-
80
- def test_only_high_confidence_transfers(self):
81
- """Only patterns with confidence >= 0.7 and evidence >= 5 transfer."""
82
- from behavioral.cross_project_transfer import CrossProjectTransfer
83
- transfer = CrossProjectTransfer(self.db_path)
84
- eligible = transfer.evaluate_transfers(target_project="project_c")
85
- for e in eligible:
86
- assert e["confidence"] >= 0.7
87
- assert e["evidence_count"] >= 5
88
-
89
- def test_low_confidence_excluded(self):
90
- """Low confidence patterns (id=2, confidence=0.2) should NOT transfer."""
91
- from behavioral.cross_project_transfer import CrossProjectTransfer
92
- transfer = CrossProjectTransfer(self.db_path)
93
- eligible = transfer.evaluate_transfers(target_project="project_c")
94
- pattern_ids = {e["pattern_id"] for e in eligible}
95
- assert 2 not in pattern_ids # Low confidence pattern excluded
96
-
97
- def test_only_metadata_transfers(self):
98
- """Transfers must be metadata-only — never content."""
99
- from behavioral.cross_project_transfer import CrossProjectTransfer
100
- transfer = CrossProjectTransfer(self.db_path)
101
- eligible = transfer.evaluate_transfers(target_project="project_c")
102
- for e in eligible:
103
- assert e["transfer_type"] == "metadata"
104
- assert "content" not in e # No content field
105
- assert "content_hash" not in e # No content hashes
106
-
107
- def test_apply_transfer(self):
108
- """apply_transfer records the transfer in cross_project_behaviors."""
109
- from behavioral.cross_project_transfer import CrossProjectTransfer
110
- transfer = CrossProjectTransfer(self.db_path)
111
- result = transfer.apply_transfer(pattern_id=1, target_project="project_c")
112
- assert result["success"] is True
113
- # Verify in DB
114
- conn = sqlite3.connect(self.db_path)
115
- row = conn.execute("SELECT * FROM cross_project_behaviors WHERE target_project='project_c'").fetchone()
116
- conn.close()
117
- assert row is not None
118
-
119
- def test_transfer_logged(self):
120
- """Transfers are logged with source and target projects."""
121
- from behavioral.cross_project_transfer import CrossProjectTransfer
122
- transfer = CrossProjectTransfer(self.db_path)
123
- transfer.apply_transfer(pattern_id=1, target_project="project_c")
124
- transfers = transfer.get_transfers(target_project="project_c")
125
- assert len(transfers) == 1
126
- assert transfers[0]["source_project"] == "project_a"
127
-
128
- def test_no_self_transfer(self):
129
- """Patterns should not transfer to their own project."""
130
- from behavioral.cross_project_transfer import CrossProjectTransfer
131
- transfer = CrossProjectTransfer(self.db_path)
132
- eligible = transfer.evaluate_transfers(target_project="project_a")
133
- # Pattern 1 is from project_a — should not be eligible for project_a
134
- source_projects = {e.get("source_project") for e in eligible}
135
- assert "project_a" not in source_projects
136
-
137
- def test_disable_via_config(self):
138
- """Transfers can be disabled via config."""
139
- from behavioral.cross_project_transfer import CrossProjectTransfer
140
- transfer = CrossProjectTransfer(self.db_path, enabled=False)
141
- eligible = transfer.evaluate_transfers(target_project="project_c")
142
- assert eligible == []
@@ -1,139 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for get_behavioral_patterns MCP tool handler.
4
-
5
- Validates the MCP wrapper around BehavioralPatternExtractor — tests
6
- pattern retrieval, confidence filtering, and project filtering.
7
- """
8
- import asyncio
9
- import os
10
- import shutil
11
- import sqlite3
12
- import sys
13
- import tempfile
14
- from pathlib import Path
15
-
16
- import pytest
17
-
18
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
19
-
20
-
21
- def _create_learning_db_with_patterns(db_path: str) -> None:
22
- """Create learning.db with pre-seeded behavioral patterns."""
23
- conn = sqlite3.connect(db_path)
24
- # The BehavioralPatternExtractor creates this table itself, but we need
25
- # pre-seeded data for read-only tests. Create it manually.
26
- conn.execute(
27
- """CREATE TABLE IF NOT EXISTS behavioral_patterns (
28
- id INTEGER PRIMARY KEY AUTOINCREMENT,
29
- pattern_type TEXT NOT NULL,
30
- pattern_key TEXT NOT NULL,
31
- success_rate REAL DEFAULT 0.0,
32
- evidence_count INTEGER DEFAULT 0,
33
- confidence REAL DEFAULT 0.0,
34
- metadata TEXT DEFAULT '{}',
35
- project TEXT,
36
- profile TEXT DEFAULT 'default',
37
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
38
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
39
- )"""
40
- )
41
- # Pattern 1: high confidence, project-scoped
42
- conn.execute(
43
- "INSERT INTO behavioral_patterns "
44
- "(pattern_type, pattern_key, success_rate, evidence_count, confidence, project) "
45
- "VALUES (?, ?, ?, ?, ?, ?)",
46
- ("project_success", "slm-v28", 0.85, 12, 0.8, "slm-v28"),
47
- )
48
- # Pattern 2: low confidence, no project
49
- conn.execute(
50
- "INSERT INTO behavioral_patterns "
51
- "(pattern_type, pattern_key, success_rate, evidence_count, confidence, project) "
52
- "VALUES (?, ?, ?, ?, ?, ?)",
53
- ("action_type_success", "code_written", 0.55, 4, 0.15, None),
54
- )
55
- conn.commit()
56
- conn.close()
57
-
58
-
59
- class TestMCPBehavioralPatterns:
60
- """Tests for the get_behavioral_patterns tool handler."""
61
-
62
- def setup_method(self):
63
- self.tmp_dir = tempfile.mkdtemp()
64
- self.db_path = os.path.join(self.tmp_dir, "learning.db")
65
- _create_learning_db_with_patterns(self.db_path)
66
-
67
- def teardown_method(self):
68
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
69
-
70
- def _run(self, coro):
71
- return asyncio.get_event_loop().run_until_complete(coro)
72
-
73
- def test_get_all_patterns(self):
74
- """Without filters, should return all patterns."""
75
- import mcp_tools_v28 as tools
76
- tools.DEFAULT_LEARNING_DB = self.db_path
77
-
78
- result = self._run(tools.get_behavioral_patterns())
79
- assert result["success"] is True
80
- assert result["count"] == 2
81
-
82
- def test_filter_by_high_confidence(self):
83
- """Filtering with min_confidence=0.9 should return 0 (none that high)."""
84
- import mcp_tools_v28 as tools
85
- tools.DEFAULT_LEARNING_DB = self.db_path
86
-
87
- result = self._run(tools.get_behavioral_patterns(min_confidence=0.9))
88
- assert result["success"] is True
89
- assert result["count"] == 0
90
-
91
- def test_filter_by_medium_confidence(self):
92
- """Filtering with min_confidence=0.5 should return only the high-confidence one."""
93
- import mcp_tools_v28 as tools
94
- tools.DEFAULT_LEARNING_DB = self.db_path
95
-
96
- result = self._run(tools.get_behavioral_patterns(min_confidence=0.5))
97
- assert result["success"] is True
98
- assert result["count"] == 1
99
- assert result["patterns"][0]["pattern_key"] == "slm-v28"
100
-
101
- def test_filter_by_project(self):
102
- """Filtering by project should scope results."""
103
- import mcp_tools_v28 as tools
104
- tools.DEFAULT_LEARNING_DB = self.db_path
105
-
106
- result = self._run(tools.get_behavioral_patterns(project="slm-v28"))
107
- assert result["success"] is True
108
- assert result["count"] == 1
109
-
110
- def test_filter_by_nonexistent_project(self):
111
- """Filtering by a project with no patterns should return 0."""
112
- import mcp_tools_v28 as tools
113
- tools.DEFAULT_LEARNING_DB = self.db_path
114
-
115
- result = self._run(tools.get_behavioral_patterns(project="nonexistent"))
116
- assert result["success"] is True
117
- assert result["count"] == 0
118
-
119
- def test_patterns_have_required_keys(self):
120
- """Each returned pattern should have standard keys."""
121
- import mcp_tools_v28 as tools
122
- tools.DEFAULT_LEARNING_DB = self.db_path
123
-
124
- result = self._run(tools.get_behavioral_patterns())
125
- for pattern in result["patterns"]:
126
- assert "pattern_type" in pattern
127
- assert "pattern_key" in pattern
128
- assert "success_rate" in pattern
129
- assert "confidence" in pattern
130
-
131
- def test_empty_db_returns_zero(self):
132
- """An empty learning DB should return count=0."""
133
- import mcp_tools_v28 as tools
134
- empty_path = os.path.join(self.tmp_dir, "empty_learning.db")
135
- tools.DEFAULT_LEARNING_DB = empty_path
136
-
137
- result = self._run(tools.get_behavioral_patterns())
138
- assert result["success"] is True
139
- assert result["count"] == 0
@@ -1,117 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for report_outcome MCP tool handler.
4
-
5
- Validates the MCP wrapper around OutcomeTracker — tests success/failure/partial
6
- outcomes, context handling, and invalid outcome rejection.
7
- """
8
- import asyncio
9
- import os
10
- import shutil
11
- import sys
12
- import tempfile
13
- from pathlib import Path
14
-
15
- import pytest
16
-
17
- # Ensure src/ is importable
18
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
19
-
20
-
21
- class TestMCPReportOutcome:
22
- """Tests for the report_outcome tool handler."""
23
-
24
- def setup_method(self):
25
- self.tmp_dir = tempfile.mkdtemp()
26
- self.db_path = os.path.join(self.tmp_dir, "learning.db")
27
-
28
- def teardown_method(self):
29
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
30
-
31
- def _run(self, coro):
32
- """Helper to run async functions synchronously."""
33
- return asyncio.get_event_loop().run_until_complete(coro)
34
-
35
- def test_report_success_outcome(self):
36
- """Reporting a 'success' outcome should return success=True and an outcome_id."""
37
- import mcp_tools_v28 as tools
38
- tools.DEFAULT_LEARNING_DB = self.db_path
39
-
40
- result = self._run(tools.report_outcome([1, 2], "success"))
41
- assert result["success"] is True
42
- assert isinstance(result["outcome_id"], int)
43
- assert result["outcome_id"] > 0
44
- assert result["outcome"] == "success"
45
- assert result["memory_ids"] == [1, 2]
46
-
47
- def test_report_failure_outcome(self):
48
- """Reporting a 'failure' outcome should succeed."""
49
- import mcp_tools_v28 as tools
50
- tools.DEFAULT_LEARNING_DB = self.db_path
51
-
52
- result = self._run(tools.report_outcome([5], "failure"))
53
- assert result["success"] is True
54
- assert result["outcome"] == "failure"
55
-
56
- def test_report_partial_outcome(self):
57
- """Reporting a 'partial' outcome should succeed."""
58
- import mcp_tools_v28 as tools
59
- tools.DEFAULT_LEARNING_DB = self.db_path
60
-
61
- result = self._run(tools.report_outcome([3], "partial"))
62
- assert result["success"] is True
63
- assert result["outcome"] == "partial"
64
-
65
- def test_report_invalid_outcome(self):
66
- """An invalid outcome label should return success=False."""
67
- import mcp_tools_v28 as tools
68
- tools.DEFAULT_LEARNING_DB = self.db_path
69
-
70
- result = self._run(tools.report_outcome([1], "invalid"))
71
- assert result["success"] is False
72
- assert "Invalid outcome" in result["error"]
73
-
74
- def test_report_with_context_json(self):
75
- """Context passed as JSON string should be accepted."""
76
- import mcp_tools_v28 as tools
77
- tools.DEFAULT_LEARNING_DB = self.db_path
78
-
79
- result = self._run(
80
- tools.report_outcome(
81
- [1], "partial", context='{"note": "worked partially"}'
82
- )
83
- )
84
- assert result["success"] is True
85
-
86
- def test_report_with_action_type(self):
87
- """Custom action_type should be accepted."""
88
- import mcp_tools_v28 as tools
89
- tools.DEFAULT_LEARNING_DB = self.db_path
90
-
91
- result = self._run(
92
- tools.report_outcome(
93
- [1, 2, 3], "success", action_type="code_written"
94
- )
95
- )
96
- assert result["success"] is True
97
-
98
- def test_report_with_agent_and_project(self):
99
- """agent_id and project parameters should be forwarded."""
100
- import mcp_tools_v28 as tools
101
- tools.DEFAULT_LEARNING_DB = self.db_path
102
-
103
- result = self._run(
104
- tools.report_outcome(
105
- [1], "success", agent_id="agent_a", project="slm-v28"
106
- )
107
- )
108
- assert result["success"] is True
109
-
110
- def test_multiple_outcomes_unique_ids(self):
111
- """Consecutive outcomes should get distinct IDs."""
112
- import mcp_tools_v28 as tools
113
- tools.DEFAULT_LEARNING_DB = self.db_path
114
-
115
- r1 = self._run(tools.report_outcome([1], "success"))
116
- r2 = self._run(tools.report_outcome([2], "failure"))
117
- assert r1["outcome_id"] != r2["outcome_id"]
@@ -1,107 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for implicit outcome inference from recall behavior patterns.
4
- """
5
- import sys
6
- from pathlib import Path
7
- from datetime import datetime, timedelta
8
-
9
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
10
-
11
-
12
- class TestOutcomeInference:
13
- """Test inference rules for implicit outcome detection."""
14
-
15
- def test_no_requery_implies_success(self):
16
- """No re-query for 10+ min after recall -> success (0.6)."""
17
- from behavioral.outcome_inference import OutcomeInference
18
- engine = OutcomeInference()
19
- now = datetime.now()
20
- # Record a recall event
21
- engine.record_recall("query_abc", [1, 2], now - timedelta(minutes=12))
22
- # Infer outcomes after enough time has passed
23
- results = engine.infer_outcomes(now)
24
- assert len(results) >= 1
25
- result = results[0]
26
- assert result["outcome"] == "success"
27
- assert abs(result["confidence"] - 0.6) < 0.01
28
-
29
- def test_memory_used_high_confirms_success(self):
30
- """memory_used(high) within 5 min -> confirmed success (0.8)."""
31
- from behavioral.outcome_inference import OutcomeInference
32
- engine = OutcomeInference()
33
- now = datetime.now()
34
- engine.record_recall("query_abc", [1], now - timedelta(minutes=3))
35
- engine.record_usage("query_abc", signal="mcp_used_high", timestamp=now - timedelta(minutes=1))
36
- results = engine.infer_outcomes(now)
37
- success_results = [r for r in results if r["outcome"] == "success"]
38
- assert len(success_results) >= 1
39
- assert success_results[0]["confidence"] >= 0.8
40
-
41
- def test_immediate_requery_implies_failure(self):
42
- """Immediate re-query with different terms -> failure (0.2)."""
43
- from behavioral.outcome_inference import OutcomeInference
44
- engine = OutcomeInference()
45
- now = datetime.now()
46
- engine.record_recall("query_abc", [1], now - timedelta(minutes=1))
47
- engine.record_recall("different_query", [3], now - timedelta(seconds=30))
48
- results = engine.infer_outcomes(now)
49
- failure_results = [r for r in results if r["outcome"] == "failure"]
50
- assert len(failure_results) >= 1
51
- assert failure_results[0]["confidence"] <= 0.3
52
-
53
- def test_memory_deleted_implies_failure(self):
54
- """Memory deleted within 1 hour -> failure (0.0)."""
55
- from behavioral.outcome_inference import OutcomeInference
56
- engine = OutcomeInference()
57
- now = datetime.now()
58
- engine.record_recall("query_abc", [1], now - timedelta(minutes=30))
59
- engine.record_deletion(memory_id=1, timestamp=now - timedelta(minutes=5))
60
- results = engine.infer_outcomes(now)
61
- failure_results = [r for r in results if r["outcome"] == "failure" and 1 in r["memory_ids"]]
62
- assert len(failure_results) >= 1
63
- assert failure_results[0]["confidence"] <= 0.05
64
-
65
- def test_rapid_fire_queries_implies_failure(self):
66
- """3+ queries in 2 min -> failure (0.1)."""
67
- from behavioral.outcome_inference import OutcomeInference
68
- engine = OutcomeInference()
69
- now = datetime.now()
70
- engine.record_recall("q1", [1], now - timedelta(seconds=90))
71
- engine.record_recall("q2", [2], now - timedelta(seconds=60))
72
- engine.record_recall("q3", [3], now - timedelta(seconds=30))
73
- results = engine.infer_outcomes(now)
74
- # At least some should be failure due to rapid-fire pattern
75
- failure_results = [r for r in results if r["outcome"] == "failure"]
76
- assert len(failure_results) >= 1
77
-
78
- def test_cross_tool_access_implies_success(self):
79
- """Cross-tool access after recall -> success (0.7)."""
80
- from behavioral.outcome_inference import OutcomeInference
81
- engine = OutcomeInference()
82
- now = datetime.now()
83
- engine.record_recall("query_abc", [1], now - timedelta(minutes=3))
84
- engine.record_usage("query_abc", signal="implicit_positive_cross_tool", timestamp=now - timedelta(minutes=1))
85
- results = engine.infer_outcomes(now)
86
- success_results = [r for r in results if r["outcome"] == "success"]
87
- assert len(success_results) >= 1
88
- assert success_results[0]["confidence"] >= 0.7
89
-
90
- def test_empty_buffer_returns_empty(self):
91
- """No recorded events -> no inferences."""
92
- from behavioral.outcome_inference import OutcomeInference
93
- engine = OutcomeInference()
94
- results = engine.infer_outcomes(datetime.now())
95
- assert results == []
96
-
97
- def test_infer_clears_processed_events(self):
98
- """After inference, processed events are cleared from buffer."""
99
- from behavioral.outcome_inference import OutcomeInference
100
- engine = OutcomeInference()
101
- now = datetime.now()
102
- engine.record_recall("q1", [1], now - timedelta(minutes=12))
103
- results1 = engine.infer_outcomes(now)
104
- assert len(results1) >= 1
105
- # Second call should have nothing new
106
- results2 = engine.infer_outcomes(now)
107
- assert len(results2) == 0
@@ -1,96 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for explicit action outcome recording.
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 TestOutcomeTracker:
16
- """Test outcome recording and querying."""
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
-
22
- def teardown_method(self):
23
- import shutil
24
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
25
-
26
- def test_record_success(self):
27
- from behavioral.outcome_tracker import OutcomeTracker
28
- tracker = OutcomeTracker(self.db_path)
29
- oid = tracker.record_outcome([1, 2], "success", action_type="code_written")
30
- assert isinstance(oid, int)
31
- assert oid > 0
32
-
33
- def test_record_failure(self):
34
- from behavioral.outcome_tracker import OutcomeTracker
35
- tracker = OutcomeTracker(self.db_path)
36
- oid = tracker.record_outcome([3], "failure", context={"error": "timeout"})
37
- assert oid > 0
38
-
39
- def test_record_partial(self):
40
- from behavioral.outcome_tracker import OutcomeTracker
41
- tracker = OutcomeTracker(self.db_path)
42
- oid = tracker.record_outcome([1], "partial", action_type="debug_resolved")
43
- assert oid > 0
44
-
45
- def test_confidence_for_explicit(self):
46
- """Explicit outcomes should have confidence >= 0.8."""
47
- from behavioral.outcome_tracker import OutcomeTracker
48
- tracker = OutcomeTracker(self.db_path)
49
- tracker.record_outcome([1], "success")
50
- outcomes = tracker.get_outcomes()
51
- assert outcomes[0]["confidence"] >= 0.8
52
-
53
- def test_multiple_memory_ids(self):
54
- from behavioral.outcome_tracker import OutcomeTracker
55
- tracker = OutcomeTracker(self.db_path)
56
- tracker.record_outcome([1, 2, 3], "success")
57
- outcomes = tracker.get_outcomes()
58
- assert len(outcomes[0]["memory_ids"]) == 3
59
-
60
- def test_get_outcomes_by_memory(self):
61
- from behavioral.outcome_tracker import OutcomeTracker
62
- tracker = OutcomeTracker(self.db_path)
63
- tracker.record_outcome([1, 2], "success")
64
- tracker.record_outcome([3], "failure")
65
- results = tracker.get_outcomes(memory_id=1)
66
- assert len(results) == 1
67
-
68
- def test_get_outcomes_by_project(self):
69
- from behavioral.outcome_tracker import OutcomeTracker
70
- tracker = OutcomeTracker(self.db_path)
71
- tracker.record_outcome([1], "success", project="proj_a")
72
- tracker.record_outcome([2], "failure", project="proj_b")
73
- results = tracker.get_outcomes(project="proj_a")
74
- assert len(results) == 1
75
-
76
- def test_get_success_rate(self):
77
- from behavioral.outcome_tracker import OutcomeTracker
78
- tracker = OutcomeTracker(self.db_path)
79
- tracker.record_outcome([1], "success")
80
- tracker.record_outcome([1], "success")
81
- tracker.record_outcome([1], "failure")
82
- rate = tracker.get_success_rate(1)
83
- assert abs(rate - 0.667) < 0.01 # 2/3
84
-
85
- def test_success_rate_no_outcomes(self):
86
- from behavioral.outcome_tracker import OutcomeTracker
87
- tracker = OutcomeTracker(self.db_path)
88
- rate = tracker.get_success_rate(999)
89
- assert rate == 0.0
90
-
91
- def test_valid_outcomes_only(self):
92
- """Only success, failure, partial are valid outcomes."""
93
- from behavioral.outcome_tracker import OutcomeTracker
94
- tracker = OutcomeTracker(self.db_path)
95
- result = tracker.record_outcome([1], "invalid_outcome")
96
- assert result is None # Rejected