@agentmemory/agentmemory 0.9.2 → 0.9.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/dist/cli.mjs +132 -23
- package/dist/cli.mjs.map +1 -1
- package/dist/image-refs-CESf9ndJ.mjs +3 -0
- package/dist/{image-store-BLOkD0xV.mjs → image-store-DGvZMMrI.mjs} +1 -1
- package/dist/index.mjs +101 -18
- package/dist/index.mjs.map +1 -1
- package/dist/{src-tmuZyobT.mjs → src-3Snd7D3T.mjs} +109 -26
- package/dist/src-3Snd7D3T.mjs.map +1 -0
- package/dist/{standalone-BiwX0rdC.mjs → standalone-BG9uPsDK.mjs} +2 -2
- package/dist/{standalone-BiwX0rdC.mjs.map → standalone-BG9uPsDK.mjs.map} +1 -1
- package/dist/standalone.mjs +1 -1
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-CHH84gIQ.mjs → tools-registry-m8Ofn9vV.mjs} +2 -2
- package/dist/{tools-registry-CHH84gIQ.mjs.map → tools-registry-m8Ofn9vV.mjs.map} +1 -1
- package/dist/viewer/index.html +283 -10
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/image-refs-Dq5wcV-a.mjs +0 -3
- package/dist/src-tmuZyobT.mjs.map +0 -1
package/dist/viewer/index.html
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
:root {
|
|
10
10
|
--bg: #F9F9F7;
|
|
11
11
|
--bg-alt: #F0F0EC;
|
|
12
|
+
--bg-subtle: #F4F4F0;
|
|
12
13
|
--bg-inset: #E8E8E3;
|
|
13
14
|
--border: #111111;
|
|
14
15
|
--border-light: #D4D4CF;
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
html[data-theme="dark"] {
|
|
44
45
|
--bg: #1a1a1e;
|
|
45
46
|
--bg-alt: #232328;
|
|
47
|
+
--bg-subtle: #1f1f24;
|
|
46
48
|
--bg-inset: #2a2a30;
|
|
47
49
|
--border: #444;
|
|
48
50
|
--border-light: #3a3a42;
|
|
@@ -77,6 +79,8 @@
|
|
|
77
79
|
line-height: 1.6;
|
|
78
80
|
overflow: hidden;
|
|
79
81
|
height: 100vh;
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-direction: column;
|
|
80
84
|
background-image: radial-gradient(circle, #D4D4CF 0.5px, transparent 0.5px);
|
|
81
85
|
background-size: 16px 16px;
|
|
82
86
|
}
|
|
@@ -168,7 +172,7 @@
|
|
|
168
172
|
border-bottom-color: var(--accent);
|
|
169
173
|
}
|
|
170
174
|
|
|
171
|
-
.view { display: none;
|
|
175
|
+
.view { display: none; flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 24px; }
|
|
172
176
|
.view.active { display: block; }
|
|
173
177
|
|
|
174
178
|
.stats-grid {
|
|
@@ -576,6 +580,81 @@
|
|
|
576
580
|
}
|
|
577
581
|
.empty-state .empty-icon { font-size: 36px; margin-bottom: 10px; opacity: 0.4; }
|
|
578
582
|
.empty-state p { font-size: 14px; font-family: var(--font-body); font-style: italic; }
|
|
583
|
+
.empty-state .empty-title { font-size: 16px; font-weight: 600; font-style: normal; color: var(--ink-muted); margin-bottom: 8px; }
|
|
584
|
+
.empty-state .empty-lead { font-style: normal; font-size: 14px; color: var(--ink-muted); max-width: 520px; margin: 0 auto 14px; line-height: 1.5; }
|
|
585
|
+
.empty-state pre.empty-cmd {
|
|
586
|
+
display: inline-block; margin: 10px auto 12px; padding: 10px 14px;
|
|
587
|
+
background: var(--bg-alt); border: 1px solid var(--border);
|
|
588
|
+
border-radius: 4px; font-family: var(--font-mono); font-size: 12px;
|
|
589
|
+
color: var(--ink); text-align: left; font-style: normal; white-space: pre;
|
|
590
|
+
}
|
|
591
|
+
.empty-state .empty-link { color: var(--accent); text-decoration: underline; font-size: 13px; font-style: normal; }
|
|
592
|
+
|
|
593
|
+
/* Feature flag banner system — compact collapsed by default */
|
|
594
|
+
.flag-banners { padding: 0 0 10px 0; }
|
|
595
|
+
button.flag-summary {
|
|
596
|
+
display: flex; align-items: center; gap: 12px;
|
|
597
|
+
padding: 8px 14px; border-radius: 4px;
|
|
598
|
+
border: 1px solid var(--border);
|
|
599
|
+
background: var(--bg-subtle);
|
|
600
|
+
font-family: var(--font-ui); font-size: 12px;
|
|
601
|
+
color: var(--ink-muted);
|
|
602
|
+
cursor: pointer; user-select: none;
|
|
603
|
+
width: 100%; text-align: left;
|
|
604
|
+
appearance: none;
|
|
605
|
+
}
|
|
606
|
+
button.flag-summary:hover,
|
|
607
|
+
button.flag-summary:focus-visible { background: var(--bg-alt); outline: 2px solid var(--border); outline-offset: 1px; }
|
|
608
|
+
.flag-summary .flag-count { color: var(--ink); font-weight: 600; }
|
|
609
|
+
.flag-summary .flag-pill {
|
|
610
|
+
display: inline-block; padding: 1px 8px; border-radius: 10px;
|
|
611
|
+
background: #f59e0b20; color: #d97706; font-size: 11px; font-weight: 600;
|
|
612
|
+
margin-right: 6px;
|
|
613
|
+
}
|
|
614
|
+
.flag-summary .flag-pill.info { background: var(--border-light); color: var(--ink-muted); }
|
|
615
|
+
.flag-summary .flag-toggle { margin-left: auto; font-size: 11px; opacity: 0.7; }
|
|
616
|
+
.flag-list {
|
|
617
|
+
display: none; flex-direction: column; gap: 6px;
|
|
618
|
+
margin-top: 6px;
|
|
619
|
+
}
|
|
620
|
+
.flag-list.open { display: flex; }
|
|
621
|
+
.flag-banner {
|
|
622
|
+
display: flex; align-items: flex-start; gap: 10px;
|
|
623
|
+
padding: 10px 14px; border-radius: 3px;
|
|
624
|
+
border: 1px solid var(--border);
|
|
625
|
+
background: var(--bg-subtle);
|
|
626
|
+
font-family: var(--font-ui); font-size: 12px;
|
|
627
|
+
}
|
|
628
|
+
.flag-banner.warn { border-left: 3px solid #f59e0b; }
|
|
629
|
+
.flag-banner.info { border-left: 3px solid var(--ink-muted); }
|
|
630
|
+
.flag-banner .flag-icon { flex-shrink: 0; font-size: 14px; line-height: 1.3; }
|
|
631
|
+
.flag-banner .flag-body { flex: 1; min-width: 0; }
|
|
632
|
+
.flag-banner .flag-title { font-weight: 600; color: var(--ink); margin-bottom: 2px; font-size: 12px; }
|
|
633
|
+
.flag-banner .flag-title code { font-family: var(--font-mono); font-size: 10px; color: var(--ink-muted); font-weight: 400; margin-left: 4px; }
|
|
634
|
+
.flag-banner .flag-desc { color: var(--ink-muted); margin-bottom: 4px; line-height: 1.4; font-size: 12px; }
|
|
635
|
+
.flag-banner .flag-enable {
|
|
636
|
+
display: block; margin-top: 2px; padding: 5px 8px;
|
|
637
|
+
background: var(--bg); border: 1px solid var(--border); border-radius: 3px;
|
|
638
|
+
font-family: var(--font-mono); font-size: 10px; color: var(--ink);
|
|
639
|
+
white-space: pre-wrap; word-break: break-all;
|
|
640
|
+
}
|
|
641
|
+
.flag-banner .flag-close {
|
|
642
|
+
background: none; border: none; color: var(--ink-faint); cursor: pointer;
|
|
643
|
+
font-size: 16px; line-height: 1; padding: 0 4px; font-family: inherit;
|
|
644
|
+
}
|
|
645
|
+
.flag-banner .flag-close:hover { color: var(--ink); }
|
|
646
|
+
|
|
647
|
+
/* Viewer footer */
|
|
648
|
+
.viewer-footer {
|
|
649
|
+
margin-top: 48px; padding: 16px 0 24px;
|
|
650
|
+
border-top: 1px solid var(--border-light);
|
|
651
|
+
display: flex; align-items: center; gap: 10px;
|
|
652
|
+
font-family: var(--font-ui); font-size: 11px;
|
|
653
|
+
color: var(--ink-faint); letter-spacing: 0.05em;
|
|
654
|
+
}
|
|
655
|
+
.viewer-footer a { color: var(--ink-muted); text-decoration: none; }
|
|
656
|
+
.viewer-footer a:hover { color: var(--ink); text-decoration: underline; }
|
|
657
|
+
.viewer-footer .footer-sep { color: var(--ink-faint); opacity: 0.5; }
|
|
579
658
|
|
|
580
659
|
.loading { color: var(--ink-faint); padding: 20px; text-align: center; font-style: italic; font-family: var(--font-body); }
|
|
581
660
|
.empty { color: var(--ink-muted); padding: 24px; text-align: center; font-family: var(--font-body); font-style: italic; border: 1px dashed var(--border); }
|
|
@@ -814,6 +893,8 @@
|
|
|
814
893
|
<button data-tab="replay">Replay</button>
|
|
815
894
|
</div>
|
|
816
895
|
|
|
896
|
+
<div id="flag-banners" class="flag-banners"></div>
|
|
897
|
+
|
|
817
898
|
<div id="view-dashboard" class="view active"></div>
|
|
818
899
|
<div id="view-graph" class="view"></div>
|
|
819
900
|
<div id="view-memories" class="view"></div>
|
|
@@ -831,6 +912,16 @@
|
|
|
831
912
|
<div class="modal" id="modal"></div>
|
|
832
913
|
</div>
|
|
833
914
|
|
|
915
|
+
<footer id="viewer-footer" class="viewer-footer">
|
|
916
|
+
<span>agentmemory viewer · <span id="footer-version">loading...</span></span>
|
|
917
|
+
<span class="footer-sep">·</span>
|
|
918
|
+
<a href="https://github.com/rohitg00/agentmemory" target="_blank" rel="noopener">github</a>
|
|
919
|
+
<span class="footer-sep">·</span>
|
|
920
|
+
<a href="https://github.com/rohitg00/agentmemory#readme" target="_blank" rel="noopener">docs</a>
|
|
921
|
+
<span class="footer-sep">·</span>
|
|
922
|
+
<a id="footer-feedback" href="#" target="_blank" rel="noopener">report issue →</a>
|
|
923
|
+
</footer>
|
|
924
|
+
|
|
834
925
|
<script nonce="__AGENTMEMORY_VIEWER_NONCE__">
|
|
835
926
|
var params = new URLSearchParams(window.location.search);
|
|
836
927
|
var viewerPort = params.get('port') || window.location.port || '3113';
|
|
@@ -903,6 +994,7 @@
|
|
|
903
994
|
crystals: { loaded: false, items: [], search: '', lessonMap: {} },
|
|
904
995
|
profile: { loaded: false, projects: [], selectedProject: '', data: null },
|
|
905
996
|
replay: { loaded: false, sessions: [], selectedId: '', timeline: null, cursor: 0, playing: false, speed: 1, timer: null, startAt: 0, offsetAt: 0 },
|
|
997
|
+
flagsConfig: null,
|
|
906
998
|
ws: null
|
|
907
999
|
};
|
|
908
1000
|
|
|
@@ -1034,13 +1126,24 @@
|
|
|
1034
1126
|
var dotClass = healthStatus === 'healthy' ? 'healthy' : healthStatus === 'degraded' ? 'degraded' : healthStatus === 'critical' ? 'critical' : '';
|
|
1035
1127
|
var activeSessions = d.sessions.filter(function(s) { return s.status === 'active'; }).length;
|
|
1036
1128
|
var gs = d.graphStats || {};
|
|
1037
|
-
var nodeCount = (gs.nodes !== undefined
|
|
1038
|
-
var edgeCount = (gs.edges !== undefined
|
|
1129
|
+
var nodeCount = gs.totalNodes !== undefined ? gs.totalNodes : (gs.nodes !== undefined ? gs.nodes : (gs.nodeCount || 0));
|
|
1130
|
+
var edgeCount = gs.totalEdges !== undefined ? gs.totalEdges : (gs.edges !== undefined ? gs.edges : (gs.edgeCount || 0));
|
|
1039
1131
|
var fMetrics = h.functionMetrics || [];
|
|
1040
1132
|
var cb = h.circuitBreaker || null;
|
|
1041
1133
|
var workers = snap.workers || [];
|
|
1042
1134
|
|
|
1043
|
-
var html = '
|
|
1135
|
+
var html = '';
|
|
1136
|
+
// First-run hero: empty dashboard = guided next step
|
|
1137
|
+
if (d.sessions.length === 0) {
|
|
1138
|
+
html += '<div class="card" style="margin-bottom:14px;padding:24px 28px;background:var(--bg-subtle);border-left:3px solid var(--accent);">' +
|
|
1139
|
+
'<div style="font-family:var(--font-ui);font-size:11px;letter-spacing:0.15em;text-transform:uppercase;color:var(--accent);font-weight:700;margin-bottom:8px;">First run → magical moment in 10 seconds</div>' +
|
|
1140
|
+
'<div style="font-family:var(--font-display,Lora,Georgia,serif);font-size:22px;font-weight:700;color:var(--ink);margin-bottom:8px;">Seed sample data + prove semantic recall works</div>' +
|
|
1141
|
+
'<div style="font-size:13px;color:var(--ink-muted);margin-bottom:12px;line-height:1.5;max-width:640px;">agentmemory is running but hasn’t seen any sessions yet. Run the demo command in a second terminal: it seeds 3 realistic coding sessions and proves the hybrid search finds semantically-related memories that keyword search would miss.</div>' +
|
|
1142
|
+
'<pre style="display:inline-block;margin:0;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:4px;font-family:var(--font-mono);font-size:12px;color:var(--ink);">npx @agentmemory/agentmemory demo</pre>' +
|
|
1143
|
+
'<div style="margin-top:10px;"><a class="empty-link" href="https://github.com/rohitg00/agentmemory#quick-start" target="_blank" rel="noopener" style="font-size:12px;">Or: wire up your real agent →</a></div>' +
|
|
1144
|
+
'</div>';
|
|
1145
|
+
}
|
|
1146
|
+
html += '<div class="stats-grid">';
|
|
1044
1147
|
html += '<div class="stat-card"><div class="label">Sessions</div><div class="value">' + d.sessions.length + '</div><div class="sub">' + activeSessions + ' active</div></div>';
|
|
1045
1148
|
html += '<div class="stat-card"><div class="label">Memories</div><div class="value">' + d.memories.length + '</div><div class="sub">latest versions</div></div>';
|
|
1046
1149
|
var lessonCount = (d.lessons || []).length;
|
|
@@ -1336,8 +1439,8 @@
|
|
|
1336
1439
|
var sb = document.getElementById('graph-sidebar');
|
|
1337
1440
|
if (!sb) return;
|
|
1338
1441
|
var gs = state.graph.stats || {};
|
|
1339
|
-
var nodeCount = gs.nodes !== undefined ? gs.nodes : (gs.nodeCount || state.graph.nodes.length);
|
|
1340
|
-
var edgeCount = gs.edges !== undefined ? gs.edges : (gs.edgeCount || state.graph.edges.length);
|
|
1442
|
+
var nodeCount = gs.totalNodes !== undefined ? gs.totalNodes : (gs.nodes !== undefined ? gs.nodes : (gs.nodeCount || state.graph.nodes.length));
|
|
1443
|
+
var edgeCount = gs.totalEdges !== undefined ? gs.totalEdges : (gs.edges !== undefined ? gs.edges : (gs.edgeCount || state.graph.edges.length));
|
|
1341
1444
|
|
|
1342
1445
|
var html = '<input type="text" class="graph-search" id="graph-search" placeholder="Search nodes...">';
|
|
1343
1446
|
|
|
@@ -1961,7 +2064,13 @@
|
|
|
1961
2064
|
html += '</select></div>';
|
|
1962
2065
|
|
|
1963
2066
|
if (filtered.length === 0) {
|
|
1964
|
-
html += '<div class="empty-state"
|
|
2067
|
+
html += '<div class="empty-state">' +
|
|
2068
|
+
'<div class="empty-icon">📚</div>' +
|
|
2069
|
+
'<div class="empty-title">No memories yet</div>' +
|
|
2070
|
+
'<div class="empty-lead">Memories are the distilled facts agentmemory keeps across sessions — things like file paths, architectural decisions, and user preferences. Hooks capture them automatically during coding sessions; you can also save one directly.</div>' +
|
|
2071
|
+
'<pre class="empty-cmd">memory_remember {\n title: "auth uses jose middleware",\n content: "src/middleware/auth.ts handles JWT validation",\n type: "architecture"\n}</pre>' +
|
|
2072
|
+
'<div><a class="empty-link" href="https://github.com/rohitg00/agentmemory#memories" target="_blank" rel="noopener">Memory types →</a></div>' +
|
|
2073
|
+
'</div>';
|
|
1965
2074
|
} else {
|
|
1966
2075
|
html += '<table><tr><th>Title</th><th>Type</th><th>Strength</th><th>Version</th><th>Updated</th><th>Actions</th></tr>';
|
|
1967
2076
|
filtered.forEach(function(m) {
|
|
@@ -2583,7 +2692,13 @@
|
|
|
2583
2692
|
html += '</div>';
|
|
2584
2693
|
|
|
2585
2694
|
if (items.length === 0) {
|
|
2586
|
-
html += '<div class="empty-state"
|
|
2695
|
+
html += '<div class="empty-state">' +
|
|
2696
|
+
'<div class="empty-icon">💡</div>' +
|
|
2697
|
+
'<div class="empty-title">No lessons yet</div>' +
|
|
2698
|
+
'<div class="empty-lead">Lessons are confidence-scored pattern observations — things you corrected once that the agent should never do again. They persist across projects.</div>' +
|
|
2699
|
+
'<pre class="empty-cmd"># Save a lesson explicitly\nmemory_lesson_save { rule, reason, confidence }\n\n# Or: Replay tab → Import JSONL auto-extracts lessons\n# from your past Claude Code sessions</pre>' +
|
|
2700
|
+
'<div><a class="empty-link" href="https://github.com/rohitg00/agentmemory#lessons" target="_blank" rel="noopener">Lesson decay & scoring →</a></div>' +
|
|
2701
|
+
'</div>';
|
|
2587
2702
|
} else {
|
|
2588
2703
|
html += '<table><thead><tr><th>Lesson</th><th>Confidence</th><th>Reinforcements</th><th>Source</th><th>Project</th><th>Updated</th></tr></thead><tbody>';
|
|
2589
2704
|
items.forEach(function(l) {
|
|
@@ -2642,7 +2757,14 @@
|
|
|
2642
2757
|
html += '</div>';
|
|
2643
2758
|
|
|
2644
2759
|
if (items.length === 0) {
|
|
2645
|
-
html += '<div class="empty-state"
|
|
2760
|
+
html += '<div class="empty-state">' +
|
|
2761
|
+
'<div class="empty-icon">☑</div>' +
|
|
2762
|
+
'<div class="empty-title">No actions tracked yet</div>' +
|
|
2763
|
+
'<div class="empty-lead">Actions are follow-ups the agent surfaced during a session: <em>decisions to revisit</em>, <em>files to inspect</em>, <em>tasks blocked on input</em>. They show up here with status pending → active → done/blocked so nothing slips through between sessions.</div>' +
|
|
2764
|
+
'<div class="empty-lead" style="margin-top:0;">Three ways to create them:</div>' +
|
|
2765
|
+
'<pre class="empty-cmd"># 1. MCP tool (from any agent)\nmemory_action_create { title, description, priority }\n\n# 2. Curl\ncurl -X POST http://localhost:3111/agentmemory/actions \\\n -H \'Content-Type: application/json\' \\\n -d \'{"title":"ship v1","priority":"high"}\'\n\n# 3. Hooks auto-extract from long session bodies</pre>' +
|
|
2766
|
+
'<div><a class="empty-link" href="https://github.com/rohitg00/agentmemory#actions" target="_blank" rel="noopener">Action lifecycle docs →</a></div>' +
|
|
2767
|
+
'</div>';
|
|
2646
2768
|
} else {
|
|
2647
2769
|
html += '<table><thead><tr><th>Title</th><th>Status</th><th>Priority</th><th>Tags</th><th>Frontier</th><th>Updated</th></tr></thead><tbody>';
|
|
2648
2770
|
items = items.slice().sort(function(a, b) { return (b.priority || 0) - (a.priority || 0); });
|
|
@@ -2716,7 +2838,13 @@
|
|
|
2716
2838
|
html += '</div>';
|
|
2717
2839
|
|
|
2718
2840
|
if (items.length === 0) {
|
|
2719
|
-
html += '<div class="empty-state"
|
|
2841
|
+
html += '<div class="empty-state">' +
|
|
2842
|
+
'<div class="empty-icon">💎</div>' +
|
|
2843
|
+
'<div class="empty-title">No crystals yet</div>' +
|
|
2844
|
+
'<div class="empty-lead">Crystals are compressed action digests — the 3-line summary of what happened in a session. Generated from long conversations to give the next session fast context without re-reading everything.</div>' +
|
|
2845
|
+
'<pre class="empty-cmd"># Auto: import a JSONL transcript\n# Replay tab → Import JSONL\n\n# Manual: crystallize a specific session\nmemory_crystallize { sessionId }</pre>' +
|
|
2846
|
+
'<div><a class="empty-link" href="https://github.com/rohitg00/agentmemory#crystals" target="_blank" rel="noopener">Crystal pipeline →</a></div>' +
|
|
2847
|
+
'</div>';
|
|
2720
2848
|
} else {
|
|
2721
2849
|
items.forEach(function(c) {
|
|
2722
2850
|
html += '<div class="card" style="margin-bottom:12px;border-left:3px solid var(--accent);">';
|
|
@@ -3153,6 +3281,151 @@
|
|
|
3153
3281
|
switchTab(e.target.dataset.tab);
|
|
3154
3282
|
}
|
|
3155
3283
|
});
|
|
3284
|
+
|
|
3285
|
+
// --- Feature flag banners ---------------------------------------------
|
|
3286
|
+
var FLAG_DISMISS_KEY = 'agentmemory.viewer.flags.dismissed.v1';
|
|
3287
|
+
function loadDismissedFlags() {
|
|
3288
|
+
try {
|
|
3289
|
+
var raw = localStorage.getItem(FLAG_DISMISS_KEY);
|
|
3290
|
+
return raw ? JSON.parse(raw) : {};
|
|
3291
|
+
} catch (_) { return {}; }
|
|
3292
|
+
}
|
|
3293
|
+
function saveDismissedFlags(d) {
|
|
3294
|
+
try { localStorage.setItem(FLAG_DISMISS_KEY, JSON.stringify(d)); } catch (_) {}
|
|
3295
|
+
}
|
|
3296
|
+
function renderFlagBanners(cfg) {
|
|
3297
|
+
var host = document.getElementById('flag-banners');
|
|
3298
|
+
if (!host) return;
|
|
3299
|
+
var dismissed = loadDismissedFlags();
|
|
3300
|
+
var banners = [];
|
|
3301
|
+
// Per-flag banner (only for off flags, affecting current tab or dashboard)
|
|
3302
|
+
(cfg.flags || []).forEach(function(f) {
|
|
3303
|
+
if (f.enabled) return;
|
|
3304
|
+
if (dismissed[f.key]) return;
|
|
3305
|
+
var tabsAffected = (f.affects || []).map(function(t) { return t.toLowerCase(); });
|
|
3306
|
+
if (tabsAffected.length && tabsAffected.indexOf(state.activeTab) === -1 && state.activeTab !== 'dashboard') return;
|
|
3307
|
+
banners.push({
|
|
3308
|
+
kind: 'warn',
|
|
3309
|
+
icon: '⚠',
|
|
3310
|
+
title: f.label,
|
|
3311
|
+
keyLabel: f.key,
|
|
3312
|
+
desc: f.description + (f.needsLlm ? ' Requires an LLM provider key (ANTHROPIC_API_KEY, GEMINI_API_KEY, etc.).' : ''),
|
|
3313
|
+
enable: f.enableHow,
|
|
3314
|
+
docs: f.docsHref,
|
|
3315
|
+
dismissKey: f.key,
|
|
3316
|
+
});
|
|
3317
|
+
});
|
|
3318
|
+
if (cfg.provider === 'noop' && !dismissed['__provider_noop']) {
|
|
3319
|
+
banners.unshift({
|
|
3320
|
+
kind: 'warn',
|
|
3321
|
+
icon: '🔒',
|
|
3322
|
+
title: 'No LLM provider key set',
|
|
3323
|
+
keyLabel: 'ANTHROPIC_API_KEY',
|
|
3324
|
+
desc: 'Compression, summarization, and graph extraction stay disabled until a key is provided.',
|
|
3325
|
+
enable: 'export ANTHROPIC_API_KEY=sk-ant-...\n# then restart: npx @agentmemory/agentmemory',
|
|
3326
|
+
docs: 'https://github.com/rohitg00/agentmemory#quick-start',
|
|
3327
|
+
dismissKey: '__provider_noop',
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3330
|
+
if (cfg.embeddingProvider === 'none' && !dismissed['__embedding_none']) {
|
|
3331
|
+
banners.push({
|
|
3332
|
+
kind: 'info',
|
|
3333
|
+
icon: '⚙',
|
|
3334
|
+
title: 'Running in BM25-only mode',
|
|
3335
|
+
keyLabel: 'OPENAI_API_KEY',
|
|
3336
|
+
desc: 'Semantic vector search is off. BM25 keyword search is active and good for exact matches.',
|
|
3337
|
+
enable: 'export OPENAI_API_KEY=sk-...\n# or VOYAGE_API_KEY, COHERE_API_KEY, OLLAMA_HOST',
|
|
3338
|
+
docs: 'https://github.com/rohitg00/agentmemory#embedding-providers',
|
|
3339
|
+
dismissKey: '__embedding_none',
|
|
3340
|
+
});
|
|
3341
|
+
}
|
|
3342
|
+
if (banners.length === 0) { host.innerHTML = ''; return; }
|
|
3343
|
+
var warnCount = banners.filter(function(b) { return b.kind === 'warn'; }).length;
|
|
3344
|
+
var infoCount = banners.filter(function(b) { return b.kind === 'info'; }).length;
|
|
3345
|
+
var expanded = host.getAttribute('data-expanded') === '1';
|
|
3346
|
+
var pills = '';
|
|
3347
|
+
if (warnCount) pills += '<span class="flag-pill">' + warnCount + ' off</span>';
|
|
3348
|
+
if (infoCount) pills += '<span class="flag-pill info">' + infoCount + ' note</span>';
|
|
3349
|
+
var escHtml = function(s) {
|
|
3350
|
+
return String(s).replace(/[<>&"]/g, function(c) {
|
|
3351
|
+
return { '<': '<', '>': '>', '&': '&', '"': '"' }[c];
|
|
3352
|
+
});
|
|
3353
|
+
};
|
|
3354
|
+
var listHtml = banners.map(function(b) {
|
|
3355
|
+
return '<div class="flag-banner ' + b.kind + '" data-flag="' + b.dismissKey + '">' +
|
|
3356
|
+
'<span class="flag-icon">' + b.icon + '</span>' +
|
|
3357
|
+
'<div class="flag-body">' +
|
|
3358
|
+
'<div class="flag-title">' + b.title + ' <code>' + b.keyLabel + '</code></div>' +
|
|
3359
|
+
'<div class="flag-desc">' + escHtml(b.desc) + '</div>' +
|
|
3360
|
+
'<code class="flag-enable">' + escHtml(b.enable) + '</code>' +
|
|
3361
|
+
(b.docs ? ' <a class="empty-link" href="' + b.docs + '" target="_blank" rel="noopener">Learn more →</a>' : '') +
|
|
3362
|
+
'</div>' +
|
|
3363
|
+
'<button class="flag-close" data-dismiss-flag="' + b.dismissKey + '" aria-label="Dismiss">×</button>' +
|
|
3364
|
+
'</div>';
|
|
3365
|
+
}).join('');
|
|
3366
|
+
host.innerHTML = '<button type="button" class="flag-summary" data-action="toggle-flags" aria-expanded="' + (expanded ? 'true' : 'false') + '" aria-controls="flag-list">' +
|
|
3367
|
+
pills +
|
|
3368
|
+
'<span class="flag-count">Feature flags</span>' +
|
|
3369
|
+
'<span style="color:var(--ink-faint);">— click to ' + (expanded ? 'collapse' : 'expand') + '</span>' +
|
|
3370
|
+
'<span class="flag-toggle" aria-hidden="true">' + (expanded ? '▲' : '▼') + '</span>' +
|
|
3371
|
+
'</button>' +
|
|
3372
|
+
'<div class="flag-list' + (expanded ? ' open' : '') + '" id="flag-list">' + listHtml + '</div>';
|
|
3373
|
+
}
|
|
3374
|
+
async function fetchFlags() {
|
|
3375
|
+
var res = await apiGet('config/flags');
|
|
3376
|
+
if (!res) return;
|
|
3377
|
+
state.flagsConfig = res;
|
|
3378
|
+
renderFlagBanners(res);
|
|
3379
|
+
updateFooter(res);
|
|
3380
|
+
}
|
|
3381
|
+
function updateFooter(cfg) {
|
|
3382
|
+
var vEl = document.getElementById('footer-version');
|
|
3383
|
+
if (vEl) vEl.textContent = 'v' + (cfg.version || '?');
|
|
3384
|
+
var fbEl = document.getElementById('footer-feedback');
|
|
3385
|
+
if (fbEl) {
|
|
3386
|
+
var flagSummary = (cfg.flags || []).map(function(f) { return f.key + '=' + (f.enabled ? 'on' : 'off'); }).join(', ');
|
|
3387
|
+
var body = encodeURIComponent(
|
|
3388
|
+
'**Version:** ' + (cfg.version || '?') + '\n' +
|
|
3389
|
+
'**Provider:** ' + (cfg.provider || '?') + '\n' +
|
|
3390
|
+
'**Embedding:** ' + (cfg.embeddingProvider || '?') + '\n' +
|
|
3391
|
+
'**Flags:** ' + flagSummary + '\n' +
|
|
3392
|
+
'**User agent:** ' + navigator.userAgent + '\n\n' +
|
|
3393
|
+
'### What went wrong\n\n' +
|
|
3394
|
+
'(describe the issue)\n\n' +
|
|
3395
|
+
'### Steps to reproduce\n\n' +
|
|
3396
|
+
'1. \n2. \n3. \n'
|
|
3397
|
+
);
|
|
3398
|
+
fbEl.href = 'https://github.com/rohitg00/agentmemory/issues/new?title=' +
|
|
3399
|
+
encodeURIComponent('[viewer] ') + '&body=' + body;
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
document.addEventListener('click', function(e) {
|
|
3403
|
+
if (!(e.target instanceof Element)) return;
|
|
3404
|
+
var btn = e.target.closest('[data-dismiss-flag]');
|
|
3405
|
+
if (btn) {
|
|
3406
|
+
e.stopPropagation();
|
|
3407
|
+
var key = btn.getAttribute('data-dismiss-flag');
|
|
3408
|
+
var d = loadDismissedFlags();
|
|
3409
|
+
d[key] = true;
|
|
3410
|
+
saveDismissedFlags(d);
|
|
3411
|
+
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
3412
|
+
return;
|
|
3413
|
+
}
|
|
3414
|
+
var toggle = e.target.closest('[data-action="toggle-flags"]');
|
|
3415
|
+
if (toggle) {
|
|
3416
|
+
var host = document.getElementById('flag-banners');
|
|
3417
|
+
var cur = host.getAttribute('data-expanded') === '1';
|
|
3418
|
+
host.setAttribute('data-expanded', cur ? '0' : '1');
|
|
3419
|
+
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
3420
|
+
}
|
|
3421
|
+
});
|
|
3422
|
+
// Re-render banners when switching tabs so tab-specific banners appear
|
|
3423
|
+
var _origSwitchTab = switchTab;
|
|
3424
|
+
switchTab = function(tab) {
|
|
3425
|
+
_origSwitchTab(tab);
|
|
3426
|
+
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
3427
|
+
};
|
|
3428
|
+
fetchFlags();
|
|
3156
3429
|
document.addEventListener('click', function(e) {
|
|
3157
3430
|
if (!(e.target instanceof Element)) return;
|
|
3158
3431
|
var target = e.target.closest('[data-action]');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentmemory",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Persistent memory for AI coding agents -- captures tool usage, compresses via LLM, injects context into future sessions. 12 hooks, 51 MCP tools, 4 skills, real-time viewer.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rohit Ghumare",
|