superlocalmemory 4.0.9 → 4.1.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +245 -0
- package/README.md +7 -7
- package/package.json +4 -2
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +4 -4
- 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 +2 -2
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +5 -5
- package/plugin/skills/slm-recall/SKILL.md +102 -15
- package/plugin/skills/slm-remember/SKILL.md +35 -3
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +29 -3
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +16 -8
- 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 +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-loop/SKILL.md +2 -2
- package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
- package/plugin-src/skills/slm-profile/SKILL.md +5 -5
- package/plugin-src/skills/slm-recall/SKILL.md +102 -15
- package/plugin-src/skills/slm-remember/SKILL.md +35 -3
- package/plugin-src/skills/slm-scope/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +29 -3
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/pyproject.toml +1 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/commands.py +308 -20
- package/src/superlocalmemory/cli/daemon.py +30 -0
- package/src/superlocalmemory/cli/db_migrate.py +71 -1
- package/src/superlocalmemory/cli/gdpr_cmd.py +15 -2
- package/src/superlocalmemory/cli/main.py +26 -4
- package/src/superlocalmemory/code_graph/bridge/maintenance.py +8 -0
- package/src/superlocalmemory/code_graph/database.py +44 -0
- package/src/superlocalmemory/compliance/gdpr.py +449 -39
- package/src/superlocalmemory/core/admission.py +231 -11
- package/src/superlocalmemory/core/backend_orchestrator.py +190 -84
- package/src/superlocalmemory/core/config.py +90 -11
- package/src/superlocalmemory/core/consolidation_engine.py +34 -0
- package/src/superlocalmemory/core/engine.py +140 -11
- package/src/superlocalmemory/core/fact_consolidator.py +316 -125
- package/src/superlocalmemory/core/graph_analyzer.py +76 -112
- package/src/superlocalmemory/core/graph_metrics.py +597 -0
- package/src/superlocalmemory/core/graph_pruner.py +121 -0
- package/src/superlocalmemory/core/maintenance.py +44 -6
- package/src/superlocalmemory/core/maintenance_scheduler.py +205 -0
- package/src/superlocalmemory/core/memory_health.py +266 -0
- package/src/superlocalmemory/core/mode_capability.py +111 -0
- package/src/superlocalmemory/core/ollama_validator.py +315 -0
- package/src/superlocalmemory/core/operation_policy_registry.py +1 -1
- package/src/superlocalmemory/core/operation_request.py +1 -1
- package/src/superlocalmemory/core/ops_remediation.py +2 -2
- package/src/superlocalmemory/core/projection_drain.py +380 -0
- package/src/superlocalmemory/core/recall_pipeline.py +390 -3
- package/src/superlocalmemory/core/recall_worker.py +6 -3
- package/src/superlocalmemory/core/scale_autopromote.py +196 -0
- package/src/superlocalmemory/core/scale_engine.py +16 -2
- package/src/superlocalmemory/core/score_contract.py +21 -1
- package/src/superlocalmemory/core/session_identity.py +85 -0
- package/src/superlocalmemory/core/status_contract.py +108 -0
- package/src/superlocalmemory/core/store_pipeline.py +78 -3
- package/src/superlocalmemory/core/worker_pool.py +4 -4
- package/src/superlocalmemory/core/working_memory.py +288 -0
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +51 -7
- package/src/superlocalmemory/encoding/context_generator.py +1 -1
- package/src/superlocalmemory/encoding/entity_resolver.py +38 -0
- package/src/superlocalmemory/encoding/fact_extractor.py +18 -14
- package/src/superlocalmemory/encoding/prospective_markers.py +262 -0
- package/src/superlocalmemory/encoding/type_router.py +12 -12
- package/src/superlocalmemory/evolution/mutation_generator.py +30 -4
- package/src/superlocalmemory/graph/cozo_adjacency.py +122 -0
- package/src/superlocalmemory/graph/cozo_backend.py +103 -138
- package/src/superlocalmemory/hooks/portable_kit.py +10 -2
- package/src/superlocalmemory/learning/bandit.py +43 -0
- package/src/superlocalmemory/learning/consolidation_worker.py +54 -0
- package/src/superlocalmemory/learning/database.py +60 -3
- package/src/superlocalmemory/learning/entity_compiler.py +21 -58
- package/src/superlocalmemory/learning/feedback.py +3 -1
- package/src/superlocalmemory/learning/outcomes.py +47 -16
- package/src/superlocalmemory/learning/pattern_miner.py +28 -3
- package/src/superlocalmemory/learning/pattern_miner_constants.py +43 -0
- package/src/superlocalmemory/learning/pcos.py +291 -0
- package/src/superlocalmemory/learning/reward_from_outcomes.py +365 -0
- package/src/superlocalmemory/learning/reward_proxy.py +100 -10
- package/src/superlocalmemory/learning/signal_kinds.py +79 -0
- package/src/superlocalmemory/mcp/profiles.py +14 -2
- package/src/superlocalmemory/mcp/server.py +1 -1
- package/src/superlocalmemory/mcp/session_binding.py +92 -0
- package/src/superlocalmemory/mcp/tools_active.py +2 -1
- package/src/superlocalmemory/mcp/tools_core.py +71 -42
- package/src/superlocalmemory/mcp/tools_ops.py +2 -2
- package/src/superlocalmemory/mcp/tools_v28.py +20 -1
- package/src/superlocalmemory/parameterization/pattern_extractor.py +14 -1
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +98 -0
- package/src/superlocalmemory/retrieval/bm25_channel.py +68 -11
- package/src/superlocalmemory/retrieval/channel_status.py +117 -0
- package/src/superlocalmemory/retrieval/engine.py +106 -11
- package/src/superlocalmemory/retrieval/entity_channel.py +217 -257
- package/src/superlocalmemory/retrieval/graph_adjacency.py +219 -0
- package/src/superlocalmemory/retrieval/scope_policy.py +42 -1
- package/src/superlocalmemory/retrieval/semantic_channel.py +47 -5
- package/src/superlocalmemory/retrieval/spreading.py +288 -0
- package/src/superlocalmemory/retrieval/temporal_channel.py +13 -1
- package/src/superlocalmemory/retrieval/vector_store.py +63 -0
- package/src/superlocalmemory/server/api.py +26 -2
- package/src/superlocalmemory/server/asset_versions.py +171 -0
- package/src/superlocalmemory/server/bandit_loops.py +17 -1
- package/src/superlocalmemory/server/rbac_enforce.py +26 -6
- package/src/superlocalmemory/server/recall_serializer.py +9 -0
- package/src/superlocalmemory/server/routes/abstraction.py +201 -0
- package/src/superlocalmemory/server/routes/behavioral.py +75 -10
- package/src/superlocalmemory/server/routes/compliance.py +98 -18
- package/src/superlocalmemory/server/routes/config_api.py +186 -4
- package/src/superlocalmemory/server/routes/data_io.py +29 -1
- package/src/superlocalmemory/server/routes/entity.py +13 -1
- package/src/superlocalmemory/server/routes/evolution.py +178 -0
- package/src/superlocalmemory/server/routes/ingest.py +8 -0
- package/src/superlocalmemory/server/routes/learning_telemetry.py +2 -1
- package/src/superlocalmemory/server/routes/memories.py +49 -7
- package/src/superlocalmemory/server/routes/mesh.py +1 -1
- package/src/superlocalmemory/server/routes/timeline.py +4 -0
- package/src/superlocalmemory/server/routes/v3_api.py +193 -17
- package/src/superlocalmemory/server/ui.py +24 -1
- package/src/superlocalmemory/server/unified_daemon.py +292 -9
- package/src/superlocalmemory/storage/_migration_internals.py +35 -0
- package/src/superlocalmemory/storage/_schema_version.py +24 -3
- package/src/superlocalmemory/storage/database.py +598 -82
- package/src/superlocalmemory/storage/embedding_codec.py +71 -0
- package/src/superlocalmemory/storage/lineage_retention.py +236 -0
- package/src/superlocalmemory/storage/logical_edges.py +43 -2
- package/src/superlocalmemory/storage/migration_runner.py +130 -0
- package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +488 -0
- package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +127 -0
- package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +158 -0
- package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +620 -0
- package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +306 -0
- package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +207 -0
- package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +201 -0
- package/src/superlocalmemory/storage/migrations.py +18 -2
- package/src/superlocalmemory/storage/models.py +40 -1
- package/src/superlocalmemory/storage/projection_outbox.py +346 -0
- package/src/superlocalmemory/storage/retention_policy.py +860 -0
- package/src/superlocalmemory/storage/schema.py +110 -1
- package/src/superlocalmemory/storage/write_coordinator.py +19 -2
- package/src/superlocalmemory/summaries/base.py +1 -1
- package/src/superlocalmemory/summaries/non_answer.py +223 -0
- package/src/superlocalmemory/trust/scorer.py +43 -1
- package/src/superlocalmemory/ui/index.html +10 -19
- package/src/superlocalmemory/ui/js/event-delegation.js +12 -1
- package/src/superlocalmemory/ui/js/od-health.js +28 -6
- package/src/superlocalmemory/ui/js/od-memories.js +209 -1
- package/src/superlocalmemory/ui/js/od-ops-health.js +1 -1
- package/src/superlocalmemory/ui/js/od-settings.js +87 -1
- package/src/superlocalmemory/ui/js/recall-lab.js +78 -3
|
@@ -41,126 +41,90 @@ class GraphAnalyzer:
|
|
|
41
41
|
self._db = db
|
|
42
42
|
|
|
43
43
|
def compute_and_store(self, profile_id: str) -> dict[str, Any]:
|
|
44
|
-
"""
|
|
44
|
+
"""Recompute structural importance for a profile and persist it.
|
|
45
|
+
|
|
46
|
+
The computation and the write now live in ``core/graph_metrics``, which
|
|
47
|
+
is the only thing that writes ``fact_importance``. This method keeps its
|
|
48
|
+
shape for its three callers and adds the community labels the dashboard
|
|
49
|
+
reads, which are a presentation concern and not part of the ranking
|
|
50
|
+
signal.
|
|
51
|
+
|
|
52
|
+
Two behaviours changed with the move, both deliberate. Isolated facts now
|
|
53
|
+
get a row instead of being skipped, so "no position in the graph" stops
|
|
54
|
+
looking like "not computed yet" to the ranker. And the graph is the
|
|
55
|
+
*visible* graph: the previous version read ``atomic_facts`` and
|
|
56
|
+
``graph_edges`` raw, so on the author's store it ranked 1,299 facts the
|
|
57
|
+
store is not allowed to return, diluting every real score.
|
|
58
|
+
"""
|
|
59
|
+
from superlocalmemory.core.graph_metrics import compute_graph_metrics
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
report = compute_graph_metrics(self._db, profile_id)
|
|
62
|
+
if not report.ok:
|
|
63
|
+
logger.warning("Graph metrics: %s", report.summary())
|
|
64
|
+
return {
|
|
65
|
+
"node_count": 0,
|
|
66
|
+
"edge_count": report.edges,
|
|
67
|
+
"community_count": 0,
|
|
68
|
+
"top_5_nodes": [],
|
|
69
|
+
"error": report.error,
|
|
70
|
+
}
|
|
48
71
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
communities: dict[str, int] = {}
|
|
73
|
+
top_5: list[tuple[str, float]] = []
|
|
74
|
+
bridge_count = 0
|
|
75
|
+
top_bridges: list[tuple[str, float]] = []
|
|
52
76
|
try:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)
|
|
76
|
-
if not has_bridge:
|
|
77
|
-
self._db.execute(
|
|
78
|
-
"ALTER TABLE fact_importance "
|
|
79
|
-
"ADD COLUMN bridge_score REAL DEFAULT 0.0",
|
|
80
|
-
(),
|
|
81
|
-
)
|
|
82
|
-
except Exception:
|
|
83
|
-
pass
|
|
84
|
-
|
|
85
|
-
# Persist to fact_importance (with bridge_score)
|
|
86
|
-
for node_id in graph.nodes():
|
|
87
|
-
pr_score = pagerank.get(node_id, 0.0)
|
|
88
|
-
comm_id = communities.get(node_id)
|
|
89
|
-
deg_cent = centrality.get(node_id, 0.0)
|
|
90
|
-
br_score = bridge_scores.get(node_id, 0.0)
|
|
91
|
-
try:
|
|
92
|
-
self._db.execute(
|
|
93
|
-
"INSERT OR REPLACE INTO fact_importance "
|
|
94
|
-
"(fact_id, profile_id, pagerank_score, community_id, "
|
|
95
|
-
" degree_centrality, bridge_score, computed_at) "
|
|
96
|
-
"VALUES (?, ?, ?, ?, ?, ?, datetime('now'))",
|
|
97
|
-
(node_id, profile_id, round(pr_score, 6),
|
|
98
|
-
comm_id, round(deg_cent, 4),
|
|
99
|
-
round(br_score, 6)),
|
|
100
|
-
)
|
|
101
|
-
except Exception:
|
|
102
|
-
# Fallback without bridge_score if column doesn't exist
|
|
103
|
-
self._db.execute(
|
|
104
|
-
"INSERT OR REPLACE INTO fact_importance "
|
|
105
|
-
"(fact_id, profile_id, pagerank_score, community_id, "
|
|
106
|
-
" degree_centrality, computed_at) "
|
|
107
|
-
"VALUES (?, ?, ?, ?, ?, datetime('now'))",
|
|
108
|
-
(node_id, profile_id, round(pr_score, 6),
|
|
109
|
-
comm_id, round(deg_cent, 4)),
|
|
110
|
-
)
|
|
77
|
+
rows = self._db.execute(
|
|
78
|
+
"SELECT fact_id, pagerank_score, community_id, bridge_score "
|
|
79
|
+
"FROM fact_importance WHERE profile_id = ? "
|
|
80
|
+
"ORDER BY pagerank_score DESC",
|
|
81
|
+
(profile_id,),
|
|
82
|
+
)
|
|
83
|
+
ranked = [dict(row) for row in rows]
|
|
84
|
+
for row in ranked:
|
|
85
|
+
if row.get("community_id") is not None:
|
|
86
|
+
communities[row["fact_id"]] = int(row["community_id"])
|
|
87
|
+
top_5 = [
|
|
88
|
+
(row["fact_id"], round(float(row["pagerank_score"] or 0.0), 4))
|
|
89
|
+
for row in ranked[:5]
|
|
90
|
+
]
|
|
91
|
+
bridges = [
|
|
92
|
+
(row["fact_id"], float(row.get("bridge_score") or 0.0))
|
|
93
|
+
for row in ranked
|
|
94
|
+
]
|
|
95
|
+
bridge_count = len([1 for _fid, score in bridges if score > 0.1])
|
|
96
|
+
top_bridges = sorted(bridges, key=lambda item: -item[1])[:5]
|
|
97
|
+
except Exception as exc:
|
|
98
|
+
logger.debug("Reading back graph metrics failed: %s", exc)
|
|
111
99
|
|
|
112
|
-
|
|
100
|
+
labels: dict[int, str] = {}
|
|
101
|
+
if communities:
|
|
113
102
|
try:
|
|
103
|
+
labels = self.compute_community_labels(profile_id, communities)
|
|
114
104
|
from superlocalmemory.infra.data_root import canonical_data_root
|
|
115
105
|
labels_dir = canonical_data_root()
|
|
116
106
|
labels_dir.mkdir(parents=True, exist_ok=True)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
bridge_count
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"labels=%s",
|
|
139
|
-
graph.number_of_nodes(), unique_communities,
|
|
140
|
-
bridge_count, labels,
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
"node_count": graph.number_of_nodes(),
|
|
145
|
-
"edge_count": graph.number_of_edges(),
|
|
146
|
-
"community_count": unique_communities,
|
|
147
|
-
"top_5_nodes": [
|
|
148
|
-
(nid, round(score, 4)) for nid, score in top_5
|
|
149
|
-
],
|
|
150
|
-
"bridge_count": bridge_count,
|
|
151
|
-
"top_bridge_nodes": [
|
|
152
|
-
(nid, round(s, 4)) for nid, s in top_bridges
|
|
153
|
-
],
|
|
154
|
-
"community_labels": labels,
|
|
155
|
-
}
|
|
156
|
-
except Exception as exc:
|
|
157
|
-
logger.debug("GraphAnalyzer.compute_and_store failed: %s", exc)
|
|
158
|
-
return {
|
|
159
|
-
"node_count": 0,
|
|
160
|
-
"edge_count": 0,
|
|
161
|
-
"community_count": 0,
|
|
162
|
-
"top_5_nodes": [],
|
|
163
|
-
}
|
|
107
|
+
(labels_dir / f"{profile_id}_community_labels.json").write_text(
|
|
108
|
+
json.dumps(labels, indent=2),
|
|
109
|
+
)
|
|
110
|
+
except Exception as exc:
|
|
111
|
+
logger.debug("Community labels skipped: %s", exc)
|
|
112
|
+
|
|
113
|
+
logger.info("GraphAnalyzer: %s", report.summary())
|
|
114
|
+
return {
|
|
115
|
+
"node_count": report.written,
|
|
116
|
+
"edge_count": report.edges,
|
|
117
|
+
"community_count": report.communities,
|
|
118
|
+
"top_5_nodes": top_5,
|
|
119
|
+
"bridge_count": bridge_count,
|
|
120
|
+
"top_bridge_nodes": [
|
|
121
|
+
(fid, round(score, 4)) for fid, score in top_bridges
|
|
122
|
+
],
|
|
123
|
+
"community_labels": labels,
|
|
124
|
+
"engine": report.engine,
|
|
125
|
+
"isolated_facts": report.isolated,
|
|
126
|
+
"duration_ms": report.duration_ms,
|
|
127
|
+
}
|
|
164
128
|
|
|
165
129
|
def compute_pagerank(
|
|
166
130
|
self,
|