@memtensor/memos-local-openclaw-plugin 1.0.6-beta.2 → 1.0.6-beta.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.
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/viewer/html.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAq6RzD"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/viewer/html.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CA28RzD"}
@@ -2238,6 +2238,7 @@ const I18N={
2238
2238
  'logs.empty':'No logs yet. Logs will appear here when tools are called.',
2239
2239
  'logs.ago':'ago',
2240
2240
  'logs.recall.initial':'Initial Retrieval',
2241
+ 'logs.recall.hubRemote':'Hub Remote',
2241
2242
  'logs.recall.filtered':'LLM Filtered',
2242
2243
  'logs.recall.noHits':'No matching memories',
2243
2244
  'logs.recall.noneRelevant':'LLM filter: none relevant',
@@ -2981,6 +2982,7 @@ const I18N={
2981
2982
  'logs.empty':'暂无日志。当工具被调用时日志会显示在这里。',
2982
2983
  'logs.ago':'前',
2983
2984
  'logs.recall.initial':'初始检索',
2985
+ 'logs.recall.hubRemote':'远程召回',
2984
2986
  'logs.recall.filtered':'LLM 过滤后',
2985
2987
  'logs.recall.noHits':'未匹配到记忆',
2986
2988
  'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
@@ -5605,6 +5607,24 @@ function buildLogSummary(lg){
5605
5607
  html+='</div>';
5606
5608
  });
5607
5609
  html+='</div></div>';
5610
+ var hubCands=recallData.hubCandidates||[];
5611
+ html+='<div class="recall-layer hub-recall" onclick="this.classList.toggle(\\\'expanded\\\')">';
5612
+ html+='<div class="recall-layer-title"><span class="recall-expand-icon">\u25B6</span>\u{1F310} '+t('logs.recall.hubRemote')+' <span class="recall-count">'+hubCands.length+'</span></div>';
5613
+ if(hubCands.length>0){
5614
+ html+='<div class="recall-items">';
5615
+ hubCands.forEach(function(c){
5616
+ var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
5617
+ var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5618
+ var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5619
+ var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5620
+ html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5621
+ 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>';
5622
+ html+='<div class="recall-summary-full">'+fullText+'</div>';
5623
+ html+='</div>';
5624
+ });
5625
+ html+='</div>';
5626
+ }
5627
+ html+='</div>';
5608
5628
  if(filtered.length>0){
5609
5629
  html+='<div class="recall-layer filtered" onclick="this.classList.toggle(\\\'expanded\\\')">';
5610
5630
  html+='<div class="recall-layer-title"><span class="recall-expand-icon">\u25B6</span>\u2705 '+t('logs.recall.filtered')+' <span class="recall-count">'+filtered.length+'</span></div>';
@@ -5670,6 +5690,7 @@ function buildLogSummary(lg){
5670
5690
  function buildRecallDetailHtml(rd){
5671
5691
  var html='<div class="recall-detail">';
5672
5692
  var cands=rd.candidates||[];
5693
+ var hubCands=rd.hubCandidates||[];
5673
5694
  var filtered=rd.filtered||[];
5674
5695
  if(cands.length>0){
5675
5696
  html+='<div class="recall-detail-section" onclick="this.classList.toggle(\\\'expanded\\\')">';
@@ -5687,6 +5708,23 @@ function buildRecallDetailHtml(rd){
5687
5708
  });
5688
5709
  html+='</div></div>';
5689
5710
  }
5711
+ html+='<div class="recall-detail-section hub-recall" onclick="this.classList.toggle(\\\'expanded\\\')">';
5712
+ html+='<div class="recall-detail-title"><span class="recall-expand-icon">\u25B6</span>\u{1F310} '+t('logs.recall.hubRemote')+' ('+hubCands.length+')</div>';
5713
+ if(hubCands.length>0){
5714
+ html+='<div class="recall-detail-items">';
5715
+ hubCands.forEach(function(c,i){
5716
+ var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
5717
+ var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5718
+ var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5719
+ var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5720
+ html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5721
+ 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>';
5722
+ html+='<div class="recall-summary-full">'+fullText+'</div>';
5723
+ html+='</div>';
5724
+ });
5725
+ html+='</div>';
5726
+ }
5727
+ html+='</div>';
5690
5728
  if(filtered.length>0){
5691
5729
  html+='<div class="recall-detail-section filtered" onclick="this.classList.toggle(\\\'expanded\\\')">';
5692
5730
  html+='<div class="recall-detail-title"><span class="recall-expand-icon">\u25B6</span>\u2705 '+t('logs.recall.filtered')+' ('+filtered.length+')</div>';
@@ -5702,7 +5740,7 @@ function buildRecallDetailHtml(rd){
5702
5740
  html+='</div>';
5703
5741
  });
5704
5742
  html+='</div></div>';
5705
- }else if(cands.length>0){
5743
+ }else if(cands.length>0||hubCands.length>0){
5706
5744
  html+='<div style="font-size:10px;color:var(--text-muted);margin-top:4px">\u26A0 '+t('logs.recall.noneRelevant')+'</div>';
5707
5745
  }
5708
5746
  if(rd.status==='error'&&rd.error){
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/viewer/html.ts"],"names":[],"mappings":";;AAAA,gCAq6RC;AAr6RD,SAAgB,UAAU,CAAC,aAAsB;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,gCAAgC,aAAa,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3F,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2KAwqCoK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA0vPzK,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/viewer/html.ts"],"names":[],"mappings":";;AAAA,gCA28RC;AA38RD,SAAgB,UAAU,CAAC,aAAsB;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,gCAAgC,aAAa,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3F,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2KAwqCoK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAgyPzK,CAAC;AACT,CAAC"}
package/index.ts CHANGED
@@ -340,25 +340,11 @@ const memosLocalPlugin = {
340
340
  try {
341
341
  let outputText: string;
342
342
  const det = result?.details;
343
- if (det && Array.isArray(det.candidates)) {
343
+ if (det && (Array.isArray(det.candidates) || Array.isArray(det.filtered))) {
344
344
  outputText = JSON.stringify({
345
- candidates: det.candidates,
346
- filtered: det.hits ?? det.filtered ?? [],
347
- });
348
- } else if (det && det.local && det.hub) {
349
- const localHits = det.local?.hits ?? [];
350
- const hubHits = (det.hub?.hits ?? []).map((h: any) => ({
351
- score: h.score ?? 0,
352
- role: h.source?.role ?? h.role ?? "assistant",
353
- summary: h.summary ?? "",
354
- original_excerpt: h.excerpt ?? h.summary ?? "",
355
- origin: "hub-remote",
356
- ownerName: h.ownerName ?? "",
357
- groupName: h.groupName ?? "",
358
- }));
359
- outputText = JSON.stringify({
360
- candidates: [...localHits, ...hubHits],
361
- filtered: [...localHits, ...hubHits],
345
+ candidates: det.candidates ?? [],
346
+ hubCandidates: det.hubCandidates ?? [],
347
+ filtered: det.filtered ?? det.hits ?? [],
362
348
  });
363
349
  } else {
364
350
  outputText = result?.content?.[0]?.text ?? JSON.stringify(result ?? "");
@@ -505,10 +491,22 @@ const memosLocalPlugin = {
505
491
  const ownerFilter = [`agent:${agentId}`, "public"];
506
492
  const effectiveMaxResults = searchLimit;
507
493
  ctx.log.debug(`memory_search query="${query}" maxResults=${effectiveMaxResults} minScore=${minScore ?? 0.45} role=${role ?? "all"} owner=agent:${agentId}`);
508
- const result = await engine.search({ query, maxResults: effectiveMaxResults, minScore, role, ownerFilter });
509
- ctx.log.debug(`memory_search raw candidates: ${result.hits.length}`);
510
494
 
511
- const rawCandidates = result.hits.map((h) => ({
495
+ // ── Phase 1: Local search ∥ Hub search (parallel) ──
496
+ const localSearchP = engine.search({ query, maxResults: effectiveMaxResults, minScore, role, ownerFilter });
497
+ const hubSearchP = searchScope !== "local"
498
+ ? hubSearchMemories(store, ctx, { query, maxResults: searchLimit, scope: searchScope as any, hubAddress, userToken })
499
+ .catch(() => ({ hits: [] as any[], meta: { totalCandidates: 0, searchedGroups: [] as string[], includedPublic: searchScope === "all" } }))
500
+ : Promise.resolve(null);
501
+
502
+ const [result, hubResult] = await Promise.all([localSearchP, hubSearchP]);
503
+ ctx.log.debug(`memory_search raw candidates: local=${result.hits.length}, hub=${hubResult?.hits?.length ?? 0}`);
504
+
505
+ // Split local results: pure-local vs hub-memory (Hub role's hub_memories mixed in by RecallEngine)
506
+ const localHits = result.hits.filter((h) => h.origin !== "hub-memory");
507
+ const hubLocalHits = result.hits.filter((h) => h.origin === "hub-memory");
508
+
509
+ const rawLocalCandidates = localHits.map((h) => ({
512
510
  chunkId: h.ref.chunkId,
513
511
  role: h.source.role,
514
512
  score: h.score,
@@ -517,208 +515,156 @@ const memosLocalPlugin = {
517
515
  origin: h.origin || "local",
518
516
  }));
519
517
 
520
- if (result.hits.length === 0 && searchScope === "local") {
518
+ // Hub remote candidates (from HTTP call) + hub-memory candidates (from RecallEngine for Hub role)
519
+ const hubRemoteHits = hubResult?.hits ?? [];
520
+ const rawHubCandidates = [
521
+ ...hubLocalHits.map((h) => ({
522
+ score: h.score,
523
+ role: h.source.role,
524
+ summary: h.summary,
525
+ original_excerpt: (h.original_excerpt ?? "").slice(0, 200),
526
+ origin: "hub-memory" as const,
527
+ ownerName: "",
528
+ groupName: "",
529
+ })),
530
+ ...hubRemoteHits.map((h: any) => ({
531
+ score: h.score ?? 0,
532
+ role: h.source?.role ?? h.role ?? "assistant",
533
+ summary: h.summary ?? "",
534
+ original_excerpt: (h.excerpt ?? h.summary ?? "").slice(0, 200),
535
+ origin: "hub-remote" as const,
536
+ ownerName: h.ownerName ?? "",
537
+ groupName: h.groupName ?? "",
538
+ })),
539
+ ];
540
+
541
+ if (localHits.length === 0 && rawHubCandidates.length === 0) {
521
542
  return {
522
543
  content: [{ type: "text", text: result.meta.note ?? "No relevant memories found." }],
523
- details: { candidates: [], meta: result.meta },
544
+ details: { candidates: rawLocalCandidates, hubCandidates: [], filtered: [], meta: result.meta },
524
545
  };
525
546
  }
526
547
 
527
- let filteredHits = result.hits;
528
- let sufficient = false;
529
-
530
- const candidates = result.hits.map((h, i) => ({
531
- index: i + 1,
532
- role: h.source.role,
533
- content: (h.original_excerpt ?? "").slice(0, 300),
534
- time: h.source.ts ? new Date(h.source.ts).toISOString().slice(0, 16) : "",
535
- }));
536
-
537
- const filterResult = await summarizer.filterRelevant(query, candidates);
538
- if (filterResult !== null) {
539
- sufficient = filterResult.sufficient;
540
- if (filterResult.relevant.length > 0) {
541
- const indexSet = new Set(filterResult.relevant);
542
- filteredHits = result.hits.filter((_, i) => indexSet.has(i + 1));
543
- ctx.log.debug(`memory_search LLM filter: ${result.hits.length} → ${filteredHits.length} hits, sufficient=${sufficient}`);
544
- } else if (searchScope === "local") {
545
- return {
546
- content: [{ type: "text", text: "No relevant memories found for this query." }],
547
- details: { candidates: rawCandidates, filtered: [], meta: result.meta },
548
- };
549
- } else {
550
- filteredHits = [];
551
- }
552
- }
553
-
554
- const beforeDedup = filteredHits.length;
555
- filteredHits = deduplicateHits(filteredHits);
556
- ctx.log.debug(`memory_search dedup: ${beforeDedup} → ${filteredHits.length}`);
557
-
558
- const localDetailsHits = filteredHits.map((h) => {
559
- let effectiveTaskId = h.taskId;
560
- if (effectiveTaskId) {
561
- const t = store.getTask(effectiveTaskId);
562
- if (t && t.status === "skipped") effectiveTaskId = null;
563
- }
564
- return {
565
- ref: h.ref,
566
- chunkId: h.ref.chunkId,
567
- taskId: effectiveTaskId,
568
- skillId: h.skillId,
548
+ // ── Phase 2: Merge all candidates → single LLM filter ──
549
+ const allHitsForFilter = [...localHits, ...hubLocalHits];
550
+ const hubRemoteForFilter = hubRemoteHits;
551
+ const mergedCandidates = [
552
+ ...allHitsForFilter.map((h, i) => ({
553
+ index: i + 1,
569
554
  role: h.source.role,
570
- score: h.score,
571
- summary: h.summary,
572
- origin: h.origin || "local",
573
- };
574
- });
555
+ content: (h.original_excerpt ?? "").slice(0, 300),
556
+ time: h.source.ts ? new Date(h.source.ts).toISOString().slice(0, 16) : "",
557
+ })),
558
+ ...hubRemoteForFilter.map((h: any, i: number) => ({
559
+ index: allHitsForFilter.length + i + 1,
560
+ role: (h.source?.role || "assistant") as string,
561
+ content: (h.summary || h.excerpt || "").slice(0, 300),
562
+ time: h.source?.ts ? new Date(h.source.ts).toISOString().slice(0, 16) : "",
563
+ })),
564
+ ];
565
+
566
+ let filteredLocalHits = allHitsForFilter;
567
+ let filteredHubRemoteHits = hubRemoteForFilter;
568
+ let sufficient = false;
575
569
 
576
- if (searchScope !== "local") {
577
- const hub = await hubSearchMemories(store, ctx, { query, maxResults: searchLimit, scope: searchScope as any, hubAddress, userToken }).catch(() => ({ hits: [], meta: { totalCandidates: 0, searchedGroups: [], includedPublic: searchScope === "all" } }));
578
-
579
- let filteredHubHits = hub.hits;
580
- if (hub.hits.length > 0) {
581
- const hubCandidates = hub.hits.map((h, i) => ({
582
- index: filteredHits.length + i + 1,
583
- role: (h.source?.role || "assistant") as string,
584
- content: (h.summary || h.excerpt || "").slice(0, 300),
585
- time: h.source?.ts ? new Date(h.source.ts).toISOString().slice(0, 16) : "",
586
- }));
587
- const localCandidatesForMerge = filteredHits.map((h, i) => ({
588
- index: i + 1,
589
- role: h.source.role,
590
- content: (h.original_excerpt ?? "").slice(0, 300),
591
- time: h.source.ts ? new Date(h.source.ts).toISOString().slice(0, 16) : "",
592
- }));
593
- const mergedCandidates = [...localCandidatesForMerge, ...hubCandidates];
594
- const mergedFilter = await summarizer.filterRelevant(query, mergedCandidates);
595
- if (mergedFilter !== null && mergedFilter.relevant.length > 0) {
596
- const relevantSet = new Set(mergedFilter.relevant);
597
- const hubStartIdx = filteredHits.length + 1;
598
- filteredHits = filteredHits.filter((_, i) => relevantSet.has(i + 1));
599
- filteredHubHits = hub.hits.filter((_, i) => relevantSet.has(hubStartIdx + i));
600
- ctx.log.debug(`memory_search LLM filter (merged): local ${localCandidatesForMerge.length}→${filteredHits.length}, hub ${hub.hits.length}→${filteredHubHits.length}`);
570
+ if (mergedCandidates.length > 0) {
571
+ const filterResult = await summarizer.filterRelevant(query, mergedCandidates);
572
+ if (filterResult !== null) {
573
+ sufficient = filterResult.sufficient;
574
+ if (filterResult.relevant.length > 0) {
575
+ const relevantSet = new Set(filterResult.relevant);
576
+ const hubStartIdx = allHitsForFilter.length + 1;
577
+ filteredLocalHits = allHitsForFilter.filter((_, i) => relevantSet.has(i + 1));
578
+ filteredHubRemoteHits = hubRemoteForFilter.filter((_: any, i: number) => relevantSet.has(hubStartIdx + i));
579
+ ctx.log.debug(`memory_search LLM filter: merged ${mergedCandidates.length} local ${filteredLocalHits.length}, hub ${filteredHubRemoteHits.length}`);
580
+ } else {
581
+ filteredLocalHits = [];
582
+ filteredHubRemoteHits = [];
601
583
  }
602
584
  }
603
-
604
- const originLabel = (h: SearchHit) => {
605
- if (h.origin === "hub-memory") return " [团队缓存]";
606
- if (h.origin === "local-shared") return " [本机共享]";
607
- return "";
608
- };
609
- const localText = filteredHits.length > 0
610
- ? filteredHits.map((h, i) => {
611
- const excerpt = h.original_excerpt.length > 220 ? h.original_excerpt.slice(0, 217) + "..." : h.original_excerpt;
612
- return `${i + 1}. [${h.source.role}]${originLabel(h)} ${excerpt}`;
613
- }).join("\n")
614
- : "(none)";
615
- const hubText = filteredHubHits.length > 0
616
- ? filteredHubHits.map((h, i) => `${i + 1}. [${h.ownerName}] [团队] ${h.summary}${h.groupName ? ` (${h.groupName})` : ""}`).join("\n")
617
- : "(none)";
618
-
619
- const localDetailsFiltered = filteredHits.map((h) => {
620
- let effectiveTaskId = h.taskId;
621
- if (effectiveTaskId) {
622
- const t = store.getTask(effectiveTaskId);
623
- if (t && t.status === "skipped") effectiveTaskId = null;
624
- }
625
- return {
626
- ref: h.ref,
627
- chunkId: h.ref.chunkId,
628
- taskId: effectiveTaskId,
629
- skillId: h.skillId,
630
- role: h.source.role,
631
- score: h.score,
632
- summary: h.summary,
633
- origin: h.origin,
634
- };
635
- });
636
-
637
- return {
638
- content: [{
639
- type: "text",
640
- text: `Local results:\n${localText}\n\nHub results:\n${hubText}`,
641
- }],
642
- details: {
643
- local: { hits: localDetailsFiltered, meta: result.meta },
644
- hub: { ...hub, hits: filteredHubHits },
645
- },
646
- };
647
585
  }
648
586
 
649
- if (filteredHits.length === 0) {
587
+ const beforeDedup = filteredLocalHits.length;
588
+ filteredLocalHits = deduplicateHits(filteredLocalHits);
589
+ ctx.log.debug(`memory_search dedup: ${beforeDedup} → ${filteredLocalHits.length}`);
590
+
591
+ if (filteredLocalHits.length === 0 && filteredHubRemoteHits.length === 0) {
650
592
  return {
651
593
  content: [{ type: "text", text: "No relevant memories found for this query." }],
652
- details: { candidates: rawCandidates, filtered: [], meta: result.meta },
594
+ details: { candidates: rawLocalCandidates, hubCandidates: rawHubCandidates, filtered: [], meta: result.meta },
653
595
  };
654
596
  }
655
597
 
598
+ // ── Phase 3: Build response text ──
656
599
  const originTag = (o?: string) => {
657
600
  if (o === "local-shared") return " [本机共享]";
658
601
  if (o === "hub-memory") return " [团队缓存]";
659
602
  if (o === "hub-remote") return " [团队]";
660
603
  return "";
661
604
  };
662
- const lines = filteredHits.map((h, i) => {
663
- const excerpt = h.original_excerpt;
664
- const parts = [`${i + 1}. [${h.source.role}]${originTag(h.origin)}`];
665
- if (excerpt) parts.push(` ${excerpt}`);
605
+
606
+ const localLines = filteredLocalHits.map((h, i) => {
607
+ const excerpt = h.original_excerpt.length > 220 ? h.original_excerpt.slice(0, 217) + "..." : h.original_excerpt;
608
+ const parts = [`${i + 1}. [${h.source.role}]${originTag(h.origin)} ${excerpt}`];
666
609
  parts.push(` chunkId="${h.ref.chunkId}"`);
667
610
  if (h.taskId) {
668
611
  const task = store.getTask(h.taskId);
669
- if (task && task.status !== "skipped") {
670
- parts.push(` task_id="${h.taskId}"`);
671
- }
612
+ if (task && task.status !== "skipped") parts.push(` task_id="${h.taskId}"`);
672
613
  }
673
614
  return parts.join("\n");
674
615
  });
675
616
 
617
+ const hubLines = filteredHubRemoteHits.map((h: any, i: number) =>
618
+ `${i + 1}. [${h.ownerName ?? "team"}] [团队] ${h.summary ?? ""}${h.groupName ? ` (${h.groupName})` : ""}`
619
+ );
620
+
676
621
  let tipsText = "";
677
622
  if (!sufficient) {
678
- const hasTask = filteredHits.some((h) => {
623
+ const hasTask = filteredLocalHits.some((h) => {
679
624
  if (!h.taskId) return false;
680
625
  const t = store.getTask(h.taskId);
681
626
  return t && t.status !== "skipped";
682
627
  });
683
-
684
628
  const tips: string[] = [];
685
629
  if (hasTask) {
686
630
  tips.push("→ call task_summary(taskId) for full task context");
687
631
  tips.push("→ call skill_get(taskId=...) if the task has a proven experience guide");
688
632
  }
689
633
  tips.push("→ call memory_timeline(chunkId) to expand surrounding conversation");
690
-
691
- if (tips.length > 0) {
692
- tipsText = "\n\nThese memories may not be enough. You can fetch more context:\n" + tips.join("\n");
693
- }
634
+ if (tips.length > 0) tipsText = "\n\nThese memories may not be enough. You can fetch more context:\n" + tips.join("\n");
694
635
  }
695
636
 
637
+ const localText = localLines.length > 0 ? localLines.join("\n\n") : "(none)";
638
+ const hubText = hubLines.length > 0 ? hubLines.join("\n") : "(none)";
639
+ const totalFiltered = filteredLocalHits.length + filteredHubRemoteHits.length;
640
+ const responseText = filteredHubRemoteHits.length > 0
641
+ ? `Found ${totalFiltered} relevant memories:\n\nLocal results:\n${localText}\n\nHub results:\n${hubText}${tipsText}`
642
+ : `Found ${totalFiltered} relevant memories:\n\n${localText}${tipsText}`;
643
+
644
+ const filteredDetails = [
645
+ ...filteredLocalHits.map((h) => {
646
+ let effectiveTaskId = h.taskId;
647
+ if (effectiveTaskId) { const t = store.getTask(effectiveTaskId); if (t && t.status === "skipped") effectiveTaskId = null; }
648
+ return {
649
+ chunkId: h.ref.chunkId, taskId: effectiveTaskId, skillId: h.skillId,
650
+ role: h.source.role, score: h.score, summary: h.summary,
651
+ original_excerpt: (h.original_excerpt ?? "").slice(0, 200), origin: h.origin || "local",
652
+ };
653
+ }),
654
+ ...filteredHubRemoteHits.map((h: any) => ({
655
+ chunkId: "", taskId: null, skillId: null,
656
+ role: h.source?.role ?? h.role ?? "assistant", score: h.score ?? 0,
657
+ summary: h.summary ?? "", original_excerpt: (h.excerpt ?? h.summary ?? "").slice(0, 200),
658
+ origin: "hub-remote", ownerName: h.ownerName ?? "", groupName: h.groupName ?? "",
659
+ })),
660
+ ];
661
+
696
662
  return {
697
- content: [
698
- {
699
- type: "text",
700
- text: `Found ${filteredHits.length} relevant memories:\n\n${lines.join("\n\n")}${tipsText}`,
701
- },
702
- ],
663
+ content: [{ type: "text", text: responseText }],
703
664
  details: {
704
- candidates: rawCandidates,
705
- hits: filteredHits.map((h) => {
706
- let effectiveTaskId = h.taskId;
707
- if (effectiveTaskId) {
708
- const t = store.getTask(effectiveTaskId);
709
- if (t && t.status === "skipped") effectiveTaskId = null;
710
- }
711
- return {
712
- chunkId: h.ref.chunkId,
713
- taskId: effectiveTaskId,
714
- skillId: h.skillId,
715
- role: h.source.role,
716
- score: h.score,
717
- summary: h.summary,
718
- original_excerpt: (h.original_excerpt ?? "").slice(0, 200),
719
- origin: h.origin || "local",
720
- };
721
- }),
665
+ candidates: rawLocalCandidates,
666
+ hubCandidates: rawHubCandidates,
667
+ filtered: filteredDetails,
722
668
  meta: result.meta,
723
669
  },
724
670
  };
@@ -1869,46 +1815,53 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
1869
1815
  }
1870
1816
  ctx.log.debug(`auto-recall: query="${query.slice(0, 80)}"`);
1871
1817
 
1872
- const result = await engine.search({ query, maxResults: 10, minScore: 0.45, ownerFilter: recallOwnerFilter });
1818
+ // ── Phase 1: Local search Hub search (parallel) ──
1819
+ const arLocalP = engine.search({ query, maxResults: 10, minScore: 0.45, ownerFilter: recallOwnerFilter });
1820
+ const arHubP = ctx.config?.sharing?.enabled
1821
+ ? hubSearchMemories(store, ctx, { query, maxResults: 10, scope: "all" })
1822
+ .catch((err: any) => { ctx.log.debug(`auto-recall: hub search failed (${err})`); return { hits: [] as any[], meta: {} }; })
1823
+ : Promise.resolve({ hits: [] as any[], meta: {} });
1824
+
1825
+ const [result, arHubResult] = await Promise.all([arLocalP, arHubP]);
1826
+
1827
+ const localHits = result.hits.filter((h) => h.origin !== "hub-memory");
1828
+ const hubLocalHits = result.hits.filter((h) => h.origin === "hub-memory");
1829
+ const hubRemoteHits: SearchHit[] = (arHubResult.hits ?? []).map((h: any) => ({
1830
+ summary: h.summary,
1831
+ original_excerpt: h.excerpt || h.summary,
1832
+ ref: { sessionKey: "", chunkId: h.remoteHitId ?? "", turnId: "", seq: 0 },
1833
+ score: 0.9,
1834
+ taskId: null,
1835
+ skillId: null,
1836
+ origin: "hub-remote" as const,
1837
+ source: { ts: h.source?.ts, role: h.source?.role ?? "assistant", sessionKey: "" },
1838
+ ownerName: h.ownerName,
1839
+ groupName: h.groupName,
1840
+ }));
1841
+ const allHubHits = [...hubLocalHits, ...hubRemoteHits];
1873
1842
 
1874
- // Hub fallback helper: search team shared memories when local search has no relevant results
1875
- const hubFallback = async (): Promise<SearchHit[]> => {
1876
- if (!ctx.config?.sharing?.enabled) return [];
1877
- try {
1878
- const hubResult = await hubSearchMemories(store, ctx, { query, maxResults: 10, scope: "all" });
1879
- if (hubResult.hits.length === 0) return [];
1880
- ctx.log.debug(`auto-recall: hub fallback returned ${hubResult.hits.length} hit(s)`);
1881
- return hubResult.hits.map((h) => ({
1882
- summary: h.summary,
1883
- original_excerpt: h.excerpt || h.summary,
1884
- ref: { sessionKey: "", chunkId: h.remoteHitId, turnId: "", seq: 0 },
1885
- score: 0.9,
1886
- taskId: null,
1887
- skillId: null,
1888
- origin: "hub-remote" as const,
1889
- source: { ts: h.source.ts, role: h.source.role, sessionKey: "" },
1890
- }));
1891
- } catch (err) {
1892
- ctx.log.debug(`auto-recall: hub fallback failed (${err})`);
1893
- return [];
1894
- }
1895
- };
1843
+ ctx.log.debug(`auto-recall: local=${localHits.length}, hub-memory=${hubLocalHits.length}, hub-remote=${hubRemoteHits.length}`);
1896
1844
 
1897
- if (result.hits.length === 0) {
1898
- // Local found nothing try hub before giving up
1899
- const hubHits = await hubFallback();
1900
- if (hubHits.length > 0) {
1901
- result.hits.push(...hubHits);
1902
- ctx.log.debug(`auto-recall: local empty, using ${hubHits.length} hub hit(s)`);
1903
- }
1904
- }
1905
- if (result.hits.length === 0) {
1845
+ const rawLocalCandidates = localHits.map((h) => ({
1846
+ score: h.score, role: h.source.role, summary: h.summary,
1847
+ content: (h.original_excerpt ?? "").slice(0, 200), origin: h.origin || "local",
1848
+ }));
1849
+ const rawHubCandidates = allHubHits.map((h) => ({
1850
+ score: h.score, role: h.source.role, summary: h.summary,
1851
+ content: (h.original_excerpt ?? "").slice(0, 200), origin: h.origin || "hub-remote",
1852
+ ownerName: (h as any).ownerName ?? "", groupName: (h as any).groupName ?? "",
1853
+ }));
1854
+
1855
+ const allRawHits = [...localHits, ...allHubHits];
1856
+
1857
+ if (allRawHits.length === 0) {
1906
1858
  ctx.log.debug("auto-recall: no memory candidates found");
1907
1859
  const dur = performance.now() - recallT0;
1908
1860
  store.recordToolCall("memory_search", dur, true);
1909
- store.recordApiLog("memory_search", { type: "auto_recall", query }, JSON.stringify({ candidates: [], filtered: [] }), dur, true);
1861
+ store.recordApiLog("memory_search", { type: "auto_recall", query }, JSON.stringify({
1862
+ candidates: rawLocalCandidates, hubCandidates: rawHubCandidates, filtered: [],
1863
+ }), dur, true);
1910
1864
 
1911
- // Even without memory hits, try skill recall
1912
1865
  const skillAutoRecallEarly = ctx.config.skillEvolution?.autoRecallSkills ?? DEFAULTS.skillAutoRecall;
1913
1866
  if (skillAutoRecallEarly) {
1914
1867
  try {
@@ -1948,59 +1901,44 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
1948
1901
  return;
1949
1902
  }
1950
1903
 
1951
- const candidates = result.hits.map((h, i) => ({
1904
+ // ── Phase 2: Merge all → single LLM filter ──
1905
+ const mergedForFilter = allRawHits.map((h, i) => ({
1952
1906
  index: i + 1,
1953
1907
  role: h.source.role,
1954
1908
  content: (h.original_excerpt ?? "").slice(0, 300),
1955
1909
  time: h.source.ts ? new Date(h.source.ts).toISOString().slice(0, 16) : "",
1956
1910
  }));
1957
1911
 
1958
- let filteredHits = result.hits;
1912
+ let filteredHits = allRawHits;
1959
1913
  let sufficient = false;
1960
1914
 
1961
- const filterResult = await summarizer.filterRelevant(query, candidates);
1915
+ const filterResult = await summarizer.filterRelevant(query, mergedForFilter);
1962
1916
  if (filterResult !== null) {
1963
1917
  sufficient = filterResult.sufficient;
1964
1918
  if (filterResult.relevant.length > 0) {
1965
1919
  const indexSet = new Set(filterResult.relevant);
1966
- filteredHits = result.hits.filter((_, i) => indexSet.has(i + 1));
1920
+ filteredHits = allRawHits.filter((_, i) => indexSet.has(i + 1));
1967
1921
  } else {
1968
- ctx.log.debug("auto-recall: LLM filter returned no relevant local hits, trying hub fallback");
1969
- const hubHits = await hubFallback();
1970
- if (hubHits.length > 0) {
1971
- ctx.log.debug(`auto-recall: hub fallback provided ${hubHits.length} hit(s) after local filter yielded 0`);
1972
- filteredHits = hubHits;
1973
- } else {
1974
- const dur = performance.now() - recallT0;
1975
- store.recordToolCall("memory_search", dur, true);
1976
- store.recordApiLog("memory_search", { type: "auto_recall", query }, JSON.stringify({
1977
- candidates: result.hits.map(h => ({ score: h.score, role: h.source.role, summary: h.summary, content: h.original_excerpt, origin: h.origin || "local" })),
1978
- filtered: []
1979
- }), dur, true);
1980
- if (query.length > 50) {
1981
- const noRecallHint =
1982
- "## Memory system — ACTION REQUIRED\n\n" +
1983
- "Auto-recall found no relevant results for a long query. " +
1984
- "You MUST call `memory_search` now with a shortened query (2-5 key words) before answering. " +
1985
- "Do NOT skip this step. Do NOT answer without searching first.";
1986
- return { prependContext: noRecallHint };
1987
- }
1988
- return;
1922
+ const dur = performance.now() - recallT0;
1923
+ store.recordToolCall("memory_search", dur, true);
1924
+ store.recordApiLog("memory_search", { type: "auto_recall", query }, JSON.stringify({
1925
+ candidates: rawLocalCandidates, hubCandidates: rawHubCandidates, filtered: [],
1926
+ }), dur, true);
1927
+ if (query.length > 50) {
1928
+ const noRecallHint =
1929
+ "## Memory system — ACTION REQUIRED\n\n" +
1930
+ "Auto-recall found no relevant results for a long query. " +
1931
+ "You MUST call `memory_search` now with a shortened query (2-5 key words) before answering. " +
1932
+ "Do NOT skip this step. Do NOT answer without searching first.";
1933
+ return { prependContext: noRecallHint };
1989
1934
  }
1990
- }
1991
- }
1992
-
1993
- if (!sufficient && filteredHits.length > 0 && ctx.config?.sharing?.enabled) {
1994
- const hubSupp = await hubFallback();
1995
- if (hubSupp.length > 0) {
1996
- ctx.log.debug(`auto-recall: local insufficient, supplementing with ${hubSupp.length} hub hit(s)`);
1997
- filteredHits.push(...hubSupp);
1935
+ return;
1998
1936
  }
1999
1937
  }
2000
1938
 
2001
1939
  const beforeDedup = filteredHits.length;
2002
1940
  filteredHits = deduplicateHits(filteredHits);
2003
- ctx.log.debug(`auto-recall: ${result.hits.length} → ${beforeDedup} relevant → ${filteredHits.length} after dedup, sufficient=${sufficient}`);
1941
+ ctx.log.debug(`auto-recall: merged ${allRawHits.length} → ${beforeDedup} relevant → ${filteredHits.length} after dedup, sufficient=${sufficient}`);
2004
1942
 
2005
1943
  const lines = filteredHits.map((h, i) => {
2006
1944
  const excerpt = h.original_excerpt;
@@ -2114,8 +2052,9 @@ Groups: ${groupNames.length > 0 ? groupNames.join(", ") : "(none)"}`,
2114
2052
  const recallDur = performance.now() - recallT0;
2115
2053
  store.recordToolCall("memory_search", recallDur, true);
2116
2054
  store.recordApiLog("memory_search", { type: "auto_recall", query }, JSON.stringify({
2117
- candidates: result.hits.map(h => ({ score: h.score, role: h.source.role, summary: h.summary, content: h.original_excerpt, origin: h.origin || "local" })),
2118
- filtered: filteredHits.map(h => ({ score: h.score, role: h.source.role, summary: h.summary, content: h.original_excerpt, origin: h.origin || "local" }))
2055
+ candidates: rawLocalCandidates,
2056
+ hubCandidates: rawHubCandidates,
2057
+ filtered: filteredHits.map(h => ({ score: h.score, role: h.source.role, summary: h.summary, content: h.original_excerpt, origin: h.origin || "local" })),
2119
2058
  }), recallDur, true);
2120
2059
  telemetry.trackAutoRecall(filteredHits.length, recallDur);
2121
2060
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memtensor/memos-local-openclaw-plugin",
3
- "version": "1.0.6-beta.2",
3
+ "version": "1.0.6-beta.3",
4
4
  "description": "MemOS Local memory plugin for OpenClaw — full-write, hybrid-recall, progressive retrieval",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -2235,6 +2235,7 @@ const I18N={
2235
2235
  'logs.empty':'No logs yet. Logs will appear here when tools are called.',
2236
2236
  'logs.ago':'ago',
2237
2237
  'logs.recall.initial':'Initial Retrieval',
2238
+ 'logs.recall.hubRemote':'Hub Remote',
2238
2239
  'logs.recall.filtered':'LLM Filtered',
2239
2240
  'logs.recall.noHits':'No matching memories',
2240
2241
  'logs.recall.noneRelevant':'LLM filter: none relevant',
@@ -2978,6 +2979,7 @@ const I18N={
2978
2979
  'logs.empty':'暂无日志。当工具被调用时日志会显示在这里。',
2979
2980
  'logs.ago':'前',
2980
2981
  'logs.recall.initial':'初始检索',
2982
+ 'logs.recall.hubRemote':'远程召回',
2981
2983
  'logs.recall.filtered':'LLM 过滤后',
2982
2984
  'logs.recall.noHits':'未匹配到记忆',
2983
2985
  'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
@@ -5602,6 +5604,24 @@ function buildLogSummary(lg){
5602
5604
  html+='</div>';
5603
5605
  });
5604
5606
  html+='</div></div>';
5607
+ var hubCands=recallData.hubCandidates||[];
5608
+ html+='<div class="recall-layer hub-recall" onclick="this.classList.toggle(\\\'expanded\\\')">';
5609
+ html+='<div class="recall-layer-title"><span class="recall-expand-icon">\u25B6</span>\u{1F310} '+t('logs.recall.hubRemote')+' <span class="recall-count">'+hubCands.length+'</span></div>';
5610
+ if(hubCands.length>0){
5611
+ html+='<div class="recall-items">';
5612
+ hubCands.forEach(function(c){
5613
+ var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
5614
+ var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5615
+ var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5616
+ var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5617
+ html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5618
+ 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>';
5619
+ html+='<div class="recall-summary-full">'+fullText+'</div>';
5620
+ html+='</div>';
5621
+ });
5622
+ html+='</div>';
5623
+ }
5624
+ html+='</div>';
5605
5625
  if(filtered.length>0){
5606
5626
  html+='<div class="recall-layer filtered" onclick="this.classList.toggle(\\\'expanded\\\')">';
5607
5627
  html+='<div class="recall-layer-title"><span class="recall-expand-icon">\u25B6</span>\u2705 '+t('logs.recall.filtered')+' <span class="recall-count">'+filtered.length+'</span></div>';
@@ -5667,6 +5687,7 @@ function buildLogSummary(lg){
5667
5687
  function buildRecallDetailHtml(rd){
5668
5688
  var html='<div class="recall-detail">';
5669
5689
  var cands=rd.candidates||[];
5690
+ var hubCands=rd.hubCandidates||[];
5670
5691
  var filtered=rd.filtered||[];
5671
5692
  if(cands.length>0){
5672
5693
  html+='<div class="recall-detail-section" onclick="this.classList.toggle(\\\'expanded\\\')">';
@@ -5684,6 +5705,23 @@ function buildRecallDetailHtml(rd){
5684
5705
  });
5685
5706
  html+='</div></div>';
5686
5707
  }
5708
+ html+='<div class="recall-detail-section hub-recall" onclick="this.classList.toggle(\\\'expanded\\\')">';
5709
+ html+='<div class="recall-detail-title"><span class="recall-expand-icon">\u25B6</span>\u{1F310} '+t('logs.recall.hubRemote')+' ('+hubCands.length+')</div>';
5710
+ if(hubCands.length>0){
5711
+ html+='<div class="recall-detail-items">';
5712
+ hubCands.forEach(function(c,i){
5713
+ var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
5714
+ var shortText=escapeHtml(c.summary||c.original_excerpt||'');
5715
+ var fullText=escapeHtml(c.original_excerpt||c.summary||'');
5716
+ var owner=c.ownerName?' ['+escapeHtml(c.ownerName)+']':'';
5717
+ html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
5718
+ 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>';
5719
+ html+='<div class="recall-summary-full">'+fullText+'</div>';
5720
+ html+='</div>';
5721
+ });
5722
+ html+='</div>';
5723
+ }
5724
+ html+='</div>';
5687
5725
  if(filtered.length>0){
5688
5726
  html+='<div class="recall-detail-section filtered" onclick="this.classList.toggle(\\\'expanded\\\')">';
5689
5727
  html+='<div class="recall-detail-title"><span class="recall-expand-icon">\u25B6</span>\u2705 '+t('logs.recall.filtered')+' ('+filtered.length+')</div>';
@@ -5699,7 +5737,7 @@ function buildRecallDetailHtml(rd){
5699
5737
  html+='</div>';
5700
5738
  });
5701
5739
  html+='</div></div>';
5702
- }else if(cands.length>0){
5740
+ }else if(cands.length>0||hubCands.length>0){
5703
5741
  html+='<div style="font-size:10px;color:var(--text-muted);margin-top:4px">\u26A0 '+t('logs.recall.noneRelevant')+'</div>';
5704
5742
  }
5705
5743
  if(rd.status==='error'&&rd.error){