stratagate-dsh 0.2.21 → 0.2.25
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/CHANGELOG.md +24 -0
- package/README.md +14 -11
- package/dist/client.js +232 -53
- package/dist/index.js +954 -142
- package/dist/index.js.map +1 -1
- package/docs/README.zh-CN.md +14 -11
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -35,7 +35,7 @@ window.__ModuleLoader__.load({
|
|
|
35
35
|
--sg-warn-soft:var(--dsw-alias-state-warn-tertiary,#fef5e7);
|
|
36
36
|
--sg-danger:var(--dsw-alias-state-error-primary,#ec1313);
|
|
37
37
|
--sg-danger-soft:var(--dsw-alias-interactive-bg-hover-danger,rgba(236,19,19,.05));
|
|
38
|
-
box-sizing:border-box;width:100%;max-width:
|
|
38
|
+
box-sizing:border-box;width:100%;max-width:1200px;min-width:0;margin:0 auto;padding:16px 18px 32px;
|
|
39
39
|
background:var(--sg-page);color:var(--sg-text);font:14px/1.55 ui-sans-serif,system-ui,-apple-system,"Segoe UI","Microsoft YaHei",sans-serif;
|
|
40
40
|
letter-spacing:0;overflow-wrap:anywhere;
|
|
41
41
|
}
|
|
@@ -57,6 +57,15 @@ window.__ModuleLoader__.load({
|
|
|
57
57
|
.sg-block-list{position:relative;border:1px solid var(--sg-border);border-radius:9px;background:color-mix(in srgb,var(--sg-surface) 52%,transparent)}.sg-block-header,.sg-block-toggle{display:grid;grid-template-columns:88px 98px minmax(128px,1fr) 116px 24px;align-items:center;gap:8px;width:100%;min-width:0}.sg-block-header{padding:8px 12px;border-bottom:1px solid var(--sg-border);color:var(--sg-muted);font-size:11px}.sg-block-unit+.sg-block-unit{border-top:1px solid var(--sg-border)}.sg-block-toggle{padding:9px 12px;border:0;background:transparent;text-align:left;cursor:pointer}.sg-block-toggle:hover{background:color-mix(in srgb,var(--sg-accent) 5%,transparent)}.sg-level-cell{display:flex;align-items:center;gap:6px;min-width:0}.sg-level-badge{display:inline-grid;place-items:center;min-width:38px;height:25px;padding:0 8px;border:1px solid color-mix(in srgb,var(--sg-accent) 42%,var(--sg-border));border-radius:5px;font-weight:720}.sg-lifted{padding:1px 5px;border:1px solid var(--sg-border);border-radius:999px;color:var(--sg-muted);font-size:10px;white-space:nowrap}.sg-block-name{font-weight:670}.sg-block-distance,.sg-block-turn{color:var(--sg-muted);font-size:12px}.sg-row-chevron{color:var(--sg-muted);font-size:17px;text-align:right}.sg-open-row{cursor:default}.sg-open-row:hover{background:transparent}.sg-open-badge{display:inline-flex;align-items:center;height:25px;padding:0 8px;border:1px dashed var(--sg-muted);border-radius:5px;white-space:nowrap}.sg-block-expanded{padding:0 10px 11px}.sg-layer-panel{padding:10px;border:1px solid var(--sg-border);border-radius:8px;background:color-mix(in srgb,var(--sg-page) 82%,var(--sg-surface))}.sg-layer-heading{display:flex;justify-content:space-between;gap:10px;margin-bottom:8px}.sg-layer-heading strong{font-size:13px}.sg-layer-heading span{color:var(--sg-muted);font-size:11px}.sg-layer-stack{display:flex;flex-direction:column;gap:5px}.sg-layer-hover{position:relative}.sg-layer-hover:after{content:"";position:absolute;left:100%;top:0;width:12px;height:100%}.sg-layer-item{position:relative;display:grid;grid-template-columns:39px minmax(0,1fr) 30px;align-items:stretch;min-height:39px;border:1px solid var(--sg-border);border-radius:6px;background:color-mix(in srgb,var(--sg-soft) 55%,transparent);color:var(--sg-muted)}.sg-layer-item.current{border-color:color-mix(in srgb,var(--sg-accent) 72%,var(--sg-border));color:var(--sg-text);box-shadow:inset 2px 0 0 var(--sg-accent)}.sg-layer-label{display:grid;place-items:center;border-right:1px solid var(--sg-border);font-weight:720;color:inherit}.sg-layer-preview{padding:8px 10px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:12px}.sg-layer-more{width:30px;border:0;border-left:1px solid transparent;border-radius:0 6px 6px 0;background:transparent;color:inherit;cursor:pointer;font-weight:800;letter-spacing:1px}.sg-layer-more:hover,.sg-layer-more[aria-expanded="true"]{background:color-mix(in srgb,var(--sg-accent) 14%,transparent)}.sg-layer-menu{position:absolute;right:3px;top:34px;z-index:14;min-width:132px;padding:4px;border:1px solid var(--sg-border);border-radius:7px;background:var(--sg-surface);box-shadow:0 8px 24px rgba(0,0,0,.24)}.sg-layer-menu button{width:100%;padding:7px 9px;border:0;border-radius:5px;background:transparent;text-align:left;cursor:pointer;white-space:nowrap}.sg-layer-menu button:hover:not(:disabled){background:var(--sg-soft);color:var(--sg-accent)}.sg-layer-menu button:disabled{cursor:not-allowed;opacity:.45}.sg-layer-popover{position:absolute;left:calc(100% + 11px);top:-7px;z-index:12;width:min(360px,46vw);max-height:340px;padding:12px;overflow:auto;border:1px solid color-mix(in srgb,var(--sg-accent) 32%,var(--sg-border));border-radius:9px;background:var(--sg-surface);box-shadow:0 14px 36px rgba(0,0,0,.28);visibility:hidden;opacity:0;transform:translateX(-4px);transition:opacity .12s ease,transform .12s ease,visibility .12s}.sg-layer-hover:hover .sg-layer-popover,.sg-layer-item:focus-visible + .sg-layer-popover{visibility:visible;opacity:1;transform:translateX(0)}.sg-layer-popover strong{display:block;margin-bottom:7px}.sg-layer-full{margin:0;white-space:pre-wrap;font:12px/1.55 ui-sans-serif,system-ui,-apple-system,"Segoe UI","Microsoft YaHei",sans-serif}.sg-inline-error{padding:7px 9px;margin-bottom:7px;border-radius:6px;background:var(--sg-danger-soft);color:var(--sg-danger);font-size:12px}
|
|
58
58
|
.sg-loading{padding:32px 0}.sg-skeleton{height:12px;margin:10px 0;border-radius:4px;background:var(--sg-soft)}.sg-skeleton:nth-child(2){width:72%}.sg-empty{padding:34px 14px;text-align:center;color:var(--sg-muted)}.sg-empty strong{display:block;margin-bottom:5px;color:var(--sg-text)}.sg-error{padding:13px;margin-bottom:16px;border:1px solid color-mix(in srgb,var(--sg-danger) 28%,var(--sg-border));border-radius:8px;background:var(--sg-danger-soft)}.sg-error-title{font-weight:700;color:var(--sg-danger)}.sg-error details{margin-top:7px;font-size:12px}
|
|
59
59
|
.sg-muted{color:var(--sg-muted);font-size:12px}
|
|
60
|
+
.sg-long-tabs{display:flex;gap:4px;width:max-content;margin:0 0 14px;padding:4px;border:1px solid var(--sg-border);border-radius:999px;background:color-mix(in srgb,var(--sg-surface) 62%,transparent)}.sg-long-tabs button{padding:7px 19px;border:0;border-radius:999px;background:transparent;color:var(--sg-muted);cursor:pointer}.sg-long-tabs button.active{background:var(--sg-soft);color:var(--sg-accent)}
|
|
61
|
+
.sg-migration{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:9px;margin:0 0 10px;padding:9px 12px;border:1px solid color-mix(in srgb,var(--sg-accent) 28%,var(--sg-border));border-radius:8px;background:color-mix(in srgb,var(--sg-accent) 7%,transparent);font-size:12px}.sg-migration small{color:var(--sg-muted)}
|
|
62
|
+
.sg-long-explorer{position:relative}.sg-long-explorer.fullscreen{position:fixed;inset:12px;z-index:2147482000;display:flex;flex-direction:column;max-width:none;padding:18px;border:1px solid var(--sg-border);border-radius:12px;background:var(--sg-page);box-shadow:0 24px 80px rgba(0,0,0,.48)}.sg-long-explorer.fullscreen .sg-long-layout{flex:1;height:auto;min-height:0}.sg-long-explorer.fullscreen .sg-long-tabs{flex:0 0 auto}.sg-long-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:8px}.sg-long-toolbar .sg-search{flex:1;margin:0}.sg-toolbar-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:39px;padding:0 13px;border:1px solid var(--sg-border);border-radius:7px;background:var(--sg-surface);color:var(--sg-text);cursor:pointer;white-space:nowrap}.sg-toolbar-button:hover,.sg-toolbar-button[aria-expanded="true"]{border-color:var(--sg-accent);color:var(--sg-accent)}.sg-toolbar-count{color:var(--sg-muted);font-size:11px;white-space:nowrap}.sg-long-layout{display:grid;grid-template-columns:minmax(0,1.72fr) minmax(280px,.9fr);height:min(680px,calc(100vh - 320px));min-height:480px;border:1px solid var(--sg-border);border-radius:9px;overflow:hidden;background:color-mix(in srgb,var(--sg-page) 74%,transparent)}.sg-summary-layout{grid-template-columns:minmax(0,1fr)}
|
|
63
|
+
.sg-filterbar{display:flex;gap:7px;margin:0 0 8px;padding:8px;border:1px solid var(--sg-border);border-radius:7px;background:color-mix(in srgb,var(--sg-surface) 62%,transparent);flex-wrap:wrap}.sg-filterbar select{min-width:112px;padding:6px 25px 6px 8px;border:1px solid var(--sg-border);border-radius:6px;background:var(--sg-surface);color:var(--sg-text);font-size:11px}.sg-active-filter-count{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--sg-accent);color:white;font-size:10px}
|
|
64
|
+
.sg-graph-canvas{position:relative;min-width:0;overflow:hidden;background-image:radial-gradient(circle at center,color-mix(in srgb,var(--sg-accent) 6%,transparent),transparent 62%)}.sg-graph-canvas svg{display:block;width:100%;height:calc(100% - 38px)}.sg-graph-edge{stroke:color-mix(in srgb,var(--sg-muted) 58%,transparent);stroke-width:1.25}.sg-edge-label{fill:var(--sg-text);paint-order:stroke;stroke:var(--sg-page);stroke-width:4px;font-size:11px}.sg-graph-node{cursor:pointer;outline:none}.sg-graph-node:hover circle,.sg-graph-node.selected circle{filter:drop-shadow(0 0 9px rgba(86,145,255,.35))}.sg-node-name{fill:var(--sg-text);font-size:13px;font-weight:720;pointer-events:none}.sg-node-type{fill:color-mix(in srgb,var(--sg-text) 70%,transparent);font-size:10px;pointer-events:none}.sg-graph-legend{position:absolute;left:14px;bottom:10px;display:flex;gap:14px;flex-wrap:wrap;color:var(--sg-muted);font-size:11px}.sg-graph-legend span{display:flex;align-items:center;gap:5px}.sg-graph-legend i{width:9px;height:9px;border-radius:50%}.sg-node-bubble{position:absolute;z-index:8;width:min(310px,42%);padding:12px;border:1px solid color-mix(in srgb,var(--sg-accent) 38%,var(--sg-border));border-radius:9px;background:color-mix(in srgb,var(--sg-surface) 94%,transparent);box-shadow:0 14px 34px rgba(0,0,0,.3);transform:translate(35px,-50%)}.sg-node-bubble.flip{transform:translate(calc(-100% - 35px),-50%)}.sg-node-bubble h3{margin:0;font-size:14px}.sg-node-bubble-head,.sg-node-bubble-foot{display:flex;align-items:center;justify-content:space-between;gap:8px}.sg-node-bubble-state{margin:7px 0;color:var(--sg-muted);font-size:11px}.sg-node-bubble ul{margin:7px 0;padding-left:17px;font-size:11px;line-height:1.55}.sg-node-bubble-foot{padding-top:8px;border-top:1px solid var(--sg-border);color:var(--sg-muted);font-size:11px}.sg-node-bubble button{border:0;background:transparent;color:var(--sg-accent);cursor:pointer;font-weight:680}
|
|
65
|
+
.sg-long-detail{min-width:0;padding:16px;overflow:auto;border-left:1px solid var(--sg-border);background:color-mix(in srgb,var(--sg-surface) 70%,transparent)}.sg-placeholder-detail{display:grid;place-items:center;color:var(--sg-muted);text-align:center}.sg-long-detail h2{margin:0;font-size:17px}.sg-long-detail section{padding:13px 0;border-top:1px solid var(--sg-border)}.sg-long-detail section:first-of-type{margin-top:13px}.sg-long-detail h3{margin:0 0 8px;font-size:13px}.sg-long-detail ul{margin:0;padding-left:18px;font-size:12px;line-height:1.65}.sg-detail-copy{margin:0;color:var(--sg-muted);font-size:12px;line-height:1.65;white-space:pre-wrap}.sg-node-head{display:flex;align-items:center;gap:10px}.sg-node-avatar{display:grid;place-items:center;width:42px;height:42px;border-radius:50%;color:white;font-size:20px}.sg-status-dot{color:var(--sg-good);font-size:12px}.sg-relation-row{display:grid;grid-template-columns:68px 1fr auto;gap:7px;padding:7px 0;border-bottom:1px solid color-mix(in srgb,var(--sg-border) 65%,transparent);font-size:12px}.sg-relation-row span,.sg-relation-row small{color:var(--sg-muted)}.sg-support-event{display:flex;align-items:center;justify-content:space-between;width:100%;margin:5px 0;padding:9px;border:1px solid var(--sg-border);border-radius:7px;background:transparent;color:var(--sg-text);text-align:left;cursor:pointer}.sg-support-event:hover{border-color:var(--sg-accent)}
|
|
66
|
+
.sg-timeline-layout{grid-template-columns:minmax(420px,1.35fr) minmax(320px,.9fr)}.sg-timeline{position:relative;padding:10px 20px 18px;overflow:auto}.sg-time-group{position:relative}.sg-time-group>h3{margin:7px 0 8px;padding-left:17px;font-size:13px}.sg-time-group:before{content:"";position:absolute;left:5px;top:30px;bottom:-12px;width:1px;background:var(--sg-border)}.sg-timeline-card{position:relative;display:grid;grid-template-columns:112px minmax(0,1fr) auto;gap:12px;width:100%;margin:0 0 8px;padding:12px 14px;border:1px solid var(--sg-border);border-radius:8px;background:color-mix(in srgb,var(--sg-surface) 62%,transparent);color:var(--sg-text);text-align:left;cursor:pointer}.sg-timeline-card:hover,.sg-timeline-card.selected{border-color:var(--sg-accent);background:color-mix(in srgb,var(--sg-accent) 7%,var(--sg-surface))}.sg-timeline-dot{position:absolute;left:-19px;top:17px;width:9px;height:9px;border:2px solid var(--sg-accent);border-radius:50%;background:var(--sg-page)}.sg-event-clock{font-size:11px;white-space:normal}.sg-event-clock small{display:block;margin-top:3px;color:var(--sg-muted);line-height:1.35}.sg-event-title-row{display:flex;align-items:center;gap:7px;min-width:0}.sg-event-title-row strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sg-event-main p{margin:5px 0 7px;color:var(--sg-muted);font-size:12px;line-height:1.4;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.sg-type-badge{display:inline-flex;align-items:center;width:max-content;padding:2px 7px;border:1px solid color-mix(in srgb,var(--sg-accent) 30%,var(--sg-border));border-radius:5px;background:color-mix(in srgb,var(--sg-accent) 10%,transparent);color:var(--sg-accent);font-size:10px}.sg-event-status{display:inline-flex;width:max-content;height:max-content;padding:3px 8px;border:1px solid var(--sg-border);border-radius:999px;color:var(--sg-muted);font-size:10px;white-space:nowrap}.sg-event-status.occurred{border-color:color-mix(in srgb,var(--sg-good) 40%,var(--sg-border));background:var(--sg-good-soft);color:var(--sg-good)}.sg-event-status.planned,.sg-event-status.ongoing{border-color:color-mix(in srgb,var(--sg-accent) 35%,var(--sg-border));color:var(--sg-accent)}.sg-event-status.cancelled{color:var(--sg-danger)}.sg-event-detail-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:7px}.sg-event-popover{position:fixed;z-index:2147483000;width:min(380px,calc(100vw - 24px));max-height:min(72vh,620px);overflow:auto;border:1px solid color-mix(in srgb,var(--sg-accent) 38%,var(--sg-border));border-radius:10px;background:var(--sg-page);box-shadow:0 18px 50px rgba(0,0,0,.38)}.sg-event-popover .sg-long-detail{border:0;background:transparent}.sg-popover-close{position:absolute;right:8px;top:8px;z-index:2;width:27px;height:27px;border:0;border-radius:6px;background:var(--sg-soft);cursor:pointer}.sg-time-grid{display:grid;grid-template-columns:92px 1fr;margin:0;border:1px solid var(--sg-border);border-radius:7px;overflow:hidden;font-size:11px}.sg-time-grid dt,.sg-time-grid dd{margin:0;padding:7px 8px;border-bottom:1px solid var(--sg-border)}.sg-time-grid dt{color:var(--sg-muted);background:var(--sg-soft)}.sg-time-grid dt:nth-last-of-type(1),.sg-time-grid dd:nth-last-of-type(1){border-bottom:0}.sg-entity-pill{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;border:1px solid var(--sg-border);border-radius:999px;background:transparent;color:var(--sg-text);font-size:11px;cursor:pointer}.sg-evidence-row{display:flex;justify-content:space-between;gap:8px;padding:6px 0;color:var(--sg-muted);font-size:11px}.sg-evidence-row code{max-width:180px;overflow:hidden;text-overflow:ellipsis}.sg-source-button{width:100%;padding:9px;border:1px solid color-mix(in srgb,var(--sg-accent) 42%,var(--sg-border));border-radius:7px;background:transparent;color:var(--sg-accent);cursor:pointer}
|
|
67
|
+
@media (max-width:900px){.sg-long-layout{grid-template-columns:1fr;height:auto;max-height:none}.sg-long-explorer.fullscreen{inset:4px;padding:10px}.sg-long-explorer.fullscreen .sg-long-layout{overflow:auto}.sg-graph-canvas{height:520px}.sg-long-detail{max-height:520px;border-top:1px solid var(--sg-border);border-left:0}.sg-timeline{max-height:520px}.sg-toolbar-count{display:none}.sg-node-bubble{width:min(300px,72%)}}
|
|
68
|
+
@media (max-width:620px){.sg-long-toolbar{flex-wrap:wrap}.sg-long-toolbar .sg-search{flex-basis:100%}.sg-toolbar-button{flex:1}.sg-timeline-card{grid-template-columns:78px minmax(0,1fr)}.sg-timeline-card>.sg-event-status{grid-column:2}.sg-node-bubble{left:50%!important;top:auto!important;bottom:45px;width:calc(100% - 24px);transform:translateX(-50%)!important}}
|
|
60
69
|
@media (max-width:860px){.sg-layer-hover:after{display:none}.sg-layer-popover{position:relative;left:auto;top:auto;width:auto;max-height:280px;margin:5px 0 1px;display:none;transform:none}.sg-layer-hover:hover .sg-layer-popover,.sg-layer-item:focus-visible + .sg-layer-popover{display:block;transform:none}}
|
|
61
70
|
@media (max-width:560px){.sg-memory{padding:12px 12px 26px}.sg-brand-name{font-size:14px}.sg-tabs{margin-left:-2px;margin-right:-2px}.sg-tab{padding-left:0;padding-right:0}.sg-alert{grid-template-columns:auto minmax(0,1fr)}.sg-alert>.sg-chevron{display:none}.sg-tech-row{grid-template-columns:1fr;gap:1px}.sg-counts{gap:16px}.sg-entry-title{font-size:14px}.sg-block-header{display:none}.sg-block-toggle{grid-template-columns:76px minmax(76px,1fr) 24px;gap:6px}.sg-block-turn{grid-column:1/3}.sg-block-distance{display:none}.sg-layer-heading{display:block}.sg-layer-heading span{display:block;margin-top:2px}}
|
|
62
71
|
.sg-decay-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.sg-conversation{display:flex;align-items:center;justify-content:flex-end;gap:5px;min-width:0;color:var(--sg-muted);font-size:11px}.sg-conversation select{min-width:0;max-width:230px;padding:3px 21px 3px 6px;border:1px solid var(--sg-border);border-radius:5px;background:var(--sg-surface);font-size:11px;text-overflow:ellipsis}.sg-distribution{scrollbar-width:none}.sg-distribution::-webkit-scrollbar{display:none}.sg-distribution-rail{display:block;width:100%;height:14px;margin:4px 0 0;accent-color:var(--sg-accent);cursor:pointer}.sg-distribution-rail:disabled{cursor:default;opacity:.38}.sg-layer-hover:after{display:none}.sg-layer-more-placeholder{width:30px}.sg-layer-popover{position:fixed!important;left:0;top:0;z-index:2147483000;width:min(390px,calc(100vw - 24px));max-height:min(70vh,520px);display:block!important;margin:0;overflow:auto;visibility:visible!important;opacity:1!important;transform:none!important;transition:opacity .1s ease;border:1px solid color-mix(in srgb,var(--sg-accent) 38%,var(--sg-border));background:var(--sg-surface);color:var(--sg-text);box-shadow:0 18px 50px rgba(0,0,0,.38)}
|
|
@@ -156,36 +165,208 @@ window.__ModuleLoader__.load({
|
|
|
156
165
|
h('span', { className: 'sg-processing-icon', 'aria-hidden': 'true' }, '↻'),
|
|
157
166
|
h('span', null,
|
|
158
167
|
h('span', { className: 'sg-processing-title' }, '正在触发记忆整理'),
|
|
159
|
-
h('span', { className: 'sg-processing-copy' }, 'Block、Event
|
|
168
|
+
h('span', { className: 'sg-processing-copy' }, 'Block、Event 和知识图谱正在生成,请稍候。')))
|
|
160
169
|
}
|
|
161
170
|
|
|
162
171
|
function SearchBox({ value, onChange }) {
|
|
163
172
|
return h('div', { className: 'sg-search' }, h('span', { className: 'sg-search-mark', 'aria-hidden': 'true' }, '⌕'), h('input', { value, onChange: (event) => onChange(event.target.value), placeholder: '搜索记忆、人物、项目、概念…', 'aria-label': '搜索长期记忆' }))
|
|
164
173
|
}
|
|
165
174
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
const NODE_META = {
|
|
176
|
+
person: ['人物', '#8b6ccf', '♙'], project: ['项目', '#6f55ae', '▣'], organization: ['组织', '#3978cf', '⌘'],
|
|
177
|
+
tool: ['工具', '#3b854d', '▤'], place: ['地点', '#a9632b', '⌂'],
|
|
169
178
|
}
|
|
179
|
+
const EVENT_TYPE_TEXT = { decision: '决策', release: '发布', task_completed: '任务完成', plan: '计划', change: '变更', cancellation: '取消', incident: '事件', meeting: '会议', collaboration: '协作', migration: '迁移', other: '其他' }
|
|
180
|
+
const EVENT_STATUS_TEXT = { occurred: '已发生', planned: '计划中', cancelled: '已取消', ongoing: '进行中', unknown: '未知' }
|
|
181
|
+
const EVENT_RELATIONS = [['supersedesEventIds', '取代'], ['conflictsWithEventIds', '冲突'], ['sameEventId', '同一事件'], ['beforeEventIds', '之前'], ['afterEventIds', '之后'], ['relatedEventIds', '相关']]
|
|
170
182
|
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
function exactTime(value) {
|
|
184
|
+
if (!value) return '未知'
|
|
185
|
+
const date = new Date(value)
|
|
186
|
+
return Number.isNaN(date.getTime()) ? String(value) : new Intl.DateTimeFormat('zh-CN', { timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false }).format(date)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function eventOccurrence(event) {
|
|
190
|
+
const happened = event.temporal?.happenedStart || event.temporal?.happenedEnd
|
|
191
|
+
return { value: happened || event.temporal?.mentionedAt || event.createdAt, known: Boolean(happened) }
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function NodePill({ node, onClick }) {
|
|
195
|
+
const meta = NODE_META[node.type] || ['实体', '#64748b', '•']
|
|
196
|
+
return h('button', { className: 'sg-entity-pill', onClick }, h('span', { style: { color: meta[1] } }, meta[2]), node.name)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function NodeSummaryBubble({ node, x, y, width, onViewDetails }) {
|
|
200
|
+
if (!node) return null
|
|
201
|
+
const facts = (node.facts || []).filter((fact) => fact.status === 'active').slice(0, 5)
|
|
202
|
+
const eventCount = new Set(node.sourceEventIds || []).size
|
|
203
|
+
return h('aside', { className: 'sg-node-bubble ' + (x > width * .62 ? 'flip' : ''), style: { left: (x / width * 100) + '%', top: (y / 560 * 100) + '%' } },
|
|
204
|
+
h('div', { className: 'sg-node-bubble-head' }, h('h3', null, node.name), h('span', { className: 'sg-status-dot' }, '● ' + (node.status === 'active' ? '活跃' : node.status || '未知'))),
|
|
205
|
+
h('p', { className: 'sg-node-bubble-state' }, node.currentState || '暂无当前状态'),
|
|
206
|
+
facts.length ? h('ul', null, facts.map((fact) => h('li', { key: fact.id }, h('strong', null, fact.key + ':'), Array.isArray(fact.value) ? fact.value.join('、') : fact.value))) : h('p', { className: 'sg-node-bubble-state' }, '暂无关键事实'),
|
|
207
|
+
h('div', { className: 'sg-node-bubble-foot' }, h('span', null, eventCount + ' 条相关事件'), h('button', { type: 'button', onClick: onViewDetails }, '查看详情 →')))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function GraphCanvas({ nodes, edges, selectedId, onSelect, showSummary = false, onViewDetails }) {
|
|
211
|
+
if (!nodes.length) return h(Empty, { title: '知识图谱正在形成', copy: 'Event 会在后台分批投影为节点与关系。' })
|
|
212
|
+
const width = 760; const height = 560; const cx = width / 2; const cy = height / 2
|
|
213
|
+
const placed = nodes.slice(0, 40).map((node, index) => {
|
|
214
|
+
if (index === 0) return { node, x: cx, y: cy }
|
|
215
|
+
const ring = index <= 10 ? 1 : 2; const slot = ring === 1 ? index - 1 : index - 11
|
|
216
|
+
const count = ring === 1 ? Math.min(10, Math.max(1, nodes.length - 1)) : Math.max(1, Math.min(29, nodes.length - 11))
|
|
217
|
+
const angle = -Math.PI / 2 + slot * Math.PI * 2 / count
|
|
218
|
+
const radiusX = ring === 1 ? 205 : 320; const radiusY = ring === 1 ? 170 : 245
|
|
219
|
+
return { node, x: cx + Math.cos(angle) * radiusX, y: cy + Math.sin(angle) * radiusY }
|
|
220
|
+
})
|
|
221
|
+
const positions = new Map(placed.map((item) => [item.node.id, item]))
|
|
222
|
+
return h('div', { className: 'sg-graph-canvas' },
|
|
223
|
+
h('svg', { viewBox: `0 0 ${width} ${height}`, role: 'img', 'aria-label': '知识图谱' },
|
|
224
|
+
h('defs', null, h('marker', { id: 'sg-arrow', markerWidth: '8', markerHeight: '8', refX: '7', refY: '4', orient: 'auto' }, h('path', { d: 'M0,0 L8,4 L0,8 Z', fill: 'var(--sg-muted)' }))),
|
|
225
|
+
edges.filter((edge) => edge.status === 'active').map((edge) => {
|
|
226
|
+
const from = positions.get(edge.fromNodeId); const to = positions.get(edge.toNodeId)
|
|
227
|
+
if (!from || !to) return null
|
|
228
|
+
const mx = (from.x + to.x) / 2; const my = (from.y + to.y) / 2
|
|
229
|
+
return h('g', { key: edge.id }, h('line', { x1: from.x, y1: from.y, x2: to.x, y2: to.y, className: 'sg-graph-edge', markerEnd: 'url(#sg-arrow)' }), h('text', { x: mx, y: my - 5, className: 'sg-edge-label' }, edge.relation))
|
|
230
|
+
}),
|
|
231
|
+
placed.map(({ node, x, y }) => {
|
|
232
|
+
const meta = NODE_META[node.type] || ['实体', '#64748b', '•']; const selected = node.id === selectedId
|
|
233
|
+
return h('g', { key: node.id, className: 'sg-graph-node ' + (selected ? 'selected' : ''), onClick: () => onSelect(node.id), onKeyDown: (event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); onSelect(node.id) } }, role: 'button', tabIndex: 0, 'aria-label': node.name + ',' + meta[0] },
|
|
234
|
+
h('circle', { cx: x, cy: y, r: selected ? 47 : 42, fill: meta[1], fillOpacity: '.28', stroke: meta[1], strokeWidth: selected ? '3' : '1.5' }),
|
|
235
|
+
h('text', { x, y: y - 7, textAnchor: 'middle', className: 'sg-node-name' }, node.name.slice(0, 14)),
|
|
236
|
+
h('text', { x, y: y + 14, textAnchor: 'middle', className: 'sg-node-type' }, meta[0]))
|
|
237
|
+
})),
|
|
238
|
+
showSummary && selectedId ? (() => { const item = positions.get(selectedId); return item ? h(NodeSummaryBubble, { node: item.node, x: item.x, y: item.y, width, onViewDetails }) : null })() : null,
|
|
239
|
+
h('div', { className: 'sg-graph-legend' }, Object.entries(NODE_META).map(([type, meta]) => h('span', { key: type }, h('i', { style: { background: meta[1] } }), meta[0]))))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function NodeDetailPanel({ node, nodes, edges, events, onEvent }) {
|
|
243
|
+
if (!node) return h('aside', { className: 'sg-long-detail sg-placeholder-detail' }, '选择节点查看当前状态与证据')
|
|
244
|
+
const meta = NODE_META[node.type] || ['实体', '#64748b', '•']
|
|
245
|
+
const relations = edges.filter((edge) => edge.status === 'active' && (edge.fromNodeId === node.id || edge.toNodeId === node.id))
|
|
246
|
+
const eventMap = new Map(events.map((event) => [event.id, event]))
|
|
247
|
+
return h('aside', { className: 'sg-long-detail' },
|
|
248
|
+
h('div', { className: 'sg-node-head' }, h('span', { className: 'sg-node-avatar', style: { background: meta[1] } }, meta[2]), h('div', null, h('h2', null, node.name), h('span', { className: 'sg-muted' }, meta[0]))),
|
|
249
|
+
h('section', null, h('h3', null, '当前状态'), h('span', { className: 'sg-status-dot' }, '● ' + (node.status === 'active' ? '活跃' : node.status)), node.currentState ? h('p', { className: 'sg-detail-copy' }, node.currentState) : null),
|
|
250
|
+
h('section', null, h('h3', null, '关键事实'), node.facts?.filter((fact) => fact.status === 'active').length ? h('ul', null, node.facts.filter((fact) => fact.status === 'active').map((fact) => h('li', { key: fact.id }, h('strong', null, fact.key + ':'), Array.isArray(fact.value) ? fact.value.join('、') : fact.value))) : h('p', { className: 'sg-muted' }, '暂无关键事实')),
|
|
251
|
+
h('section', null, h('h3', null, '相关关系'), relations.length ? relations.map((edge) => { const outgoing = edge.fromNodeId === node.id; const other = nodes.find((item) => item.id === (outgoing ? edge.toNodeId : edge.fromNodeId)); return h('div', { key: edge.id, className: 'sg-relation-row' }, h('span', null, outgoing ? edge.relation : '被' + edge.relation), h('strong', null, other?.name || '未知节点'), h('small', null, Math.round(edge.confidence * 100) + '%')) }) : h('p', { className: 'sg-muted' }, '暂无关系')),
|
|
252
|
+
h('section', null, h('h3', null, '支撑事件'), (node.sourceEventIds || []).flatMap((id) => eventMap.get(id) || []).slice(0, 8).map((event) => h('button', { key: event.id, className: 'sg-support-event', onClick: () => onEvent(event.id) }, h('span', null, exactTime(eventOccurrence(event).value) + ' · ' + event.title), h('b', null, '›')))))
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function EventDetailPanel({ event, nodes, events, onNode, openSource, className = '', onMouseEnter, onMouseLeave }) {
|
|
256
|
+
if (!event) return h('aside', { className: 'sg-long-detail sg-placeholder-detail' }, '选择事件查看完整时间、关系与证据')
|
|
257
|
+
const temporal = event.temporal || {}; const eventMap = new Map(events.map((item) => [item.id, item])); const nodeMap = new Map(nodes.map((node) => [node.id, node]))
|
|
258
|
+
const relations = EVENT_RELATIONS.flatMap(([key, label]) => { const value = temporal[key]; const ids = Array.isArray(value) ? value : value ? [value] : []; return ids.map((id) => ({ id, label })) })
|
|
259
|
+
return h('aside', { className: 'sg-long-detail ' + className, onMouseEnter, onMouseLeave },
|
|
260
|
+
h('div', { className: 'sg-event-detail-head' }, h('h2', null, event.title), h('span', { className: 'sg-event-status ' + (temporal.status || 'unknown') }, EVENT_STATUS_TEXT[temporal.status] || '未知')),
|
|
261
|
+
h('span', { className: 'sg-type-badge' }, EVENT_TYPE_TEXT[temporal.eventType] || temporal.eventType || '其他'),
|
|
262
|
+
h('section', null, h('h3', null, '摘要'), h('p', { className: 'sg-detail-copy' }, event.summary || '暂无摘要')),
|
|
263
|
+
event.narrative && event.narrative !== event.summary ? h('section', null, h('h3', null, '事件叙述'), h('p', { className: 'sg-detail-copy' }, event.narrative)) : null,
|
|
264
|
+
h('section', null, h('h3', null, '时间信息'), h('dl', { className: 'sg-time-grid' },
|
|
265
|
+
h('dt', null, '实际发生时间'), h('dd', null, temporal.happenedStart ? exactTime(temporal.happenedStart) + (temporal.happenedEnd && temporal.happenedEnd !== temporal.happenedStart ? ' — ' + exactTime(temporal.happenedEnd) : '') : '未知'),
|
|
266
|
+
h('dt', null, '提及时间'), h('dd', null, exactTime(temporal.mentionedAt || event.createdAt)),
|
|
267
|
+
h('dt', null, '时间精度'), h('dd', null, temporal.precision || 'unknown'),
|
|
268
|
+
h('dt', null, '原始表达'), h('dd', null, temporal.originalText || '未记录'))),
|
|
269
|
+
h('section', null, h('h3', null, '参与实体'), h('div', { className: 'sg-tags' }, (temporal.participantNodeIds || []).flatMap((id) => nodeMap.get(id) || []).map((node) => h(NodePill, { key: node.id, node, onClick: () => onNode(node.id) })), !(temporal.participantNodeIds || []).length ? (temporal.participants || []).map((name) => h('span', { key: name, className: 'sg-tag' }, name)) : null)),
|
|
270
|
+
relations.length ? h('section', null, h('h3', null, '事件关系'), relations.map((relation) => h('div', { key: relation.label + relation.id, className: 'sg-relation-row' }, h('span', null, relation.label), h('strong', null, eventMap.get(relation.id)?.title || relation.id)))) : null,
|
|
271
|
+
h('section', null, h('h3', null, '证据来源'), h('div', { className: 'sg-evidence-row' }, h('span', null, '来源 Block'), h('code', null, event.sourceBlockId)), h('div', { className: 'sg-evidence-row' }, h('span', null, '置信度'), h('strong', null, Math.round((event.confidence || 0) * 100) + '%'))),
|
|
272
|
+
h('button', { className: 'sg-source-button', onClick: () => openSource(event) }, '查看来源原始消息 →'))
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function TimelineList({ events, nodes, query, filters, onSelect, selectedId, floating = false, onNode, openSource }) {
|
|
276
|
+
const [preview, setPreview] = React.useState(null)
|
|
277
|
+
const pinnedId = React.useRef('')
|
|
278
|
+
const hideTimer = React.useRef(null)
|
|
279
|
+
const cancelHide = () => { if (hideTimer.current) window.clearTimeout(hideTimer.current); hideTimer.current = null }
|
|
280
|
+
const hidePreview = () => { cancelHide(); setPreview(null); pinnedId.current = '' }
|
|
281
|
+
const showPreview = (event, target, pin = false) => {
|
|
282
|
+
if (!floating || (!pin && pinnedId.current)) return
|
|
283
|
+
cancelHide()
|
|
284
|
+
const rect = target.getBoundingClientRect(); const width = Math.min(380, window.innerWidth - 24); const maxHeight = Math.min(620, window.innerHeight * .72)
|
|
285
|
+
const rightSide = rect.right + 12 + width <= window.innerWidth - 12
|
|
286
|
+
const left = rightSide ? rect.right + 12 : Math.max(12, rect.left - width - 12)
|
|
287
|
+
const top = Math.min(Math.max(12, rect.top - 8), Math.max(12, window.innerHeight - maxHeight - 12))
|
|
288
|
+
setPreview({ event, left, top })
|
|
289
|
+
if (pin) pinnedId.current = event.id
|
|
290
|
+
}
|
|
291
|
+
const scheduleHide = () => {
|
|
292
|
+
if (pinnedId.current) return
|
|
293
|
+
cancelHide()
|
|
294
|
+
hideTimer.current = window.setTimeout(() => setPreview(null), 140)
|
|
295
|
+
}
|
|
296
|
+
React.useEffect(() => () => cancelHide(), [])
|
|
297
|
+
const normalized = query.trim().toLocaleLowerCase(); const now = new Date(); const weekAgo = now.getTime() - 7 * 86400000
|
|
298
|
+
const groups = { '今天': [], '本周': [], '更早': [] }
|
|
299
|
+
events.filter((event) => event.status !== 'forgotten' && event.status !== 'archived')
|
|
300
|
+
.filter((event) => !normalized || JSON.stringify(event).toLocaleLowerCase().includes(normalized))
|
|
301
|
+
.filter((event) => !filters.type || event.temporal?.eventType === filters.type)
|
|
302
|
+
.filter((event) => !filters.status || event.temporal?.status === filters.status)
|
|
303
|
+
.filter((event) => !filters.node || (event.temporal?.participantNodeIds || []).includes(filters.node))
|
|
304
|
+
.filter((event) => { const info = eventOccurrence(event); const time = Date.parse(info.value); return !filters.time || (filters.time === 'unknown' ? !info.known : filters.time === 'today' ? Number.isFinite(time) && new Date(time).toDateString() === now.toDateString() : filters.time === 'week' ? time >= weekAgo : true) })
|
|
305
|
+
.sort((a, b) => String(eventOccurrence(b).value).localeCompare(String(eventOccurrence(a).value)))
|
|
306
|
+
.forEach((event) => { const info = eventOccurrence(event); const time = Date.parse(info.value); const sameDay = Number.isFinite(time) && new Date(time).toDateString() === now.toDateString(); groups[sameDay ? '今天' : time >= weekAgo ? '本周' : '更早'].push(event) })
|
|
307
|
+
const nodeMap = new Map(nodes.map((node) => [node.id, node]))
|
|
308
|
+
return h('div', { className: 'sg-timeline' }, Object.entries(groups).map(([label, items]) => items.length ? h('section', { key: label, className: 'sg-time-group' }, h('h3', null, label), items.map((event) => {
|
|
309
|
+
const info = eventOccurrence(event); const temporal = event.temporal || {}
|
|
310
|
+
return h('button', { key: event.id, className: 'sg-timeline-card ' + (event.id === selectedId ? 'selected' : ''), onMouseEnter: (hover) => showPreview(event, hover.currentTarget), onMouseLeave: scheduleHide, onFocus: (focus) => showPreview(event, focus.currentTarget), onBlur: scheduleHide, onClick: (click) => { onSelect(event.id); showPreview(event, click.currentTarget, true) } },
|
|
311
|
+
h('span', { className: 'sg-timeline-dot' }), h('div', { className: 'sg-event-clock' }, info.known ? exactTime(info.value).replace(/^\d{4}\//, '') : '发生时间未知', !info.known ? h('small', null, '提及于 ' + exactTime(info.value)) : null),
|
|
312
|
+
h('div', { className: 'sg-event-main' }, h('div', { className: 'sg-event-title-row' }, h('strong', null, event.title), h('span', { className: 'sg-type-badge' }, EVENT_TYPE_TEXT[temporal.eventType] || temporal.eventType || '其他')), h('p', null, event.summary || '暂无摘要'), h('div', { className: 'sg-tags' }, (temporal.participantNodeIds || []).flatMap((id) => nodeMap.get(id) || []).map((node) => h('span', { key: node.id, className: 'sg-tag' }, node.name)), !(temporal.participantNodeIds || []).length ? (temporal.participants || []).map((name) => h('span', { key: name, className: 'sg-tag' }, name)) : null)),
|
|
313
|
+
h('span', { className: 'sg-event-status ' + (temporal.status || 'unknown') }, EVENT_STATUS_TEXT[temporal.status] || '未知'))
|
|
314
|
+
})) : null), floating && preview ? h('div', { className: 'sg-event-popover', style: { left: preview.left + 'px', top: preview.top + 'px' }, onMouseEnter: cancelHide, onMouseLeave: scheduleHide },
|
|
315
|
+
h('button', { type: 'button', className: 'sg-popover-close', 'aria-label': '关闭事件详情', onClick: hidePreview }, '×'),
|
|
316
|
+
h(EventDetailPanel, { event: preview.event, nodes, events, onNode, openSource })) : null)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function LongTermPage({ events, graph, project, query, setQuery, openEvent }) {
|
|
320
|
+
const [mode, setMode] = React.useState('graph')
|
|
321
|
+
const [selectedNodeId, setSelectedNodeId] = React.useState('')
|
|
322
|
+
const [selectedEventId, setSelectedEventId] = React.useState('')
|
|
323
|
+
const [eventFilters, setEventFilters] = React.useState({ time: '', node: '', type: '', status: '' })
|
|
324
|
+
const [nodeType, setNodeType] = React.useState('')
|
|
325
|
+
const [filtersOpen, setFiltersOpen] = React.useState(false)
|
|
326
|
+
const [fullScreen, setFullScreen] = React.useState(false)
|
|
327
|
+
const nodes = graph.nodes || []; const edges = graph.edges || []; const normalized = query.trim().toLocaleLowerCase()
|
|
328
|
+
React.useEffect(() => {
|
|
329
|
+
if (!fullScreen) return undefined
|
|
330
|
+
const previous = document.body.style.overflow
|
|
331
|
+
document.body.style.overflow = 'hidden'
|
|
332
|
+
const onKeyDown = (event) => { if (event.key === 'Escape') { setFullScreen(false); setFiltersOpen(false) } }
|
|
333
|
+
window.addEventListener('keydown', onKeyDown)
|
|
334
|
+
return () => { document.body.style.overflow = previous; window.removeEventListener('keydown', onKeyDown) }
|
|
335
|
+
}, [fullScreen])
|
|
336
|
+
const visibleNodes = nodes.filter((node) => node.status !== 'archived').filter((node) => !nodeType || node.type === nodeType).filter((node) => !normalized || JSON.stringify(node).toLocaleLowerCase().includes(normalized))
|
|
337
|
+
const selectEvent = (id) => { setSelectedEventId(id); setMode('timeline') }
|
|
338
|
+
const selectNode = (id) => { setSelectedNodeId(id); setMode('graph') }
|
|
339
|
+
const openExplorer = () => {
|
|
340
|
+
if (mode === 'graph' && !selectedNodeId && visibleNodes[0]) setSelectedNodeId(visibleNodes[0].id)
|
|
341
|
+
if (mode === 'timeline' && !selectedEventId && events[0]) setSelectedEventId(events[0].id)
|
|
342
|
+
setFiltersOpen(true)
|
|
343
|
+
setFullScreen(true)
|
|
344
|
+
}
|
|
345
|
+
const migration = graph.migration || { projected: events.length, total: events.length, complete: true }
|
|
346
|
+
const activeFilterCount = mode === 'graph' ? Number(Boolean(nodeType)) : Object.values(eventFilters).filter(Boolean).length
|
|
347
|
+
const filterControls = mode === 'graph'
|
|
348
|
+
? h('div', { className: 'sg-filterbar' }, h('select', { value: nodeType, onChange: (event) => setNodeType(event.target.value), 'aria-label': '节点类型' }, h('option', { value: '' }, '全部节点类型'), Object.entries(NODE_META).map(([value, meta]) => h('option', { key: value, value }, meta[0]))))
|
|
349
|
+
: h('div', { className: 'sg-filterbar' },
|
|
350
|
+
h('select', { value: eventFilters.time, onChange: (event) => setEventFilters({ ...eventFilters, time: event.target.value }), 'aria-label': '时间范围' }, h('option', { value: '' }, '全部时间'), h('option', { value: 'today' }, '今天'), h('option', { value: 'week' }, '本周'), h('option', { value: 'unknown' }, '发生时间未知')),
|
|
351
|
+
h('select', { value: eventFilters.node, onChange: (event) => setEventFilters({ ...eventFilters, node: event.target.value }), 'aria-label': '参与实体' }, h('option', { value: '' }, '全部实体'), nodes.map((node) => h('option', { key: node.id, value: node.id }, node.name))),
|
|
352
|
+
h('select', { value: eventFilters.type, onChange: (event) => setEventFilters({ ...eventFilters, type: event.target.value }), 'aria-label': '事件类型' }, h('option', { value: '' }, '全部类型'), Object.entries(EVENT_TYPE_TEXT).map(([value, label]) => h('option', { key: value, value }, label))),
|
|
353
|
+
h('select', { value: eventFilters.status, onChange: (event) => setEventFilters({ ...eventFilters, status: event.target.value }), 'aria-label': '事件状态' }, h('option', { value: '' }, '全部状态'), Object.entries(EVENT_STATUS_TEXT).map(([value, label]) => h('option', { key: value, value }, label))))
|
|
354
|
+
return h('section', { className: 'sg-long-explorer ' + (fullScreen ? 'fullscreen' : ''), 'aria-label': fullScreen ? '长期记忆全屏探索' : '长期记忆浏览' },
|
|
355
|
+
h('nav', { className: 'sg-long-tabs' }, h('button', { className: mode === 'graph' ? 'active' : '', onClick: () => setMode('graph') }, '知识图谱'), h('button', { className: mode === 'timeline' ? 'active' : '', onClick: () => setMode('timeline') }, '事件时间线')),
|
|
356
|
+
!migration.complete ? h('div', { className: 'sg-migration', role: 'status' }, h('span', { className: 'sg-processing-icon' }, '↻'), h('span', null, '正在升级长期记忆 · ' + migration.projected + ' / ' + migration.total + ' Events'), h('small', null, migration.failed ? migration.failed + ' 批待重试' : '后台增量处理,不影响其他功能')) : null,
|
|
357
|
+
h('div', { className: 'sg-long-toolbar' },
|
|
358
|
+
h(SearchBox, { value: query, onChange: setQuery }),
|
|
359
|
+
h('button', { type: 'button', className: 'sg-toolbar-button', 'aria-expanded': filtersOpen ? 'true' : 'false', onClick: () => setFiltersOpen(!filtersOpen) }, '筛选 ▾', activeFilterCount ? h('span', { className: 'sg-active-filter-count' }, activeFilterCount) : null),
|
|
360
|
+
h('span', { className: 'sg-toolbar-count' }, mode === 'graph' ? visibleNodes.length + ' 个节点 · ' + edges.filter((edge) => edge.status === 'active').length + ' 条关系' : events.length + ' 条事件 · ' + project),
|
|
361
|
+
h('button', { type: 'button', className: 'sg-toolbar-button', onClick: fullScreen ? () => { setFullScreen(false); setFiltersOpen(false) } : openExplorer }, fullScreen ? '退出全屏' : '⛶ 全屏查看' + (mode === 'graph' ? '图谱' : '时间线'))),
|
|
362
|
+
filtersOpen ? filterControls : null,
|
|
363
|
+
mode === 'graph'
|
|
364
|
+
? h('div', { className: 'sg-long-layout ' + (fullScreen ? '' : 'sg-summary-layout') },
|
|
365
|
+
h(GraphCanvas, { nodes: visibleNodes, edges, selectedId: selectedNodeId, onSelect: setSelectedNodeId, showSummary: !fullScreen, onViewDetails: openExplorer }),
|
|
366
|
+
fullScreen ? h(NodeDetailPanel, { node: nodes.find((node) => node.id === selectedNodeId), nodes, edges, events, onEvent: selectEvent }) : null)
|
|
367
|
+
: h('div', { className: 'sg-long-layout ' + (fullScreen ? 'sg-timeline-layout' : 'sg-summary-layout') },
|
|
368
|
+
h(TimelineList, { events, nodes, query, filters: eventFilters, onSelect: setSelectedEventId, selectedId: selectedEventId, floating: !fullScreen, onNode: selectNode, openSource: openEvent }),
|
|
369
|
+
fullScreen ? h(EventDetailPanel, { event: events.find((event) => event.id === selectedEventId), nodes, events, onNode: selectNode, openSource: openEvent }) : null))
|
|
189
370
|
}
|
|
190
371
|
|
|
191
372
|
function previewText(value) {
|
|
@@ -372,17 +553,17 @@ window.__ModuleLoader__.load({
|
|
|
372
553
|
h('h3', { className: 'sg-section-title' }, '来源'),
|
|
373
554
|
h('div', { className: 'sg-source-label' }, h('span', { className: 'sg-source-icon', 'aria-hidden': 'true' }, '▣'), h('span', null, '当前 DeepSeek 对话')),
|
|
374
555
|
h('details', { className: 'sg-tech' }, h('summary', null, '技术详情'), h('div', { className: 'sg-tech-body' },
|
|
375
|
-
h('div', { className: 'sg-tech-row' }, h('span', { className: 'sg-muted' }, kind === 'block' ? 'Block ID' :
|
|
556
|
+
h('div', { className: 'sg-tech-row' }, h('span', { className: 'sg-muted' }, kind === 'block' ? 'Block ID' : 'Event ID'), h('span', { className: 'sg-code' }, item.id)),
|
|
376
557
|
kind === 'block' && item.turnRange ? h('div', { className: 'sg-tech-row' }, h('span', { className: 'sg-muted' }, 'Turn'), h('span', null, item.turnRange.join(' - '))) : null,
|
|
377
558
|
messages.length ? messages.map((message) => h('div', { key: message.id, className: 'sg-raw-message' }, h('div', { className: 'sg-muted' }, String(message.role || '') + ' · ' + formatTime(message.createdAt)), h('div', { className: 'sg-code' }, String(message.content || '')))) : h('div', { className: 'sg-muted' }, '当前数据中没有可显示的来源消息。'))))
|
|
378
559
|
}
|
|
379
560
|
|
|
380
|
-
function EventDetail({ event, project, source,
|
|
561
|
+
function EventDetail({ event, project, source, onBack, backLabel }) {
|
|
381
562
|
return h(React.Fragment, null,
|
|
382
563
|
h(BackBar, { label: backLabel, onBack }),
|
|
383
564
|
h('header', { className: 'sg-detail-header' }, h('h2', { className: 'sg-detail-title' }, event.title || '记忆详情'), event.summary ? h('p', { className: 'sg-detail-subtitle' }, event.summary) : null, h('div', { className: 'sg-meta' }, h('span', null, formatTime(event.updatedAt || event.createdAt)), h('span', { className: 'sg-meta-sep' }, project))),
|
|
384
565
|
event.narrative ? h('div', { className: 'sg-detail-section' }, h('h3', { className: 'sg-section-title' }, 'AI 对这段经历的理解'), h('p', { className: 'sg-prose' }, event.narrative)) : null,
|
|
385
|
-
h('div', { className: 'sg-detail-section' }, h('h3', { className: 'sg-section-title' }, '
|
|
566
|
+
h('div', { className: 'sg-detail-section' }, h('h3', { className: 'sg-section-title' }, '参与实体'), (event.temporal?.participants || []).length ? h('div', { className: 'sg-tags' }, event.temporal.participants.map((name) => h('span', { key: name, className: 'sg-tag' }, name))) : h('span', { className: 'sg-muted' }, '未记录')),
|
|
386
567
|
h(SourceDetails, { item: event, source, kind: 'event' }))
|
|
387
568
|
}
|
|
388
569
|
|
|
@@ -413,7 +594,7 @@ window.__ModuleLoader__.load({
|
|
|
413
594
|
h('div', { className: 'sg-detail-section' }, h('div', { className: 'sg-pipeline' },
|
|
414
595
|
h('div', { className: 'sg-stage' }, h('span', null, '记忆保存'), h('span', { className: 'sg-stage-value done' }, '✓ 已完成')),
|
|
415
596
|
h('div', { className: 'sg-stage' }, h('span', null, '事件提取'), h('span', { className: 'sg-stage-value ' + (first?.kind === 'event-extraction' ? 'failed' : 'done') }, first?.kind === 'event-extraction' ? '× 失败' : '✓ 已完成')),
|
|
416
|
-
h('div', { className: 'sg-stage' }, h('span', null, '
|
|
597
|
+
h('div', { className: 'sg-stage' }, h('span', null, '图谱投影'), h('span', { className: 'sg-stage-value ' + (first?.kind === 'graph-projection' ? 'failed' : first?.kind === 'event-extraction' ? 'waiting' : 'done') }, first?.kind === 'graph-projection' ? '× 失败' : first?.kind === 'event-extraction' ? '— 等待' : '✓ 已完成')))),
|
|
417
598
|
failedBlocks.length ? h('div', { className: 'sg-detail-section' }, h('h3', { className: 'sg-section-title' }, '受影响的短期记忆'), failedBlocks.map((block) => h('div', { key: block.id, className: 'sg-result-event' }, block.title || block.summary || '短期记忆'))) : null,
|
|
418
599
|
h('button', { className: 'sg-alert', onClick: refresh, style: { marginTop: '16px' } }, h('span', { className: 'sg-alert-mark' }, '↻'), h('span', null, h('span', { className: 'sg-alert-title' }, '重新检查状态'), h('br'), h('span', { className: 'sg-alert-copy' }, '任务会沿用现有重试机制继续处理。')), h('span', { className: 'sg-chevron' }, '›')),
|
|
419
600
|
h('details', { className: 'sg-tech' }, h('summary', null, '技术错误详情'), h('pre', { className: 'sg-tech-body sg-code' }, first?.lastErrorFull || first?.lastError || '没有记录技术错误。')))
|
|
@@ -421,10 +602,10 @@ window.__ModuleLoader__.load({
|
|
|
421
602
|
|
|
422
603
|
function MoreHome({ selected, setView }) {
|
|
423
604
|
const rows = [
|
|
424
|
-
['structure', '◇', '记忆结构', '
|
|
605
|
+
['structure', '◇', '记忆结构', '浏览 Event 与知识图谱'],
|
|
425
606
|
['system', '✓', '系统状态', '处理任务和最近整理时间'],
|
|
426
607
|
['audit', '↗', '使用记录', '长期记忆何时被使用'],
|
|
427
|
-
['raw', '{}', '原始数据', 'Block、Event、
|
|
608
|
+
['raw', '{}', '原始数据', 'Block、Event、Graph 与模型响应'],
|
|
428
609
|
['settings', '⚙', '高级设置', 'Schema、提取间隔与项目空间'],
|
|
429
610
|
['support', '?', '反馈与支持', '报告问题、提出建议或咨询使用方法'],
|
|
430
611
|
]
|
|
@@ -456,19 +637,19 @@ window.__ModuleLoader__.load({
|
|
|
456
637
|
'- 当前工作区:' + project,
|
|
457
638
|
'- blockTurnSize:' + (selected?.blockTurnSize ?? 'unknown'),
|
|
458
639
|
'- 已封存块:' + (selected?.blocks ?? 0),
|
|
459
|
-
'- Event /
|
|
640
|
+
'- Event / Graph Node 数量:' + (selected?.events ?? 0) + ' / ' + (selected?.graphNodes ?? 0),
|
|
460
641
|
'- 最近错误:' + (safeErrorSummary(recentError || latestJobError) || '无'),
|
|
461
642
|
'',
|
|
462
|
-
'> 默认诊断不包含原始聊天、L5、Event 或
|
|
643
|
+
'> 默认诊断不包含原始聊天、L5、Event 或 Graph 内容。',
|
|
463
644
|
]
|
|
464
645
|
if (includeLogs) lines.push('', '<details><summary>诊断日志</summary>', '', '```json', limitedJson({ frontendError: recentError || null, failedJobs: selected?.failedJobDetails || [] }), '```', '</details>')
|
|
465
|
-
if (includeMemory) lines.push('', '<details><summary>用户主动附加的记忆数据(可能包含对话内容)</summary>', '', '```json', limitedJson({ blocks: data.blocks, events: data.events,
|
|
646
|
+
if (includeMemory) lines.push('', '<details><summary>用户主动附加的记忆数据(可能包含对话内容)</summary>', '', '```json', limitedJson({ blocks: data.blocks, events: data.events, graph: data.graph }), '```', '</details>')
|
|
466
647
|
const issueParams = new URLSearchParams({ title: '[Bug] StrataGate:', body: lines.join('\n') })
|
|
467
648
|
const featureParams = new URLSearchParams({ title: '[Feature] StrataGate:', body: '请描述希望增加的能力、使用场景和预期行为。' })
|
|
468
649
|
return h(React.Fragment, null,
|
|
469
650
|
h(BackBar, { label: '更多', onBack }),
|
|
470
651
|
h('div', { className: 'sg-intro' }, h('h2', null, '反馈与支持'), h('p', null, '选择最合适的入口,我们会带上必要且安全的上下文。')),
|
|
471
|
-
h('div', { className: 'sg-privacy-note' }, '基础诊断不会附带原始聊天、L5、Event 或
|
|
652
|
+
h('div', { className: 'sg-privacy-note' }, '基础诊断不会附带原始聊天、L5、Event 或 Graph 内容。'),
|
|
472
653
|
h('section', { className: 'sg-support-card' }, h('h3', null, '遇到问题'), h('p', null, '插件会整理版本、配置、数量和最近错误,帮助快速定位。'),
|
|
473
654
|
h('label', { className: 'sg-check' }, h('input', { type: 'checkbox', checked: includeLogs, onChange: (event) => setIncludeLogs(event.target.checked) }), h('span', null, '附加诊断日志')),
|
|
474
655
|
h('label', { className: 'sg-check' }, h('input', { type: 'checkbox', checked: includeMemory, onChange: (event) => setIncludeMemory(event.target.checked) }), h('span', null, '附加记忆数据(可能包含对话内容)')),
|
|
@@ -478,25 +659,25 @@ window.__ModuleLoader__.load({
|
|
|
478
659
|
h('section', { className: 'sg-support-card' }, h('h3', null, '使用疑问'), h('p', null, '在 GitHub Discussion 的 Q&A 区交流使用方法。'), h('a', { className: 'sg-link', href: DISCUSSION_URL, target: '_blank', rel: 'noopener noreferrer' }, '前往 Discussion / Q&A →')))
|
|
479
660
|
}
|
|
480
661
|
|
|
481
|
-
function StructurePage({ events,
|
|
662
|
+
function StructurePage({ events, graph, openEvent, onBack }) {
|
|
482
663
|
return h(React.Fragment, null,
|
|
483
664
|
h(BackBar, { label: '更多', onBack }),
|
|
484
665
|
h('div', { className: 'sg-intro' }, h('h2', null, '记忆结构'), h('p', null, '完整浏览现有结构化记忆')),
|
|
485
666
|
h('div', { className: 'sg-counts' },
|
|
486
667
|
h('div', null, h('div', { className: 'sg-count-value' }, events.length), h('div', { className: 'sg-count-label' }, '经历 / Event')),
|
|
487
|
-
h('div', null, h('div', { className: 'sg-count-value' },
|
|
668
|
+
h('div', null, h('div', { className: 'sg-count-value' }, graph.nodes.length), h('div', { className: 'sg-count-label' }, '知识图谱节点'))),
|
|
488
669
|
h('div', { className: 'sg-structured-group' },
|
|
489
670
|
h('h3', { className: 'sg-section-title' }, '经历'),
|
|
490
671
|
events.map((event) => h('button', { key: event.id, className: 'sg-related', onClick: () => openEvent(event) }, h('span', null, event.title), h('span', { className: 'sg-related-time' }, formatTime(event.updatedAt))))),
|
|
491
672
|
h('div', { className: 'sg-structured-group' },
|
|
492
|
-
h('h3', { className: 'sg-section-title' }, '
|
|
493
|
-
|
|
673
|
+
h('h3', { className: 'sg-section-title' }, '图谱节点'),
|
|
674
|
+
graph.nodes.map((node) => h('div', { key: node.id, className: 'sg-related' }, h('span', null, node.name), h('span', { className: 'sg-related-time' }, (node.sourceEventIds || []).length + ' 条支撑事件')))))
|
|
494
675
|
}
|
|
495
676
|
|
|
496
677
|
function SystemPage({ selected, blocks, onBack, refresh }) {
|
|
497
678
|
const processing = blocks.filter((block) => block.status === 'processing').length
|
|
498
679
|
return h(React.Fragment, null, h(BackBar, { label: '更多', onBack }), h('div', { className: 'sg-intro' }, h('h2', null, '系统状态'), h('p', null, '仅在这里展示记忆处理的工程状态')), h('div', { className: 'sg-pipeline' },
|
|
499
|
-
[['Block 数量', selected.blocks], ['待处理任务', processing], ['失败任务', selected.failedJobs], ['最近整理时间', formatTime(selected.lastActivityAt)], ['Event 提取', selected.failedJobDetails?.some((item) => item.kind === 'event-extraction') ? '有失败' : '正常'], ['
|
|
680
|
+
[['Block 数量', selected.blocks], ['待处理任务', processing], ['失败任务', selected.failedJobs], ['最近整理时间', formatTime(selected.lastActivityAt)], ['Event 提取', selected.failedJobDetails?.some((item) => item.kind === 'event-extraction') ? '有失败' : '正常'], ['图谱投影', selected.failedJobDetails?.some((item) => item.kind === 'graph-projection') ? '有失败' : '正常']].map(([label, value]) => h('div', { key: label, className: 'sg-stage' }, h('span', null, label), h('span', { className: 'sg-stage-value ' + (label === '失败任务' && value ? 'failed' : 'waiting') }, String(value))))), h('button', { className: 'sg-quiet-button', onClick: refresh, style: { marginTop: '14px' } }, '↻ 重新检查'))
|
|
500
681
|
}
|
|
501
682
|
|
|
502
683
|
function AuditPage({ audit, onBack }) {
|
|
@@ -504,8 +685,8 @@ window.__ModuleLoader__.load({
|
|
|
504
685
|
}
|
|
505
686
|
|
|
506
687
|
function RawPage({ data, selected, onBack }) {
|
|
507
|
-
const groups = [['Block raw', data.blocks], ['Event raw', data.events], ['
|
|
508
|
-
return h(React.Fragment, null, h(BackBar, { label: '更多', onBack }), h('div', { className: 'sg-intro' }, h('h2', null, '原始数据'), h('p', null, '供排查问题使用的内部字段与 JSON')), groups.map(([label, value]) => h('details', { key: label, className: 'sg-raw-group' }, h('summary', null, label + ' (' + value.length + ')'), h('pre', { className: 'sg-raw-json sg-code' }, JSON.stringify(value, null, 2)))))
|
|
688
|
+
const groups = [['Block raw', data.blocks], ['Event raw', data.events], ['Graph raw', data.graph], ['Usage raw', data.audit], ['模型响应', selected.successfulModelResponses || []]]
|
|
689
|
+
return h(React.Fragment, null, h(BackBar, { label: '更多', onBack }), h('div', { className: 'sg-intro' }, h('h2', null, '原始数据'), h('p', null, '供排查问题使用的内部字段与 JSON')), groups.map(([label, value]) => h('details', { key: label, className: 'sg-raw-group' }, h('summary', null, label + ' (' + (Array.isArray(value) ? value.length : ((value.nodes?.length || 0) + (value.edges?.length || 0))) + ')'), h('pre', { className: 'sg-raw-json sg-code' }, JSON.stringify(value, null, 2)))))
|
|
509
690
|
}
|
|
510
691
|
|
|
511
692
|
function SettingsPage({ selected, namespace, onBack, updateLambda, savingLambda }) {
|
|
@@ -538,7 +719,7 @@ window.__ModuleLoader__.load({
|
|
|
538
719
|
const [conversationId, setConversationId] = React.useState('')
|
|
539
720
|
const [section, setSection] = React.useState('short')
|
|
540
721
|
const [view, setView] = React.useState({ name: 'root' })
|
|
541
|
-
const [data, setData] = React.useState({ events: [],
|
|
722
|
+
const [data, setData] = React.useState({ events: [], graph: { nodes: [], edges: [], migration: null }, blocks: [], openBlock: null, conversations: [], activeThreadId: null, audit: [] })
|
|
542
723
|
const [query, setQuery] = React.useState('')
|
|
543
724
|
const [source, setSource] = React.useState(null)
|
|
544
725
|
const [loading, setLoading] = React.useState(true)
|
|
@@ -572,18 +753,18 @@ window.__ModuleLoader__.load({
|
|
|
572
753
|
|
|
573
754
|
const loadMemoryData = React.useCallback((activeNamespace, options = {}) => {
|
|
574
755
|
const background = options.background === true
|
|
575
|
-
if (!activeNamespace) { setData({ events: [],
|
|
756
|
+
if (!activeNamespace) { setData({ events: [], graph: { nodes: [], edges: [], migration: null }, blocks: [], openBlock: null, conversations: [], activeThreadId: null, audit: [] }); if (!background) setLoading(false); return Promise.resolve() }
|
|
576
757
|
if (!background) setLoading(true)
|
|
577
758
|
return Promise.allSettled([
|
|
578
759
|
api('memories', { namespace: activeNamespace, kind: 'events', limit: '200' }),
|
|
579
|
-
api('memories', { namespace: activeNamespace, kind: '
|
|
760
|
+
api('memories', { namespace: activeNamespace, kind: 'graph' }),
|
|
580
761
|
api('memories', { namespace: activeNamespace, kind: 'blocks', limit: '200', ...(options.threadId ? { threadId: options.threadId } : {}) }),
|
|
581
762
|
api('audit', { namespace: activeNamespace, limit: '100' }),
|
|
582
763
|
]).then((results) => {
|
|
583
|
-
const [events,
|
|
764
|
+
const [events, graph, blocks, audit] = results
|
|
584
765
|
setData((previous) => ({
|
|
585
766
|
events: events.status === 'fulfilled' ? events.value.items || [] : previous.events,
|
|
586
|
-
|
|
767
|
+
graph: graph.status === 'fulfilled' ? graph.value : previous.graph,
|
|
587
768
|
blocks: blocks.status === 'fulfilled' ? blocks.value.items || [] : previous.blocks,
|
|
588
769
|
openBlock: blocks.status === 'fulfilled' ? blocks.value.openBlock || null : previous.openBlock,
|
|
589
770
|
conversations: blocks.status === 'fulfilled' ? blocks.value.conversations || [] : previous.conversations,
|
|
@@ -599,7 +780,7 @@ window.__ModuleLoader__.load({
|
|
|
599
780
|
|
|
600
781
|
React.useEffect(() => { setLoading(true); void loadOverview().finally(() => setLoading(false)) }, [])
|
|
601
782
|
React.useEffect(() => {
|
|
602
|
-
setConversationId(''); setView({ name: 'root' }); setSource(null); setData({ events: [],
|
|
783
|
+
setConversationId(''); setView({ name: 'root' }); setSource(null); setData({ events: [], graph: { nodes: [], edges: [], migration: null }, blocks: [], openBlock: null, conversations: [], activeThreadId: null, audit: [] }); void loadMemoryData(namespace)
|
|
603
784
|
}, [namespace])
|
|
604
785
|
React.useEffect(() => {
|
|
605
786
|
if (!namespace) return undefined
|
|
@@ -642,14 +823,13 @@ window.__ModuleLoader__.load({
|
|
|
642
823
|
setView((current) => ({ name: kind, item, back: current })); loadSource(kind, item)
|
|
643
824
|
}
|
|
644
825
|
const openEvent = (event) => openWithSource('event', data.events.find((item) => item.id === event.id) || event)
|
|
645
|
-
const openElement = (id) => { const element = data.elements.find((item) => item.id === id); if (element) openWithSource('element', element) }
|
|
646
826
|
const goBack = () => {
|
|
647
827
|
const previous = view.back || { name: 'root' }
|
|
648
828
|
setView(previous)
|
|
649
|
-
if (previous.item && ['event', '
|
|
829
|
+
if (previous.item && ['event', 'block'].includes(previous.name)) loadSource(previous.name, previous.item)
|
|
650
830
|
else setSource(null)
|
|
651
831
|
}
|
|
652
|
-
const backLabel = view.back?.name === 'block' ? '短期记忆' : view.back?.name === '
|
|
832
|
+
const backLabel = view.back?.name === 'block' ? '短期记忆' : view.back?.name === 'event' ? '长期记忆' : view.back?.name === 'structure' ? '记忆结构' : section === 'short' ? '短期记忆' : '长期记忆'
|
|
653
833
|
const refresh = () => Promise.all([loadOverview(), loadMemoryData(namespace, { threadId: conversationId })])
|
|
654
834
|
const selectConversation = (nextConversationId) => {
|
|
655
835
|
setConversationId(nextConversationId)
|
|
@@ -673,10 +853,9 @@ window.__ModuleLoader__.load({
|
|
|
673
853
|
let content = null
|
|
674
854
|
if (loading && !selected) content = h(Loading)
|
|
675
855
|
else if (!selected) content = h(Empty, { title: '还没有记忆', copy: '完成一些 DSH 对话后,短期记忆和长期记忆会出现在这里。' })
|
|
676
|
-
else if (view.name === 'event') content = h(EventDetail, { event: view.item, project, source,
|
|
677
|
-
else if (view.name === 'element') content = h(ElementDetail, { element: view.item, events: data.events, source, openEvent, onBack: goBack, backLabel })
|
|
856
|
+
else if (view.name === 'event') content = h(EventDetail, { event: view.item, project, source, onBack: goBack, backLabel })
|
|
678
857
|
else if (view.name === 'status') content = h(ProcessingStatus, { overview: selected, blocks: data.blocks, onBack: () => setView({ name: 'root' }), refresh })
|
|
679
|
-
else if (view.name === 'structure') content = h(StructurePage, { events: data.events,
|
|
858
|
+
else if (view.name === 'structure') content = h(StructurePage, { events: data.events, graph: data.graph, openEvent, onBack: moreBack })
|
|
680
859
|
else if (view.name === 'system') content = h(SystemPage, { selected, blocks: data.blocks, onBack: moreBack, refresh })
|
|
681
860
|
else if (view.name === 'audit') content = h(AuditPage, { audit: data.audit, onBack: moreBack })
|
|
682
861
|
else if (view.name === 'raw') content = h(RawPage, { data, selected, onBack: moreBack })
|
|
@@ -684,7 +863,7 @@ window.__ModuleLoader__.load({
|
|
|
684
863
|
else if (view.name === 'support') content = h(SupportPage, { overview, selected, project, data, recentError, onBack: moreBack })
|
|
685
864
|
else content = h(React.Fragment, null,
|
|
686
865
|
h(FailureAlert, { count: failedCount, onOpen: () => setView({ name: 'status' }) }),
|
|
687
|
-
loading ? h(Loading) : section === 'short' ? h(ShortTermPage, { key: namespace + ':' + conversationId, blocks: data.blocks, openBlock: data.openBlock, conversations, activeThreadId: conversationId || data.activeThreadId || '', namespace, onConversationChange: selectConversation, refresh }) : section === 'long' ? h(LongTermPage, { events: data.events,
|
|
866
|
+
loading ? h(Loading) : section === 'short' ? h(ShortTermPage, { key: namespace + ':' + conversationId, blocks: data.blocks, openBlock: data.openBlock, conversations, activeThreadId: conversationId || data.activeThreadId || '', namespace, onConversationChange: selectConversation, refresh }) : section === 'long' ? h(LongTermPage, { events: data.events, graph: data.graph, project, query, setQuery, openEvent }) : h(MoreHome, { setView }))
|
|
688
867
|
|
|
689
868
|
return h('main', { className: 'sg-memory', 'data-testid': 'stratagate-memory-ui' },
|
|
690
869
|
h('style', null, css),
|