superlocalmemory 3.8.13 → 4.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.
- package/ATTRIBUTION.md +4 -4
- package/CHANGELOG.md +113 -121
- package/README.md +65 -63
- package/docs/pi-dev-integration.md +1 -1
- package/package.json +6 -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-governance/SKILL.md +248 -0
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-loop/SKILL.md +99 -0
- package/plugin-src/skills/slm-mesh/SKILL.md +282 -0
- package/plugin-src/skills/slm-profile/SKILL.md +148 -0
- 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-scope/SKILL.md +176 -0
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/pyproject.toml +11 -4
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/commands.py +125 -11
- package/src/superlocalmemory/cli/daemon.py +5 -1
- package/src/superlocalmemory/cli/main.py +35 -2
- package/src/superlocalmemory/cli/ops_cmd.py +281 -0
- package/src/superlocalmemory/cli/setup_wizard.py +1 -1
- package/src/superlocalmemory/compliance/audit.py +65 -0
- package/src/superlocalmemory/compliance/eu_ai_act.py +27 -57
- package/src/superlocalmemory/compliance/gdpr.py +416 -20
- package/src/superlocalmemory/compliance/retention.py +74 -22
- package/src/superlocalmemory/compliance/scheduler.py +78 -9
- package/src/superlocalmemory/core/actor_context.py +166 -0
- package/src/superlocalmemory/core/admission.py +549 -0
- package/src/superlocalmemory/core/backend_orchestrator.py +23 -10
- package/src/superlocalmemory/core/config.py +202 -24
- package/src/superlocalmemory/core/consolidation_engine.py +13 -13
- package/src/superlocalmemory/core/context_cache.py +28 -0
- package/src/superlocalmemory/core/embeddings.py +64 -2
- package/src/superlocalmemory/core/engine.py +7 -2
- package/src/superlocalmemory/core/engine_ingestion.py +65 -3
- package/src/superlocalmemory/core/engine_wiring.py +36 -9
- package/src/superlocalmemory/core/ingest_policy.py +38 -0
- package/src/superlocalmemory/core/maintenance.py +255 -0
- package/src/superlocalmemory/core/modes.py +40 -13
- package/src/superlocalmemory/core/mutations.py +437 -44
- package/src/superlocalmemory/core/operation_policy.py +92 -0
- package/src/superlocalmemory/core/operation_policy_registry.py +542 -0
- package/src/superlocalmemory/core/operation_request.py +127 -0
- package/src/superlocalmemory/core/ops_remediation.py +542 -0
- package/src/superlocalmemory/core/recall_pipeline.py +7 -0
- package/src/superlocalmemory/core/remember_runtime.py +202 -4
- package/src/superlocalmemory/core/remote_mode.py +20 -5
- package/src/superlocalmemory/core/store_pipeline.py +150 -0
- package/src/superlocalmemory/core/topic_signature.py +19 -4
- package/src/superlocalmemory/core/transactions/__init__.py +78 -0
- package/src/superlocalmemory/core/transactions/concrete_owners.py +597 -0
- package/src/superlocalmemory/core/transactions/erasure.py +825 -0
- package/src/superlocalmemory/core/transactions/manifest.py +255 -0
- package/src/superlocalmemory/core/transactions/manifest_key.py +155 -0
- package/src/superlocalmemory/core/transactions/obligations.py +272 -0
- package/src/superlocalmemory/core/transactions/owners.py +114 -0
- package/src/superlocalmemory/core/transactions/reconciler.py +285 -0
- package/src/superlocalmemory/core/transactions/service.py +330 -0
- package/src/superlocalmemory/core/worker_pool.py +33 -5
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +70 -28
- package/src/superlocalmemory/encoding/emotional.py +75 -14
- package/src/superlocalmemory/encoding/scene_builder.py +115 -13
- package/src/superlocalmemory/encoding/temporal_parser.py +4 -0
- package/src/superlocalmemory/evolution/blind_verifier.py +11 -4
- package/src/superlocalmemory/evolution/evolution_store.py +244 -4
- package/src/superlocalmemory/evolution/llm_dispatch.py +40 -0
- package/src/superlocalmemory/evolution/model_selection.py +18 -3
- package/src/superlocalmemory/evolution/mutation_generator.py +3 -0
- package/src/superlocalmemory/evolution/skill_activator.py +270 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +281 -59
- package/src/superlocalmemory/evolution/types.py +30 -8
- package/src/superlocalmemory/graph/cozo_backend.py +17 -9
- package/src/superlocalmemory/hooks/auto_invoker.py +2 -1
- package/src/superlocalmemory/hooks/auto_recall.py +64 -30
- package/src/superlocalmemory/hooks/codex_assets.py +14 -1
- package/src/superlocalmemory/infra/backup.py +434 -7
- package/src/superlocalmemory/infra/process_reaper.py +18 -0
- package/src/superlocalmemory/infra/self_heal.py +401 -0
- package/src/superlocalmemory/learning/feedback.py +52 -9
- package/src/superlocalmemory/loops/engine.py +10 -0
- package/src/superlocalmemory/mcp/_daemon_proxy.py +3 -0
- package/src/superlocalmemory/mcp/http_transport.py +30 -331
- package/src/superlocalmemory/mcp/profiles.py +5 -0
- package/src/superlocalmemory/mcp/resources.py +8 -0
- package/src/superlocalmemory/mcp/server.py +51 -4
- package/src/superlocalmemory/mcp/shared.py +19 -0
- package/src/superlocalmemory/mcp/tools_active.py +25 -4
- package/src/superlocalmemory/mcp/tools_code_graph.py +26 -18
- package/src/superlocalmemory/mcp/tools_context.py +50 -8
- package/src/superlocalmemory/mcp/tools_core.py +69 -21
- package/src/superlocalmemory/mcp/tools_evolution.py +9 -2
- package/src/superlocalmemory/mcp/tools_learning.py +21 -10
- package/src/superlocalmemory/mcp/tools_loops.py +29 -18
- package/src/superlocalmemory/mcp/tools_mesh.py +8 -0
- package/src/superlocalmemory/mcp/tools_ops.py +115 -0
- package/src/superlocalmemory/mcp/tools_optimize.py +4 -0
- package/src/superlocalmemory/mcp/tools_v28.py +10 -3
- package/src/superlocalmemory/mcp/tools_v3.py +34 -14
- package/src/superlocalmemory/mcp/tools_v33.py +18 -33
- package/src/superlocalmemory/mesh/broker.py +124 -46
- package/src/superlocalmemory/mesh/broker_security.py +470 -0
- package/src/superlocalmemory/mesh/discovery.py +365 -0
- package/src/superlocalmemory/mesh/lock_protocol.py +313 -0
- package/src/superlocalmemory/mesh/node_identity.py +97 -0
- package/src/superlocalmemory/mesh/outbox_remote.py +429 -0
- package/src/superlocalmemory/mesh/remote_sync.py +511 -28
- package/src/superlocalmemory/mesh/state_sync.py +286 -0
- package/src/superlocalmemory/optimize/config/store.py +45 -0
- package/src/superlocalmemory/parameterization/cross_project.py +12 -0
- package/src/superlocalmemory/parameterization/prompt_injector.py +13 -11
- package/src/superlocalmemory/parameterization/prompt_lifecycle.py +8 -2
- package/src/superlocalmemory/parameterization/workflow_miner.py +17 -0
- package/src/superlocalmemory/retrieval/ann_index.py +5 -0
- package/src/superlocalmemory/retrieval/bm25_channel.py +49 -2
- package/src/superlocalmemory/retrieval/engine.py +19 -4
- package/src/superlocalmemory/retrieval/fusion.py +4 -1
- package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -3
- package/src/superlocalmemory/retrieval/remote_reranker.py +47 -22
- package/src/superlocalmemory/retrieval/reranker.py +32 -1
- package/src/superlocalmemory/retrieval/temporal_channel.py +16 -3
- package/src/superlocalmemory/retrieval/temporal_utils.py +107 -0
- package/src/superlocalmemory/retrieval/temporal_validity_filter.py +155 -42
- package/src/superlocalmemory/retrieval/vector_store.py +214 -8
- package/src/superlocalmemory/server/api.py +5 -5
- package/src/superlocalmemory/server/egress_policy.py +258 -0
- package/src/superlocalmemory/server/rbac_enforce.py +32 -0
- package/src/superlocalmemory/server/route_mutations.py +20 -0
- package/src/superlocalmemory/server/routes/compliance.py +153 -7
- package/src/superlocalmemory/server/routes/data_io.py +43 -2
- package/src/superlocalmemory/server/routes/events.py +15 -0
- package/src/superlocalmemory/server/routes/memories.py +56 -3
- package/src/superlocalmemory/server/routes/mesh.py +82 -1
- package/src/superlocalmemory/server/routes/mesh_lock.py +54 -0
- package/src/superlocalmemory/server/routes/mesh_state.py +63 -0
- package/src/superlocalmemory/server/routes/v3_api.py +50 -27
- package/src/superlocalmemory/server/routes/ws.py +86 -0
- package/src/superlocalmemory/server/ui.py +6 -6
- package/src/superlocalmemory/server/unified_daemon.py +942 -119
- package/src/superlocalmemory/storage/_migration_internals.py +568 -0
- package/src/superlocalmemory/storage/_schema_version.py +110 -0
- package/src/superlocalmemory/storage/database.py +329 -24
- package/src/superlocalmemory/storage/embedding_migrator.py +246 -51
- package/src/superlocalmemory/storage/erasure_fence.py +45 -0
- package/src/superlocalmemory/storage/generation_fence.py +63 -0
- package/src/superlocalmemory/storage/migration_runner.py +140 -417
- package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +40 -0
- package/src/superlocalmemory/storage/migrations/M033_projection_transactions.py +148 -0
- package/src/superlocalmemory/storage/migrations/M034_obligation_integrity.py +58 -0
- package/src/superlocalmemory/storage/migrations/M035_erasure_receipts.py +113 -0
- package/src/superlocalmemory/storage/migrations/M036_vector_row_map.py +107 -0
- package/src/superlocalmemory/storage/migrations/M037_manifest_hmac_version.py +162 -0
- package/src/superlocalmemory/storage/migrations/{M033_learning_feedback_channel.py → M038_learning_feedback_channel.py} +3 -3
- package/src/superlocalmemory/storage/migrations/M039_scene_fact_members.py +137 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +4 -2
- package/src/superlocalmemory/storage/schema.py +67 -0
- package/src/superlocalmemory/storage/write_coordinator.py +125 -0
- package/src/superlocalmemory/trust/scorer.py +28 -4
- package/src/superlocalmemory/ui/index.html +14 -3
- package/src/superlocalmemory/ui/js/auto-settings.js +12 -1
- package/src/superlocalmemory/ui/js/brain.js +6 -4
- package/src/superlocalmemory/ui/js/compliance.js +66 -12
- package/src/superlocalmemory/ui/js/dashboard.js +13 -3
- package/src/superlocalmemory/ui/js/feedback.js +8 -2
- package/src/superlocalmemory/ui/js/lifecycle.js +7 -1
- package/src/superlocalmemory/ui/js/modal.js +272 -5
- package/src/superlocalmemory/ui/js/od-backup.js +9 -2
- package/src/superlocalmemory/ui/js/od-compliance-ext.js +301 -0
- package/src/superlocalmemory/ui/js/od-operations.js +154 -23
- package/src/superlocalmemory/ui/js/od-ops-health.js +417 -0
- package/src/superlocalmemory/ui/js/od-optimize.js +35 -21
- package/src/superlocalmemory/ui/js/od-team.js +9 -2
- package/src/superlocalmemory/ui/js/optimize.js +13 -16
- package/src/superlocalmemory/ui/js/profiles.js +7 -3
- package/src/superlocalmemory/ui/js/settings.js +7 -1
- package/src/superlocalmemory/vector/lancedb_backend.py +19 -9
- package/src/superlocalmemory/attribution/mathematical_dna.py +0 -235
- package/src/superlocalmemory/cli/post_install.py +0 -114
- package/src/superlocalmemory/core/clock_monitor.py +0 -45
- package/src/superlocalmemory/core/db_pool.py +0 -80
- package/src/superlocalmemory/core/error_catalog.py +0 -113
- package/src/superlocalmemory/core/loop_watchdog.py +0 -56
- package/src/superlocalmemory/core/priority_queue.py +0 -61
- package/src/superlocalmemory/core/pruning_engine.py +0 -216
- package/src/superlocalmemory/core/queue_dispatcher.py +0 -73
- package/src/superlocalmemory/core/slmignore.py +0 -125
- package/src/superlocalmemory/infra/heartbeat_monitor.py +0 -140
- package/src/superlocalmemory/infra/webhook_dispatcher.py +0 -247
- package/src/superlocalmemory/learning/quantization_scheduler.py +0 -320
- package/src/superlocalmemory/storage/access_control.py +0 -182
|
@@ -1,235 +0,0 @@
|
|
|
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 | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""Self-enforcing inter-layer parameter constraints.
|
|
6
|
-
|
|
7
|
-
The mathematical layers have parameters that are coupled through
|
|
8
|
-
a constraint derived from a private seed. If anyone modifies the
|
|
9
|
-
parameters without knowing the constraint, performance degrades.
|
|
10
|
-
|
|
11
|
-
Constraint: alpha * kappa = C * beta
|
|
12
|
-
Where:
|
|
13
|
-
alpha = metric scaling parameter
|
|
14
|
-
kappa = curvature parameter
|
|
15
|
-
beta = inverse temperature
|
|
16
|
-
C = derived from private HMAC key
|
|
17
|
-
|
|
18
|
-
If the constraint is violated:
|
|
19
|
-
- Similarity calibration drifts
|
|
20
|
-
- Hierarchical distance fidelity drops
|
|
21
|
-
- Energy landscape flattens
|
|
22
|
-
- Overall retrieval quality drops 15-20%
|
|
23
|
-
|
|
24
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
25
|
-
License: AGPL-3.0-or-later
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
from __future__ import annotations
|
|
29
|
-
|
|
30
|
-
import hashlib
|
|
31
|
-
import hmac
|
|
32
|
-
import os
|
|
33
|
-
|
|
34
|
-
import numpy as np
|
|
35
|
-
|
|
36
|
-
# Hopfield inverse temperature (legacy constant, kept for DNA compatibility)
|
|
37
|
-
HOPFIELD_INVERSE_TEMP = 4.0
|
|
38
|
-
|
|
39
|
-
# Default seed — production should use env var SLM_DNA_SEED
|
|
40
|
-
_DNA_SEED = "qualixar-slm-alpha-dna-v1"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class MathematicalDNA:
|
|
44
|
-
"""Self-enforcing parameter constraint system.
|
|
45
|
-
|
|
46
|
-
Derives a coupling constant from a private seed and provides
|
|
47
|
-
utilities to:
|
|
48
|
-
- Get a parameter set satisfying the constraint.
|
|
49
|
-
- Verify whether arbitrary parameters satisfy it.
|
|
50
|
-
- Compute an integrity score (1.0 = perfect).
|
|
51
|
-
- Embed / detect computation fingerprints at the precision level.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
seed: Override the DNA seed. If ``None``, falls back to
|
|
55
|
-
``SLM_DNA_SEED`` env var, then the built-in default.
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
def __init__(self, seed: str | None = None) -> None:
|
|
59
|
-
self._seed = seed or os.environ.get("SLM_DNA_SEED", _DNA_SEED)
|
|
60
|
-
self._constraint_C = self._derive_constraint()
|
|
61
|
-
|
|
62
|
-
# ── Constraint derivation ─────────────────────────────────────
|
|
63
|
-
|
|
64
|
-
def _derive_constraint(self) -> float:
|
|
65
|
-
"""Derive the inter-layer coupling constant from seed.
|
|
66
|
-
|
|
67
|
-
Uses HMAC-SHA256 to produce a deterministic float in [0.5, 2.0].
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
Coupling constant C.
|
|
71
|
-
"""
|
|
72
|
-
h = hmac.new(
|
|
73
|
-
self._seed.encode("utf-8"),
|
|
74
|
-
b"layer-coupling",
|
|
75
|
-
hashlib.sha256,
|
|
76
|
-
)
|
|
77
|
-
hash_int = int(h.hexdigest()[:8], 16)
|
|
78
|
-
return 0.5 + (hash_int / 0xFFFFFFFF) * 1.5
|
|
79
|
-
|
|
80
|
-
# ── Parameter generation ──────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
def get_coupled_parameters(self) -> dict[str, float | bool]:
|
|
83
|
-
"""Get a parameter set satisfying the constraint.
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
Dict with ``fisher_alpha``, ``poincare_kappa``,
|
|
87
|
-
``hopfield_beta``, ``constraint_C``, and
|
|
88
|
-
``constraint_satisfied`` (always ``True``).
|
|
89
|
-
"""
|
|
90
|
-
beta = HOPFIELD_INVERSE_TEMP
|
|
91
|
-
target_product = self._constraint_C * beta
|
|
92
|
-
|
|
93
|
-
kappa = abs(self._constraint_C)
|
|
94
|
-
alpha = target_product / kappa if kappa > 1e-10 else 1.0
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
"fisher_alpha": float(alpha),
|
|
98
|
-
"poincare_kappa": float(kappa),
|
|
99
|
-
"hopfield_beta": float(beta),
|
|
100
|
-
"constraint_C": float(self._constraint_C),
|
|
101
|
-
"constraint_satisfied": True,
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# ── Constraint verification ───────────────────────────────────
|
|
105
|
-
|
|
106
|
-
def verify_constraint(
|
|
107
|
-
self,
|
|
108
|
-
alpha: float,
|
|
109
|
-
kappa: float,
|
|
110
|
-
beta: float,
|
|
111
|
-
tolerance: float = 0.01,
|
|
112
|
-
) -> bool:
|
|
113
|
-
"""Check if parameters satisfy alpha * kappa ≈ C * beta.
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
alpha: Metric scaling parameter.
|
|
117
|
-
kappa: Curvature parameter.
|
|
118
|
-
beta: Inverse temperature.
|
|
119
|
-
tolerance: Relative tolerance for the check.
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
``True`` if the constraint is satisfied.
|
|
123
|
-
"""
|
|
124
|
-
lhs = alpha * kappa
|
|
125
|
-
rhs = self._constraint_C * beta
|
|
126
|
-
denom = max(abs(rhs), 1e-10)
|
|
127
|
-
return abs(lhs - rhs) / denom < tolerance
|
|
128
|
-
|
|
129
|
-
def compute_integrity_score(
|
|
130
|
-
self,
|
|
131
|
-
alpha: float,
|
|
132
|
-
kappa: float,
|
|
133
|
-
beta: float,
|
|
134
|
-
) -> float:
|
|
135
|
-
"""Compute integrity score in [0, 1]. 1.0 = perfect.
|
|
136
|
-
|
|
137
|
-
The score multiplies retrieval quality — violation degrades
|
|
138
|
-
performance through a sigmoid penalty.
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
alpha: Metric scaling parameter.
|
|
142
|
-
kappa: Curvature parameter.
|
|
143
|
-
beta: Inverse temperature.
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
Integrity score in [0.0, 1.0].
|
|
147
|
-
"""
|
|
148
|
-
lhs = alpha * kappa
|
|
149
|
-
rhs = self._constraint_C * beta
|
|
150
|
-
denom = max(abs(rhs), 1e-10)
|
|
151
|
-
deviation = abs(lhs - rhs) / denom
|
|
152
|
-
# Sigmoid degradation: small deviations tolerated
|
|
153
|
-
return float(1.0 / (1.0 + 10.0 * deviation ** 2))
|
|
154
|
-
|
|
155
|
-
# ── Fingerprinting ────────────────────────────────────────────
|
|
156
|
-
|
|
157
|
-
def embed_fingerprint(self, value: float, memory_id: int) -> float:
|
|
158
|
-
"""Embed a computation fingerprint at the precision level.
|
|
159
|
-
|
|
160
|
-
Modifies the 12th decimal place to encode a signature.
|
|
161
|
-
The fingerprint is below the noise floor and does not affect
|
|
162
|
-
retrieval quality but can be forensically detected.
|
|
163
|
-
|
|
164
|
-
Args:
|
|
165
|
-
value: Original floating point value.
|
|
166
|
-
memory_id: Unique memory identifier for per-memory signing.
|
|
167
|
-
|
|
168
|
-
Returns:
|
|
169
|
-
Value with embedded fingerprint.
|
|
170
|
-
"""
|
|
171
|
-
sig = hmac.new(
|
|
172
|
-
self._seed.encode("utf-8"),
|
|
173
|
-
f"fingerprint:{memory_id}".encode("utf-8"),
|
|
174
|
-
hashlib.sha256,
|
|
175
|
-
).hexdigest()
|
|
176
|
-
# 8-digit fingerprint from hash, mapped to [0, 1)
|
|
177
|
-
fp = int(sig[:8], 16) / 0xFFFFFFFF
|
|
178
|
-
scale = 1e-10
|
|
179
|
-
return value + fp * scale
|
|
180
|
-
|
|
181
|
-
def detect_fingerprint(
|
|
182
|
-
self,
|
|
183
|
-
value: float,
|
|
184
|
-
memory_id: int,
|
|
185
|
-
original: float,
|
|
186
|
-
) -> bool:
|
|
187
|
-
"""Check if a value carries our fingerprint.
|
|
188
|
-
|
|
189
|
-
Args:
|
|
190
|
-
value: The potentially fingerprinted value.
|
|
191
|
-
memory_id: Memory ID used during embedding.
|
|
192
|
-
original: The original pre-fingerprint value.
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
``True`` if the fingerprint is detected.
|
|
196
|
-
"""
|
|
197
|
-
expected = self.embed_fingerprint(original, memory_id)
|
|
198
|
-
return abs(value - expected) < 1e-14
|
|
199
|
-
|
|
200
|
-
def generate_dna_hash(self, memory_id: int) -> str:
|
|
201
|
-
"""Generate a unique DNA hash for a memory.
|
|
202
|
-
|
|
203
|
-
This hash can be stored alongside the memory for provenance.
|
|
204
|
-
|
|
205
|
-
Args:
|
|
206
|
-
memory_id: Memory identifier.
|
|
207
|
-
|
|
208
|
-
Returns:
|
|
209
|
-
Hex digest string (64 chars).
|
|
210
|
-
"""
|
|
211
|
-
return hmac.new(
|
|
212
|
-
self._seed.encode("utf-8"),
|
|
213
|
-
f"dna:{memory_id}".encode("utf-8"),
|
|
214
|
-
hashlib.sha256,
|
|
215
|
-
).hexdigest()
|
|
216
|
-
|
|
217
|
-
def verify_dna_hash(self, memory_id: int, dna_hash: str) -> bool:
|
|
218
|
-
"""Verify that a DNA hash matches the expected value.
|
|
219
|
-
|
|
220
|
-
Args:
|
|
221
|
-
memory_id: Memory identifier.
|
|
222
|
-
dna_hash: Hash to verify.
|
|
223
|
-
|
|
224
|
-
Returns:
|
|
225
|
-
``True`` if the hash is valid.
|
|
226
|
-
"""
|
|
227
|
-
expected = self.generate_dna_hash(memory_id)
|
|
228
|
-
return hmac.compare_digest(expected, dna_hash)
|
|
229
|
-
|
|
230
|
-
# ── Properties ────────────────────────────────────────────────
|
|
231
|
-
|
|
232
|
-
@property
|
|
233
|
-
def constraint_C(self) -> float:
|
|
234
|
-
"""The derived coupling constant."""
|
|
235
|
-
return self._constraint_C
|
|
@@ -1,114 +0,0 @@
|
|
|
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 | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""Post-install script for npm package.
|
|
6
|
-
|
|
7
|
-
Runs after `npm install -g superlocalmemory`. Detects V2 installations,
|
|
8
|
-
prompts for migration, and runs the setup wizard for new users.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
import sys
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def run_post_install():
|
|
18
|
-
"""Main post-install entry point."""
|
|
19
|
-
print()
|
|
20
|
-
print("SuperLocalMemory V3")
|
|
21
|
-
print("=" * 30)
|
|
22
|
-
print()
|
|
23
|
-
|
|
24
|
-
# Upgrade banner — fires when a prior-version user runs
|
|
25
|
-
# ``npm install -g superlocalmemory@latest``. Silent on fresh
|
|
26
|
-
# installs (setup wizard handles welcome).
|
|
27
|
-
try:
|
|
28
|
-
from superlocalmemory import __version__ as _slm_ver
|
|
29
|
-
from superlocalmemory.cli.version_banner import (
|
|
30
|
-
check_and_emit_upgrade_banner,
|
|
31
|
-
)
|
|
32
|
-
if check_and_emit_upgrade_banner(_slm_ver):
|
|
33
|
-
# Upgrade detected — the banner already covered it;
|
|
34
|
-
# skip the V2 path + fresh-install copy and return.
|
|
35
|
-
return
|
|
36
|
-
except Exception:
|
|
37
|
-
pass
|
|
38
|
-
|
|
39
|
-
# Step 1: Check for V2 installation
|
|
40
|
-
from superlocalmemory.storage.v2_migrator import V2Migrator
|
|
41
|
-
|
|
42
|
-
migrator = V2Migrator()
|
|
43
|
-
|
|
44
|
-
if migrator.detect_v2() and not migrator.is_already_migrated():
|
|
45
|
-
_handle_v2_upgrade(migrator)
|
|
46
|
-
else:
|
|
47
|
-
_handle_fresh_install()
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def _handle_v2_upgrade(migrator):
|
|
51
|
-
"""Handle upgrade from V2."""
|
|
52
|
-
stats = migrator.get_v2_stats()
|
|
53
|
-
|
|
54
|
-
print("Existing V2 installation detected!")
|
|
55
|
-
print(f" Database: {stats.get('db_path', '~/.superlocalmemory/memory.db')}")
|
|
56
|
-
print(f" Memories: {stats.get('memory_count', 'unknown')}")
|
|
57
|
-
print(f" Profiles: {stats.get('profile_count', 1)}")
|
|
58
|
-
print()
|
|
59
|
-
print("V3 requires a one-time migration to upgrade your database.")
|
|
60
|
-
print("Your data will be preserved. A backup is created automatically.")
|
|
61
|
-
print("You can rollback anytime within 30 days.")
|
|
62
|
-
print()
|
|
63
|
-
|
|
64
|
-
choice = input("Run migration now? [Y/n]: ").strip().lower()
|
|
65
|
-
|
|
66
|
-
if choice in ("", "y", "yes"):
|
|
67
|
-
print()
|
|
68
|
-
print("Migrating...")
|
|
69
|
-
result = migrator.migrate()
|
|
70
|
-
|
|
71
|
-
if result.get("success"):
|
|
72
|
-
print()
|
|
73
|
-
for step in result.get("steps", []):
|
|
74
|
-
print(f" [ok] {step}")
|
|
75
|
-
print()
|
|
76
|
-
print("Migration complete!")
|
|
77
|
-
print(f" V3 database: {result.get('v3_db', '')}")
|
|
78
|
-
print(f" Backup: {result.get('backup_db', '')}")
|
|
79
|
-
print()
|
|
80
|
-
# Run setup wizard after migration
|
|
81
|
-
_run_setup()
|
|
82
|
-
else:
|
|
83
|
-
print(f"Migration failed: {result.get('error', 'unknown')}")
|
|
84
|
-
print("Your V2 data is untouched. Run `slm migrate` to try again.")
|
|
85
|
-
sys.exit(1)
|
|
86
|
-
else:
|
|
87
|
-
print()
|
|
88
|
-
print("Migration skipped. Run `slm migrate` when ready.")
|
|
89
|
-
print("Note: V3 features are unavailable until you migrate.")
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def _handle_fresh_install():
|
|
93
|
-
"""Handle fresh install (no V2 detected)."""
|
|
94
|
-
from superlocalmemory.storage.v2_migrator import V2Migrator
|
|
95
|
-
|
|
96
|
-
migrator = V2Migrator()
|
|
97
|
-
|
|
98
|
-
if migrator.is_already_migrated():
|
|
99
|
-
print("V3 already configured. Run `slm setup` to reconfigure.")
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
print("Welcome! Let's set up SuperLocalMemory V3.")
|
|
103
|
-
_run_setup()
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def _run_setup():
|
|
107
|
-
"""Run the interactive setup wizard."""
|
|
108
|
-
from superlocalmemory.cli.setup_wizard import run_wizard
|
|
109
|
-
|
|
110
|
-
run_wizard()
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if __name__ == "__main__":
|
|
114
|
-
run_post_install()
|
|
@@ -1,45 +0,0 @@
|
|
|
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 | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""Wall-clock jump detector.
|
|
6
|
-
|
|
7
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
from typing import Literal, Optional
|
|
13
|
-
|
|
14
|
-
Event = Literal["forward", "backward"]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class ClockJumpDetector:
|
|
18
|
-
"""Detects NTP-style jumps by comparing wall-clock and monotonic deltas."""
|
|
19
|
-
|
|
20
|
-
def __init__(self, threshold_s: float = 1.0) -> None:
|
|
21
|
-
self._threshold = threshold_s
|
|
22
|
-
self._last_wall: Optional[float] = None
|
|
23
|
-
self._last_mono: Optional[float] = None
|
|
24
|
-
self.last_drift_s: float = 0.0
|
|
25
|
-
self.last_event: Optional[Event] = None
|
|
26
|
-
|
|
27
|
-
def tick(self, wall: float, monotonic: float) -> Optional[Event]:
|
|
28
|
-
if self._last_wall is None or self._last_mono is None:
|
|
29
|
-
self._last_wall = wall
|
|
30
|
-
self._last_mono = monotonic
|
|
31
|
-
return None
|
|
32
|
-
dw = wall - self._last_wall
|
|
33
|
-
dm = monotonic - self._last_mono
|
|
34
|
-
drift = dw - dm
|
|
35
|
-
self._last_wall = wall
|
|
36
|
-
self._last_mono = monotonic
|
|
37
|
-
self.last_drift_s = drift
|
|
38
|
-
if abs(drift) < self._threshold:
|
|
39
|
-
self.last_event = None
|
|
40
|
-
return None
|
|
41
|
-
self.last_event = "forward" if drift > 0 else "backward"
|
|
42
|
-
return self.last_event
|
|
43
|
-
|
|
44
|
-
def drift_magnitude_s(self) -> float:
|
|
45
|
-
return abs(self.last_drift_s)
|
|
@@ -1,80 +0,0 @@
|
|
|
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 | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""Simple bounded SQLite connection pool.
|
|
6
|
-
|
|
7
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
import sqlite3
|
|
13
|
-
import threading
|
|
14
|
-
from contextlib import contextmanager
|
|
15
|
-
from queue import Empty, Queue
|
|
16
|
-
from typing import Callable, Iterator
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ConnectionPool:
|
|
20
|
-
"""Bounded pool of SQLite connections created on-demand."""
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
opener: Callable[[], sqlite3.Connection],
|
|
25
|
-
size: int = 8,
|
|
26
|
-
) -> None:
|
|
27
|
-
if size < 1:
|
|
28
|
-
raise ValueError("size must be >= 1")
|
|
29
|
-
self._opener = opener
|
|
30
|
-
self._size = size
|
|
31
|
-
self._available: Queue[sqlite3.Connection] = Queue(maxsize=size)
|
|
32
|
-
self._created = 0
|
|
33
|
-
self._lock = threading.Lock()
|
|
34
|
-
self._closed = False
|
|
35
|
-
self._all: list[sqlite3.Connection] = []
|
|
36
|
-
|
|
37
|
-
def _get_or_create(self, timeout: float | None) -> sqlite3.Connection:
|
|
38
|
-
try:
|
|
39
|
-
return self._available.get_nowait()
|
|
40
|
-
except Empty:
|
|
41
|
-
pass
|
|
42
|
-
with self._lock:
|
|
43
|
-
if self._closed:
|
|
44
|
-
raise RuntimeError("pool is closed")
|
|
45
|
-
if self._created < self._size:
|
|
46
|
-
conn = self._opener()
|
|
47
|
-
self._all.append(conn)
|
|
48
|
-
self._created += 1
|
|
49
|
-
return conn
|
|
50
|
-
# Pool saturated — block for a returned connection
|
|
51
|
-
try:
|
|
52
|
-
return self._available.get(timeout=timeout)
|
|
53
|
-
except Empty as exc:
|
|
54
|
-
raise TimeoutError("timed out acquiring DB connection") from exc
|
|
55
|
-
|
|
56
|
-
@contextmanager
|
|
57
|
-
def acquire(self, timeout: float | None = 30.0) -> Iterator[sqlite3.Connection]:
|
|
58
|
-
if self._closed:
|
|
59
|
-
raise RuntimeError("pool is closed")
|
|
60
|
-
conn = self._get_or_create(timeout)
|
|
61
|
-
try:
|
|
62
|
-
yield conn
|
|
63
|
-
finally:
|
|
64
|
-
if not self._closed:
|
|
65
|
-
self._available.put(conn)
|
|
66
|
-
|
|
67
|
-
def close(self) -> None:
|
|
68
|
-
with self._lock:
|
|
69
|
-
if self._closed:
|
|
70
|
-
return
|
|
71
|
-
self._closed = True
|
|
72
|
-
for conn in self._all:
|
|
73
|
-
try:
|
|
74
|
-
conn.close()
|
|
75
|
-
except Exception:
|
|
76
|
-
pass
|
|
77
|
-
self._all.clear()
|
|
78
|
-
|
|
79
|
-
def size(self) -> int:
|
|
80
|
-
return self._size
|
|
@@ -1,113 +0,0 @@
|
|
|
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 | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""User-facing strings for queue error codes."""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import TypedDict
|
|
10
|
-
|
|
11
|
-
from superlocalmemory.core.error_envelope import ErrorCode
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class ErrorEntry(TypedDict):
|
|
15
|
-
code: str
|
|
16
|
-
title: str
|
|
17
|
-
cli_message: str
|
|
18
|
-
recovery: list[str]
|
|
19
|
-
exit_code: int
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
CATALOG: dict[str, ErrorEntry] = {
|
|
23
|
-
ErrorCode.RATE_LIMITED.value: {
|
|
24
|
-
"code": "RATE_LIMITED",
|
|
25
|
-
"title": "Rate limited",
|
|
26
|
-
"cli_message": "Too many recalls in the last second.",
|
|
27
|
-
"recovery": [
|
|
28
|
-
"Wait a moment and try again.",
|
|
29
|
-
"For batch work, export SLM_RATE_LIMIT_PER_AGENT=50 and restart the daemon.",
|
|
30
|
-
],
|
|
31
|
-
"exit_code": 3,
|
|
32
|
-
},
|
|
33
|
-
ErrorCode.QUEUE_FULL.value: {
|
|
34
|
-
"code": "QUEUE_FULL",
|
|
35
|
-
"title": "Queue is full",
|
|
36
|
-
"cli_message": "The request queue cannot accept more work right now.",
|
|
37
|
-
"recovery": [
|
|
38
|
-
"Retry with backoff.",
|
|
39
|
-
"Run: slm queue status",
|
|
40
|
-
],
|
|
41
|
-
"exit_code": 5,
|
|
42
|
-
},
|
|
43
|
-
ErrorCode.TIMEOUT.value: {
|
|
44
|
-
"code": "TIMEOUT",
|
|
45
|
-
"title": "Timed out",
|
|
46
|
-
"cli_message": "The recall did not finish in the allotted time.",
|
|
47
|
-
"recovery": [
|
|
48
|
-
"Retry.",
|
|
49
|
-
"Run: slm doctor",
|
|
50
|
-
],
|
|
51
|
-
"exit_code": 2,
|
|
52
|
-
},
|
|
53
|
-
ErrorCode.CANCELLED.value: {
|
|
54
|
-
"code": "CANCELLED",
|
|
55
|
-
"title": "Cancelled",
|
|
56
|
-
"cli_message": "The request was cancelled before it completed.",
|
|
57
|
-
"recovery": ["Re-issue the request if needed."],
|
|
58
|
-
"exit_code": 6,
|
|
59
|
-
},
|
|
60
|
-
ErrorCode.DEAD_LETTER.value: {
|
|
61
|
-
"code": "DEAD_LETTER",
|
|
62
|
-
"title": "Request failed after retries",
|
|
63
|
-
"cli_message": (
|
|
64
|
-
"The request could not complete after the maximum number of "
|
|
65
|
-
"attempts. Your query is preserved in the dead-letter queue."
|
|
66
|
-
),
|
|
67
|
-
"recovery": [
|
|
68
|
-
"Inspect: slm queue dlq",
|
|
69
|
-
"Run: slm doctor",
|
|
70
|
-
],
|
|
71
|
-
"exit_code": 4,
|
|
72
|
-
},
|
|
73
|
-
ErrorCode.DAEMON_DOWN.value: {
|
|
74
|
-
"code": "DAEMON_DOWN",
|
|
75
|
-
"title": "Daemon unreachable",
|
|
76
|
-
"cli_message": "Cannot reach the SLM daemon.",
|
|
77
|
-
"recovery": [
|
|
78
|
-
"Start the daemon: slm daemon start",
|
|
79
|
-
"Check status: slm daemon status",
|
|
80
|
-
],
|
|
81
|
-
"exit_code": 7,
|
|
82
|
-
},
|
|
83
|
-
ErrorCode.INTERNAL.value: {
|
|
84
|
-
"code": "INTERNAL",
|
|
85
|
-
"title": "Internal error",
|
|
86
|
-
"cli_message": "An unexpected internal error occurred.",
|
|
87
|
-
"recovery": [
|
|
88
|
-
"Run: slm doctor",
|
|
89
|
-
"If the issue persists, file an issue with the log excerpt.",
|
|
90
|
-
],
|
|
91
|
-
"exit_code": 8,
|
|
92
|
-
},
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def lookup(code: str | ErrorCode) -> ErrorEntry:
|
|
97
|
-
key = code.value if isinstance(code, ErrorCode) else code
|
|
98
|
-
if key not in CATALOG:
|
|
99
|
-
return CATALOG[ErrorCode.INTERNAL.value]
|
|
100
|
-
return CATALOG[key]
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def format_cli(code: str | ErrorCode, detail: str | None = None) -> str:
|
|
104
|
-
entry = lookup(code)
|
|
105
|
-
lines = [f"\u2717 {entry['title']}"]
|
|
106
|
-
lines.append(f" {entry['cli_message']}")
|
|
107
|
-
if detail:
|
|
108
|
-
lines.append(f" Detail: {detail}")
|
|
109
|
-
if entry["recovery"]:
|
|
110
|
-
lines.append(" Try:")
|
|
111
|
-
for step in entry["recovery"]:
|
|
112
|
-
lines.append(f" - {step}")
|
|
113
|
-
return "\n".join(lines)
|
|
@@ -1,56 +0,0 @@
|
|
|
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 | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""Tick-based watchdog that fires once when a cooperative loop goes silent.
|
|
6
|
-
|
|
7
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
import threading
|
|
13
|
-
import time
|
|
14
|
-
from typing import Callable, Optional
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class LoopWatchdog:
|
|
18
|
-
def __init__(
|
|
19
|
-
self,
|
|
20
|
-
stale_threshold_s: float,
|
|
21
|
-
on_stale: Optional[Callable[[float], None]] = None,
|
|
22
|
-
) -> None:
|
|
23
|
-
self._threshold = stale_threshold_s
|
|
24
|
-
self._on_stale = on_stale
|
|
25
|
-
self._last_tick = time.monotonic()
|
|
26
|
-
self._fired = False
|
|
27
|
-
self._lock = threading.Lock()
|
|
28
|
-
|
|
29
|
-
def tick(self) -> None:
|
|
30
|
-
with self._lock:
|
|
31
|
-
self._last_tick = time.monotonic()
|
|
32
|
-
self._fired = False
|
|
33
|
-
|
|
34
|
-
def age_s(self) -> float:
|
|
35
|
-
with self._lock:
|
|
36
|
-
return time.monotonic() - self._last_tick
|
|
37
|
-
|
|
38
|
-
def is_stale(self) -> bool:
|
|
39
|
-
return self.age_s() >= self._threshold
|
|
40
|
-
|
|
41
|
-
def check(self) -> bool:
|
|
42
|
-
"""Fire callback once if stale; return True if just fired."""
|
|
43
|
-
with self._lock:
|
|
44
|
-
age = time.monotonic() - self._last_tick
|
|
45
|
-
if age < self._threshold or self._fired:
|
|
46
|
-
return False
|
|
47
|
-
self._fired = True
|
|
48
|
-
cb = self._on_stale
|
|
49
|
-
if cb is not None:
|
|
50
|
-
cb(age)
|
|
51
|
-
return True
|
|
52
|
-
|
|
53
|
-
def run_forever(self, stop: threading.Event, interval_s: float = 1.0) -> None:
|
|
54
|
-
while not stop.is_set():
|
|
55
|
-
self.check()
|
|
56
|
-
stop.wait(timeout=interval_s)
|