superlocalmemory 3.8.3 → 3.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +3 -2
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/pyproject.toml +9 -4
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/access/rbac.py +68 -76
- package/src/superlocalmemory/cli/commands.py +158 -404
- package/src/superlocalmemory/cli/ingest_cmd.py +11 -1
- package/src/superlocalmemory/cli/main.py +30 -0
- package/src/superlocalmemory/cli/pending_store.py +39 -14
- package/src/superlocalmemory/core/backend_orchestrator.py +93 -0
- package/src/superlocalmemory/core/component_registry.py +4 -2
- package/src/superlocalmemory/core/config.py +78 -0
- package/src/superlocalmemory/core/consolidation_engine.py +79 -73
- package/src/superlocalmemory/core/embeddings.py +33 -6
- package/src/superlocalmemory/core/engine.py +186 -60
- package/src/superlocalmemory/core/engine_ingestion.py +150 -63
- package/src/superlocalmemory/core/fact_consolidator.py +148 -30
- package/src/superlocalmemory/core/graph_pruner.py +436 -39
- package/src/superlocalmemory/core/ingestion_command.py +273 -32
- package/src/superlocalmemory/core/maintenance_scheduler.py +61 -1
- package/src/superlocalmemory/core/mutations.py +32 -10
- package/src/superlocalmemory/core/recall_pipeline.py +111 -74
- package/src/superlocalmemory/core/registry.py +5 -1
- package/src/superlocalmemory/core/remember_admission.py +152 -0
- package/src/superlocalmemory/core/remember_runtime.py +712 -0
- package/src/superlocalmemory/core/remote_mode.py +3 -1
- package/src/superlocalmemory/core/scale_engine.py +41 -18
- package/src/superlocalmemory/core/store_pipeline.py +18 -4
- package/src/superlocalmemory/encoding/entity_resolver.py +18 -11
- package/src/superlocalmemory/graph/cozo_backend.py +5 -5
- package/src/superlocalmemory/hooks/_outcome_common.py +9 -2
- package/src/superlocalmemory/hooks/adapter_base.py +58 -44
- package/src/superlocalmemory/hooks/ide_connector.py +26 -8
- package/src/superlocalmemory/hooks/portable_kit.py +105 -9
- package/src/superlocalmemory/hooks/prewarm_auth.py +21 -2
- package/src/superlocalmemory/infra/auth_middleware.py +3 -1
- package/src/superlocalmemory/infra/cloud_backup.py +26 -27
- package/src/superlocalmemory/infra/event_bus.py +250 -88
- package/src/superlocalmemory/learning/bandit.py +50 -1
- package/src/superlocalmemory/learning/consolidation_cycle.py +33 -16
- package/src/superlocalmemory/learning/entity_compiler.py +148 -132
- package/src/superlocalmemory/learning/memory_merge.py +97 -82
- package/src/superlocalmemory/learning/reward_archive.py +98 -90
- package/src/superlocalmemory/learning/reward_boost.py +40 -30
- package/src/superlocalmemory/learning/source_quality.py +38 -35
- package/src/superlocalmemory/mcp/_daemon_proxy.py +38 -15
- package/src/superlocalmemory/mcp/http_transport.py +335 -3
- package/src/superlocalmemory/mcp/tools_active.py +4 -41
- package/src/superlocalmemory/mcp/tools_core.py +26 -87
- package/src/superlocalmemory/mcp/tools_evolution.py +5 -10
- package/src/superlocalmemory/optimize/proxy/capture.py +196 -8
- package/src/superlocalmemory/retrieval/engine.py +15 -4
- package/src/superlocalmemory/retrieval/entity_channel.py +25 -1
- package/src/superlocalmemory/retrieval/reranker.py +130 -22
- package/src/superlocalmemory/retrieval/spreading_activation.py +20 -12
- package/src/superlocalmemory/retrieval/vector_store.py +84 -69
- package/src/superlocalmemory/server/loopback.py +85 -0
- package/src/superlocalmemory/server/origin.py +9 -4
- package/src/superlocalmemory/server/profile_runtime.py +14 -0
- package/src/superlocalmemory/server/routes/abstraction.py +2 -4
- package/src/superlocalmemory/server/routes/agents.py +3 -5
- package/src/superlocalmemory/server/routes/backup.py +6 -2
- package/src/superlocalmemory/server/routes/behavioral.py +11 -25
- package/src/superlocalmemory/server/routes/brain.py +6 -9
- package/src/superlocalmemory/server/routes/compliance.py +20 -23
- package/src/superlocalmemory/server/routes/config_api.py +83 -0
- package/src/superlocalmemory/server/routes/entity.py +3 -7
- package/src/superlocalmemory/server/routes/evolution.py +3 -5
- package/src/superlocalmemory/server/routes/helpers.py +57 -25
- package/src/superlocalmemory/server/routes/insights.py +2 -4
- package/src/superlocalmemory/server/routes/learning.py +2 -5
- package/src/superlocalmemory/server/routes/lifecycle.py +2 -4
- package/src/superlocalmemory/server/routes/memories.py +119 -98
- package/src/superlocalmemory/server/routes/mesh.py +7 -2
- package/src/superlocalmemory/server/routes/profiles.py +20 -21
- package/src/superlocalmemory/server/routes/rbac.py +0 -1
- package/src/superlocalmemory/server/routes/tiers.py +28 -35
- package/src/superlocalmemory/server/routes/timeline.py +2 -4
- package/src/superlocalmemory/server/routes/v3_api.py +85 -93
- package/src/superlocalmemory/server/unified_daemon.py +400 -140
- package/src/superlocalmemory/server/write_identity.py +22 -4
- package/src/superlocalmemory/storage/admission_codec.py +119 -0
- package/src/superlocalmemory/storage/admission_journal.py +728 -0
- package/src/superlocalmemory/storage/database.py +168 -19
- package/src/superlocalmemory/storage/deferred_writes.py +209 -0
- package/src/superlocalmemory/storage/embedding_migrator.py +19 -0
- package/src/superlocalmemory/storage/memory_write.py +115 -0
- package/src/superlocalmemory/storage/migration_runner.py +44 -0
- package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +113 -78
- package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +80 -0
- package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +188 -0
- package/src/superlocalmemory/storage/read_connection.py +115 -0
- package/src/superlocalmemory/storage/write_coordinator.py +756 -0
- package/src/superlocalmemory/storage/write_lock.py +88 -0
- package/src/superlocalmemory/ui/index.html +1 -1
- package/src/superlocalmemory/ui/js/auto-settings.js +14 -1
- package/src/superlocalmemory/ui/js/od-settings.js +9 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com
|
|
4
|
+
|
|
5
|
+
"""Process-level per-path write-lock registry for memory.db.
|
|
6
|
+
|
|
7
|
+
ALL code that writes to a given SQLite file MUST acquire the lock returned
|
|
8
|
+
by ``get_write_lock(db_path)`` BEFORE opening a sqlite3 connection for
|
|
9
|
+
writing. This serialises writes at the Python layer so that only ONE
|
|
10
|
+
sqlite3 connection holds the SQLite WAL write lock at any instant, which
|
|
11
|
+
eliminates all SQLITE_BUSY retries within the process.
|
|
12
|
+
|
|
13
|
+
Invariant
|
|
14
|
+
---------
|
|
15
|
+
Every memory.db write path in the process acquires the same RLock before
|
|
16
|
+
touching sqlite3. Because SQLite WAL mode allows one writer at a time, a
|
|
17
|
+
Python-level RLock gives us the same serialisation guarantee while
|
|
18
|
+
completely avoiding the SQLITE_BUSY / busy_timeout retry loop.
|
|
19
|
+
|
|
20
|
+
Lock ordering rule (must never be violated)
|
|
21
|
+
-------------------------------------------
|
|
22
|
+
get_write_lock(memory.db) ← OUTERMOST
|
|
23
|
+
↳ VectorStore._lock (inner — VectorStore in-memory state)
|
|
24
|
+
↳ sqlite3 write transaction (BEGIN … COMMIT)
|
|
25
|
+
|
|
26
|
+
Re-entrancy
|
|
27
|
+
-----------
|
|
28
|
+
``threading.RLock`` is used so that the same thread can re-acquire the
|
|
29
|
+
lock without deadlocking. This is required by the self-heal backfill
|
|
30
|
+
pattern::
|
|
31
|
+
|
|
32
|
+
with db._lock: # db._lock IS get_write_lock(memory.db)
|
|
33
|
+
vs.upsert(...) # also calls get_write_lock → re-entrant OK
|
|
34
|
+
|
|
35
|
+
Usage
|
|
36
|
+
-----
|
|
37
|
+
from superlocalmemory.storage.write_lock import get_write_lock
|
|
38
|
+
|
|
39
|
+
with get_write_lock(db_path):
|
|
40
|
+
conn = sqlite3.connect(str(db_path))
|
|
41
|
+
conn.execute("INSERT INTO ...")
|
|
42
|
+
conn.commit()
|
|
43
|
+
conn.close()
|
|
44
|
+
"""
|
|
45
|
+
from __future__ import annotations
|
|
46
|
+
|
|
47
|
+
import threading
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
|
|
50
|
+
# Registry: resolved absolute path string → RLock.
|
|
51
|
+
# Protected by its own Lock so the registry itself is thread-safe.
|
|
52
|
+
_registry: dict[str, threading.RLock] = {}
|
|
53
|
+
_registry_lock = threading.Lock()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_write_lock(db_path: str | Path) -> threading.RLock:
|
|
57
|
+
"""Return the process-level write-serialisation RLock for *db_path*.
|
|
58
|
+
|
|
59
|
+
Resolves the path to its canonical absolute form before hashing so
|
|
60
|
+
that relative paths, ``.`` components, and symlinks all map to the
|
|
61
|
+
same lock as their resolved target. Creates a new ``RLock`` on first
|
|
62
|
+
call for each unique resolved path. Thread-safe.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
db_path:
|
|
67
|
+
Path to the SQLite database file. The file need not exist yet.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
threading.RLock
|
|
72
|
+
The shared write-serialisation lock for *db_path*. All writers
|
|
73
|
+
of this file in the current process share the same object.
|
|
74
|
+
"""
|
|
75
|
+
p = Path(db_path)
|
|
76
|
+
try:
|
|
77
|
+
key = str(p.resolve())
|
|
78
|
+
except OSError:
|
|
79
|
+
# File doesn't exist yet; use absolute path as best-effort key.
|
|
80
|
+
key = str(p.absolute())
|
|
81
|
+
|
|
82
|
+
with _registry_lock:
|
|
83
|
+
if key not in _registry:
|
|
84
|
+
_registry[key] = threading.RLock()
|
|
85
|
+
return _registry[key]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
__all__ = ["get_write_lock"]
|
|
@@ -1578,7 +1578,7 @@
|
|
|
1578
1578
|
<script src="static/js/od-skills.js?v=379"></script>
|
|
1579
1579
|
<script src="static/js/od-mesh.js?v=379"></script>
|
|
1580
1580
|
<script src="static/js/od-optimize.js?v=379"></script>
|
|
1581
|
-
<script src="static/js/od-settings.js?v=
|
|
1581
|
+
<script src="static/js/od-settings.js?v=386"></script>
|
|
1582
1582
|
<script src="static/js/od-backup.js?v=379"></script>
|
|
1583
1583
|
<!-- MCP & Integrations pane (v3.8.0): shows exposed MCP tool profile + counts -->
|
|
1584
1584
|
<script src="static/js/od-mcp.js?v=380"></script>
|
|
@@ -463,7 +463,10 @@ async function saveAllSettings() {
|
|
|
463
463
|
async function loadEmbeddingSettings() {
|
|
464
464
|
try {
|
|
465
465
|
var resp = await fetch('/api/v3/embedding/config');
|
|
466
|
-
if (!resp.ok)
|
|
466
|
+
if (!resp.ok) {
|
|
467
|
+
showEmbeddingConfigUnavailable();
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
467
470
|
var data = await resp.json();
|
|
468
471
|
|
|
469
472
|
var provEl = document.getElementById('settings-emb-provider');
|
|
@@ -495,9 +498,19 @@ async function loadEmbeddingSettings() {
|
|
|
495
498
|
}
|
|
496
499
|
} catch (e) {
|
|
497
500
|
console.log('Load embedding settings error:', e);
|
|
501
|
+
showEmbeddingConfigUnavailable();
|
|
498
502
|
}
|
|
499
503
|
}
|
|
500
504
|
|
|
505
|
+
function showEmbeddingConfigUnavailable() {
|
|
506
|
+
var info = document.getElementById('settings-emb-info');
|
|
507
|
+
if (!info) return;
|
|
508
|
+
// Do not alter any form values here: rendering fallback values would make
|
|
509
|
+
// a transient daemon/config failure look like a valid Mode A setup.
|
|
510
|
+
info.textContent = 'Embedding configuration unavailable. Check daemon health and retry.';
|
|
511
|
+
info.className = 'text-warning small';
|
|
512
|
+
}
|
|
513
|
+
|
|
501
514
|
function updateEmbeddingUI() {
|
|
502
515
|
var provider = document.getElementById('settings-emb-provider')?.value || 'default';
|
|
503
516
|
var isCustom = provider === 'openai';
|
|
@@ -368,9 +368,12 @@
|
|
|
368
368
|
]);
|
|
369
369
|
}
|
|
370
370
|
function loadEmb() {
|
|
371
|
-
fetch('/api/v3/embedding/config').then(function (r) {
|
|
371
|
+
fetch('/api/v3/embedding/config').then(function (r) {
|
|
372
|
+
if (!r.ok) throw new Error('embedding config unavailable');
|
|
373
|
+
return r.json();
|
|
374
|
+
})
|
|
372
375
|
.then(function (d) {
|
|
373
|
-
if (!d)
|
|
376
|
+
if (!d) throw new Error('embedding config unavailable');
|
|
374
377
|
var p = q('emb-prov');
|
|
375
378
|
if (p) { p.value = d.is_openai_compatible ? 'openai' : 'default'; p.dispatchEvent(new Event('change')); }
|
|
376
379
|
var m = q('emb-model'); if (m) m.value = d.model_name || '';
|
|
@@ -378,7 +381,10 @@
|
|
|
378
381
|
var ep = q('emb-endpoint'); if (ep) ep.value = d.api_endpoint || '';
|
|
379
382
|
var inf = q('emb-info');
|
|
380
383
|
if (inf) inf.textContent = 'Current: ' + (d.model_name || 'nomic-embed-text') + ' (' + (d.dimension || 768) + 'd)';
|
|
381
|
-
}).catch(function () {
|
|
384
|
+
}).catch(function () {
|
|
385
|
+
var inf = q('emb-info');
|
|
386
|
+
if (inf) inf.textContent = 'Embedding configuration unavailable. Check daemon health and retry.';
|
|
387
|
+
});
|
|
382
388
|
}
|
|
383
389
|
function saveEmb() {
|
|
384
390
|
setSt('emb', 'Saving…', null);
|