@memtensor/memos-local-openclaw-plugin 1.0.8-beta.2 → 1.0.8-beta.4
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/index.ts +63 -38
- package/package.json +1 -1
- package/src/hub/server.ts +5 -4
- package/src/ingest/providers/anthropic.ts +9 -6
- package/src/ingest/providers/bedrock.ts +9 -6
- package/src/ingest/providers/gemini.ts +9 -6
- package/src/ingest/providers/index.ts +122 -21
- package/src/ingest/providers/openai.ts +141 -6
- package/src/ingest/task-processor.ts +61 -41
- package/src/ingest/worker.ts +32 -11
- package/src/recall/engine.ts +1 -0
- package/src/sharing/types.ts +1 -0
- package/src/storage/sqlite.ts +39 -5
- package/src/types.ts +3 -0
- package/src/viewer/html.ts +54 -28
- package/src/viewer/server.ts +63 -1
package/src/viewer/html.ts
CHANGED
|
@@ -144,10 +144,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
144
144
|
.stat-card.rose .stat-value{color:var(--rose)}
|
|
145
145
|
|
|
146
146
|
.sidebar .section-title{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;margin:24px 0 12px;padding:0 2px}
|
|
147
|
-
.sidebar .session-list{display:flex;flex-direction:column;gap:6px;flex:1;min-height:0;overflow-y:auto;padding-right:4px;flex-shrink:1}
|
|
148
|
-
.session-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;cursor:pointer;transition:all .15s;font-size:13px;color:var(--text)}
|
|
149
|
-
.session-item:hover{border-color:var(--pri);background:var(--pri-glow)}
|
|
150
|
-
.session-item.active{border-color:var(--pri);background:var(--pri-glow);font-weight:600;color:var(--pri)}
|
|
151
147
|
.session-item .count{color:var(--text-sec);font-size:11px;font-weight:600;background:rgba(0,0,0,.2);padding:3px 8px;border-radius:8px}
|
|
152
148
|
|
|
153
149
|
.provider-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--green-bg);color:var(--green);border-radius:999px;font-size:11px;font-weight:600;margin-top:10px}
|
|
@@ -833,6 +829,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
833
829
|
.recall-origin.local-shared{background:rgba(59,130,246,.12);color:#3b82f6}
|
|
834
830
|
.recall-origin.hub-memory{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
835
831
|
.recall-origin.hub-remote{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
832
|
+
.recall-origin.agent-tag{background:rgba(20,184,166,.12);color:#14b8a6}
|
|
836
833
|
.recall-summary-short{flex:1;color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
837
834
|
.recall-expand-icon{flex-shrink:0;font-size:10px;color:var(--text-muted);transition:transform .15s}
|
|
838
835
|
.recall-item.expanded .recall-expand-icon{transform:rotate(90deg)}
|
|
@@ -1263,7 +1260,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1263
1260
|
</div>
|
|
1264
1261
|
<div id="embeddingStatus"></div>
|
|
1265
1262
|
<button class="btn btn-sm btn-ghost" style="width:100%;margin:20px 0 12px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
|
|
1266
|
-
<div class="session-list" id="sessionList" style="display:none"></div>
|
|
1267
1263
|
</div>
|
|
1268
1264
|
|
|
1269
1265
|
<div class="view-container">
|
|
@@ -1820,6 +1816,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1820
1816
|
<input type="number" id="cfgViewerPort" placeholder="18799">
|
|
1821
1817
|
<div class="field-hint" data-i18n="settings.viewerport.hint">Requires restart to take effect</div>
|
|
1822
1818
|
</div>
|
|
1819
|
+
<div class="settings-field">
|
|
1820
|
+
<label data-i18n="settings.taskAutoFinalize">Task Auto-Finalize (hours)</label>
|
|
1821
|
+
<input type="number" id="cfgTaskAutoFinalizeHours" placeholder="4" min="0" step="1" style="max-width:120px">
|
|
1822
|
+
<div class="field-hint" data-i18n="settings.taskAutoFinalize.hint">Active tasks with no new messages beyond this duration will be automatically summarized and completed when the Tasks page is opened. Set to 0 to disable. Default: 4 hours.</div>
|
|
1823
|
+
</div>
|
|
1823
1824
|
</div>
|
|
1824
1825
|
<div class="settings-card-divider"></div>
|
|
1825
1826
|
<div class="settings-toggle">
|
|
@@ -2320,6 +2321,8 @@ const I18N={
|
|
|
2320
2321
|
'settings.telemetry.hint':'Only collects tool names, latencies and version info. No memory content or personal data.',
|
|
2321
2322
|
'settings.viewerport':'Viewer Port',
|
|
2322
2323
|
'settings.viewerport.hint':'Requires restart to take effect',
|
|
2324
|
+
'settings.taskAutoFinalize':'Task Auto-Finalize (hours)',
|
|
2325
|
+
'settings.taskAutoFinalize.hint':'Active tasks with no new messages beyond this duration will be automatically summarized and completed when the Tasks page is opened. Set to 0 to disable. Default: 4 hours.',
|
|
2323
2326
|
'settings.test':'Test Connection',
|
|
2324
2327
|
'settings.test.loading':'Testing...',
|
|
2325
2328
|
'settings.test.ok':'Connected',
|
|
@@ -3087,6 +3090,8 @@ const I18N={
|
|
|
3087
3090
|
'settings.telemetry.hint':'仅收集工具名称、响应时间和版本号,不涉及任何记忆内容或个人数据。',
|
|
3088
3091
|
'settings.viewerport':'Viewer 端口',
|
|
3089
3092
|
'settings.viewerport.hint':'修改后需重启网关生效',
|
|
3093
|
+
'settings.taskAutoFinalize':'任务自动完结(小时)',
|
|
3094
|
+
'settings.taskAutoFinalize.hint':'处于进行中的任务如果超过设定时间没有新消息,打开任务页面时会自动生成总结并标记为已完成。设为 0 则关闭此功能。默认:4 小时。',
|
|
3090
3095
|
'settings.test':'测试连接',
|
|
3091
3096
|
'settings.test.loading':'测试中...',
|
|
3092
3097
|
'settings.test.ok':'连接成功',
|
|
@@ -3963,6 +3968,11 @@ function _updateScopeSelectorsVisibility(hubAvailable){
|
|
|
3963
3968
|
var el=document.getElementById(ids[i]);
|
|
3964
3969
|
if(el) el.style.display=hubAvailable?'':'none';
|
|
3965
3970
|
}
|
|
3971
|
+
if(!hubAvailable){
|
|
3972
|
+
if(memorySearchScope==='hub'){memorySearchScope='allLocal';try{localStorage.setItem('memos_memorySearchScope','allLocal');}catch(e){}}
|
|
3973
|
+
if(taskSearchScope==='hub'){taskSearchScope='allLocal';try{localStorage.setItem('memos_taskSearchScope','allLocal');}catch(e){}}
|
|
3974
|
+
if(skillSearchScope==='hub'){skillSearchScope='allLocal';try{localStorage.setItem('memos_skillSearchScope','allLocal');}catch(e){}}
|
|
3975
|
+
}
|
|
3966
3976
|
}
|
|
3967
3977
|
async function loadSharingStatus(forcePending){
|
|
3968
3978
|
try{
|
|
@@ -5184,11 +5194,13 @@ function renderSharingMemorySearchResults(data,query){
|
|
|
5184
5194
|
'<div class="result-section">'+
|
|
5185
5195
|
'<div class="result-section-header"><div class="result-section-title">'+t('search.localResults')+'</div><div class="result-section-sub">'+localHits.length+' hit(s)</div></div>'+
|
|
5186
5196
|
'<div class="search-hit-list">'+(localHits.length?localHits.map(function(hit,idx){
|
|
5197
|
+
var agentName='';if(hit.owner){var ap=(hit.owner||'').split(':');agentName=ap.length>=3?ap[ap.length-1]:(ap.length>=2?ap[1]:hit.owner);}
|
|
5187
5198
|
return '<div class="search-hit-card">'+
|
|
5188
5199
|
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
5189
5200
|
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
5190
5201
|
'<div class="search-hit-meta">'+
|
|
5191
5202
|
'<span class="meta-chip">role: '+esc(hit.role||'unknown')+'</span>'+
|
|
5203
|
+
(agentName?'<span class="meta-chip" style="background:rgba(20,184,166,.12);color:#14b8a6">'+esc(agentName)+'</span>':'')+
|
|
5192
5204
|
(hit.score!=null?'<span class="meta-chip">score: '+Math.round(hit.score*100)+'%</span>':'')+
|
|
5193
5205
|
(hit.taskId?'<span class="meta-chip">task: '+esc(hit.taskId)+'</span>':'')+
|
|
5194
5206
|
'</div>'+
|
|
@@ -5198,11 +5210,13 @@ function renderSharingMemorySearchResults(data,query){
|
|
|
5198
5210
|
'<div class="result-section">'+
|
|
5199
5211
|
'<div class="result-section-header"><div class="result-section-title">'+t('search.hubResults')+'</div><div class="result-section-sub">'+hubHits.length+' hit(s)</div></div>'+
|
|
5200
5212
|
'<div class="search-hit-list">'+(hubHits.length?hubHits.map(function(hit,idx){
|
|
5213
|
+
var hubAgentName='';if(hit.sourceAgent){var hap=(hit.sourceAgent||'').split(':');hubAgentName=hap.length>=3?hap[hap.length-1]:(hap.length>=2?hap[1]:hit.sourceAgent);}
|
|
5201
5214
|
return '<div class="hub-hit-card">'+
|
|
5202
5215
|
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
5203
5216
|
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
5204
5217
|
'<div class="hub-hit-meta">'+
|
|
5205
5218
|
'<span class="meta-chip">owner: '+fmtOwner(hit)+'</span>'+
|
|
5219
|
+
(hubAgentName?'<span class="meta-chip" style="background:rgba(20,184,166,.12);color:#14b8a6">'+esc(hubAgentName)+'</span>':'')+
|
|
5206
5220
|
(hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
|
|
5207
5221
|
'<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
|
|
5208
5222
|
'</div>'+
|
|
@@ -5710,6 +5724,13 @@ function recallOriginBadge(origin){
|
|
|
5710
5724
|
if(origin==='hub-remote') return '<span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>';
|
|
5711
5725
|
return '';
|
|
5712
5726
|
}
|
|
5727
|
+
function agentBadge(owner){
|
|
5728
|
+
if(!owner) return '';
|
|
5729
|
+
var parts=(owner||'').split(':');
|
|
5730
|
+
var name=parts.length>=3?parts[parts.length-1]:(parts.length>=2?parts[1]:owner);
|
|
5731
|
+
if(!name) return '';
|
|
5732
|
+
return '<span class="recall-origin agent-tag">\u{1F916} '+escapeHtml(name)+'</span>';
|
|
5733
|
+
}
|
|
5713
5734
|
|
|
5714
5735
|
function buildLogSummary(lg){
|
|
5715
5736
|
let inputObj=null;
|
|
@@ -5736,8 +5757,9 @@ function buildLogSummary(lg){
|
|
|
5736
5757
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5737
5758
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5738
5759
|
var oBadge=recallOriginBadge(c.origin);
|
|
5760
|
+
var aBadge2=agentBadge(c.owner);
|
|
5739
5761
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5740
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5762
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+aBadge2+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5741
5763
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5742
5764
|
html+='</div>';
|
|
5743
5765
|
});
|
|
@@ -5752,8 +5774,9 @@ function buildLogSummary(lg){
|
|
|
5752
5774
|
var shortText=escapeHtml(c.summary||c.original_excerpt||'');
|
|
5753
5775
|
var fullText=escapeHtml(c.original_excerpt||c.summary||'');
|
|
5754
5776
|
var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
|
|
5777
|
+
var haBadge2=agentBadge(c.sourceAgent||'');
|
|
5755
5778
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5756
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'assistant')+'">'+(c.role||'assistant')+'</span><span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>'+owner+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5779
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'assistant')+'">'+(c.role||'assistant')+'</span><span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>'+owner+haBadge2+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5757
5780
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5758
5781
|
html+='</div>';
|
|
5759
5782
|
});
|
|
@@ -5769,8 +5792,9 @@ function buildLogSummary(lg){
|
|
|
5769
5792
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5770
5793
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5771
5794
|
var oBadge=recallOriginBadge(f.origin);
|
|
5795
|
+
var faBadge2=agentBadge(f.owner);
|
|
5772
5796
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5773
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+f.score.toFixed(2)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5797
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+f.score.toFixed(2)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+faBadge2+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5774
5798
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5775
5799
|
html+='</div>';
|
|
5776
5800
|
});
|
|
@@ -5836,8 +5860,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5836
5860
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5837
5861
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5838
5862
|
var oBadge=recallOriginBadge(c.origin);
|
|
5863
|
+
var aBadge=agentBadge(c.owner);
|
|
5839
5864
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5840
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(3)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5865
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(3)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+aBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5841
5866
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5842
5867
|
html+='</div>';
|
|
5843
5868
|
});
|
|
@@ -5852,8 +5877,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5852
5877
|
var shortText=escapeHtml(c.summary||c.original_excerpt||'');
|
|
5853
5878
|
var fullText=escapeHtml(c.original_excerpt||c.summary||'');
|
|
5854
5879
|
var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
|
|
5880
|
+
var haBadge=agentBadge(c.sourceAgent||'');
|
|
5855
5881
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5856
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'assistant')+'">'+(c.role||'assistant')+'</span><span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>'+owner+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5882
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'assistant')+'">'+(c.role||'assistant')+'</span><span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>'+owner+haBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5857
5883
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5858
5884
|
html+='</div>';
|
|
5859
5885
|
});
|
|
@@ -5869,8 +5895,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5869
5895
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5870
5896
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5871
5897
|
var oBadge=recallOriginBadge(f.origin);
|
|
5898
|
+
var faBadge=agentBadge(f.owner);
|
|
5872
5899
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5873
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+f.score.toFixed(3)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5900
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+f.score.toFixed(3)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+faBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5874
5901
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5875
5902
|
html+='</div>';
|
|
5876
5903
|
});
|
|
@@ -6105,7 +6132,7 @@ function renderTaskCards(tasks,container){
|
|
|
6105
6132
|
'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>'+
|
|
6106
6133
|
(durationStr?'<span class="tag"><span class="icon">\\u23F1</span> '+durationStr+'</span>':'')+
|
|
6107
6134
|
'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+(task.chunkCount||0)+' '+t('tasks.chunks.label')+'</span>'+
|
|
6108
|
-
'<span class="tag"><span class="icon">\\u{1F4C2}</span> '+(task.sessionKey||'')
|
|
6135
|
+
'<span class="tag"><span class="icon">\\u{1F4C2}</span> '+(task.sessionKey||'')+'</span>'+
|
|
6109
6136
|
'</div>'+
|
|
6110
6137
|
'<div class="card-actions" onclick="event.stopPropagation()">'+
|
|
6111
6138
|
'<button class="btn btn-sm btn-ghost" onclick="openTaskDetail(\\''+task.id+'\\')">'+t('card.expand')+'</button>'+
|
|
@@ -7081,6 +7108,7 @@ async function loadConfig(){
|
|
|
7081
7108
|
document.getElementById('cfgSkillApiKey').value=skSum.apiKey||'';
|
|
7082
7109
|
|
|
7083
7110
|
document.getElementById('cfgViewerPort').value=cfg.viewerPort||'';
|
|
7111
|
+
document.getElementById('cfgTaskAutoFinalizeHours').value=cfg.taskAutoFinalizeHours!=null?cfg.taskAutoFinalizeHours:'';
|
|
7084
7112
|
|
|
7085
7113
|
const tel=cfg.telemetry||{};
|
|
7086
7114
|
document.getElementById('cfgTelemetryEnabled').checked=tel.enabled!==false;
|
|
@@ -7385,6 +7413,8 @@ async function saveGeneralConfig(){
|
|
|
7385
7413
|
const cfg={};
|
|
7386
7414
|
const vp=document.getElementById('cfgViewerPort').value.trim();
|
|
7387
7415
|
if(vp) cfg.viewerPort=Number(vp);
|
|
7416
|
+
const tafh=document.getElementById('cfgTaskAutoFinalizeHours').value.trim();
|
|
7417
|
+
cfg.taskAutoFinalizeHours=tafh!==''?Number(tafh):4;
|
|
7388
7418
|
cfg.telemetry={enabled:document.getElementById('cfgTelemetryEnabled').checked};
|
|
7389
7419
|
|
|
7390
7420
|
await doSaveConfig(cfg, saveBtn, 'generalSaved');
|
|
@@ -8207,14 +8237,6 @@ async function loadStats(ownerFilter){
|
|
|
8207
8237
|
}
|
|
8208
8238
|
|
|
8209
8239
|
const sidebarSessions=getSessionsForView(_activeView);
|
|
8210
|
-
const sl=document.getElementById('sessionList');
|
|
8211
|
-
if(sl) sl.style.display=sidebarSessions.length>0?'':'none';
|
|
8212
|
-
sl.innerHTML='<div class="session-item'+(activeSession===null?' active':'')+'" onclick="filterSession(null)"><span>'+t('sidebar.allsessions')+'</span>'+countBadgeHtml(sidebarSessions.reduce(function(sum,s){return sum+(s.count||0);},0))+'</div>';
|
|
8213
|
-
sidebarSessions.forEach(s=>{
|
|
8214
|
-
const isActive=activeSession===s.session_key;
|
|
8215
|
-
const name=s.session_key.length>20?s.session_key.slice(0,8)+'...'+s.session_key.slice(-8):s.session_key;
|
|
8216
|
-
sl.innerHTML+='<div class="session-item'+(isActive?' active':'')+'" onclick="filterSession(\\''+s.session_key.replace(/'/g,"\\\\'")+'\\')"><span title="'+s.session_key+'">'+name+'</span>'+countBadgeHtml(s.count||0)+'</div>';
|
|
8217
|
-
});
|
|
8218
8240
|
|
|
8219
8241
|
[['filterSession','memories'],['taskFilterSession','tasks'],['skillFilterSession','skills']].forEach(function(pair){
|
|
8220
8242
|
var selId=pair[0];
|
|
@@ -8244,8 +8266,7 @@ async function loadStats(ownerFilter){
|
|
|
8244
8266
|
var label=o.replace('agent:','');
|
|
8245
8267
|
sel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
|
|
8246
8268
|
});
|
|
8247
|
-
|
|
8248
|
-
else sel.style.display='';
|
|
8269
|
+
sel.style.display='';
|
|
8249
8270
|
});
|
|
8250
8271
|
}
|
|
8251
8272
|
}
|
|
@@ -8458,10 +8479,6 @@ function filterSession(key){
|
|
|
8458
8479
|
var fSel=document.getElementById(selId);
|
|
8459
8480
|
if(fSel) fSel.value=key||'';
|
|
8460
8481
|
});
|
|
8461
|
-
document.querySelectorAll('#sessionList .session-item').forEach(function(el,i){
|
|
8462
|
-
if(i===0) el.classList.toggle('active',!key);
|
|
8463
|
-
else el.classList.toggle('active',el.querySelector('span')?.title===key);
|
|
8464
|
-
});
|
|
8465
8482
|
if(_activeView==='tasks'){
|
|
8466
8483
|
loadStats();
|
|
8467
8484
|
loadTasks();
|
|
@@ -8772,7 +8789,7 @@ async function showMemoryModal(chunkId){
|
|
|
8772
8789
|
h+='<div class="mm-section"><div class="mm-section-label">'+t('admin.content')+'</div><pre class="mm-content">'+esc(m.content)+'</pre></div>';
|
|
8773
8790
|
}
|
|
8774
8791
|
h+='<div class="mm-meta">';
|
|
8775
|
-
if(m.session_key) h+='<div class="mm-meta-chip"><strong>'+t('admin.session')+'</strong><span>'+esc(m.session_key
|
|
8792
|
+
if(m.session_key) h+='<div class="mm-meta-chip"><strong>'+t('admin.session')+'</strong><span>'+esc(m.session_key)+'</span></div>';
|
|
8776
8793
|
h+='<div class="mm-meta-chip"><strong>'+t('memory.detail.created')+'</strong><span>'+fmtModalDate(m.created_at)+'</span></div>';
|
|
8777
8794
|
if(m.updated_at) h+='<div class="mm-meta-chip"><strong>'+t('memory.detail.updated')+'</strong><span>'+fmtModalDate(m.updated_at)+'</span></div>';
|
|
8778
8795
|
if(m.kind) h+='<div class="mm-meta-chip"><strong>'+t('admin.kind')+'</strong><span>'+esc(m.kind)+'</span></div>';
|
|
@@ -8917,7 +8934,13 @@ async function clearAll(){
|
|
|
8917
8934
|
const r=await fetch('/api/memories',{method:'DELETE'});
|
|
8918
8935
|
if(r.status===401){toast(t('settings.session.expired'),'error');return;}
|
|
8919
8936
|
const d=await r.json();
|
|
8920
|
-
if(d.ok){
|
|
8937
|
+
if(d.ok){
|
|
8938
|
+
toast(t('toast.cleared'),'success');
|
|
8939
|
+
selectedMemoryIds.clear();selectedTaskIds.clear();selectedSkillIds.clear();
|
|
8940
|
+
_lastMemoriesFingerprint='';_lastTasksFingerprint='';_lastSkillsFingerprint='';_lastStatsFp='';
|
|
8941
|
+
await loadStats();
|
|
8942
|
+
await Promise.all([loadMemories(),loadTasks(),loadSkills(),loadSharingStatus(false)]);
|
|
8943
|
+
}
|
|
8921
8944
|
else{toast(t('toast.clearfail'),'error')}
|
|
8922
8945
|
}catch(e){toast('Error: '+e.message,'error')}
|
|
8923
8946
|
}
|
|
@@ -9631,7 +9654,10 @@ function doUpdateInstall(packageSpec,btnEl,statusEl,targetVersion){
|
|
|
9631
9654
|
btnEl.disabled=false;
|
|
9632
9655
|
});
|
|
9633
9656
|
}
|
|
9657
|
+
var _updateChecked=false;
|
|
9634
9658
|
async function checkForUpdate(){
|
|
9659
|
+
if(_updateChecked) return;
|
|
9660
|
+
_updateChecked=true;
|
|
9635
9661
|
try{
|
|
9636
9662
|
const r=await fetch('/api/update-check?_t='+Date.now(),{cache:'no-store'});
|
|
9637
9663
|
if(!r.ok)return;
|
package/src/viewer/server.ts
CHANGED
|
@@ -144,6 +144,8 @@ export class ViewerServer {
|
|
|
144
144
|
private lastKnownNotifCount = 0;
|
|
145
145
|
private hubHeartbeatTimer?: ReturnType<typeof setInterval>;
|
|
146
146
|
private static readonly HUB_HEARTBEAT_INTERVAL_MS = 45_000;
|
|
147
|
+
private static readonly STALE_TASK_TIMEOUT_MS = 4 * 60 * 60 * 1000;
|
|
148
|
+
private staleFinalizeRunning = false;
|
|
147
149
|
|
|
148
150
|
constructor(opts: ViewerServerOptions) {
|
|
149
151
|
this.store = opts.store;
|
|
@@ -637,6 +639,61 @@ export class ViewerServer {
|
|
|
637
639
|
|
|
638
640
|
this.backfillTaskEmbeddings(items);
|
|
639
641
|
this.jsonResponse(res, { tasks: items, total, limit, offset });
|
|
642
|
+
this.autoFinalizeStaleTasks();
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private getTaskAutoFinalizeMs(): number {
|
|
646
|
+
const hours = this.ctx?.config?.taskAutoFinalizeHours;
|
|
647
|
+
if (hours !== undefined && hours !== null) return hours * 60 * 60 * 1000;
|
|
648
|
+
try {
|
|
649
|
+
const cfgPath = this.getOpenClawConfigPath();
|
|
650
|
+
if (fs.existsSync(cfgPath)) {
|
|
651
|
+
const raw = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
|
|
652
|
+
const entries = raw?.plugins?.entries ?? {};
|
|
653
|
+
const pluginCfg = entries["memos-local-openclaw-plugin"]?.config
|
|
654
|
+
?? entries["memos-local"]?.config ?? {};
|
|
655
|
+
if (pluginCfg.taskAutoFinalizeHours !== undefined) return pluginCfg.taskAutoFinalizeHours * 60 * 60 * 1000;
|
|
656
|
+
}
|
|
657
|
+
} catch { /* fall through */ }
|
|
658
|
+
return ViewerServer.STALE_TASK_TIMEOUT_MS;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
private autoFinalizeStaleTasks(): void {
|
|
662
|
+
if (this.staleFinalizeRunning || !this.ctx) return;
|
|
663
|
+
const thresholdMs = this.getTaskAutoFinalizeMs();
|
|
664
|
+
if (thresholdMs <= 0) return;
|
|
665
|
+
const db = (this.store as any).db;
|
|
666
|
+
const now = Date.now();
|
|
667
|
+
let staleTasks: Array<{ id: string }>;
|
|
668
|
+
try {
|
|
669
|
+
staleTasks = db.prepare(`
|
|
670
|
+
SELECT t.id
|
|
671
|
+
FROM tasks t
|
|
672
|
+
LEFT JOIN chunks c ON c.task_id = t.id
|
|
673
|
+
WHERE t.status = 'active'
|
|
674
|
+
GROUP BY t.id
|
|
675
|
+
HAVING (? - COALESCE(MAX(c.created_at), t.started_at)) > ?
|
|
676
|
+
`).all(now, thresholdMs) as Array<{ id: string }>;
|
|
677
|
+
} catch { return; }
|
|
678
|
+
if (staleTasks.length === 0) return;
|
|
679
|
+
|
|
680
|
+
this.staleFinalizeRunning = true;
|
|
681
|
+
const hours = Math.round(thresholdMs / 3600000);
|
|
682
|
+
this.log.info(`Auto-finalizing ${staleTasks.length} stale active task(s) (idle > ${hours}h)`);
|
|
683
|
+
const tp = new TaskProcessor(this.store, this.ctx);
|
|
684
|
+
(async () => {
|
|
685
|
+
for (const row of staleTasks) {
|
|
686
|
+
const task = this.store.getTask(row.id);
|
|
687
|
+
if (!task || task.status !== "active") continue;
|
|
688
|
+
try {
|
|
689
|
+
await tp.finalizeTask(task);
|
|
690
|
+
this.log.info(`Auto-finalized stale task=${task.id}`);
|
|
691
|
+
} catch (err) {
|
|
692
|
+
this.log.warn(`Failed to auto-finalize task=${task.id}: ${err}`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
})().catch((err) => this.log.warn(`autoFinalizeStaleTasks error: ${err}`))
|
|
696
|
+
.finally(() => { this.staleFinalizeRunning = false; });
|
|
640
697
|
}
|
|
641
698
|
|
|
642
699
|
private async serveTaskSearch(res: http.ServerResponse, url: URL): Promise<void> {
|
|
@@ -1483,7 +1540,7 @@ export class ViewerServer {
|
|
|
1483
1540
|
const refreshedChunk = db.prepare("SELECT * FROM chunks WHERE id = ?").get(chunkId) as any;
|
|
1484
1541
|
const response = await hubRequestJson(hubClient.hubUrl, hubClient.userToken, "/api/v1/hub/memories/share", {
|
|
1485
1542
|
method: "POST",
|
|
1486
|
-
body: JSON.stringify({ memory: { sourceChunkId: refreshedChunk.id, role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary, kind: refreshedChunk.kind, groupId: null, visibility: "public" } }),
|
|
1543
|
+
body: JSON.stringify({ memory: { sourceChunkId: refreshedChunk.id, sourceAgent: refreshedChunk.owner || "", role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary, kind: refreshedChunk.kind, groupId: null, visibility: "public" } }),
|
|
1487
1544
|
});
|
|
1488
1545
|
if (!isLocalShared) this.store.markMemorySharedLocally(chunkId);
|
|
1489
1546
|
const memoryId = String((response as any)?.memoryId ?? "");
|
|
@@ -1493,6 +1550,7 @@ export class ViewerServer {
|
|
|
1493
1550
|
this.store.upsertHubMemory({
|
|
1494
1551
|
id: memoryId || existing?.id || crypto.randomUUID(),
|
|
1495
1552
|
sourceChunkId: chunkId, sourceUserId: hubClient.userId,
|
|
1553
|
+
sourceAgent: refreshedChunk.owner || "",
|
|
1496
1554
|
role: refreshedChunk.role, content: refreshedChunk.content, summary: refreshedChunk.summary ?? "",
|
|
1497
1555
|
kind: refreshedChunk.kind, groupId: null, visibility: "public",
|
|
1498
1556
|
createdAt: existing?.createdAt ?? Date.now(), updatedAt: Date.now(),
|
|
@@ -2302,6 +2360,7 @@ export class ViewerServer {
|
|
|
2302
2360
|
ref: { sessionKey: row.session_key, chunkId: row.id, turnId: row.turn_id, seq: row.seq },
|
|
2303
2361
|
taskId: row.task_id ?? null,
|
|
2304
2362
|
skillId: row.skill_id ?? null,
|
|
2363
|
+
owner: row.owner || "",
|
|
2305
2364
|
}));
|
|
2306
2365
|
return { hits, meta: { total: hits.length, usedMaxResults: maxResults } };
|
|
2307
2366
|
}
|
|
@@ -2411,6 +2470,7 @@ export class ViewerServer {
|
|
|
2411
2470
|
body: JSON.stringify({
|
|
2412
2471
|
memory: {
|
|
2413
2472
|
sourceChunkId: chunk.id,
|
|
2473
|
+
sourceAgent: chunk.owner || "",
|
|
2414
2474
|
role: chunk.role,
|
|
2415
2475
|
content: chunk.content,
|
|
2416
2476
|
summary: chunk.summary,
|
|
@@ -2428,6 +2488,7 @@ export class ViewerServer {
|
|
|
2428
2488
|
id: mid || existing?.id || crypto.randomUUID(),
|
|
2429
2489
|
sourceChunkId: chunk.id,
|
|
2430
2490
|
sourceUserId: hubClient.userId,
|
|
2491
|
+
sourceAgent: chunk.owner || "",
|
|
2431
2492
|
role: chunk.role,
|
|
2432
2493
|
content: chunk.content,
|
|
2433
2494
|
summary: chunk.summary ?? "",
|
|
@@ -2976,6 +3037,7 @@ export class ViewerServer {
|
|
|
2976
3037
|
if (newCfg.summarizer) config.summarizer = newCfg.summarizer;
|
|
2977
3038
|
if (newCfg.skillEvolution) config.skillEvolution = newCfg.skillEvolution;
|
|
2978
3039
|
if (newCfg.viewerPort) config.viewerPort = newCfg.viewerPort;
|
|
3040
|
+
if (newCfg.taskAutoFinalizeHours !== undefined) config.taskAutoFinalizeHours = newCfg.taskAutoFinalizeHours;
|
|
2979
3041
|
if (newCfg.telemetry !== undefined) config.telemetry = newCfg.telemetry;
|
|
2980
3042
|
if (newCfg.sharing !== undefined) {
|
|
2981
3043
|
const existing = (config.sharing as Record<string, unknown>) || {};
|