seren-memory 2.2.1__tar.gz → 2.2.2__tar.gz

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.
Files changed (48) hide show
  1. {seren_memory-2.2.1 → seren_memory-2.2.2}/PKG-INFO +1 -1
  2. {seren_memory-2.2.1 → seren_memory-2.2.2}/SerenMemory.pyproj +1 -0
  3. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/_version.py +3 -3
  4. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/app.py +1 -0
  5. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/viewer/halls.html +140 -24
  6. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory.egg-info/PKG-INFO +1 -1
  7. {seren_memory-2.2.1 → seren_memory-2.2.2}/pyproject.toml +0 -0
  8. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren-memory.service.sample +0 -0
  9. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren-memory.yaml.sample +0 -0
  10. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/__init__.py +0 -0
  11. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/__main__.py +0 -0
  12. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/_supervised.py +0 -0
  13. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/collections.py +0 -0
  14. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/config.py +0 -0
  15. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/consolidator/__init__.py +0 -0
  16. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/consolidator/service.py +0 -0
  17. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/embedder.py +0 -0
  18. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/mcp/__init__.py +0 -0
  19. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/mcp/server.py +0 -0
  20. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/mcp/tools.py +0 -0
  21. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/models/__init__.py +0 -0
  22. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/models/schemas.py +0 -0
  23. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/routes/__init__.py +0 -0
  24. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/routes/long.py +0 -0
  25. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/routes/near.py +0 -0
  26. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/routes/search.py +0 -0
  27. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory/routes/short.py +0 -0
  28. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory.egg-info/SOURCES.txt +0 -0
  29. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory.egg-info/dependency_links.txt +0 -0
  30. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory.egg-info/entry_points.txt +0 -0
  31. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory.egg-info/requires.txt +0 -0
  32. {seren_memory-2.2.1 → seren_memory-2.2.2}/seren_memory.egg-info/top_level.txt +0 -0
  33. {seren_memory-2.2.1 → seren_memory-2.2.2}/setup.cfg +0 -0
  34. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/__init__.py +0 -0
  35. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/conftest.py +0 -0
  36. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_auth.py +0 -0
  37. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_brief.py +0 -0
  38. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_drafts.py +0 -0
  39. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_embedder.py +0 -0
  40. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_mcp_endpoint.py +0 -0
  41. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_mcp_fallback.py +0 -0
  42. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_mcp_mount.py +0 -0
  43. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_mcp_tools.py +0 -0
  44. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_near_listing.py +0 -0
  45. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_search.py +0 -0
  46. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_smoke.py +0 -0
  47. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_tls.py +0 -0
  48. {seren_memory-2.2.1 → seren_memory-2.2.2}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seren-memory
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: Three-tier LLM memory with consolidation. The Halls of Memory.
5
5
  Author: Chad Roesler
6
6
  License: GPL-3.0-or-later
@@ -80,6 +80,7 @@
80
80
  <Content Include="seren_memory\mcp\__pycache__\tools.cpython-311.pyc" />
81
81
  <Content Include="seren_memory\mcp\__pycache__\__init__.cpython-311.pyc" />
82
82
  <Content Include="seren_memory\viewer\halls.html" />
83
+ <Content Include="seren_memory\viewer\loci.html" />
83
84
  <Content Include="tests\__pycache__\test_smoke.cpython-311-pytest-9.0.3.pyc" />
84
85
  <Content Include="tests\__pycache__\__init__.cpython-311.pyc" />
