superlocalmemory 3.6.23 → 3.7.1

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 (285) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +271 -71
  3. package/bin/slm-npm +43 -89
  4. package/ide/configs/antigravity-mcp.json +2 -2
  5. package/ide/configs/chatgpt-desktop-mcp.json +1 -1
  6. package/ide/configs/claude-desktop-mcp.json +2 -2
  7. package/ide/configs/windsurf-mcp.json +2 -2
  8. package/ide/hooks/context-hook.js +6 -2
  9. package/ide/hooks/post-recall-hook.js +7 -3
  10. package/ide/hooks/tool-event-hook.sh +2 -1
  11. package/package.json +17 -9
  12. package/plugin/.claude-plugin/plugin.json +1 -1
  13. package/plugin/_GENERATED.md +1 -1
  14. package/plugin/agents/slm-memory-advisor.md +1 -1
  15. package/plugin/requirements.txt +1 -1
  16. package/plugin/skills/slm-session/SKILL.md +1 -1
  17. package/plugin-src/agents/slm-memory-advisor.md +1 -1
  18. package/plugin-src/manifest.json +1 -1
  19. package/plugin-src/requirements.txt +1 -1
  20. package/plugin-src/rules/AGENTS.md +1 -1
  21. package/plugin-src/skills/slm-session/SKILL.md +1 -1
  22. package/pyproject.toml +40 -8
  23. package/scripts/postinstall-interactive.js +17 -94
  24. package/scripts/postinstall.js +185 -258
  25. package/scripts/preuninstall.js +9 -50
  26. package/src/superlocalmemory/__init__.py +2 -2
  27. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  28. package/src/superlocalmemory/attribution/signer.py +34 -19
  29. package/src/superlocalmemory/attribution/watermark.py +1 -1
  30. package/src/superlocalmemory/cli/_lazy_init.py +7 -7
  31. package/src/superlocalmemory/cli/commands.py +453 -191
  32. package/src/superlocalmemory/cli/context_commands.py +5 -4
  33. package/src/superlocalmemory/cli/daemon.py +282 -187
  34. package/src/superlocalmemory/cli/db_migrate.py +3 -1
  35. package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
  36. package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
  37. package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
  38. package/src/superlocalmemory/cli/main.py +128 -31
  39. package/src/superlocalmemory/cli/pending_store.py +54 -38
  40. package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
  41. package/src/superlocalmemory/cli/service_installer.py +57 -52
  42. package/src/superlocalmemory/cli/setup_wizard.py +142 -88
  43. package/src/superlocalmemory/cli/version_banner.py +2 -1
  44. package/src/superlocalmemory/code_graph/config.py +3 -1
  45. package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
  46. package/src/superlocalmemory/core/config.py +65 -20
  47. package/src/superlocalmemory/core/consolidation_engine.py +9 -7
  48. package/src/superlocalmemory/core/context_cache.py +56 -8
  49. package/src/superlocalmemory/core/derivation_lineage.py +246 -0
  50. package/src/superlocalmemory/core/embedding_worker.py +32 -20
  51. package/src/superlocalmemory/core/embeddings.py +54 -18
  52. package/src/superlocalmemory/core/engine.py +150 -104
  53. package/src/superlocalmemory/core/engine_ingestion.py +513 -0
  54. package/src/superlocalmemory/core/engine_wiring.py +32 -23
  55. package/src/superlocalmemory/core/evidence_bundle.py +526 -0
  56. package/src/superlocalmemory/core/fact_consolidator.py +5 -11
  57. package/src/superlocalmemory/core/graph_analyzer.py +2 -2
  58. package/src/superlocalmemory/core/health_monitor.py +4 -2
  59. package/src/superlocalmemory/core/ingestion_command.py +636 -0
  60. package/src/superlocalmemory/core/injection.py +69 -18
  61. package/src/superlocalmemory/core/lifecycle_state.py +153 -0
  62. package/src/superlocalmemory/core/maintenance.py +1 -1
  63. package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
  64. package/src/superlocalmemory/core/mutations.py +143 -0
  65. package/src/superlocalmemory/core/platform_utils.py +7 -4
  66. package/src/superlocalmemory/core/ram_lock.py +16 -5
  67. package/src/superlocalmemory/core/rate_limit.py +1 -1
  68. package/src/superlocalmemory/core/recall_pipeline.py +60 -101
  69. package/src/superlocalmemory/core/recall_worker.py +76 -59
  70. package/src/superlocalmemory/core/registry.py +1 -1
  71. package/src/superlocalmemory/core/scale_engine.py +293 -0
  72. package/src/superlocalmemory/core/score_contract.py +62 -0
  73. package/src/superlocalmemory/core/security_primitives.py +3 -1
  74. package/src/superlocalmemory/core/slm_disabled.py +3 -5
  75. package/src/superlocalmemory/core/store_pipeline.py +172 -40
  76. package/src/superlocalmemory/core/tier_manager.py +32 -20
  77. package/src/superlocalmemory/core/worker_pool.py +13 -4
  78. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  79. package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
  80. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  81. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  82. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  83. package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
  84. package/src/superlocalmemory/encoding/consolidator.py +22 -5
  85. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  86. package/src/superlocalmemory/encoding/foresight.py +2 -0
  87. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  88. package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
  89. package/src/superlocalmemory/evaluation/__init__.py +13 -0
  90. package/src/superlocalmemory/evaluation/calibration.py +308 -0
  91. package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
  92. package/src/superlocalmemory/graph/cozo_backend.py +256 -23
  93. package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
  94. package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
  95. package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
  96. package/src/superlocalmemory/hooks/auto_recall.py +31 -6
  97. package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
  98. package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
  99. package/src/superlocalmemory/hooks/claude_code_hooks.py +123 -35
  100. package/src/superlocalmemory/hooks/codex_assets.py +59 -0
  101. package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
  102. package/src/superlocalmemory/hooks/context_payload.py +1 -1
  103. package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
  104. package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
  105. package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
  106. package/src/superlocalmemory/hooks/hook_handlers.py +219 -32
  107. package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
  108. package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
  109. package/src/superlocalmemory/hooks/session_registry.py +15 -8
  110. package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
  111. package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
  112. package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
  113. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
  114. package/src/superlocalmemory/infra/auth_middleware.py +38 -5
  115. package/src/superlocalmemory/infra/backup.py +7 -5
  116. package/src/superlocalmemory/infra/cloud_backup.py +18 -8
  117. package/src/superlocalmemory/infra/daemon_identity.py +248 -0
  118. package/src/superlocalmemory/infra/data_root.py +199 -0
  119. package/src/superlocalmemory/infra/event_bus.py +3 -1
  120. package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
  121. package/src/superlocalmemory/infra/process_reaper.py +23 -0
  122. package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
  123. package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
  124. package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
  125. package/src/superlocalmemory/ingestion/credentials.py +14 -7
  126. package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
  127. package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
  128. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  129. package/src/superlocalmemory/learning/ensemble.py +11 -0
  130. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  131. package/src/superlocalmemory/learning/feedback.py +1 -1
  132. package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
  133. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  134. package/src/superlocalmemory/learning/ranker.py +4 -1
  135. package/src/superlocalmemory/learning/source_quality.py +1 -1
  136. package/src/superlocalmemory/learning/trigram_index.py +3 -2
  137. package/src/superlocalmemory/llm/backbone.py +1 -1
  138. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  139. package/src/superlocalmemory/math/fisher.py +1 -1
  140. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  141. package/src/superlocalmemory/math/hopfield.py +1 -1
  142. package/src/superlocalmemory/math/langevin.py +1 -1
  143. package/src/superlocalmemory/math/polar_quant.py +3 -4
  144. package/src/superlocalmemory/math/qjl.py +1 -1
  145. package/src/superlocalmemory/math/sheaf.py +1 -1
  146. package/src/superlocalmemory/math/turbo_quant.py +3 -2
  147. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
  148. package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
  149. package/src/superlocalmemory/mcp/http_transport.py +53 -0
  150. package/src/superlocalmemory/mcp/server.py +39 -13
  151. package/src/superlocalmemory/mcp/shared.py +69 -3
  152. package/src/superlocalmemory/mcp/tools_active.py +141 -31
  153. package/src/superlocalmemory/mcp/tools_core.py +130 -31
  154. package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
  155. package/src/superlocalmemory/mcp/tools_learning.py +42 -2
  156. package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
  157. package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
  158. package/src/superlocalmemory/mcp/tools_v28.py +23 -2
  159. package/src/superlocalmemory/mcp/tools_v3.py +26 -1
  160. package/src/superlocalmemory/mcp/tools_v33.py +56 -17
  161. package/src/superlocalmemory/mesh/broker.py +2 -0
  162. package/src/superlocalmemory/mesh/remote_sync.py +50 -12
  163. package/src/superlocalmemory/optimize/cache/manager.py +77 -1
  164. package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
  165. package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
  166. package/src/superlocalmemory/optimize/compress/router.py +6 -1
  167. package/src/superlocalmemory/optimize/config/__init__.py +5 -0
  168. package/src/superlocalmemory/optimize/config/store.py +6 -4
  169. package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
  170. package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
  171. package/src/superlocalmemory/optimize/proxy/server.py +2 -2
  172. package/src/superlocalmemory/optimize/storage/db.py +12 -12
  173. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  174. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  175. package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
  176. package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
  177. package/src/superlocalmemory/retrieval/engine.py +169 -79
  178. package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
  179. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  180. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  181. package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
  182. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  183. package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
  184. package/src/superlocalmemory/retrieval/reranker.py +56 -20
  185. package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
  186. package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
  187. package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
  188. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  189. package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
  190. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  191. package/src/superlocalmemory/server/api.py +10 -7
  192. package/src/superlocalmemory/server/bandit_loops.py +4 -2
  193. package/src/superlocalmemory/server/recall_serializer.py +24 -0
  194. package/src/superlocalmemory/server/route_mutations.py +84 -0
  195. package/src/superlocalmemory/server/routes/agents.py +8 -6
  196. package/src/superlocalmemory/server/routes/brain.py +14 -12
  197. package/src/superlocalmemory/server/routes/chat.py +29 -12
  198. package/src/superlocalmemory/server/routes/data_io.py +55 -24
  199. package/src/superlocalmemory/server/routes/helpers.py +8 -63
  200. package/src/superlocalmemory/server/routes/ingest.py +53 -36
  201. package/src/superlocalmemory/server/routes/memories.py +104 -43
  202. package/src/superlocalmemory/server/routes/mesh.py +31 -0
  203. package/src/superlocalmemory/server/routes/profiles.py +26 -4
  204. package/src/superlocalmemory/server/routes/tiers.py +43 -11
  205. package/src/superlocalmemory/server/routes/timeline.py +5 -1
  206. package/src/superlocalmemory/server/routes/v3_api.py +76 -21
  207. package/src/superlocalmemory/server/security_middleware.py +1 -1
  208. package/src/superlocalmemory/server/unified_daemon.py +680 -293
  209. package/src/superlocalmemory/server/write_identity.py +147 -0
  210. package/src/superlocalmemory/storage/access_log.py +4 -3
  211. package/src/superlocalmemory/storage/database.py +118 -25
  212. package/src/superlocalmemory/storage/migration_runner.py +84 -1
  213. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  214. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
  215. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
  216. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
  217. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
  218. package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
  219. package/src/superlocalmemory/storage/models.py +16 -0
  220. package/src/superlocalmemory/storage/quantized_store.py +20 -3
  221. package/src/superlocalmemory/storage/v2_migrator.py +5 -3
  222. package/src/superlocalmemory/ui/favicon.svg +5 -0
  223. package/src/superlocalmemory/ui/index.html +1 -0
  224. package/src/superlocalmemory/ui/js/compliance.js +1 -1
  225. package/src/superlocalmemory/ui/js/core.js +49 -8
  226. package/src/superlocalmemory/ui/js/dashboard.js +23 -2
  227. package/src/superlocalmemory/ui/js/feedback.js +1 -1
  228. package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
  229. package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
  230. package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
  231. package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
  232. package/src/superlocalmemory/ui/js/settings.js +4 -2
  233. package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
  234. package/bin/slm +0 -59
  235. package/bin/slm.bat +0 -77
  236. package/bin/slm.cmd +0 -5
  237. package/ide/integrations/langchain/README.md +0 -106
  238. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
  239. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
  240. package/ide/integrations/langchain/pyproject.toml +0 -38
  241. package/ide/integrations/langchain/tests/__init__.py +0 -3
  242. package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
  243. package/ide/integrations/langchain/tests/test_security.py +0 -117
  244. package/ide/integrations/llamaindex/README.md +0 -81
  245. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
  246. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
  247. package/ide/integrations/llamaindex/pyproject.toml +0 -43
  248. package/ide/integrations/llamaindex/tests/__init__.py +0 -3
  249. package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
  250. package/ide/integrations/llamaindex/tests/test_security.py +0 -241
  251. package/scripts/__tests__/build-plugin.test.mjs +0 -613
  252. package/scripts/_savings_math.py +0 -270
  253. package/scripts/build-dmg.sh +0 -417
  254. package/scripts/build-plugin.js +0 -742
  255. package/scripts/build-slm-hook.ps1 +0 -40
  256. package/scripts/build-slm-hook.sh +0 -45
  257. package/scripts/build_entry.py +0 -452
  258. package/scripts/ci/stage5b_gate.sh +0 -50
  259. package/scripts/dogfood_savings.py +0 -490
  260. package/scripts/generate-thumbnails.py +0 -218
  261. package/scripts/install-skills.ps1 +0 -4
  262. package/scripts/install-skills.sh +0 -5
  263. package/scripts/install.ps1 +0 -701
  264. package/scripts/install.sh +0 -1015
  265. package/scripts/postinstall_binary.js +0 -287
  266. package/scripts/prepack.js +0 -33
  267. package/scripts/release_manifest.py +0 -273
  268. package/scripts/slm-hook.spec +0 -56
  269. package/scripts/start-dashboard.ps1 +0 -52
  270. package/scripts/start-dashboard.sh +0 -41
  271. package/scripts/sync-wiki.ps1 +0 -127
  272. package/scripts/sync-wiki.sh +0 -82
  273. package/scripts/test-dmg.sh +0 -161
  274. package/scripts/test-npm-package.ps1 +0 -252
  275. package/scripts/test-npm-package.sh +0 -207
  276. package/scripts/verify-install.ps1 +0 -294
  277. package/scripts/verify-install.sh +0 -266
  278. package/scripts/verify-v27.ps1 +0 -301
  279. package/scripts/verify-v27.sh +0 -233
  280. package/src/superlocalmemory.egg-info/PKG-INFO +0 -516
  281. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
  282. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  283. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  284. package/src/superlocalmemory.egg-info/requires.txt +0 -71
  285. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -1,215 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """SuperLocalMemory V2 - LangChain Chat Message History Tests
5
-
6
- Functional tests for SuperLocalMemoryChatMessageHistory.
7
- All tests use a temporary database -- the user's real memory is never touched.
8
- """
9
- import os
10
- import tempfile
11
-
12
- import pytest
13
- from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
14
-
15
- from langchain_superlocalmemory import SuperLocalMemoryChatMessageHistory
16
-
17
-
18
- # ---------------------------------------------------------------------------
19
- # Fixtures
20
- # ---------------------------------------------------------------------------
21
-
22
-
23
- @pytest.fixture
24
- def tmp_db():
25
- """Yield a path to a temporary SQLite database that is cleaned up after use."""
26
- with tempfile.TemporaryDirectory() as d:
27
- db = os.path.join(d, "test_memory.db")
28
- yield db
29
-
30
-
31
- @pytest.fixture
32
- def history(tmp_db):
33
- """Return a fresh history instance bound to the temp DB."""
34
- return SuperLocalMemoryChatMessageHistory(session_id="test-session", db_path=tmp_db)
35
-
36
-
37
- # ---------------------------------------------------------------------------
38
- # Tests
39
- # ---------------------------------------------------------------------------
40
-
41
-
42
- def test_add_single_human_message(tmp_db):
43
- """A single HumanMessage can be added and retrieved."""
44
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
45
- h.add_messages([HumanMessage(content="Hello, world!")])
46
-
47
- msgs = h.messages
48
- assert len(msgs) == 1
49
- assert isinstance(msgs[0], HumanMessage)
50
- assert msgs[0].content == "Hello, world!"
51
-
52
-
53
- def test_add_single_ai_message(tmp_db):
54
- """A single AIMessage can be added and retrieved."""
55
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
56
- h.add_messages([AIMessage(content="I am an AI.")])
57
-
58
- msgs = h.messages
59
- assert len(msgs) == 1
60
- assert isinstance(msgs[0], AIMessage)
61
- assert msgs[0].content == "I am an AI."
62
-
63
-
64
- def test_add_multiple_messages(tmp_db):
65
- """A batch of three messages is stored and all are retrievable."""
66
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
67
- h.add_messages([
68
- HumanMessage(content="Hi"),
69
- AIMessage(content="Hello"),
70
- HumanMessage(content="How are you?"),
71
- ])
72
-
73
- msgs = h.messages
74
- assert len(msgs) == 3
75
- assert msgs[0].content == "Hi"
76
- assert msgs[1].content == "Hello"
77
- assert msgs[2].content == "How are you?"
78
-
79
-
80
- def test_messages_order(tmp_db):
81
- """Messages are returned in chronological (insertion) order."""
82
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
83
-
84
- h.add_messages([HumanMessage(content="first")])
85
- h.add_messages([AIMessage(content="second")])
86
- h.add_messages([HumanMessage(content="third")])
87
-
88
- msgs = h.messages
89
- assert [m.content for m in msgs] == ["first", "second", "third"]
90
-
91
-
92
- def test_message_roundtrip(tmp_db):
93
- """A HumanMessage with additional_kwargs survives serialization."""
94
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
95
-
96
- original = HumanMessage(
97
- content="Test with kwargs",
98
- additional_kwargs={"custom_key": "custom_value", "number": 42},
99
- )
100
- h.add_messages([original])
101
-
102
- msgs = h.messages
103
- assert len(msgs) == 1
104
- assert msgs[0].content == "Test with kwargs"
105
- assert msgs[0].additional_kwargs.get("custom_key") == "custom_value"
106
- assert msgs[0].additional_kwargs.get("number") == 42
107
-
108
-
109
- def test_system_message(tmp_db):
110
- """A SystemMessage round-trips correctly."""
111
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
112
- h.add_messages([SystemMessage(content="You are a helpful assistant.")])
113
-
114
- msgs = h.messages
115
- assert len(msgs) == 1
116
- assert isinstance(msgs[0], SystemMessage)
117
- assert msgs[0].content == "You are a helpful assistant."
118
-
119
-
120
- def test_clear(tmp_db):
121
- """clear() removes all messages from the session."""
122
- h = SuperLocalMemoryChatMessageHistory(session_id="s1", db_path=tmp_db)
123
- h.add_messages([
124
- HumanMessage(content="A"),
125
- AIMessage(content="B"),
126
- ])
127
-
128
- assert len(h.messages) == 2
129
- h.clear()
130
- assert len(h.messages) == 0
131
-
132
-
133
- def test_clear_only_affects_session(tmp_db):
134
- """Clearing session A does not affect session B."""
135
- ha = SuperLocalMemoryChatMessageHistory(session_id="session-a", db_path=tmp_db)
136
- hb = SuperLocalMemoryChatMessageHistory(session_id="session-b", db_path=tmp_db)
137
-
138
- ha.add_messages([HumanMessage(content="Message in A")])
139
- hb.add_messages([HumanMessage(content="Message in B")])
140
-
141
- ha.clear()
142
-
143
- assert len(ha.messages) == 0
144
- assert len(hb.messages) == 1
145
- assert hb.messages[0].content == "Message in B"
146
-
147
-
148
- def test_session_isolation(tmp_db):
149
- """Two sessions with the same DB path do not see each other's messages."""
150
- ha = SuperLocalMemoryChatMessageHistory(session_id="alpha", db_path=tmp_db)
151
- hb = SuperLocalMemoryChatMessageHistory(session_id="beta", db_path=tmp_db)
152
-
153
- ha.add_messages([HumanMessage(content="Alpha message")])
154
- hb.add_messages([HumanMessage(content="Beta message")])
155
-
156
- assert len(ha.messages) == 1
157
- assert ha.messages[0].content == "Alpha message"
158
-
159
- assert len(hb.messages) == 1
160
- assert hb.messages[0].content == "Beta message"
161
-
162
-
163
- def test_empty_session(tmp_db):
164
- """A brand-new session returns an empty list."""
165
- h = SuperLocalMemoryChatMessageHistory(session_id="empty", db_path=tmp_db)
166
- assert h.messages == []
167
-
168
-
169
- def test_persistence_across_instances(tmp_db):
170
- """Messages persist when a new Python instance is created with the same session_id."""
171
- h1 = SuperLocalMemoryChatMessageHistory(session_id="persist", db_path=tmp_db)
172
- h1.add_messages([HumanMessage(content="Persisted message")])
173
-
174
- # Create a completely new instance pointing at the same DB + session.
175
- h2 = SuperLocalMemoryChatMessageHistory(session_id="persist", db_path=tmp_db)
176
- msgs = h2.messages
177
- assert len(msgs) == 1
178
- assert msgs[0].content == "Persisted message"
179
-
180
-
181
- def test_unicode_content(tmp_db):
182
- """Unicode and emoji content round-trips correctly."""
183
- h = SuperLocalMemoryChatMessageHistory(session_id="unicode", db_path=tmp_db)
184
- text = "Bonjour le monde! Hola mundo! Konnichiwa sekai!"
185
- h.add_messages([HumanMessage(content=text)])
186
-
187
- msgs = h.messages
188
- assert len(msgs) == 1
189
- assert msgs[0].content == text
190
-
191
-
192
- def test_long_content(tmp_db):
193
- """A 10K character message is stored and retrieved intact."""
194
- h = SuperLocalMemoryChatMessageHistory(session_id="long", db_path=tmp_db)
195
- long_text = "A" * 10_000
196
- h.add_messages([HumanMessage(content=long_text)])
197
-
198
- msgs = h.messages
199
- assert len(msgs) == 1
200
- assert len(msgs[0].content) == 10_000
201
- assert msgs[0].content == long_text
202
-
203
-
204
- def test_special_chars_session_id(tmp_db):
205
- """Session IDs with dots, dashes, and underscores work correctly."""
206
- for sid in ["my.session.123", "my-session-456", "my_session_789", "a.b-c_d"]:
207
- h = SuperLocalMemoryChatMessageHistory(session_id=sid, db_path=tmp_db)
208
- h.add_messages([HumanMessage(content=f"msg for {sid}")])
209
-
210
- msgs = h.messages
211
- assert len(msgs) == 1, f"Failed for session_id={sid}"
212
- assert msgs[0].content == f"msg for {sid}"
213
-
214
- h.clear()
215
- assert len(h.messages) == 0, f"clear() failed for session_id={sid}"
@@ -1,117 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- """SuperLocalMemory V2 - LangChain Integration Security Tests
5
-
6
- Security tests covering SQL injection, XSS payloads, oversized content,
7
- and edge-case session identifiers. These mirror OWASP agentic-AI concerns
8
- relevant to a local-first memory store.
9
- """
10
- import os
11
- import tempfile
12
-
13
- import pytest
14
- from langchain_core.messages import HumanMessage
15
-
16
- from langchain_superlocalmemory import SuperLocalMemoryChatMessageHistory
17
-
18
-
19
- @pytest.fixture
20
- def tmp_db():
21
- """Yield a path to a temporary SQLite database that is cleaned up after use."""
22
- with tempfile.TemporaryDirectory() as d:
23
- db = os.path.join(d, "test_memory.db")
24
- yield db
25
-
26
-
27
- # ---------------------------------------------------------------------------
28
- # SQL injection
29
- # ---------------------------------------------------------------------------
30
-
31
-
32
- def test_sql_injection_session_id(tmp_db):
33
- """SQL injection in session_id should not work."""
34
- history = SuperLocalMemoryChatMessageHistory(
35
- session_id="'; DROP TABLE memories; --", db_path=tmp_db
36
- )
37
- history.add_messages([HumanMessage(content="test")])
38
- assert len(history.messages) == 1 # Should work normally, not crash
39
-
40
-
41
- def test_sql_injection_content(tmp_db):
42
- """SQL injection in message content is safely stored and retrieved."""
43
- history = SuperLocalMemoryChatMessageHistory(session_id="test", db_path=tmp_db)
44
- payload = "'; DROP TABLE memories; --"
45
- history.add_messages([HumanMessage(content=payload)])
46
-
47
- msgs = history.messages
48
- assert len(msgs) == 1
49
- assert msgs[0].content == payload
50
-
51
-
52
- # ---------------------------------------------------------------------------
53
- # XSS
54
- # ---------------------------------------------------------------------------
55
-
56
-
57
- def test_xss_content(tmp_db):
58
- """XSS payloads are stored verbatim (no sanitization needed for storage)."""
59
- history = SuperLocalMemoryChatMessageHistory(session_id="test", db_path=tmp_db)
60
- payload = "<script>alert('xss')</script>"
61
- history.add_messages([HumanMessage(content=payload)])
62
-
63
- msgs = history.messages
64
- assert len(msgs) == 1
65
- assert "<script>" in msgs[0].content
66
-
67
-
68
- # ---------------------------------------------------------------------------
69
- # Size limits
70
- # ---------------------------------------------------------------------------
71
-
72
-
73
- def test_large_content(tmp_db):
74
- """A large message (near the SLM 1 MB limit) is stored and retrieved intact.
75
-
76
- MemoryStoreV2 enforces MAX_CONTENT_SIZE = 1_000_000 on the *stored*
77
- string, which is the JSON-serialized message (not the raw text). The
78
- JSON envelope adds ~150 bytes of overhead, so we use 999_000 chars to
79
- stay safely under the limit.
80
- """
81
- history = SuperLocalMemoryChatMessageHistory(session_id="test", db_path=tmp_db)
82
- big_msg = "x" * 999_000
83
- history.add_messages([HumanMessage(content=big_msg)])
84
-
85
- msgs = history.messages
86
- assert len(msgs) == 1
87
- assert len(msgs[0].content) == 999_000
88
-
89
-
90
- def test_oversized_content_raises(tmp_db):
91
- """Content that exceeds SLM's 1 MB limit after serialization raises ValueError."""
92
- history = SuperLocalMemoryChatMessageHistory(session_id="test", db_path=tmp_db)
93
- # 1_000_000 chars + JSON overhead will exceed the 1 MB limit.
94
- big_msg = "x" * 1_000_000
95
- with pytest.raises(ValueError, match="exceeds maximum size"):
96
- history.add_messages([HumanMessage(content=big_msg)])
97
-
98
-
99
- # ---------------------------------------------------------------------------
100
- # Edge-case session IDs
101
- # ---------------------------------------------------------------------------
102
-
103
-
104
- def test_empty_session_id(tmp_db):
105
- """An empty string session_id still functions correctly."""
106
- history = SuperLocalMemoryChatMessageHistory(session_id="", db_path=tmp_db)
107
- history.add_messages([HumanMessage(content="test")])
108
- assert len(history.messages) == 1
109
-
110
-
111
- def test_null_bytes_session_id(tmp_db):
112
- """Null bytes in session_id do not cause crashes."""
113
- history = SuperLocalMemoryChatMessageHistory(
114
- session_id="test\x00evil", db_path=tmp_db
115
- )
116
- history.add_messages([HumanMessage(content="test")])
117
- assert len(history.messages) == 1
@@ -1,81 +0,0 @@
1
- # LlamaIndex Chat Store — SuperLocalMemory V2
2
-
3
- A LlamaIndex `BaseChatStore` implementation backed by [SuperLocalMemory V2](https://github.com/qualixar/superlocalmemory). All chat history stays **100% local** on your machine — zero cloud calls, zero telemetry, zero API keys.
4
-
5
- ## Prerequisites
6
-
7
- - Python 3.9+
8
- - SuperLocalMemory V2 installed (`~/.superlocalmemory/` must exist)
9
-
10
- ```bash
11
- # Install SuperLocalMemory V2 (one-time)
12
- curl -fsSL https://raw.githubusercontent.com/qualixar/superlocalmemory/main/install.sh | bash
13
- ```
14
-
15
- ## Installation
16
-
17
- ```bash
18
- pip install llama-index-storage-chat-store-superlocalmemory
19
- ```
20
-
21
- ## Quick Start
22
-
23
- ```python
24
- from llama_index.core.memory import ChatMemoryBuffer
25
- from llama_index.core.base.llms.types import ChatMessage, MessageRole
26
- from llama_index.storage.chat_store.superlocalmemory import SuperLocalMemoryChatStore
27
-
28
- # Create the chat store (uses default SLM database)
29
- chat_store = SuperLocalMemoryChatStore()
30
-
31
- # Use with ChatMemoryBuffer for automatic conversation management
32
- memory = ChatMemoryBuffer.from_defaults(
33
- chat_store=chat_store,
34
- chat_store_key="user-123",
35
- token_limit=3000,
36
- )
37
-
38
- # Or use directly for manual message management
39
- chat_store.add_message("session-1", ChatMessage(role=MessageRole.USER, content="Hello!"))
40
- chat_store.add_message("session-1", ChatMessage(role=MessageRole.ASSISTANT, content="Hi there!"))
41
-
42
- messages = chat_store.get_messages("session-1")
43
- print(messages) # [ChatMessage(role=user, content="Hello!"), ChatMessage(role=assistant, content="Hi there!")]
44
-
45
- # List all session keys
46
- keys = chat_store.get_keys()
47
-
48
- # Delete a session
49
- chat_store.delete_messages("session-1")
50
- ```
51
-
52
- ## Features
53
-
54
- - **100% Local** — All data stored in SQLite at `~/.superlocalmemory/memory.db`
55
- - **Zero Cloud** — No API keys, no subscriptions, no data leaves your machine
56
- - **Shared Memory** — Chat history is accessible from Claude, Cursor, Windsurf, and 16+ other AI tools via SuperLocalMemory
57
- - **Session Isolation** — Each chat key is cleanly isolated using SLM tags
58
- - **Persistent** — Survives process restarts (SQLite-backed, not in-memory)
59
- - **Full BaseChatStore API** — `set_messages`, `get_messages`, `add_message`, `delete_messages`, `delete_message`, `delete_last_message`, `get_keys`
60
- - **Async Support** — Async methods inherited from BaseChatStore (delegates to sync via `asyncio.to_thread`)
61
-
62
- ## How It Works
63
-
64
- Each chat message is stored as a separate memory entry in SuperLocalMemory V2:
65
- - **Content**: JSON-serialized `{role, content, additional_kwargs}`
66
- - **Tag**: `llamaindex:chat:<session_key>` for session isolation
67
- - **Project**: `llamaindex` for easy identification
68
- - **Importance**: 3 (low, since chat messages are transient)
69
-
70
- ## Custom Database Path
71
-
72
- ```python
73
- # Use a custom database file
74
- chat_store = SuperLocalMemoryChatStore(db_path="/path/to/custom/memory.db")
75
- ```
76
-
77
- ## Links
78
-
79
- - [SuperLocalMemory V2](https://github.com/qualixar/superlocalmemory)
80
- - [LlamaIndex Documentation](https://docs.llamaindex.ai/)
81
- - [LlamaIndex Chat Stores Guide](https://docs.llamaindex.ai/en/stable/module_guides/storing/chat_stores/)
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env python3
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
3
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
4
- from llama_index.storage.chat_store.superlocalmemory.base import (
5
- SuperLocalMemoryChatStore,
6
- )
7
-
8
- __all__ = ["SuperLocalMemoryChatStore"]
9
- __version__ = "0.1.0"