@memtensor/memos-local-openclaw-plugin 1.0.2-beta.4 → 1.0.2-beta.5
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/ingest/providers/anthropic.d.ts.map +1 -1
- package/dist/ingest/providers/anthropic.js +11 -12
- package/dist/ingest/providers/anthropic.js.map +1 -1
- package/dist/ingest/providers/bedrock.d.ts.map +1 -1
- package/dist/ingest/providers/bedrock.js +11 -12
- package/dist/ingest/providers/bedrock.js.map +1 -1
- package/dist/ingest/providers/gemini.d.ts.map +1 -1
- package/dist/ingest/providers/gemini.js +11 -12
- package/dist/ingest/providers/gemini.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +11 -12
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/skill/bundled-memory-guide.d.ts +1 -1
- package/dist/skill/bundled-memory-guide.d.ts.map +1 -1
- package/dist/skill/bundled-memory-guide.js +9 -0
- package/dist/skill/bundled-memory-guide.js.map +1 -1
- package/dist/viewer/html.d.ts +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +166 -54
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +1 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +60 -13
- package/dist/viewer/server.js.map +1 -1
- package/package.json +2 -1
- package/src/ingest/providers/anthropic.ts +11 -12
- package/src/ingest/providers/bedrock.ts +11 -12
- package/src/ingest/providers/gemini.ts +11 -12
- package/src/ingest/providers/openai.ts +11 -12
- package/src/skill/bundled-memory-guide.ts +9 -0
- package/src/viewer/html.ts +165 -53
- package/src/viewer/server.ts +51 -16
|
@@ -84,7 +84,7 @@ export async function summarizeTaskGemini(
|
|
|
84
84
|
return json.candidates?.[0]?.content?.parts?.[0]?.text?.trim() ?? "";
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
const TOPIC_JUDGE_PROMPT = `You are a conversation topic boundary detector. Given the CURRENT task context
|
|
87
|
+
const TOPIC_JUDGE_PROMPT = `You are a conversation topic boundary detector. Given the CURRENT task context and a NEW user message, decide if the new message belongs to the SAME task or starts a NEW one.
|
|
88
88
|
|
|
89
89
|
Answer ONLY "NEW" or "SAME".
|
|
90
90
|
|
|
@@ -92,22 +92,21 @@ SAME — the new message:
|
|
|
92
92
|
- Continues, follows up on, refines, or corrects the same subject/project/task
|
|
93
93
|
- Asks a clarification or next-step question about what was just discussed
|
|
94
94
|
- Reports a result, error, or feedback about the current task
|
|
95
|
-
- Discusses different tools
|
|
96
|
-
-
|
|
97
|
-
- Is a short acknowledgment (ok, thanks, 好的, 嗯) in direct response to the current flow
|
|
95
|
+
- Discusses different tools or approaches for the SAME goal (e.g., learning English via BBC → via ChatGPT = SAME)
|
|
96
|
+
- Is a short acknowledgment (ok, thanks, 好的) in response to the current flow
|
|
98
97
|
|
|
99
98
|
NEW — the new message:
|
|
100
|
-
- Introduces a
|
|
101
|
-
-
|
|
102
|
-
- Starts a request about a
|
|
99
|
+
- Introduces a subject from a DIFFERENT domain than the current task (e.g., tech → cooking, work → personal life, database → travel)
|
|
100
|
+
- Has NO logical connection to what was being discussed
|
|
101
|
+
- Starts a request about a different project, system, or life area
|
|
103
102
|
- Begins with a new greeting/reset followed by a different topic
|
|
104
103
|
|
|
105
104
|
Key principles:
|
|
106
|
-
-
|
|
107
|
-
- Different aspects
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
- Examples: "
|
|
105
|
+
- If the topic domain clearly changed (e.g., server config → recipe, code review → vacation plan), choose NEW
|
|
106
|
+
- Different aspects of the SAME project/system are SAME (e.g., Nginx SSL → Nginx gzip = SAME)
|
|
107
|
+
- Different unrelated technologies discussed independently are NEW (e.g., Redis config → cooking recipe = NEW)
|
|
108
|
+
- When unsure, lean toward SAME for closely related topics, but do NOT hesitate to mark NEW for obvious domain shifts
|
|
109
|
+
- Examples: "配置Nginx" → "加gzip压缩" = SAME; "配置Nginx" → "做红烧肉" = NEW; "MySQL配置" → "K8s部署" in same infra project = SAME; "部署服务器" → "年会安排" = NEW
|
|
111
110
|
|
|
112
111
|
Output exactly one word: NEW or SAME`;
|
|
113
112
|
|
|
@@ -123,7 +123,7 @@ export async function summarizeOpenAI(
|
|
|
123
123
|
return json.choices[0]?.message?.content?.trim() ?? "";
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
const TOPIC_JUDGE_PROMPT = `You are a conversation topic boundary detector. Given the CURRENT task context
|
|
126
|
+
const TOPIC_JUDGE_PROMPT = `You are a conversation topic boundary detector. Given the CURRENT task context and a NEW user message, decide if the new message belongs to the SAME task or starts a NEW one.
|
|
127
127
|
|
|
128
128
|
Answer ONLY "NEW" or "SAME".
|
|
129
129
|
|
|
@@ -131,22 +131,21 @@ SAME — the new message:
|
|
|
131
131
|
- Continues, follows up on, refines, or corrects the same subject/project/task
|
|
132
132
|
- Asks a clarification or next-step question about what was just discussed
|
|
133
133
|
- Reports a result, error, or feedback about the current task
|
|
134
|
-
- Discusses different tools
|
|
135
|
-
-
|
|
136
|
-
- Is a short acknowledgment (ok, thanks, 好的, 嗯) in direct response to the current flow
|
|
134
|
+
- Discusses different tools or approaches for the SAME goal (e.g., learning English via BBC → via ChatGPT = SAME)
|
|
135
|
+
- Is a short acknowledgment (ok, thanks, 好的) in response to the current flow
|
|
137
136
|
|
|
138
137
|
NEW — the new message:
|
|
139
|
-
- Introduces a
|
|
140
|
-
-
|
|
141
|
-
- Starts a request about a
|
|
138
|
+
- Introduces a subject from a DIFFERENT domain than the current task (e.g., tech → cooking, work → personal life, database → travel)
|
|
139
|
+
- Has NO logical connection to what was being discussed
|
|
140
|
+
- Starts a request about a different project, system, or life area
|
|
142
141
|
- Begins with a new greeting/reset followed by a different topic
|
|
143
142
|
|
|
144
143
|
Key principles:
|
|
145
|
-
-
|
|
146
|
-
- Different aspects
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
- Examples: "
|
|
144
|
+
- If the topic domain clearly changed (e.g., server config → recipe, code review → vacation plan), choose NEW
|
|
145
|
+
- Different aspects of the SAME project/system are SAME (e.g., Nginx SSL → Nginx gzip = SAME)
|
|
146
|
+
- Different unrelated technologies discussed independently are NEW (e.g., Redis config → cooking recipe = NEW)
|
|
147
|
+
- When unsure, lean toward SAME for closely related topics, but do NOT hesitate to mark NEW for obvious domain shifts
|
|
148
|
+
- Examples: "配置Nginx" → "加gzip压缩" = SAME; "配置Nginx" → "做红烧肉" = NEW; "MySQL配置" → "K8s部署" in same infra project = SAME; "部署服务器" → "年会安排" = NEW
|
|
150
149
|
|
|
151
150
|
Output exactly one word: NEW or SAME`;
|
|
152
151
|
|
|
@@ -88,4 +88,13 @@ This skill describes how to use the MemOS memory tools so you can reliably searc
|
|
|
88
88
|
- Use **concrete terms**: names, topics, tools, or decisions (e.g. "preferred editor", "deploy script", "API key setup").
|
|
89
89
|
- If the user's message is long, **derive one or two sub-queries** rather than pasting the whole message.
|
|
90
90
|
- Use \`role='user'\` when you specifically want to find what the user said (e.g. preferences, past questions).
|
|
91
|
+
|
|
92
|
+
## Memory ownership and agent isolation
|
|
93
|
+
|
|
94
|
+
Each memory is tagged with an \`owner\` (e.g. \`agent:main\`, \`agent:sales-bot\`). This is handled **automatically** — you do not need to pass any owner parameter.
|
|
95
|
+
|
|
96
|
+
- **Your memories:** All tools (\`memory_search\`, \`memory_get\`, \`memory_timeline\`) automatically scope queries to your agent's own memories.
|
|
97
|
+
- **Public memories:** Memories marked as \`public\` are visible to all agents. Use \`memory_write_public\` to write shared knowledge.
|
|
98
|
+
- **Cross-agent isolation:** You cannot see memories owned by other agents (unless they are public).
|
|
99
|
+
- **How it works:** The system identifies your agent ID from the OpenClaw runtime context and applies owner filtering automatically on every search, recall, and retrieval.
|
|
91
100
|
`;
|
package/src/viewer/html.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export
|
|
1
|
+
export function viewerHTML(pluginVersion?: string): string {
|
|
2
|
+
const vBadge = pluginVersion ? `<span class="version-badge">v${pluginVersion}</span>` : '';
|
|
3
|
+
return `<!DOCTYPE html>
|
|
2
4
|
<html lang="zh-CN">
|
|
3
5
|
<head>
|
|
4
6
|
<meta charset="UTF-8">
|
|
@@ -110,13 +112,15 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
110
112
|
.topbar .brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
111
113
|
.topbar .brand .icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:22px;background:none;border-radius:0}
|
|
112
114
|
.topbar .brand .sub{font-weight:400;color:var(--text-muted);font-size:11px}
|
|
115
|
+
.version-badge{font-size:10px;font-weight:600;color:var(--text-muted);background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.1);padding:1px 7px;border-radius:6px;margin-left:6px;letter-spacing:.02em;user-select:all}
|
|
116
|
+
[data-theme="light"] .version-badge{background:rgba(0,0,0,.05);border-color:rgba(0,0,0,.08);color:var(--text-sec)}
|
|
113
117
|
.topbar-center{flex:1;display:flex;justify-content:center}
|
|
114
118
|
.topbar .actions{display:flex;align-items:center;gap:6px;flex-shrink:0}
|
|
115
119
|
|
|
116
120
|
.main-content{display:flex;flex:1;max-width:1400px;margin:0 auto;width:100%;padding:28px 32px;gap:28px}
|
|
117
121
|
|
|
118
122
|
/* ─── Sidebar ─── */
|
|
119
|
-
.sidebar{width:260px;flex-shrink:0}
|
|
123
|
+
.sidebar{width:260px;min-width:260px;flex-shrink:0}
|
|
120
124
|
.sidebar .stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:24px}
|
|
121
125
|
.stat-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:18px;transition:all .2s}
|
|
122
126
|
.stat-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover)}
|
|
@@ -241,6 +245,16 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
241
245
|
.modal-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:28px}
|
|
242
246
|
|
|
243
247
|
/* ─── Toast ─── */
|
|
248
|
+
.emb-banner{display:flex;align-items:center;gap:10px;padding:12px 20px;font-size:13px;font-weight:500;border-radius:10px;margin:0 32px 0;animation:slideIn .3s ease}
|
|
249
|
+
.emb-banner.warning{background:rgba(245,158,11,.1);color:#d97706;border:1px solid rgba(245,158,11,.25)}
|
|
250
|
+
.emb-banner.error{background:rgba(239,68,68,.1);color:#ef4444;border:1px solid rgba(239,68,68,.25)}
|
|
251
|
+
[data-theme="light"] .emb-banner.warning{background:rgba(245,158,11,.08);color:#b45309}
|
|
252
|
+
[data-theme="light"] .emb-banner.error{background:rgba(239,68,68,.08);color:#dc2626}
|
|
253
|
+
.emb-banner span{flex:1}
|
|
254
|
+
.emb-banner-btn{background:none;border:1px solid currentColor;border-radius:6px;padding:4px 12px;font-size:12px;font-weight:600;color:inherit;cursor:pointer;white-space:nowrap;opacity:.85;transition:opacity .15s}
|
|
255
|
+
.emb-banner-btn:hover{opacity:1}
|
|
256
|
+
.emb-banner-close{background:none;border:none;font-size:18px;color:inherit;cursor:pointer;opacity:.5;padding:0 4px;line-height:1}
|
|
257
|
+
.emb-banner-close:hover{opacity:1}
|
|
244
258
|
.toast-container{position:fixed;top:80px;right:24px;z-index:1000;display:flex;flex-direction:column;gap:8px}
|
|
245
259
|
.toast{padding:14px 20px;border-radius:10px;font-size:13px;font-weight:500;box-shadow:var(--shadow-lg);animation:slideIn .3s ease;display:flex;align-items:center;gap:10px;max-width:360px;border:1px solid}
|
|
246
260
|
.toast.success{background:var(--green-bg);color:var(--green);border-color:rgba(16,185,129,.3)}
|
|
@@ -330,8 +344,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
330
344
|
.task-chunk-role.user{color:var(--pri)}
|
|
331
345
|
.task-chunk-role.assistant{color:var(--green)}
|
|
332
346
|
.task-chunk-role.tool{color:var(--amber)}
|
|
333
|
-
.task-chunk-bubble{padding:12px 16px;border-radius:16px;white-space:pre-wrap;word-break:break-word;max-height:
|
|
334
|
-
.task-chunk-bubble.
|
|
347
|
+
.task-chunk-bubble{padding:12px 16px;border-radius:16px;white-space:pre-wrap;word-break:break-word;max-height:none;overflow:hidden;position:relative;transition:all .2s}
|
|
348
|
+
.task-chunk-bubble.collapsed{max-height:200px}
|
|
349
|
+
.task-chunk-expand{display:none;align-items:center;justify-content:center;gap:4px;margin-top:4px;padding:4px 12px;font-size:12px;font-weight:600;color:var(--text-sec);cursor:pointer;user-select:none;border-radius:8px;transition:all .15s}
|
|
350
|
+
.task-chunk-expand:hover{color:var(--pri);background:rgba(99,102,241,.08)}
|
|
351
|
+
.task-chunk-expand .expand-arrow{display:inline-block;font-size:10px;transition:transform .2s}
|
|
352
|
+
.task-chunk-expand.is-expanded .expand-arrow{transform:rotate(180deg)}
|
|
335
353
|
.role-user .task-chunk-bubble{background:var(--pri);color:#000;border-bottom-right-radius:4px}
|
|
336
354
|
.role-assistant .task-chunk-bubble{background:var(--bg-card);border:1px solid var(--border);color:var(--text-sec);border-bottom-left-radius:4px}
|
|
337
355
|
.role-tool .task-chunk-bubble{background:rgba(245,158,11,.08);border:1px solid rgba(245,158,11,.2);color:var(--text-sec);border-bottom-left-radius:4px;font-family:'SF Mono',Monaco,Consolas,monospace;font-size:12px}
|
|
@@ -421,6 +439,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
421
439
|
[data-theme="light"] .nav-tabs .tab.active{background:#fff;border-color:rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.08);color:var(--text)}
|
|
422
440
|
.analytics-view,.settings-view,.logs-view,.migrate-view{display:none;flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
423
441
|
.analytics-view.show,.settings-view.show,.logs-view.show,.migrate-view.show{display:flex}
|
|
442
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view{max-width:960px}
|
|
424
443
|
|
|
425
444
|
/* ─── Logs ─── */
|
|
426
445
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -568,18 +587,19 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
568
587
|
@keyframes migrateFadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
|
569
588
|
.feed-wrap{flex:1;min-width:0;display:flex;flex-direction:column}
|
|
570
589
|
.feed-wrap.hide{display:none}
|
|
590
|
+
.analytics-view{flex-direction:column;gap:20px}
|
|
571
591
|
.analytics-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
|
572
|
-
.analytics-card{position:relative;overflow:hidden;border-radius:var(--radius-lg);padding:
|
|
592
|
+
.analytics-card{position:relative;overflow:hidden;border-radius:var(--radius-lg);padding:18px 16px;transition:all .2s ease;border:1px solid var(--border);background:var(--bg-card)}
|
|
573
593
|
.analytics-card::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:var(--pri);opacity:.5}
|
|
574
594
|
.analytics-card::after{display:none}
|
|
575
595
|
.analytics-card:hover{transform:translateY(-2px);box-shadow:var(--shadow);border-color:var(--border-glow)}
|
|
576
596
|
.analytics-card.green::before{background:var(--green)}
|
|
577
597
|
.analytics-card.amber::before{background:var(--amber)}
|
|
578
|
-
.analytics-card .ac-value{font-size:
|
|
598
|
+
.analytics-card .ac-value{font-size:24px;font-weight:700;letter-spacing:-.03em;color:var(--text);line-height:1;-webkit-text-fill-color:unset;background:none}
|
|
579
599
|
.analytics-card.green .ac-value{color:var(--green);background:none}
|
|
580
600
|
.analytics-card.amber .ac-value{color:var(--amber);background:none}
|
|
581
601
|
.analytics-card .ac-label{font-size:11px;color:var(--text-muted);margin-top:6px;font-weight:500;text-transform:uppercase;letter-spacing:.06em}
|
|
582
|
-
.analytics-section{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:
|
|
602
|
+
.analytics-section{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:18px 20px;position:relative;overflow:hidden}
|
|
583
603
|
.analytics-section::before{display:none}
|
|
584
604
|
.analytics-section h3{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:16px;display:flex;align-items:center;gap:8px}
|
|
585
605
|
.analytics-section h3 .icon{font-size:14px;opacity:.6}
|
|
@@ -739,7 +759,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
739
759
|
<div class="topbar">
|
|
740
760
|
<div class="brand">
|
|
741
761
|
<div class="icon"><svg width="24" height="24" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg" style="filter:drop-shadow(0 0 8px rgba(255,77,77,.3))"><defs><linearGradient id="tLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#tLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#tLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#tLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></div>
|
|
742
|
-
<span data-i18n="title">OpenClaw Memory</span
|
|
762
|
+
<span data-i18n="title">OpenClaw Memory</span>${vBadge}
|
|
743
763
|
</div>
|
|
744
764
|
<div class="topbar-center">
|
|
745
765
|
<nav class="nav-tabs">
|
|
@@ -768,10 +788,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
768
788
|
<div class="stat-card amber"><div class="stat-value" id="statEmbeddings">-</div><div class="stat-label" data-i18n="stat.embeddings">Embeddings</div></div>
|
|
769
789
|
<div class="stat-card rose"><div class="stat-value" id="statTimeSpan">-</div><div class="stat-label" data-i18n="stat.days">Days</div></div>
|
|
770
790
|
</div>
|
|
771
|
-
<div id="
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
791
|
+
<div id="sidebarSessionSection">
|
|
792
|
+
<div id="embeddingStatus"></div>
|
|
793
|
+
<div class="section-title" data-i18n="sidebar.sessions">Sessions</div>
|
|
794
|
+
<div class="session-list" id="sessionList"></div>
|
|
795
|
+
<button class="btn btn-sm btn-ghost" style="width:100%;margin-top:20px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
|
|
796
|
+
</div>
|
|
775
797
|
</div>
|
|
776
798
|
|
|
777
799
|
<div class="feed-wrap" id="feedWrap">
|
|
@@ -897,7 +919,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
897
919
|
</div>
|
|
898
920
|
</div>
|
|
899
921
|
<div class="analytics-view" id="analyticsView">
|
|
900
|
-
<div class="metrics-toolbar">
|
|
922
|
+
<div class="metrics-toolbar" style="margin-bottom:0">
|
|
901
923
|
<span style="font-size:12px;color:var(--text-sec);font-weight:600" data-i18n="range">Range</span>
|
|
902
924
|
<button class="range-btn" data-days="7" onclick="setMetricsDays(7)">7 <span data-i18n="range.days">days</span></button>
|
|
903
925
|
<button class="range-btn active" data-days="30" onclick="setMetricsDays(30)">30 <span data-i18n="range.days">days</span></button>
|
|
@@ -929,7 +951,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
929
951
|
<div id="toolAggTable" style="margin-top:20px"></div>
|
|
930
952
|
</div>
|
|
931
953
|
|
|
932
|
-
<div class="breakdown-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:
|
|
954
|
+
<div class="breakdown-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:16px">
|
|
933
955
|
<div class="analytics-section">
|
|
934
956
|
<h3><span class="icon">\u{1F464}</span> <span data-i18n="breakdown.role">By Role</span></h3>
|
|
935
957
|
<div id="breakdownRole"></div>
|
|
@@ -962,8 +984,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
962
984
|
<div class="settings-view" id="settingsView">
|
|
963
985
|
<div class="settings-group" id="settingsModelConfig">
|
|
964
986
|
<h2 class="settings-group-title"><span data-i18n="settings.modelconfig">Model Configuration</span></h2>
|
|
965
|
-
<div class="
|
|
966
|
-
<
|
|
987
|
+
<div class="settings-section">
|
|
988
|
+
<h3><span class="icon">\u{1F4CA}</span> <span data-i18n="settings.modelhealth">Model Health</span></h3>
|
|
989
|
+
<div class="model-health-bar" id="modelHealthBar">
|
|
990
|
+
<div style="font-size:12px;color:var(--text-muted);width:100%">Loading model status...</div>
|
|
991
|
+
</div>
|
|
967
992
|
</div>
|
|
968
993
|
<div class="settings-section">
|
|
969
994
|
<h3><span class="icon">\u{1F4E1}</span> <span data-i18n="settings.embedding">Embedding Model</span></h3>
|
|
@@ -1333,6 +1358,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1333
1358
|
|
|
1334
1359
|
<script>
|
|
1335
1360
|
let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
|
|
1361
|
+
let _embeddingWarningShown=false;
|
|
1336
1362
|
|
|
1337
1363
|
/* ─── i18n ─── */
|
|
1338
1364
|
const I18N={
|
|
@@ -1392,6 +1418,8 @@ const I18N={
|
|
|
1392
1418
|
'tasks.untitled':'Untitled Task',
|
|
1393
1419
|
'tasks.chunks':'Related Memories',
|
|
1394
1420
|
'tasks.nochunks':'No memories in this task yet.',
|
|
1421
|
+
'tasks.expand':'Show more',
|
|
1422
|
+
'tasks.collapse':'Show less',
|
|
1395
1423
|
'tasks.skipped.default':'This conversation was too brief to generate a summary. It will not appear in search results.',
|
|
1396
1424
|
'refresh':'\\u21BB Refresh',
|
|
1397
1425
|
'logout':'Logout',
|
|
@@ -1484,6 +1512,9 @@ const I18N={
|
|
|
1484
1512
|
'confirm.clearall2':'Are you absolutely sure?',
|
|
1485
1513
|
'embed.on':'Embedding: ',
|
|
1486
1514
|
'embed.off':'No embedding model',
|
|
1515
|
+
'embed.warn.local':'Using built-in mini model (384d). Search quality is limited — configure an embedding model in Settings for best results.',
|
|
1516
|
+
'embed.err.fail':'Embedding model error detected. Check Settings → Model Health.',
|
|
1517
|
+
'embed.banner.goto':'Go to Settings',
|
|
1487
1518
|
'lang.switch':'中',
|
|
1488
1519
|
'tab.logs':'\u{1F4DD} Logs',
|
|
1489
1520
|
'logs.allTools':'All Tools',
|
|
@@ -1496,6 +1527,7 @@ const I18N={
|
|
|
1496
1527
|
'tab.import':'\u{1F4E5} Import',
|
|
1497
1528
|
'tab.settings':'\u2699 Settings',
|
|
1498
1529
|
'settings.modelconfig':'Model Configuration',
|
|
1530
|
+
'settings.modelhealth':'Model Health',
|
|
1499
1531
|
'settings.embedding':'Embedding Model',
|
|
1500
1532
|
'settings.summarizer':'Summarizer Model',
|
|
1501
1533
|
'settings.skill':'Skill Evolution',
|
|
@@ -1701,6 +1733,8 @@ const I18N={
|
|
|
1701
1733
|
'tasks.untitled':'未命名任务',
|
|
1702
1734
|
'tasks.chunks':'关联记忆',
|
|
1703
1735
|
'tasks.nochunks':'此任务暂无关联记忆。',
|
|
1736
|
+
'tasks.expand':'展开全文',
|
|
1737
|
+
'tasks.collapse':'收起',
|
|
1704
1738
|
'tasks.skipped.default':'对话内容过少,未生成摘要。该任务不会出现在检索结果中。',
|
|
1705
1739
|
'refresh':'\\u21BB 刷新',
|
|
1706
1740
|
'logout':'退出',
|
|
@@ -1793,6 +1827,9 @@ const I18N={
|
|
|
1793
1827
|
'confirm.clearall2':'你真的确定吗?',
|
|
1794
1828
|
'embed.on':'嵌入模型:',
|
|
1795
1829
|
'embed.off':'无嵌入模型',
|
|
1830
|
+
'embed.warn.local':'当前使用内置迷你模型(384维),搜索效果有限。强烈建议在「设置」中配置专用 Embedding 模型以获得最佳效果。',
|
|
1831
|
+
'embed.err.fail':'Embedding 模型调用异常,请前往「设置 → 模型健康」检查。',
|
|
1832
|
+
'embed.banner.goto':'前往设置',
|
|
1796
1833
|
'lang.switch':'EN',
|
|
1797
1834
|
'tab.logs':'\u{1F4DD} 日志',
|
|
1798
1835
|
'logs.allTools':'全部工具',
|
|
@@ -1805,6 +1842,7 @@ const I18N={
|
|
|
1805
1842
|
'tab.import':'\u{1F4E5} 导入',
|
|
1806
1843
|
'tab.settings':'\u2699 设置',
|
|
1807
1844
|
'settings.modelconfig':'模型配置',
|
|
1845
|
+
'settings.modelhealth':'模型健康',
|
|
1808
1846
|
'settings.embedding':'嵌入模型',
|
|
1809
1847
|
'settings.summarizer':'摘要模型',
|
|
1810
1848
|
'settings.skill':'技能进化',
|
|
@@ -2068,6 +2106,7 @@ function switchView(view){
|
|
|
2068
2106
|
const logsView=document.getElementById('logsView');
|
|
2069
2107
|
const settingsView=document.getElementById('settingsView');
|
|
2070
2108
|
const migrateView=document.getElementById('migrateView');
|
|
2109
|
+
const sidebar=document.getElementById('sidebar');
|
|
2071
2110
|
feedWrap.classList.add('hide');
|
|
2072
2111
|
analyticsView.classList.remove('show');
|
|
2073
2112
|
tasksView.classList.remove('show');
|
|
@@ -2075,27 +2114,33 @@ function switchView(view){
|
|
|
2075
2114
|
logsView.classList.remove('show');
|
|
2076
2115
|
settingsView.classList.remove('show');
|
|
2077
2116
|
migrateView.classList.remove('show');
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
loadMetrics();
|
|
2081
|
-
} else if(view==='tasks'){
|
|
2082
|
-
tasksView.classList.add('show');
|
|
2083
|
-
loadTasks();
|
|
2084
|
-
} else if(view==='skills'){
|
|
2085
|
-
skillsView.classList.add('show');
|
|
2086
|
-
loadSkills();
|
|
2087
|
-
} else if(view==='logs'){
|
|
2088
|
-
logsView.classList.add('show');
|
|
2089
|
-
loadLogs();
|
|
2090
|
-
} else if(view==='settings'){
|
|
2091
|
-
settingsView.classList.add('show');
|
|
2092
|
-
loadConfig();
|
|
2093
|
-
loadModelHealth();
|
|
2094
|
-
} else if(view==='import'){
|
|
2095
|
-
migrateView.classList.add('show');
|
|
2096
|
-
if(!window._migrateRunning) migrateScan();
|
|
2097
|
-
} else {
|
|
2117
|
+
const sessionSection=document.getElementById('sidebarSessionSection');
|
|
2118
|
+
if(view==='memories'){
|
|
2098
2119
|
feedWrap.classList.remove('hide');
|
|
2120
|
+
sessionSection.style.visibility='';
|
|
2121
|
+
sessionSection.style.pointerEvents='';
|
|
2122
|
+
} else if(view==='tasks'||view==='skills'){
|
|
2123
|
+
sessionSection.style.visibility='hidden';
|
|
2124
|
+
sessionSection.style.pointerEvents='none';
|
|
2125
|
+
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
2126
|
+
else{skillsView.classList.add('show');loadSkills();}
|
|
2127
|
+
} else {
|
|
2128
|
+
sessionSection.style.visibility='hidden';
|
|
2129
|
+
sessionSection.style.pointerEvents='none';
|
|
2130
|
+
if(view==='analytics'){
|
|
2131
|
+
analyticsView.classList.add('show');
|
|
2132
|
+
loadMetrics();
|
|
2133
|
+
} else if(view==='logs'){
|
|
2134
|
+
logsView.classList.add('show');
|
|
2135
|
+
loadLogs();
|
|
2136
|
+
} else if(view==='settings'){
|
|
2137
|
+
settingsView.classList.add('show');
|
|
2138
|
+
loadConfig();
|
|
2139
|
+
loadModelHealth();
|
|
2140
|
+
} else if(view==='import'){
|
|
2141
|
+
migrateView.classList.add('show');
|
|
2142
|
+
if(!window._migrateRunning) migrateScan();
|
|
2143
|
+
}
|
|
2099
2144
|
}
|
|
2100
2145
|
}
|
|
2101
2146
|
|
|
@@ -2448,14 +2493,16 @@ async function openTaskDetail(taskId){
|
|
|
2448
2493
|
if(task.chunks.length===0){
|
|
2449
2494
|
document.getElementById('taskDetailChunks').innerHTML='<div style="color:var(--text-muted);padding:12px;font-size:13px">'+t('tasks.nochunks')+'</div>';
|
|
2450
2495
|
}else{
|
|
2451
|
-
document.getElementById('taskDetailChunks').innerHTML=task.chunks.map(c
|
|
2496
|
+
document.getElementById('taskDetailChunks').innerHTML=task.chunks.map(function(c,i){
|
|
2452
2497
|
var roleLabel=c.role==='user'?t('tasks.role.user'):c.role==='assistant'?t('tasks.role.assistant'):c.role.toUpperCase();
|
|
2453
2498
|
return '<div class="task-chunk-item role-'+c.role+'">'+
|
|
2454
2499
|
'<div class="task-chunk-role '+c.role+'">'+roleLabel+'</div>'+
|
|
2455
|
-
'<div class="task-chunk-bubble"
|
|
2500
|
+
'<div class="task-chunk-bubble collapsed" id="chunk_b_'+i+'">'+esc(c.content)+'</div>'+
|
|
2501
|
+
'<div class="task-chunk-expand" id="chunk_e_'+i+'" onclick="toggleChunkExpand('+i+')"><span class="expand-arrow">▼</span> <span class="expand-label">'+t('tasks.expand')+'</span></div>'+
|
|
2456
2502
|
'<div class="task-chunk-time">'+formatTime(c.createdAt)+'</div>'+
|
|
2457
2503
|
'</div>';
|
|
2458
2504
|
}).join('');
|
|
2505
|
+
setTimeout(function(){initChunkExpanders(task.chunks.length)},50);
|
|
2459
2506
|
}
|
|
2460
2507
|
}catch(e){
|
|
2461
2508
|
document.getElementById('taskDetailTitle').textContent=t('tasks.error');
|
|
@@ -2519,6 +2566,33 @@ function renderTaskSkillSection(task){
|
|
|
2519
2566
|
}
|
|
2520
2567
|
}
|
|
2521
2568
|
|
|
2569
|
+
function initChunkExpanders(count){
|
|
2570
|
+
for(var i=0;i<count;i++){
|
|
2571
|
+
var b=document.getElementById('chunk_b_'+i);
|
|
2572
|
+
var e=document.getElementById('chunk_e_'+i);
|
|
2573
|
+
if(b && b.scrollHeight > b.clientHeight + 4){
|
|
2574
|
+
e.style.display='flex';
|
|
2575
|
+
} else if(b) {
|
|
2576
|
+
b.classList.remove('collapsed');
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
function toggleChunkExpand(i){
|
|
2581
|
+
var b=document.getElementById('chunk_b_'+i);
|
|
2582
|
+
var e=document.getElementById('chunk_e_'+i);
|
|
2583
|
+
if(!b||!e)return;
|
|
2584
|
+
var expanding=b.classList.contains('collapsed');
|
|
2585
|
+
if(expanding){
|
|
2586
|
+
b.classList.remove('collapsed');
|
|
2587
|
+
e.classList.add('is-expanded');
|
|
2588
|
+
e.querySelector('.expand-label').textContent=t('tasks.collapse');
|
|
2589
|
+
}else{
|
|
2590
|
+
b.classList.add('collapsed');
|
|
2591
|
+
e.classList.remove('is-expanded');
|
|
2592
|
+
e.querySelector('.expand-label').textContent=t('tasks.expand');
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2522
2596
|
function closeTaskDetail(event){
|
|
2523
2597
|
if(event && event.target!==document.getElementById('taskDetailOverlay')) return;
|
|
2524
2598
|
document.getElementById('taskDetailOverlay').classList.remove('show');
|
|
@@ -3060,15 +3134,16 @@ async function testModel(type){
|
|
|
3060
3134
|
var d=await r.json();
|
|
3061
3135
|
if(d.ok){
|
|
3062
3136
|
resultEl.className='test-result ok';
|
|
3063
|
-
resultEl.innerHTML='\\u2705 '+t('settings.test.ok')+'<div style="margin-top:4px;font-size:11px;color:var(--text-muted)">'+esc(d.detail
|
|
3137
|
+
resultEl.innerHTML='\\u2705 '+t('settings.test.ok')+(d.detail?'<div style="margin-top:4px;font-size:11px;color:var(--text-muted)">'+esc(d.detail)+'</div>':'');
|
|
3064
3138
|
}else{
|
|
3065
|
-
var errMsg=d.error||'Unknown error';
|
|
3139
|
+
var errMsg=(d.error||'Unknown error').replace(/:\s*$/,'').trim();
|
|
3066
3140
|
resultEl.className='test-result fail';
|
|
3067
|
-
resultEl.innerHTML='\\u274C '+t('settings.test.fail')+'<div style="margin-top:6px;font-size:11px;padding:8px 10px;background:rgba(239,68,68,.06);border:1px solid rgba(239,68,68,.15);border-radius:6px;white-space:pre-wrap;word-break:break-all;max-height:120px;overflow-y:auto;font-family:SF Mono,Monaco,Consolas,monospace">'+esc(errMsg)+'</div>';
|
|
3141
|
+
resultEl.innerHTML='\\u274C '+t('settings.test.fail')+(errMsg?'<div style="margin-top:6px;font-size:11px;padding:8px 10px;background:rgba(239,68,68,.06);border:1px solid rgba(239,68,68,.15);border-radius:6px;white-space:pre-wrap;word-break:break-all;max-height:120px;overflow-y:auto;font-family:SF Mono,Monaco,Consolas,monospace">'+esc(errMsg)+'</div>':'');
|
|
3068
3142
|
}
|
|
3069
3143
|
}catch(e){
|
|
3144
|
+
var catchMsg=(e.message||'Network error').replace(/:\s*$/,'').trim();
|
|
3070
3145
|
resultEl.className='test-result fail';
|
|
3071
|
-
resultEl.innerHTML='\\u274C '+t('settings.test.fail')+'<div style="margin-top:6px;font-size:11px;padding:8px 10px;background:rgba(239,68,68,.06);border:1px solid rgba(239,68,68,.15);border-radius:6px;white-space:pre-wrap;word-break:break-all">'+esc(
|
|
3146
|
+
resultEl.innerHTML='\\u274C '+t('settings.test.fail')+(catchMsg?'<div style="margin-top:6px;font-size:11px;padding:8px 10px;background:rgba(239,68,68,.06);border:1px solid rgba(239,68,68,.15);border-radius:6px;white-space:pre-wrap;word-break:break-all">'+esc(catchMsg)+'</div>':'');
|
|
3072
3147
|
}finally{btn.disabled=false;}
|
|
3073
3148
|
}
|
|
3074
3149
|
|
|
@@ -3436,6 +3511,20 @@ async function loadStats(){
|
|
|
3436
3511
|
provEl.innerHTML='<div class="provider-badge offline"><span>\\u26A0</span> '+t('embed.off')+'</div>';
|
|
3437
3512
|
}
|
|
3438
3513
|
|
|
3514
|
+
if(!_embeddingWarningShown){
|
|
3515
|
+
_embeddingWarningShown=true;
|
|
3516
|
+
if(!d.embeddingProvider||d.embeddingProvider==='local'||d.embeddingProvider==='none'){
|
|
3517
|
+
showEmbeddingBanner(t('embed.warn.local'),'warning');
|
|
3518
|
+
}
|
|
3519
|
+
fetch('/api/model-health').then(r=>r.json()).then(mh=>{
|
|
3520
|
+
var models=mh.models||[];
|
|
3521
|
+
var embModel=models.find(m=>m.role==='embedding');
|
|
3522
|
+
if(embModel&&embModel.status==='error'){
|
|
3523
|
+
showEmbeddingBanner(t('embed.err.fail'),'error');
|
|
3524
|
+
}
|
|
3525
|
+
}).catch(()=>{});
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3439
3528
|
const sl=document.getElementById('sessionList');
|
|
3440
3529
|
sl.innerHTML='<div class="session-item'+(activeSession===null?' active':'')+'" onclick="filterSession(null)"><span>'+t('sidebar.allsessions')+'</span><span class="count">'+tm+'</span></div>';
|
|
3441
3530
|
(d.sessions||[]).forEach(s=>{
|
|
@@ -3499,17 +3588,24 @@ async function doSearch(q){
|
|
|
3499
3588
|
if(!q.trim()){currentPage=1;loadMemories();return}
|
|
3500
3589
|
const list=document.getElementById('memoryList');
|
|
3501
3590
|
list.innerHTML='<div class="spinner"></div>';
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3591
|
+
try{
|
|
3592
|
+
const p=getFilterParams();
|
|
3593
|
+
p.set('q',q);
|
|
3594
|
+
const r=await fetch('/api/search?'+p.toString());
|
|
3595
|
+
const d=await r.json();
|
|
3596
|
+
const total=d.total||0;
|
|
3597
|
+
const meta=[];
|
|
3598
|
+
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
3599
|
+
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
3600
|
+
meta.push(total+t('search.meta.results'));
|
|
3601
|
+
document.getElementById('searchMeta').textContent=meta.join(' \\u00B7 ');
|
|
3602
|
+
renderMemories(d.results||[]);
|
|
3603
|
+
document.getElementById('pagination').innerHTML='';
|
|
3604
|
+
}catch(e){
|
|
3605
|
+
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
3606
|
+
renderMemories([]);
|
|
3607
|
+
document.getElementById('pagination').innerHTML='';
|
|
3608
|
+
}
|
|
3513
3609
|
}
|
|
3514
3610
|
|
|
3515
3611
|
function debounceSearch(){
|
|
@@ -4316,6 +4412,21 @@ function ppDone(wasStopped,wasFailed,skipReload){
|
|
|
4316
4412
|
if(!skipReload) loadAll();
|
|
4317
4413
|
}
|
|
4318
4414
|
|
|
4415
|
+
/* ─── Embedding Banner ─── */
|
|
4416
|
+
function showEmbeddingBanner(msg,type){
|
|
4417
|
+
if(document.getElementById('embBanner')) return;
|
|
4418
|
+
var cls=type==='error'?'emb-banner error':'emb-banner warning';
|
|
4419
|
+
var icon=type==='error'?'\\u274C':'\\u26A0\\uFE0F';
|
|
4420
|
+
var btn='<button class="emb-banner-btn" onclick="switchView(\\'settings\\');this.parentElement.remove()">'+t('embed.banner.goto')+'</button>';
|
|
4421
|
+
var close='<button class="emb-banner-close" onclick="this.parentElement.remove()">×</button>';
|
|
4422
|
+
var el=document.createElement('div');
|
|
4423
|
+
el.id='embBanner';
|
|
4424
|
+
el.className=cls;
|
|
4425
|
+
el.innerHTML=icon+' <span>'+esc(msg)+'</span>'+btn+close;
|
|
4426
|
+
var mc=document.querySelector('.main-content');
|
|
4427
|
+
if(mc) mc.parentElement.insertBefore(el,mc);
|
|
4428
|
+
}
|
|
4429
|
+
|
|
4319
4430
|
/* ─── Toast ─── */
|
|
4320
4431
|
function toast(msg,type='info'){
|
|
4321
4432
|
const c=document.getElementById('toasts');
|
|
@@ -4369,3 +4480,4 @@ checkAuth();
|
|
|
4369
4480
|
|
|
4370
4481
|
</body>
|
|
4371
4482
|
</html>`;
|
|
4483
|
+
}
|