85
86
  </ItemGroup>
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.2.1'
22
- __version_tuple__ = version_tuple = (2, 2, 1)
21
+ __version__ = version = '2.2.2'
22
+ __version_tuple__ = version_tuple = (2, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g17bc07d50'
24
+ __commit_id__ = commit_id = 'g12a1081ca'
@@ -250,6 +250,7 @@ def create_app(config: MemoryConfig | None = None, embedding_function=None,
250
250
  "service": "SerenMemory",
251
251
  "version": APP_VERSION,
252
252
  "tiers": store.counts(),
253
+ "embedding_model": cfg.storage.embedding_model or "all-MiniLM-L6-v2 (default)",
253
254
  "consolidator": {
254
255
  "enabled": cfg.consolidator.enabled,
255
256
  "mode": cfg.consolidator.mode,
@@ -51,8 +51,13 @@
51
51
  height: 100%;
52
52
  }
53
53
 
54
+ html {
55
+ background: radial-gradient(1200px 600px at 70% -10%, #2a1d2e 0%, var(--bg) 55%) no-repeat fixed;
56
+ background-color: var(--bg);
57
+ }
58
+
54
59
  body {
55
- background: radial-gradient(1200px 600px at 70% -10%, #2a1d2e 0%, var(--bg) 55%);
60
+ background: transparent;
56
61
  color: var(--ink);
57
62
  font-family: var(--sans);
58
63
  font-size: 14px;
@@ -438,6 +443,86 @@
438
443
  color: var(--muted);
439
444
  }
440
445
 
446
+ /* -- overview ----------------------------------------------------- */
447
+ .stat-row {
448
+ display: flex;
449
+ gap: 14px;
450
+ flex-wrap: wrap;
451
+ margin-bottom: 20px;
452
+ }
453
+
454
+ .stat {
455
+ background: var(--panel);
456
+ border: 1px solid var(--line);
457
+ border-radius: 12px;
458
+ padding: 16px 20px;
459
+ min-width: 120px;
460
+ }
461
+
462
+ .stat .big {
463
+ font-size: 28px;
464
+ font-weight: 700;
465
+ }
466
+
467
+ .stat .lbl {
468
+ color: var(--faint);
469
+ font-size: 12px;
470
+ font-family: var(--mono);
471
+ margin-top: 2px;
472
+ }
473
+
474
+ .stat.tier-short .big { color: var(--short); }
475
+ .stat.tier-near .big { color: var(--near); }
476
+ .stat.tier-long .big { color: var(--long); }
477
+ .stat.tier-brief .big { color: var(--brief); }
478
+ .stat.tier-draft .big { color: var(--draft); }
479
+
480
+ .overview-meta {
481
+ margin-top: 20px;
482
+ padding: 14px 16px;
483
+ background: var(--panel);
484
+ border: 1px solid var(--line);
485
+ border-radius: 10px;
486
+ font-size: 13px;
487
+ display: flex;
488
+ flex-direction: column;
489
+ gap: 8px;
490
+ }
491
+
492
+ .overview-meta .row {
493
+ display: flex;
494
+ gap: 10px;
495
+ align-items: baseline;
496
+ }
497
+
498
+ .overview-meta .k {
499
+ color: var(--faint);
500
+ font-family: var(--mono);
501
+ font-size: 11px;
502
+ min-width: 120px;
503
+ }
504
+
505
+ .overview-meta .v {
506
+ color: var(--ink);
507
+ font-family: var(--mono);
508
+ font-size: 12px;
509
+ word-break: break-all;
510
+ }
511
+
512
+ /* embedder pill in header */
513
+ .embedder-pill {
514
+ font-family: var(--mono);
515
+ font-size: 11px;
516
+ padding: 4px 10px;
517
+ border-radius: 999px;
518
+ border: 1px solid var(--accent-dim);
519
+ color: var(--accent);
520
+ white-space: nowrap;
521
+ max-width: 240px;
522
+ overflow: hidden;
523
+ text-overflow: ellipsis;
524
+ }
525
+
441
526
  /* -- auth gate ---------------------------------------------------- */
442
527
  .locked #tabs,
443
528
  .locked main {
@@ -689,11 +774,11 @@
689
774
  <body class="locked">
690
775
  <header>
691
776
  <div class="brand">
692
- <h1>Seren<b>Memory</b> · Halls of Memory</h1>
693
- <span class="sub" id="subtitle">the right brain · episodic, consolidated, gated</span>
777
+ <h1>Seren<b>Memory</b> · Halls of Right Brain</h1>
778
+ <span class="sub" id="subtitle">episodic, consolidated, gated</span>
694
779
  </div>
695
780
  <div class="grow"></div>
696
- <div class="counts" id="counts"></div>
781
+ <span class="embedder-pill" id="embedder-pill" title="embedding model"></span>
697
782
  <button class="iconbtn" id="connectBtn" title="Connection / bearer token">🔑 connect</button>
698
783
  <button class="iconbtn" id="refresh" title="Reload">⟳</button>
699
784
  </header>
@@ -707,6 +792,7 @@
707
792
  <div class="tab" data-tier="briefs"><span class="dot"></span>Briefs</div>
708
793
  <div class="tab" data-tier="drafts"><span class="dot"></span>Drafts</div>
709
794
  <div class="tab" data-tier="search"><span class="dot"></span>Search</div>
795
+ <div class="tab" data-tier="overview"><span class="dot"></span>Overview</div>
710
796
  </nav>
711
797
 
712
798
  <main>
@@ -730,6 +816,7 @@
730
816
  </div>
731
817
 
732
818
  <div class="entries" id="entries"></div>
819
+ <div id="overview-section" style="display:none;"></div>
733
820
  </main>
734
821
 
735
822
  <div class="modal-bg" id="connBg">
@@ -821,15 +908,37 @@
821
908
  // ----------------------------------------------------------------------
822
909
  // Rendering
823
910
  // ----------------------------------------------------------------------
824
- function renderCounts(counts) {
825
- if (!counts) { $('counts').innerHTML = ''; return; }
826
- const pill = (label, n, color) =>
827
- `<span class="count-pill" style="border-color:${color}"><b>${n}</b> ${label}</span>`;
828
- $('counts').innerHTML =
829
- pill('short', counts.short ?? '?', 'var(--short)') +
830
- pill('near', counts.near ?? '?', 'var(--near)') +
831
- pill('long', counts.long ?? '?', 'var(--long)') +
832
- (counts.pruned != null ? pill('pruned', counts.pruned, 'var(--faint)') : '');
911
+ function renderEmbedder(model) {
912
+ const pill = $('embedder-pill');
913
+ if (!pill) return;
914
+ pill.textContent = model || '';
915
+ pill.title = model || '';
916
+ pill.style.display = model ? '' : 'none';
917
+ }
918
+
919
+ function loadOverview(root) {
920
+ const tiers = root.tiers || {};
921
+ const stat = (label, n, cls) =>
922
+ `<div class="stat ${cls}"><div class="big">${n ?? '?'}</div><div class="lbl">${label}</div></div>`;
923
+ const statsHtml = [
924
+ stat('short-term', tiers.short, 'tier-short'),
925
+ stat('near-term', tiers.near, 'tier-near'),
926
+ stat('long-term', tiers.long, 'tier-long'),
927
+ stat('briefs', tiers.briefs ?? '?', 'tier-brief'),
928
+ stat('drafts', tiers.drafts ?? '?', 'tier-draft'),
929
+ tiers.pruned != null ? stat('pruned', tiers.pruned, '') : '',
930
+ ].join('');
931
+
932
+ const con = root.consolidator || {};
933
+ const metaRows = [
934
+ ['version', root.version || '?'],
935
+ ['embedder', root.embedding_model || '?'],
936
+ ['consolidator',con.enabled ? `enabled · ${con.mode || '?'} · every ${con.interval_seconds ?? '?'}s` : 'disabled'],
937
+ ].map(([k, v]) => `<div class="row"><span class="k">${k}</span><span class="v">${escapeHtml(String(v))}</span></div>`).join('');
938
+
939
+ $('overview-section').innerHTML = `
940
+ <div class="stat-row">${statsHtml}</div>
941
+ <div class="overview-meta">${metaRows}</div>`;
833
942
  }
834
943
 
835
944
  function entryCard(tier, content, meta, opts = {}) {
@@ -1042,17 +1151,21 @@
1042
1151
  async function switchTab(tier) {
1043
1152
  state.tab = tier;
1044
1153
  document.querySelectorAll('.tab').forEach(t => t.classList.toggle('active', t.dataset.tier === tier));
1045
- const isSearch = tier === 'search';
1046
- $('searchbar').style.display = isSearch ? 'flex' : 'none';
1047
- $('list-toolbar').style.display = isSearch ? 'none' : 'flex';
1154
+ const isSearch = tier === 'search';
1155
+ const isOverview = tier === 'overview';
1156
+ $('searchbar').style.display = isSearch ? 'flex' : 'none';
1157
+ $('list-toolbar').style.display = (isSearch || isOverview) ? 'none' : 'flex';
1158
+ $('entries').style.display = isOverview ? 'none' : 'flex';
1159
+ $('overview-section').style.display = isOverview ? 'block' : 'none';
1048
1160
  clearError();
1049
1161
  try {
1050
- if (tier === 'short') await loadShort();
1051
- else if (tier === 'near') await loadNear();
1052
- else if (tier === 'long') await loadLong();
1053
- else if (tier === 'briefs') await loadBriefs();
1054
- else if (tier === 'drafts') await loadDrafts();
1055
- else if (tier === 'search') renderEntries(`<div class="empty">enter a query and hit search</div>`);
1162
+ if (tier === 'short') await loadShort();
1163
+ else if (tier === 'near') await loadNear();
1164
+ else if (tier === 'long') await loadLong();
1165
+ else if (tier === 'briefs') await loadBriefs();
1166
+ else if (tier === 'drafts') await loadDrafts();
1167
+ else if (tier === 'search') renderEntries(`<div class="empty">enter a query and hit search</div>`);
1168
+ else if (tier === 'overview') { const r = await api('/'); loadOverview(r); }
1056
1169
  } catch (e) { showError(e.message); renderEntries(''); }
1057
1170
  }
1058
1171
 
@@ -1077,15 +1190,18 @@
1077
1190
  clearError();
1078
1191
  try {
1079
1192
  const root = await api('/');
1080
- renderCounts(root.tiers);
1193
+ renderEmbedder(root.embedding_model);
1194
+ $('subtitle').textContent = `v${root.version ?? '?'} · episodic, consolidated, gated`;
1081
1195
  sessionStorage.setItem('seren_token', state.token);
1082
1196
  unlock();
1083
1197
  // Embedder-mismatch gate: safe-mode raises the migration modal and
1084
1198
  // owns the screen until accepted/denied.
1085
1199
  if (window.checkMigrationGate && await window.checkMigrationGate()) { return; }
1200
+ // Pre-populate overview so it's ready when the user clicks it.
1201
+ loadOverview(root);
1086
1202
  } catch (e) {
1087
1203
  showError(e.message);
1088
- renderCounts(null);
1204
+ renderEmbedder(null);
1089
1205
  sessionStorage.removeItem('seren_token');
1090
1206
  lock();
1091
1207
  return;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seren-memory
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: Three-tier LLM memory with consolidation. The Halls of Memory.
5
5
  Author: Chad Roesler
6
6
  License: GPL-3.0-or-later
File without changes