superlocalmemory 3.8.1 → 3.8.3
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 +67 -0
- package/README.md +2 -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 +2 -2
- 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 +3 -5
- 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 +2 -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 +3 -5
- 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 +1 -1
- package/scripts/postinstall.js +7 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/commands.py +360 -2
- package/src/superlocalmemory/cli/main.py +62 -3
- package/src/superlocalmemory/cli/setup_wizard.py +142 -16
- package/src/superlocalmemory/core/component_healer.py +144 -0
- package/src/superlocalmemory/core/component_registry.py +487 -0
- package/src/superlocalmemory/core/config.py +21 -0
- package/src/superlocalmemory/core/embeddings.py +14 -1
- package/src/superlocalmemory/core/engine.py +9 -5
- package/src/superlocalmemory/core/ingestion_command.py +36 -16
- package/src/superlocalmemory/core/maintenance.py +43 -0
- package/src/superlocalmemory/core/maintenance_scheduler.py +28 -0
- package/src/superlocalmemory/core/recall_pipeline.py +39 -3
- package/src/superlocalmemory/core/store_pipeline.py +42 -0
- package/src/superlocalmemory/mcp/_daemon_proxy.py +6 -2
- package/src/superlocalmemory/mcp/_pool_adapter.py +4 -1
- package/src/superlocalmemory/mcp/tools_active.py +1 -1
- package/src/superlocalmemory/mcp/tools_core.py +17 -2
- package/src/superlocalmemory/retrieval/bridge_discovery.py +14 -0
- package/src/superlocalmemory/retrieval/spreading_activation.py +68 -38
- package/src/superlocalmemory/server/routes/behavioral.py +6 -2
- package/src/superlocalmemory/server/routes/learning.py +13 -3
- package/src/superlocalmemory/server/routes/memories.py +80 -26
- package/src/superlocalmemory/server/routes/v3_api.py +120 -0
- package/src/superlocalmemory/server/unified_daemon.py +349 -10
- package/src/superlocalmemory/storage/embedding_migrator.py +235 -0
- package/src/superlocalmemory/ui/index.html +3 -2
- package/src/superlocalmemory/ui/js/core.js +6 -1
- package/src/superlocalmemory/ui/js/od-components.js +147 -0
- package/src/superlocalmemory/ui/js/od-entities.js +43 -0
- package/src/superlocalmemory/ui/js/od-graph.js +35 -0
- package/src/superlocalmemory/ui/js/od-health.js +18 -0
- package/src/superlocalmemory/ui/js/od-memories.js +37 -0
- package/src/superlocalmemory/ui/js/od-operations.js +36 -0
- package/src/superlocalmemory/ui/js/od-settings.js +72 -3
|
@@ -1566,7 +1566,8 @@
|
|
|
1566
1566
|
<!-- OD screen modules (v3.7.9): approved-design panes wired to live data.
|
|
1567
1567
|
Load LAST so their window.load<Screen> overrides win over the legacy loaders. -->
|
|
1568
1568
|
<script src="static/js/od-brain.js?v=379"></script>
|
|
1569
|
-
<script src="static/js/od-
|
|
1569
|
+
<script src="static/js/od-components.js?v=382"></script>
|
|
1570
|
+
<script src="static/js/od-health.js?v=382"></script>
|
|
1570
1571
|
<script src="static/js/od-operations.js?v=380"></script>
|
|
1571
1572
|
<script src="static/js/od-team.js?v=379"></script>
|
|
1572
1573
|
<script src="static/js/od-graph.js?v=379"></script>
|
|
@@ -1577,7 +1578,7 @@
|
|
|
1577
1578
|
<script src="static/js/od-skills.js?v=379"></script>
|
|
1578
1579
|
<script src="static/js/od-mesh.js?v=379"></script>
|
|
1579
1580
|
<script src="static/js/od-optimize.js?v=379"></script>
|
|
1580
|
-
<script src="static/js/od-settings.js?v=
|
|
1581
|
+
<script src="static/js/od-settings.js?v=382"></script>
|
|
1581
1582
|
<script src="static/js/od-backup.js?v=379"></script>
|
|
1582
1583
|
<!-- MCP & Integrations pane (v3.8.0): shows exposed MCP tool profile + counts -->
|
|
1583
1584
|
<script src="static/js/od-mcp.js?v=380"></script>
|
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
// surfaces as a normal rejection and the UI can show a clear error.
|
|
14
14
|
// ============================================================================
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// v3.8.3: 30s (> the server's 25s recall budget) so the browser waits for a
|
|
17
|
+
// quality recall under heavy multi-agent load instead of aborting it early
|
|
18
|
+
// ("signal is aborted without reason"). The server self-bounds recall and
|
|
19
|
+
// falls back to keyword within its budget, so this only ever waits longer for
|
|
20
|
+
// a genuinely stuck request. Per-call init.timeoutMs still overrides.
|
|
21
|
+
window.SLM_FETCH_TIMEOUT_MS = 30000;
|
|
17
22
|
window.SLM_INSTALL_TOKEN_KEY = 'slm_install_token';
|
|
18
23
|
|
|
19
24
|
// B2 (3.7.9): the install token is kept in a private closure, never in
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// od-components.js — System Health "What's Missing" report (v3.8.2 UX-6)
|
|
2
|
+
//
|
|
3
|
+
// window.odRenderComponents(el) renders the component-registry snapshot from
|
|
4
|
+
// GET /api/v3/components → {components:[...], summary:{...}}
|
|
5
|
+
// into `el`, showing per-component status, a copy-paste fix command for the
|
|
6
|
+
// items SLM can't repair on its own, and a "Retry now" button that triggers
|
|
7
|
+
// POST /api/v3/components/heal (install token auto-attached by core.js)
|
|
8
|
+
// The daemon auto-heals on start; this panel is transparency + a manual
|
|
9
|
+
// fallback for the non-technical user.
|
|
10
|
+
//
|
|
11
|
+
// Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar — AGPL-3.0
|
|
12
|
+
|
|
13
|
+
/* global window, document, fetch, navigator, setTimeout */
|
|
14
|
+
(function () {
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
function esc(s) {
|
|
18
|
+
return String(s == null ? '' : s)
|
|
19
|
+
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
20
|
+
.replace(/"/g, '"').replace(/'/g, ''');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Severity/glyph/colour for one component, honouring its category so an
|
|
24
|
+
// absent optional backend is not shown as an error.
|
|
25
|
+
function view(c) {
|
|
26
|
+
var st = String(c.status || '').toLowerCase();
|
|
27
|
+
if (st === 'ok') return { g: '✓', col: 'var(--ok)', tip: 'ready' };
|
|
28
|
+
if (st === 'retrying') return { g: '⟳', col: 'var(--accent, #4a9)', tip: 'repairing' };
|
|
29
|
+
if (st === 'degraded') return { g: '⚠', col: 'var(--warn)', tip: 'degraded' };
|
|
30
|
+
// missing — severity depends on how much SLM needs it.
|
|
31
|
+
if (c.category === 'required') return { g: '✗', col: 'var(--danger)', tip: 'missing' };
|
|
32
|
+
if (c.category === 'recommended') return { g: '⚠', col: 'var(--warn)', tip: 'missing' };
|
|
33
|
+
return { g: '○', col: 'var(--fg-2)', tip: 'optional' };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function rowHtml(c) {
|
|
37
|
+
var v = view(c);
|
|
38
|
+
var fix = '';
|
|
39
|
+
if (c.status !== 'ok' && c.fix_cmd) {
|
|
40
|
+
if (c.auto_fixable) {
|
|
41
|
+
fix = '<div class="muted" style="margin-top:2px;font-size:12px">'
|
|
42
|
+
+ 'SLM repairs this automatically.</div>';
|
|
43
|
+
} else {
|
|
44
|
+
fix = '<div style="margin-top:4px;display:flex;gap:6px;align-items:center">'
|
|
45
|
+
+ '<code style="font-size:12px;background:var(--bg-2,#0002);'
|
|
46
|
+
+ 'padding:2px 6px;border-radius:4px">' + esc(c.fix_cmd) + '</code>'
|
|
47
|
+
+ '<button class="od-copy-fix" data-cmd="' + esc(c.fix_cmd) + '" '
|
|
48
|
+
+ 'style="font-size:11px;padding:1px 6px;cursor:pointer">Copy</button>'
|
|
49
|
+
+ '</div>';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return '<div style="padding:8px 0;border-bottom:1px solid var(--border,#8881)">'
|
|
53
|
+
+ '<div style="display:flex;gap:8px;align-items:baseline">'
|
|
54
|
+
+ '<span style="color:' + v.col + ';font-weight:700;width:16px;text-align:center">'
|
|
55
|
+
+ v.g + '</span>'
|
|
56
|
+
+ '<div style="flex:1">'
|
|
57
|
+
+ '<span style="font-weight:600">' + esc(c.label) + '</span>'
|
|
58
|
+
+ ' <span class="muted" style="font-size:12px">' + esc(c.detail || v.tip) + '</span>'
|
|
59
|
+
+ fix
|
|
60
|
+
+ '</div></div></div>';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function render(el, data) {
|
|
64
|
+
var comps = (data && data.components) || [];
|
|
65
|
+
var s = (data && data.summary) || {};
|
|
66
|
+
var healthy = !!s.healthy;
|
|
67
|
+
var hasAutoFix = (s.auto_fixable_missing || 0) > 0;
|
|
68
|
+
|
|
69
|
+
var head = '<div style="display:flex;justify-content:space-between;'
|
|
70
|
+
+ 'align-items:center;margin-bottom:6px">'
|
|
71
|
+
+ '<h3 style="margin:0">System Health — Components</h3>'
|
|
72
|
+
+ '<span style="padding:2px 10px;border-radius:12px;font-size:12px;'
|
|
73
|
+
+ 'background:' + (healthy ? 'var(--ok)' : 'var(--warn)') + ';color:#000">'
|
|
74
|
+
+ (healthy ? 'All good' : 'Needs attention') + '</span></div>';
|
|
75
|
+
|
|
76
|
+
var summary = '<div class="muted" style="font-size:12px;margin-bottom:8px">'
|
|
77
|
+
+ (s.ok || 0) + ' ready · ' + (s.missing || 0) + ' missing · '
|
|
78
|
+
+ (s.degraded || 0) + ' degraded'
|
|
79
|
+
+ (s.retrying ? ' · ' + s.retrying + ' repairing' : '') + '</div>';
|
|
80
|
+
|
|
81
|
+
var actions = '<div style="margin-top:10px;display:flex;gap:8px">'
|
|
82
|
+
+ '<button id="od-comp-recheck" style="padding:4px 12px;cursor:pointer">Recheck</button>'
|
|
83
|
+
+ (hasAutoFix
|
|
84
|
+
? '<button id="od-comp-retry" style="padding:4px 12px;cursor:pointer;'
|
|
85
|
+
+ 'background:var(--accent,#4a9);color:#000;border:none;border-radius:4px">'
|
|
86
|
+
+ 'Retry now</button>'
|
|
87
|
+
: '')
|
|
88
|
+
+ '</div>'
|
|
89
|
+
+ '<div class="muted" style="font-size:11px;margin-top:6px">'
|
|
90
|
+
+ 'SLM auto-repairs fixable items on start. Copy a command for anything '
|
|
91
|
+
+ 'it can’t install for you.</div>';
|
|
92
|
+
|
|
93
|
+
el.innerHTML = head + summary
|
|
94
|
+
+ '<div>' + comps.map(rowHtml).join('') + '</div>' + actions;
|
|
95
|
+
|
|
96
|
+
// Copy buttons.
|
|
97
|
+
el.querySelectorAll('.od-copy-fix').forEach(function (b) {
|
|
98
|
+
b.addEventListener('click', function () {
|
|
99
|
+
var cmd = b.getAttribute('data-cmd') || '';
|
|
100
|
+
if (navigator.clipboard) navigator.clipboard.writeText(cmd);
|
|
101
|
+
var old = b.textContent; b.textContent = 'Copied';
|
|
102
|
+
setTimeout(function () { b.textContent = old; }, 1200);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
var recheck = el.querySelector('#od-comp-recheck');
|
|
106
|
+
if (recheck) recheck.addEventListener('click', function () { load(el); });
|
|
107
|
+
var retry = el.querySelector('#od-comp-retry');
|
|
108
|
+
if (retry) retry.addEventListener('click', function () { doRetry(el, retry); });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function load(el) {
|
|
112
|
+
if (!el) return;
|
|
113
|
+
el.innerHTML = '<p class="muted" style="padding:8px 0">Checking components…</p>';
|
|
114
|
+
fetch('/api/v3/components')
|
|
115
|
+
.then(function (r) { return r.ok ? r.json() : null; })
|
|
116
|
+
.then(function (data) {
|
|
117
|
+
if (!data) {
|
|
118
|
+
el.innerHTML = '<p class="muted" style="padding:8px 0">'
|
|
119
|
+
+ 'Component health unavailable (is the daemon running?).</p>';
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
render(el, data);
|
|
123
|
+
})
|
|
124
|
+
.catch(function () {
|
|
125
|
+
el.innerHTML = '<p class="muted" style="padding:8px 0">'
|
|
126
|
+
+ 'Could not load component health.</p>';
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Trigger a background heal, then poll a few times so the panel reflects
|
|
131
|
+
// the retrying → ok transition without the user refreshing.
|
|
132
|
+
function doRetry(el, btn) {
|
|
133
|
+
btn.disabled = true; btn.textContent = 'Repairing…';
|
|
134
|
+
fetch('/api/v3/components/heal', { method: 'POST', credentials: 'same-origin' })
|
|
135
|
+
.then(function () {
|
|
136
|
+
var tries = 0;
|
|
137
|
+
(function poll() {
|
|
138
|
+
tries += 1;
|
|
139
|
+
load(el);
|
|
140
|
+
if (tries < 4) setTimeout(poll, 2500);
|
|
141
|
+
})();
|
|
142
|
+
})
|
|
143
|
+
.catch(function () { load(el); });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
window.odRenderComponents = load;
|
|
147
|
+
})();
|
|
@@ -396,6 +396,17 @@
|
|
|
396
396
|
_dateField('Last seen', listEnt.last_seen) +
|
|
397
397
|
_dateField('Compiled', d.last_compiled_at) +
|
|
398
398
|
'</div>' +
|
|
399
|
+
// Recompile action — restored: POST /api/entity/{name}/recompile
|
|
400
|
+
// The disabled guard was removed; data-ename carries the name to _wire() handler.
|
|
401
|
+
'<div style="margin-top:16px;display:flex;align-items:center;gap:10px">' +
|
|
402
|
+
'<button data-od-act="recompile-entity" ' +
|
|
403
|
+
'data-ename="' + _esc(d.entity_name || '') + '" ' +
|
|
404
|
+
'style="padding:5px 14px;border:1px solid var(--border);border-radius:5px;' +
|
|
405
|
+
'font-size:12px;cursor:pointer;background:var(--bg-2);color:var(--fg)">' +
|
|
406
|
+
'Recompile</button>' +
|
|
407
|
+
'<span id="' + id + '-recompile-status" ' +
|
|
408
|
+
'style="font-size:12px;color:var(--fg-2)"></span>' +
|
|
409
|
+
'</div>' +
|
|
399
410
|
'</div>' +
|
|
400
411
|
'</div>' +
|
|
401
412
|
|
|
@@ -514,12 +525,44 @@
|
|
|
514
525
|
|
|
515
526
|
// ── Event delegation ──────────────────────────────────────────────────────
|
|
516
527
|
|
|
528
|
+
// Recompile entity — POST /api/entity/{name}/recompile
|
|
529
|
+
// Updates button text and status span to give feedback without a page reload.
|
|
530
|
+
function _recompileEntity(id, name, btn) {
|
|
531
|
+
if (!name) return;
|
|
532
|
+
var statusEl = document.getElementById(id + '-recompile-status');
|
|
533
|
+
btn.disabled = true;
|
|
534
|
+
btn.textContent = 'Recompiling…';
|
|
535
|
+
if (statusEl) { statusEl.textContent = ''; }
|
|
536
|
+
fetch('/api/entity/' + encodeURIComponent(name) + '/recompile', { method: 'POST' })
|
|
537
|
+
.then(function (r) { return r.json(); })
|
|
538
|
+
.then(function (data) {
|
|
539
|
+
btn.disabled = false;
|
|
540
|
+
btn.textContent = 'Recompile';
|
|
541
|
+
if (statusEl) {
|
|
542
|
+
statusEl.style.color = 'var(--accent)';
|
|
543
|
+
statusEl.textContent = data.message || 'Recompiled successfully';
|
|
544
|
+
}
|
|
545
|
+
})
|
|
546
|
+
.catch(function (err) {
|
|
547
|
+
btn.disabled = false;
|
|
548
|
+
btn.textContent = 'Recompile';
|
|
549
|
+
if (statusEl) {
|
|
550
|
+
statusEl.style.color = 'var(--danger, #e05)';
|
|
551
|
+
statusEl.textContent = 'Recompile failed: ' + (err.message || 'unknown error');
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
517
556
|
function _wire(container, id) {
|
|
518
557
|
container.addEventListener('click', function (e) {
|
|
519
558
|
var el = e.target.closest('[data-od-act]');
|
|
520
559
|
if (!el) return;
|
|
521
560
|
var act = el.dataset.odAct;
|
|
522
561
|
|
|
562
|
+
if (act === 'recompile-entity') {
|
|
563
|
+
_recompileEntity(id, el.dataset.ename, el);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
523
566
|
if (act === 'type-filter') {
|
|
524
567
|
_st = Object.assign({}, _st, { typeFilter: el.dataset.type, page: 0 });
|
|
525
568
|
_refreshTypeChips(id, el.dataset.type);
|
|
@@ -93,6 +93,31 @@
|
|
|
93
93
|
'<div class="inspector-empty"><div style="font-size:34px;margin-bottom:8px">◇</div>' +
|
|
94
94
|
'Loading your knowledge graph…</div>' +
|
|
95
95
|
'</div>' +
|
|
96
|
+
// Quick Insight Actions — restored: 5 data-insight-action buttons + #insight-results.
|
|
97
|
+
// quick-actions.js (global, non-IIFE) defines fetchInsight(action) which calls
|
|
98
|
+
// GET /api/v3/insights/{action} and writes into #insight-results.
|
|
99
|
+
// Delegation wired in wireControls() so buttons survive re-renders.
|
|
100
|
+
'<div id="odg-insights-panel" style="border-top:1px solid var(--border);' +
|
|
101
|
+
'padding:10px 12px 8px">' +
|
|
102
|
+
'<div style="font-size:10.5px;font-weight:600;color:var(--fg-3);' +
|
|
103
|
+
'text-transform:uppercase;letter-spacing:0.06em;margin-bottom:7px">' +
|
|
104
|
+
'Quick Insights</div>' +
|
|
105
|
+
'<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:7px">' +
|
|
106
|
+
'<button class="chip" style="font-size:11px;padding:3px 9px;cursor:pointer" ' +
|
|
107
|
+
'data-insight-action="changed_this_week">Changed This Week</button>' +
|
|
108
|
+
'<button class="chip" style="font-size:11px;padding:3px 9px;cursor:pointer" ' +
|
|
109
|
+
'data-insight-action="opinions">Opinions</button>' +
|
|
110
|
+
'<button class="chip" style="font-size:11px;padding:3px 9px;cursor:pointer" ' +
|
|
111
|
+
'data-insight-action="contradictions">Contradictions</button>' +
|
|
112
|
+
'<button class="chip" style="font-size:11px;padding:3px 9px;cursor:pointer" ' +
|
|
113
|
+
'data-insight-action="health">Memory Health</button>' +
|
|
114
|
+
'<button class="chip" style="font-size:11px;padding:3px 9px;cursor:pointer" ' +
|
|
115
|
+
'data-insight-action="cross_project">Cross-Project</button>' +
|
|
116
|
+
'</div>' +
|
|
117
|
+
// #insight-results — quick-actions.js writes here via document.getElementById
|
|
118
|
+
'<div id="insight-results" ' +
|
|
119
|
+
'style="max-height:200px;overflow-y:auto;font-size:12px"></div>' +
|
|
120
|
+
'</div>' +
|
|
96
121
|
'<div class="ask">' +
|
|
97
122
|
'<div class="ask-head"><span data-ic="brain"></span> Ask your memory</div>' +
|
|
98
123
|
'<div class="ask-log" id="odg-log">' +
|
|
@@ -502,6 +527,16 @@
|
|
|
502
527
|
q('#odg-send').onclick = sendAsk;
|
|
503
528
|
q('#odg-ask').addEventListener('keydown', function (e) { if (e.key === 'Enter') sendAsk(); });
|
|
504
529
|
|
|
530
|
+
// Quick Insight Actions — delegated on mount so buttons survive od-graph.js re-renders.
|
|
531
|
+
// quick-actions.js:fetchInsight() is global (non-IIFE); it writes into #insight-results
|
|
532
|
+
// which is mounted inside odg-insights-panel above.
|
|
533
|
+
mount.addEventListener('click', function (e) {
|
|
534
|
+
var btn = e.target.closest('[data-insight-action]');
|
|
535
|
+
if (btn && typeof fetchInsight === 'function') {
|
|
536
|
+
fetchInsight(btn.getAttribute('data-insight-action'));
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
|
|
505
540
|
cv.addEventListener('mousedown', function (e) {
|
|
506
541
|
var r = cv.getBoundingClientRect(), n = nodeAt(e.clientX - r.left, e.clientY - r.top);
|
|
507
542
|
if (n) { dragNode = n; selected = n; renderInsp(n); wake(); } else { panning = true; }
|
|
@@ -183,6 +183,20 @@
|
|
|
183
183
|
'</tbody>' +
|
|
184
184
|
'</table>' +
|
|
185
185
|
'</div>' +
|
|
186
|
+
'</div>' +
|
|
187
|
+
|
|
188
|
+
// System Health — Components (v3.8.2 UX-6): what's installed vs missing,
|
|
189
|
+
// with copy-paste fix commands + a Retry-now button. The daemon
|
|
190
|
+
// auto-heals fixable items on start; this is transparency + fallback.
|
|
191
|
+
// Rendered by od-components.js → window.odRenderComponents.
|
|
192
|
+
'<div class="card" style="margin-top:16px">' +
|
|
193
|
+
'<div class="card-head">' +
|
|
194
|
+
'<h3>System Health — Components</h3>' +
|
|
195
|
+
'<span class="sub">models & dependencies · self-healing</span>' +
|
|
196
|
+
'</div>' +
|
|
197
|
+
'<div class="card-pad" id="od-h-components">' +
|
|
198
|
+
'<div class="dim" style="text-align:center;padding:20px">Loading…</div>' +
|
|
199
|
+
'</div>' +
|
|
186
200
|
'</div>'
|
|
187
201
|
);
|
|
188
202
|
}
|
|
@@ -515,6 +529,10 @@
|
|
|
515
529
|
populateTrustSignals(trustStats);
|
|
516
530
|
populateAgentSummary(agentsData, eventsStats);
|
|
517
531
|
populateAgentTable(agentsData);
|
|
532
|
+
// v3.8.2 UX-6: component "what's missing" report (od-components.js).
|
|
533
|
+
if (typeof window.odRenderComponents === 'function') {
|
|
534
|
+
window.odRenderComponents(document.getElementById('od-h-components'));
|
|
535
|
+
}
|
|
518
536
|
|
|
519
537
|
}).catch(function (err) {
|
|
520
538
|
container.innerHTML =
|
|
@@ -147,6 +147,9 @@
|
|
|
147
147
|
'<button class="tab" data-od-act="tab" data-tab="timeline">Creation timeline</button>' +
|
|
148
148
|
'<button class="tab" data-od-act="tab" data-tab="clusters">' +
|
|
149
149
|
'Knowledge clusters <span class="cnt" id="' + id + '-cnt-clusters">…</span></button>' +
|
|
150
|
+
// Recall Lab tab — restored: recall-lab.js is already loaded in index.html and uses
|
|
151
|
+
// document-level click/keydown delegation keyed on IDs below, so it survives re-renders.
|
|
152
|
+
'<button class="tab" data-od-act="tab" data-tab="recall">Recall Lab</button>' +
|
|
150
153
|
'</div>' +
|
|
151
154
|
'<div class="tabpane active" id="' + id + '-pane-all">' + _allScaffold(id) + '</div>' +
|
|
152
155
|
'<div class="tabpane" id="' + id + '-pane-timeline">' + _tlScaffold(id) + '</div>' +
|
|
@@ -155,6 +158,40 @@
|
|
|
155
158
|
_loading('Loading clusters…') +
|
|
156
159
|
'</div>' +
|
|
157
160
|
'</div>' +
|
|
161
|
+
// Recall Lab pane — exact IDs required by recall-lab.js:
|
|
162
|
+
// #recall-lab-query (input), #recall-lab-search (button — click check),
|
|
163
|
+
// #recall-lab-per-page (select, optional), #recall-lab-meta, #recall-lab-results.
|
|
164
|
+
// Backend: POST /api/v3/recall/trace
|
|
165
|
+
'<div class="tabpane" id="' + id + '-pane-recall" style="padding-top:12px">' +
|
|
166
|
+
'<div style="margin-bottom:14px">' +
|
|
167
|
+
'<p style="font-size:13px;color:var(--fg-2);margin-bottom:10px">' +
|
|
168
|
+
'Trace how a recall query is resolved — matching algorithm, scoring, and final result set.' +
|
|
169
|
+
'</p>' +
|
|
170
|
+
'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">' +
|
|
171
|
+
'<input id="recall-lab-query" placeholder="Enter recall query…" autocomplete="off" ' +
|
|
172
|
+
'style="flex:1;min-width:200px;padding:8px 12px;' +
|
|
173
|
+
'border:1px solid var(--border);border-radius:6px;font-size:13px;' +
|
|
174
|
+
'background:var(--bg-2);color:var(--fg)">' +
|
|
175
|
+
'<select id="recall-lab-per-page" ' +
|
|
176
|
+
'style="padding:7px 10px;border:1px solid var(--border);border-radius:6px;' +
|
|
177
|
+
'font-size:13px;background:var(--bg-2);color:var(--fg)">' +
|
|
178
|
+
'<option value="5">5</option>' +
|
|
179
|
+
'<option value="10" selected>10</option>' +
|
|
180
|
+
'<option value="20">20</option>' +
|
|
181
|
+
'<option value="50">50</option>' +
|
|
182
|
+
'</select>' +
|
|
183
|
+
'<button id="recall-lab-search" ' +
|
|
184
|
+
'style="padding:8px 18px;background:var(--accent);color:#fff;' +
|
|
185
|
+
'border:none;border-radius:6px;font-size:13px;cursor:pointer;' +
|
|
186
|
+
'white-space:nowrap">Run Trace</button>' +
|
|
187
|
+
'</div>' +
|
|
188
|
+
'</div>' +
|
|
189
|
+
// #recall-lab-meta — written by recall-lab.js before results (timing, count, etc.)
|
|
190
|
+
'<div id="recall-lab-meta" ' +
|
|
191
|
+
'style="font-size:12px;color:var(--fg-2);margin-bottom:8px"></div>' +
|
|
192
|
+
// #recall-lab-results — written by recall-lab.js (result cards, pagination)
|
|
193
|
+
'<div id="recall-lab-results"></div>' +
|
|
194
|
+
'</div>' +
|
|
158
195
|
'</div>'
|
|
159
196
|
);
|
|
160
197
|
}
|
|
@@ -96,6 +96,9 @@
|
|
|
96
96
|
'<button class="tab" data-od-tab="trust">Trust</button>' +
|
|
97
97
|
'<button class="tab" data-od-tab="compliance">Compliance</button>' +
|
|
98
98
|
'<button class="tab" data-od-tab="loops">Bounded Loops</button>' +
|
|
99
|
+
// Ingestion tab — restored: re-mounts #ingestion-overview + #ingestion-adapters
|
|
100
|
+
// so ng-ingestion.js (loaded in index.html) can populate them on call.
|
|
101
|
+
'<button class="tab" data-od-tab="ingestion">Ingestion</button>' +
|
|
99
102
|
'</div>' +
|
|
100
103
|
|
|
101
104
|
// ══════ LIFECYCLE TAB ══════════════════════════════════════════════
|
|
@@ -427,6 +430,31 @@
|
|
|
427
430
|
'</div>' +
|
|
428
431
|
'</div>' +
|
|
429
432
|
|
|
433
|
+
'</section>' +
|
|
434
|
+
|
|
435
|
+
// ══════ INGESTION TAB ═════════════════════════════════════════════
|
|
436
|
+
// Restoration: mounts #ingestion-overview and #ingestion-adapters so that
|
|
437
|
+
// window.loadIngestionStatus() (ng-ingestion.js) can populate them.
|
|
438
|
+
// ng-ingestion.js is loaded in index.html and defines loadIngestionStatus().
|
|
439
|
+
// Adapter action buttons use data-act-click="adapter-action" which is handled
|
|
440
|
+
// by event-delegation.js → adapterAction() defined in ng-ingestion.js.
|
|
441
|
+
// Backend: GET /api/adapters · POST /api/adapters/{enable|disable|start|stop}
|
|
442
|
+
'<section class="tabpane" data-od-pane="ingestion">' +
|
|
443
|
+
|
|
444
|
+
'<div class="page-head" style="margin-bottom:16px">' +
|
|
445
|
+
'<h2 style="font-size:20px;margin-bottom:6px">Connectors & Ingestion</h2>' +
|
|
446
|
+
'<p style="font-size:13.5px">' +
|
|
447
|
+
'Gmail, Calendar, and Transcript adapters — enable to start building memory ' +
|
|
448
|
+
'from external sources. All processing is local.' +
|
|
449
|
+
'</p>' +
|
|
450
|
+
'</div>' +
|
|
451
|
+
|
|
452
|
+
// #ingestion-overview — ng-ingestion.js: 4 stat cards (Available/Enabled/Running/Privacy)
|
|
453
|
+
'<div id="ingestion-overview"></div>' +
|
|
454
|
+
|
|
455
|
+
// #ingestion-adapters — ng-ingestion.js: adapter cards (Gmail/Calendar/Transcript)
|
|
456
|
+
'<div id="ingestion-adapters" style="margin-top:16px"></div>' +
|
|
457
|
+
|
|
430
458
|
'</section>'
|
|
431
459
|
);
|
|
432
460
|
}
|
|
@@ -1227,6 +1255,14 @@
|
|
|
1227
1255
|
window.odRenderTeam(document.getElementById('od-team-mount'));
|
|
1228
1256
|
}
|
|
1229
1257
|
|
|
1258
|
+
// Ingestion (Gmail / Calendar / Transcript) — re-linked to ng-ingestion.js.
|
|
1259
|
+
// #ingestion-overview and #ingestion-adapters are now in the skeleton DOM
|
|
1260
|
+
// (inside the Ingestion tab section); calling loadIngestionStatus() renders them.
|
|
1261
|
+
// The function is null-guarded: no-op if ng-ingestion.js failed to load.
|
|
1262
|
+
if (typeof window.loadIngestionStatus === 'function') {
|
|
1263
|
+
window.loadIngestionStatus();
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1230
1266
|
}).catch(function (err) {
|
|
1231
1267
|
container.innerHTML =
|
|
1232
1268
|
'<div style="color:var(--danger);text-align:center;padding:48px 0">' +
|
|
@@ -509,6 +509,75 @@
|
|
|
509
509
|
}).catch(function () {});
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
+
/* ═══════════════════════════════════════════════════════════
|
|
513
|
+
GROUP — Recall & Memory Behaviour (v3.8.2, live-apply, no restart)
|
|
514
|
+
PUT /api/v3/runtime/config {retrieval:{top_k,use_cross_encoder},
|
|
515
|
+
injection:{enabled,core_block_enabled,
|
|
516
|
+
core_block_max_facts}}
|
|
517
|
+
═══════════════════════════════════════════════════════════ */
|
|
518
|
+
function buildRuntime() {
|
|
519
|
+
var topkWrap = makeRange('rt-topk', 1, 200, 1, 20);
|
|
520
|
+
var topkInp = topkWrap.querySelector('input');
|
|
521
|
+
var xencSw = makeSwitch('rt-xenc', true);
|
|
522
|
+
var injSw = makeSwitch('rt-inj', true);
|
|
523
|
+
var cbSw = makeSwitch('rt-cb', true);
|
|
524
|
+
var cbWrap = makeRange('rt-cbmax', 0, 50, 1, 5);
|
|
525
|
+
var cbInp = cbWrap.querySelector('input');
|
|
526
|
+
var st = makeSt('rt');
|
|
527
|
+
function save() {
|
|
528
|
+
authPut('/api/v3/runtime/config', {
|
|
529
|
+
retrieval: {
|
|
530
|
+
top_k: Number(topkInp.value),
|
|
531
|
+
use_cross_encoder: xencSw.classList.contains('on')
|
|
532
|
+
},
|
|
533
|
+
injection: {
|
|
534
|
+
enabled: injSw.classList.contains('on'),
|
|
535
|
+
core_block_enabled: cbSw.classList.contains('on'),
|
|
536
|
+
core_block_max_facts: Number(cbInp.value)
|
|
537
|
+
}
|
|
538
|
+
}).then(function (r) { return r.json(); })
|
|
539
|
+
.then(function (d) {
|
|
540
|
+
setSt('rt', d.success !== false ? 'Applied' : esc(d.error || 'Error'), d.success !== false);
|
|
541
|
+
if (d.success !== false) loadRuntime();
|
|
542
|
+
})
|
|
543
|
+
.catch(function () { setSt('rt', 'Error', false); toast('Save failed', true); });
|
|
544
|
+
}
|
|
545
|
+
// Ranges save on release ('change'), not each drag tick ('input').
|
|
546
|
+
topkInp.addEventListener('change', save);
|
|
547
|
+
cbInp.addEventListener('change', save);
|
|
548
|
+
xencSw.addEventListener('od-toggle', save);
|
|
549
|
+
injSw.addEventListener('od-toggle', save);
|
|
550
|
+
cbSw.addEventListener('od-toggle', save);
|
|
551
|
+
return makeGrp('Recall & Memory Behaviour (auto-saves, no restart)', 'operations', [
|
|
552
|
+
makeRow('Recall depth', 'Memories each recall considers — higher is more thorough, a little slower', 'retrieval.top_k', topkWrap),
|
|
553
|
+
makeRow('Reranker', 'Re-scores results for quality (uses ~200MB RAM, adds ~200ms)', 'retrieval.use_cross_encoder', xencSw),
|
|
554
|
+
makeRow('Inject memories into prompts', 'Master switch for automatic memory injection', 'injection.enabled', injSw),
|
|
555
|
+
makeRow('Core-memory block', 'Prepend your most important facts to every prompt', 'injection.core_block_enabled', cbSw),
|
|
556
|
+
makeRow('Core-block size', 'Max facts in the core-memory block', 'injection.core_block_max_facts', cbWrap),
|
|
557
|
+
makeRow('Status', '', '', st)
|
|
558
|
+
]);
|
|
559
|
+
}
|
|
560
|
+
function loadRuntime() {
|
|
561
|
+
fetch('/api/v3/runtime/config').then(function (r) { return r.ok ? r.json() : null; })
|
|
562
|
+
.then(function (d) {
|
|
563
|
+
if (!d || !d.config) return;
|
|
564
|
+
var rt = d.config.retrieval || {}, inj = d.config.injection || {};
|
|
565
|
+
function setRange(id, val) {
|
|
566
|
+
var i = q(id); if (i == null) return;
|
|
567
|
+
i.value = val; var disp = q(id + '-disp'); if (disp) disp.textContent = val;
|
|
568
|
+
}
|
|
569
|
+
function setSw(id, on) {
|
|
570
|
+
var s = q(id); if (!s) return;
|
|
571
|
+
s.classList.toggle('on', !!on); s.setAttribute('aria-checked', String(!!on));
|
|
572
|
+
}
|
|
573
|
+
if (rt.top_k != null) setRange('rt-topk', rt.top_k);
|
|
574
|
+
setSw('rt-xenc', rt.use_cross_encoder);
|
|
575
|
+
setSw('rt-inj', inj.enabled);
|
|
576
|
+
setSw('rt-cb', inj.core_block_enabled);
|
|
577
|
+
if (inj.core_block_max_facts != null) setRange('rt-cbmax', inj.core_block_max_facts);
|
|
578
|
+
}).catch(function () {});
|
|
579
|
+
}
|
|
580
|
+
|
|
512
581
|
/* ═══════════════════════════════════════════════════════════
|
|
513
582
|
GROUP 5 — Auto-Capture
|
|
514
583
|
═══════════════════════════════════════════════════════════ */
|
|
@@ -1026,8 +1095,8 @@
|
|
|
1026
1095
|
});
|
|
1027
1096
|
}
|
|
1028
1097
|
function loadAll() {
|
|
1029
|
-
loadMode(); loadEmb(); loadStorage(); loadScope();
|
|
1030
|
-
loadRecall(); loadInvoke(); loadForgetting(); loadEvolution();
|
|
1098
|
+
loadMode(); loadEmb(); loadStorage(); loadScope(); loadRuntime();
|
|
1099
|
+
loadCapture(); loadRecall(); loadInvoke(); loadForgetting(); loadEvolution();
|
|
1031
1100
|
loadBackup(); loadMesh(); loadTrust(); loadRateLimit(); loadDaemon();
|
|
1032
1101
|
}
|
|
1033
1102
|
|
|
@@ -1062,7 +1131,7 @@
|
|
|
1062
1131
|
hub.appendChild(sWrap);
|
|
1063
1132
|
|
|
1064
1133
|
var frag = document.createDocumentFragment();
|
|
1065
|
-
[buildMode(), buildEmb(), buildStorage(), buildScope(),
|
|
1134
|
+
[buildMode(), buildEmb(), buildStorage(), buildScope(), buildRuntime(),
|
|
1066
1135
|
buildCapture(), buildRecall(), buildInvoke(), buildForgetting(),
|
|
1067
1136
|
buildEvolution(), buildBackup(), buildMesh(), buildTrust(),
|
|
1068
1137
|
buildRateLimit(), buildDaemon()
|