superlocalmemory 3.0.17 → 3.0.18

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.
@@ -1,4 +1,4 @@
1
- // SuperLocalMemory V3 — Recall Lab with Pagination
1
+ // SuperLocalMemory V3 — Recall Lab with Dual-Display + Pagination
2
2
  // Part of Qualixar | https://superlocalmemory.com
3
3
 
4
4
  var recallLabState = {
@@ -6,6 +6,7 @@ var recallLabState = {
6
6
  page: 0,
7
7
  perPage: 10,
8
8
  query: '',
9
+ synthesis: '',
9
10
  };
10
11
 
11
12
  document.getElementById('recall-lab-search')?.addEventListener('click', function() {
@@ -16,13 +17,13 @@ document.getElementById('recall-lab-search')?.addEventListener('click', function
16
17
  recallLabState.page = 0;
17
18
  var perPageEl = document.getElementById('recall-lab-per-page');
18
19
  recallLabState.perPage = perPageEl ? parseInt(perPageEl.value) : 10;
19
- var fetchLimit = Math.max(recallLabState.perPage * 5, 50); // Fetch up to 5 pages
20
+ var fetchLimit = Math.max(recallLabState.perPage * 5, 50);
20
21
 
21
22
  var resultsDiv = document.getElementById('recall-lab-results');
22
23
  var metaDiv = document.getElementById('recall-lab-meta');
23
24
  resultsDiv.textContent = '';
24
25
  var spinner = document.createElement('div');
25
- spinner.className = 'text-center';
26
+ spinner.className = 'text-center py-4';
26
27
  var spinnerInner = document.createElement('div');
27
28
  spinnerInner.className = 'spinner-border text-primary';
28
29
  spinner.appendChild(spinnerInner);
@@ -31,7 +32,7 @@ document.getElementById('recall-lab-search')?.addEventListener('click', function
31
32
  fetch('/api/v3/recall/trace', {
32
33
  method: 'POST',
33
34
  headers: {'Content-Type': 'application/json'},
34
- body: JSON.stringify({query: query, limit: fetchLimit})
35
+ body: JSON.stringify({query: query, limit: fetchLimit, synthesize: true})
35
36
  }).then(function(r) { return r.json(); }).then(function(data) {
36
37
  if (data.error) {
37
38
  resultsDiv.textContent = '';
@@ -50,6 +51,7 @@ document.getElementById('recall-lab-search')?.addEventListener('click', function
50
51
  appendMetaField(metaDiv, 'Time: ', (data.retrieval_time_ms || 0).toFixed(0) + 'ms');
51
52
 
52
53
  recallLabState.allResults = data.results || [];
54
+ recallLabState.synthesis = data.synthesis || '';
53
55
 
54
56
  if (recallLabState.allResults.length === 0) {
55
57
  resultsDiv.textContent = '';
@@ -80,6 +82,20 @@ function renderRecallPage() {
80
82
  var pageResults = results.slice(start, end);
81
83
  var totalPages = Math.ceil(results.length / recallLabState.perPage);
82
84
 
85
+ // Synthesis banner (Mode B/C only)
86
+ if (recallLabState.synthesis && recallLabState.page === 0) {
87
+ var synBanner = document.createElement('div');
88
+ synBanner.className = 'alert alert-light border-start border-4 border-primary mb-3';
89
+ var synTitle = document.createElement('strong');
90
+ synTitle.textContent = 'AI Summary';
91
+ synBanner.appendChild(synTitle);
92
+ synBanner.appendChild(document.createElement('br'));
93
+ var synText = document.createElement('span');
94
+ synText.textContent = recallLabState.synthesis;
95
+ synBanner.appendChild(synText);
96
+ resultsDiv.appendChild(synBanner);
97
+ }
98
+
83
99
  var listGroup = document.createElement('div');
84
100
  listGroup.className = 'list-group';
85
101
 
@@ -87,60 +103,108 @@ function renderRecallPage() {
87
103
  var globalIndex = start + i;
88
104
  var channels = r.channel_scores || {};
89
105
  var maxChannel = Math.max(channels.semantic || 0, channels.bm25 || 0, channels.entity_graph || 0, channels.temporal || 0) || 1;
106
+ var hasSource = r.source_content && r.source_content.length > 0;
107
+ var displayText = hasSource ? r.source_content : r.content;
90
108
 
91
109
  var item = document.createElement('div');
92
- item.className = 'list-group-item list-group-item-action';
110
+ item.className = 'list-group-item';
111
+
112
+ // Score badge row
113
+ var scoreRow = document.createElement('div');
114
+ scoreRow.className = 'd-flex justify-content-between align-items-center mb-1';
115
+ var numLabel = document.createElement('strong');
116
+ numLabel.textContent = '#' + (globalIndex + 1);
117
+ scoreRow.appendChild(numLabel);
118
+ var scoreBadges = document.createElement('div');
119
+ scoreBadges.innerHTML = '<span class="badge bg-primary me-1">Score: ' + r.score + '</span>' +
120
+ '<span class="badge bg-secondary me-1">Trust: ' + r.trust_score + '</span>' +
121
+ '<span class="badge bg-outline-info" style="border:1px solid #0dcaf0;color:#0dcaf0;">Conf: ' + r.confidence + '</span>';
122
+ scoreRow.appendChild(scoreBadges);
123
+ item.appendChild(scoreRow);
124
+
125
+ // Original memory text (primary display)
126
+ var contentDiv = document.createElement('div');
127
+ contentDiv.className = 'mb-2';
128
+ contentDiv.style.cssText = 'white-space:pre-wrap; line-height:1.5;';
129
+ var truncated = displayText.length > 500 ? displayText.substring(0, 500) + '...' : displayText;
130
+ contentDiv.textContent = truncated;
131
+ item.appendChild(contentDiv);
132
+
133
+ // Expandable atomic fact section (only if source differs from content)
134
+ if (hasSource && r.content !== r.source_content) {
135
+ var expandBtn = document.createElement('button');
136
+ expandBtn.className = 'btn btn-sm btn-outline-secondary mb-2';
137
+ expandBtn.textContent = 'Show matched fact + channels';
138
+ var factSection = document.createElement('div');
139
+ factSection.style.display = 'none';
140
+ factSection.className = 'border-top pt-2 mt-1';
141
+
142
+ var factLabel = document.createElement('small');
143
+ factLabel.className = 'text-muted d-block mb-1';
144
+ factLabel.textContent = 'Matched atomic fact:';
145
+ factSection.appendChild(factLabel);
146
+
147
+ var factContent = document.createElement('div');
148
+ factContent.className = 'small bg-light p-2 rounded mb-2';
149
+ factContent.textContent = r.content;
150
+ factSection.appendChild(factContent);
151
+
152
+ // Channel bars
153
+ factSection.appendChild(buildChannelBar('Semantic', channels.semantic || 0, maxChannel, 'primary'));
154
+ factSection.appendChild(buildChannelBar('BM25', channels.bm25 || 0, maxChannel, 'success'));
155
+ factSection.appendChild(buildChannelBar('Entity', channels.entity_graph || 0, maxChannel, 'info'));
156
+ factSection.appendChild(buildChannelBar('Temporal', channels.temporal || 0, maxChannel, 'warning'));
157
+
158
+ expandBtn.addEventListener('click', function() {
159
+ var visible = factSection.style.display !== 'none';
160
+ factSection.style.display = visible ? 'none' : 'block';
161
+ expandBtn.textContent = visible ? 'Show matched fact + channels' : 'Hide matched fact';
162
+ });
163
+
164
+ item.appendChild(expandBtn);
165
+ item.appendChild(factSection);
166
+ } else {
167
+ // No source_content — show channel bars inline
168
+ var barsDiv = document.createElement('div');
169
+ barsDiv.className = 'mt-1';
170
+ barsDiv.appendChild(buildChannelBar('Semantic', channels.semantic || 0, maxChannel, 'primary'));
171
+ barsDiv.appendChild(buildChannelBar('BM25', channels.bm25 || 0, maxChannel, 'success'));
172
+ barsDiv.appendChild(buildChannelBar('Entity', channels.entity_graph || 0, maxChannel, 'info'));
173
+ barsDiv.appendChild(buildChannelBar('Temporal', channels.temporal || 0, maxChannel, 'warning'));
174
+ item.appendChild(barsDiv);
175
+ }
176
+
177
+ // Click for detail modal
93
178
  item.style.cursor = 'pointer';
94
- item.title = 'Click to view full memory';
95
179
  (function(result) {
96
- item.addEventListener('click', function() {
180
+ contentDiv.addEventListener('click', function() {
97
181
  if (typeof openMemoryDetail === 'function') {
98
182
  openMemoryDetail({
99
183
  id: result.fact_id,
100
- content: result.content,
184
+ memory_id: result.memory_id,
185
+ content: result.source_content || result.content,
101
186
  score: result.score,
102
187
  importance: Math.round((result.confidence || 0.5) * 10),
103
188
  category: 'recall',
104
- tags: Object.keys(result.channel_scores || {}).join(', '),
105
189
  created_at: null,
106
190
  trust_score: result.trust_score,
107
191
  channel_scores: result.channel_scores
108
- });
192
+ }, 'recall'); // source='recall': show View Original, hide Expand Neighbors
109
193
  }
110
194
  });
111
195
  })(r);
112
196
 
113
- var header = document.createElement('h6');
114
- header.className = 'mb-1';
115
- header.textContent = (globalIndex + 1) + '. ' + (r.content || '').substring(0, 200);
116
- item.appendChild(header);
117
-
118
- var meta = document.createElement('small');
119
- meta.className = 'text-muted';
120
- meta.textContent = 'Score: ' + r.score + ' | Trust: ' + r.trust_score + ' | Confidence: ' + r.confidence;
121
- item.appendChild(meta);
122
-
123
- var barsDiv = document.createElement('div');
124
- barsDiv.className = 'mt-2';
125
- barsDiv.appendChild(buildChannelBar('Semantic', channels.semantic || 0, maxChannel, 'primary'));
126
- barsDiv.appendChild(buildChannelBar('BM25', channels.bm25 || 0, maxChannel, 'success'));
127
- barsDiv.appendChild(buildChannelBar('Entity', channels.entity_graph || 0, maxChannel, 'info'));
128
- barsDiv.appendChild(buildChannelBar('Temporal', channels.temporal || 0, maxChannel, 'warning'));
129
- item.appendChild(barsDiv);
130
-
131
197
  listGroup.appendChild(item);
132
198
  });
133
199
  resultsDiv.appendChild(listGroup);
134
200
 
135
- // Pagination controls
201
+ // Pagination
136
202
  if (totalPages > 1) {
137
203
  var nav = document.createElement('nav');
138
204
  nav.className = 'mt-3';
139
- nav.setAttribute('aria-label', 'Recall results pagination');
140
205
  var ul = document.createElement('ul');
141
206
  ul.className = 'pagination justify-content-center';
142
207
 
143
- // Prev
144
208
  var prevLi = document.createElement('li');
145
209
  prevLi.className = 'page-item' + (recallLabState.page === 0 ? ' disabled' : '');
146
210
  var prevA = document.createElement('a');
@@ -149,15 +213,11 @@ function renderRecallPage() {
149
213
  prevA.textContent = 'Previous';
150
214
  prevA.addEventListener('click', function(e) {
151
215
  e.preventDefault();
152
- if (recallLabState.page > 0) {
153
- recallLabState.page--;
154
- renderRecallPage();
155
- }
216
+ if (recallLabState.page > 0) { recallLabState.page--; renderRecallPage(); }
156
217
  });
157
218
  prevLi.appendChild(prevA);
158
219
  ul.appendChild(prevLi);
159
220
 
160
- // Page numbers
161
221
  for (var p = 0; p < totalPages; p++) {
162
222
  var li = document.createElement('li');
163
223
  li.className = 'page-item' + (p === recallLabState.page ? ' active' : '');
@@ -176,7 +236,6 @@ function renderRecallPage() {
176
236
  ul.appendChild(li);
177
237
  }
178
238
 
179
- // Next
180
239
  var nextLi = document.createElement('li');
181
240
  nextLi.className = 'page-item' + (recallLabState.page >= totalPages - 1 ? ' disabled' : '');
182
241
  var nextA = document.createElement('a');
@@ -185,18 +244,13 @@ function renderRecallPage() {
185
244
  nextA.textContent = 'Next';
186
245
  nextA.addEventListener('click', function(e) {
187
246
  e.preventDefault();
188
- if (recallLabState.page < totalPages - 1) {
189
- recallLabState.page++;
190
- renderRecallPage();
191
- }
247
+ if (recallLabState.page < totalPages - 1) { recallLabState.page++; renderRecallPage(); }
192
248
  });
193
249
  nextLi.appendChild(nextA);
194
250
  ul.appendChild(nextLi);
195
-
196
251
  nav.appendChild(ul);
197
252
  resultsDiv.appendChild(nav);
198
253
 
199
- // Page info
200
254
  var info = document.createElement('div');
201
255
  info.className = 'text-center text-muted small';
202
256
  info.textContent = 'Showing ' + (start + 1) + '-' + end + ' of ' + results.length + ' results';
@@ -205,8 +259,7 @@ function renderRecallPage() {
205
259
  }
206
260
 
207
261
  function appendMetaField(parent, label, value) {
208
- var text = document.createTextNode(label);
209
- parent.appendChild(text);
262
+ parent.appendChild(document.createTextNode(label));
210
263
  var strong = document.createElement('strong');
211
264
  strong.textContent = value;
212
265
  parent.appendChild(strong);
@@ -234,7 +287,6 @@ function buildChannelBar(name, score, max, color) {
234
287
  return row;
235
288
  }
236
289
 
237
- // Enter key support
238
290
  document.getElementById('recall-lab-query')?.addEventListener('keydown', function(e) {
239
291
  if (e.key === 'Enter') document.getElementById('recall-lab-search')?.click();
240
292
  });