dsh-layered-memory 0.5.4 → 0.6.1
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/README.en.md +211 -0
- package/README.md +26 -9
- package/dist/client.js +466 -70
- package/dist/config.d.ts +6 -0
- package/dist/config.js +4 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -1
- package/dist/llm.js +5 -1
- package/dist/pipeline/rebuild.d.ts +78 -0
- package/dist/pipeline/rebuild.js +300 -0
- package/dist/pipeline/runner.d.ts +36 -4
- package/dist/pipeline/runner.js +119 -24
- package/dist/settings.d.ts +4 -0
- package/dist/settings.js +10 -3
- package/dist/stats.d.ts +2 -1
- package/dist/stats.js +46 -6
- package/dist/store/pending.d.ts +15 -0
- package/dist/store/pending.js +56 -0
- package/dist/store/sqlite.d.ts +15 -0
- package/dist/store/sqlite.js +76 -0
- package/dist/store/state.d.ts +6 -0
- package/dist/store/state.js +11 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -160,6 +160,31 @@ window.__ModuleLoader__.load({
|
|
|
160
160
|
padding: "4px 12px",
|
|
161
161
|
marginBottom: 14,
|
|
162
162
|
},
|
|
163
|
+
seg: {
|
|
164
|
+
display: "inline-flex",
|
|
165
|
+
border: "1px solid var(--dsw-alias-border-secondary, #e5e5e5)",
|
|
166
|
+
borderRadius: 8,
|
|
167
|
+
overflow: "hidden",
|
|
168
|
+
flexShrink: 0,
|
|
169
|
+
},
|
|
170
|
+
segBtn: {
|
|
171
|
+
padding: "4px 12px",
|
|
172
|
+
fontSize: 12,
|
|
173
|
+
lineHeight: "16px",
|
|
174
|
+
cursor: "pointer",
|
|
175
|
+
background: "transparent",
|
|
176
|
+
color: "inherit",
|
|
177
|
+
border: "none",
|
|
178
|
+
borderRight: "1px solid var(--dsw-alias-border-secondary, #e5e5e5)",
|
|
179
|
+
},
|
|
180
|
+
segBtnOn: {
|
|
181
|
+
background: "var(--dsw-alias-interactive-bg-primary, #1a7f37)",
|
|
182
|
+
color: "#fff",
|
|
183
|
+
fontWeight: 600,
|
|
184
|
+
},
|
|
185
|
+
segBtnOff: {
|
|
186
|
+
background: "var(--dsw-alias-bg-secondary, #f6f8fa)",
|
|
187
|
+
},
|
|
163
188
|
flexRow: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
|
|
164
189
|
grow: { flex: 1 },
|
|
165
190
|
sceneHead: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 6, flexWrap: "wrap" },
|
|
@@ -228,6 +253,36 @@ window.__ModuleLoader__.load({
|
|
|
228
253
|
);
|
|
229
254
|
}
|
|
230
255
|
|
|
256
|
+
// ── Segmented 组件:分段选择器(记忆设置页的蒸馏思考档位等单选项) ──
|
|
257
|
+
function Segmented(props) {
|
|
258
|
+
var value = props.value;
|
|
259
|
+
var disabled = !!props.disabled;
|
|
260
|
+
return react.createElement(
|
|
261
|
+
"div",
|
|
262
|
+
{ style: Object.assign({}, S.seg, disabled ? S.switchDisabled : null) },
|
|
263
|
+
props.options.map(function (opt, i) {
|
|
264
|
+
var on = opt.key === value;
|
|
265
|
+
return react.createElement(
|
|
266
|
+
"span",
|
|
267
|
+
{
|
|
268
|
+
key: opt.key,
|
|
269
|
+
style: Object.assign(
|
|
270
|
+
{},
|
|
271
|
+
S.segBtn,
|
|
272
|
+
on ? S.segBtnOn : S.segBtnOff,
|
|
273
|
+
i === props.options.length - 1 ? { borderRight: "none" } : null,
|
|
274
|
+
disabled ? { cursor: "not-allowed" } : null,
|
|
275
|
+
),
|
|
276
|
+
onClick: function () {
|
|
277
|
+
if (!disabled && !on && props.onChange) props.onChange(opt.key);
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
opt.label,
|
|
281
|
+
);
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
231
286
|
// ── 会话记忆档位控件(输入栏 pill + macOS 风格滑动选择器) ──
|
|
232
287
|
// 档位顺序即滑轨顺序:关闭 → chat → work → 自动(默认档"自动"居右)
|
|
233
288
|
var MODES = [
|
|
@@ -257,40 +312,54 @@ window.__ModuleLoader__.load({
|
|
|
257
312
|
return 3;
|
|
258
313
|
}
|
|
259
314
|
|
|
260
|
-
/** 滑动选择器浮层(参考 macOS 滑动器:拖拽圆头
|
|
315
|
+
/** 滑动选择器浮层(参考 macOS 滑动器:拖拽圆头 1:1 连续跟手,松手按动量投影吸附最近档)。 */
|
|
261
316
|
function ModeSlider(props) {
|
|
317
|
+
ensureFlowStyle(); // 玻璃材质 class 与流光共用同一张注入样式表
|
|
262
318
|
var trackRef = react.useRef(null);
|
|
319
|
+
// 拖拽状态:{ x: 圆头连续位置 px, lastX: 上次指针 clientX, t: 时间戳, v: 速度 px/ms(EMA 平滑) }
|
|
263
320
|
var dragState = react.useState(null);
|
|
264
|
-
var
|
|
265
|
-
var
|
|
321
|
+
var drag = dragState[0];
|
|
322
|
+
var setDrag = dragState[1];
|
|
266
323
|
|
|
267
|
-
var
|
|
268
|
-
|
|
269
|
-
|
|
324
|
+
var clampX = function (x) {
|
|
325
|
+
if (x < 0) return 0;
|
|
326
|
+
if (x > INNER_W) return INNER_W;
|
|
327
|
+
return x;
|
|
328
|
+
};
|
|
329
|
+
var xFromClientX = function (clientX) {
|
|
270
330
|
var rect = trackRef.current.getBoundingClientRect();
|
|
271
|
-
|
|
272
|
-
if (x < 0) x = 0;
|
|
273
|
-
if (x > INNER_W) x = INNER_W;
|
|
274
|
-
return Math.round((x / INNER_W) * (MODES.length - 1));
|
|
331
|
+
return clampX(clientX - rect.left - THUMB / 2);
|
|
275
332
|
};
|
|
276
333
|
|
|
277
334
|
var onPointerDown = function (e) {
|
|
278
335
|
e.preventDefault();
|
|
279
336
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
280
|
-
|
|
337
|
+
setDrag({ x: xFromClientX(e.clientX), lastX: e.clientX, t: e.timeStamp, v: 0 });
|
|
281
338
|
};
|
|
282
339
|
var onPointerMove = function (e) {
|
|
283
|
-
if (
|
|
284
|
-
|
|
340
|
+
if (drag === null) return;
|
|
341
|
+
var dt = e.timeStamp - drag.t;
|
|
342
|
+
var instV = dt > 0 ? (e.clientX - drag.lastX) / dt : drag.v;
|
|
343
|
+
setDrag({
|
|
344
|
+
x: xFromClientX(e.clientX),
|
|
345
|
+
lastX: e.clientX,
|
|
346
|
+
t: e.timeStamp,
|
|
347
|
+
v: drag.v * 0.7 + instV * 0.3, // EMA:瞬时抖动不放大,松手投影用
|
|
348
|
+
});
|
|
285
349
|
};
|
|
286
350
|
var onPointerUp = function (e) {
|
|
287
|
-
if (
|
|
288
|
-
|
|
289
|
-
|
|
351
|
+
if (drag === null) return;
|
|
352
|
+
// 动量投影(Designing Fluid Interfaces):按松手速度前瞻落点就近吸附;
|
|
353
|
+
// 投影量 clamp 到半档(±30px)——甩动最多把边界推到相邻档,绝不会跳两档
|
|
354
|
+
var projected = xFromClientX(e.clientX) + Math.max(-30, Math.min(30, drag.v * 120));
|
|
355
|
+
var idx = Math.round((clampX(projected) / INNER_W) * (MODES.length - 1));
|
|
356
|
+
setDrag(null);
|
|
290
357
|
props.onCommit(MODES[idx].key);
|
|
291
358
|
};
|
|
292
359
|
|
|
293
|
-
|
|
360
|
+
// 拖拽中圆头 1:1 跟指针(连续位置,不吸附);静止时停在档位中心
|
|
361
|
+
var thumbLeft = drag !== null ? drag.x : (modeIndex(props.mode) / (MODES.length - 1)) * INNER_W;
|
|
362
|
+
var activeIdx = Math.min(MODES.length - 1, Math.max(0, Math.round((thumbLeft / INNER_W) * (MODES.length - 1))));
|
|
294
363
|
var info = MODES[activeIdx];
|
|
295
364
|
|
|
296
365
|
var stops = [];
|
|
@@ -310,7 +379,8 @@ window.__ModuleLoader__.load({
|
|
|
310
379
|
width: 6,
|
|
311
380
|
height: 6,
|
|
312
381
|
borderRadius: "50%",
|
|
313
|
-
background: active ? MODES[i].color : "
|
|
382
|
+
background: active ? MODES[i].color : "rgba(128,140,150,0.55)",
|
|
383
|
+
zIndex: 2,
|
|
314
384
|
},
|
|
315
385
|
},
|
|
316
386
|
),
|
|
@@ -331,9 +401,10 @@ window.__ModuleLoader__.load({
|
|
|
331
401
|
cursor: "pointer",
|
|
332
402
|
whiteSpace: "nowrap",
|
|
333
403
|
fontWeight: active ? 600 : 400,
|
|
334
|
-
|
|
404
|
+
// 未激活标签走主题 caption 令牌(浅色 #400 灰蓝 / 暗色 #600),玻璃面上保持可读
|
|
405
|
+
color: active ? MODES[i].color : "var(--dsw-alias-label-caption, #888)",
|
|
335
406
|
},
|
|
336
|
-
onClick: function () { if (
|
|
407
|
+
onClick: function () { if (drag === null) props.onCommit(MODES[i].key); },
|
|
337
408
|
},
|
|
338
409
|
MODES[i].label,
|
|
339
410
|
),
|
|
@@ -344,6 +415,8 @@ window.__ModuleLoader__.load({
|
|
|
344
415
|
return react.createElement(
|
|
345
416
|
"div",
|
|
346
417
|
{
|
|
418
|
+
// 外壳只负责定位(带 transform 居中);玻璃材质拆到内层独立元素——
|
|
419
|
+
// Chromium 中 transform 元素上的 backdrop-filter 采样异常,玻璃会失效
|
|
347
420
|
style: {
|
|
348
421
|
position: "absolute",
|
|
349
422
|
bottom: "calc(100% + 8px)",
|
|
@@ -351,67 +424,170 @@ window.__ModuleLoader__.load({
|
|
|
351
424
|
left: "50%",
|
|
352
425
|
transform: "translateX(-50%)",
|
|
353
426
|
zIndex: 1000,
|
|
354
|
-
background: "var(--dsw-alias-bg-primary, #fff)",
|
|
355
|
-
border: "1px solid var(--dsw-alias-border-secondary, #e0e0e0)",
|
|
356
|
-
borderRadius: 10,
|
|
357
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.16)",
|
|
358
|
-
padding: "12px 16px 30px",
|
|
359
427
|
},
|
|
360
428
|
},
|
|
429
|
+
react.createElement("div", {
|
|
430
|
+
className: "dsh-mem-glass",
|
|
431
|
+
style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, pointerEvents: "none" },
|
|
432
|
+
}),
|
|
361
433
|
react.createElement(
|
|
362
434
|
"div",
|
|
363
|
-
{
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
435
|
+
{ style: { position: "relative", padding: "12px 16px 30px" } },
|
|
436
|
+
react.createElement(
|
|
437
|
+
"div",
|
|
438
|
+
{
|
|
439
|
+
ref: trackRef,
|
|
440
|
+
style: {
|
|
441
|
+
position: "relative",
|
|
442
|
+
// 容器宽 = thumb 活动范围(0..INNER_W + THUMB),点击映射与视觉两端严格对齐
|
|
443
|
+
width: TRACK_W,
|
|
444
|
+
height: 16,
|
|
445
|
+
touchAction: "none",
|
|
446
|
+
cursor: drag === null ? "pointer" : "grabbing",
|
|
371
447
|
},
|
|
372
448
|
onPointerDown: onPointerDown,
|
|
373
449
|
onPointerMove: onPointerMove,
|
|
374
450
|
onPointerUp: onPointerUp,
|
|
375
451
|
onPointerCancel: onPointerUp,
|
|
376
452
|
},
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
453
|
+
// 线条(底层):只连首尾停点的中心,两端不再露出停点外;
|
|
454
|
+
// thumb(当前档定位球)压最上层,不再被线条与停点穿过。
|
|
455
|
+
// 中性半透明灰在玻璃材质上深浅主题都可辨
|
|
380
456
|
react.createElement("div", {
|
|
381
457
|
style: {
|
|
382
458
|
position: "absolute",
|
|
383
|
-
left:
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
height:
|
|
387
|
-
borderRadius:
|
|
388
|
-
background: "
|
|
389
|
-
border: "1px solid " + info.color,
|
|
390
|
-
boxShadow: "0 1px 4px rgba(0,0,0,0.3)",
|
|
459
|
+
left: THUMB / 2,
|
|
460
|
+
width: INNER_W,
|
|
461
|
+
top: 7,
|
|
462
|
+
height: 4,
|
|
463
|
+
borderRadius: 999,
|
|
464
|
+
background: "rgba(128,140,150,0.32)",
|
|
391
465
|
pointerEvents: "none",
|
|
392
|
-
|
|
466
|
+
zIndex: 1,
|
|
393
467
|
},
|
|
394
468
|
}),
|
|
469
|
+
stops,
|
|
395
470
|
react.createElement("div", {
|
|
396
471
|
style: {
|
|
397
472
|
position: "absolute",
|
|
398
|
-
left:
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
height:
|
|
402
|
-
borderRadius:
|
|
403
|
-
|
|
473
|
+
left: thumbLeft,
|
|
474
|
+
top: 1,
|
|
475
|
+
width: THUMB,
|
|
476
|
+
height: THUMB,
|
|
477
|
+
borderRadius: "50%",
|
|
478
|
+
// 微透白 + 上缘高光:与浮层玻璃材质同语言
|
|
479
|
+
background: "rgba(255,255,255,0.94)",
|
|
480
|
+
border: "1px solid " + info.color,
|
|
481
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.28), inset 0 1px 0 rgba(255,255,255,0.9)",
|
|
404
482
|
pointerEvents: "none",
|
|
483
|
+
transition: drag === null ? "left 120ms ease" : "none",
|
|
484
|
+
zIndex: 3,
|
|
405
485
|
},
|
|
406
486
|
}),
|
|
407
|
-
|
|
487
|
+
),
|
|
488
|
+
props.error
|
|
489
|
+
? react.createElement("div", { style: { fontSize: 11, color: "#cf222e", marginTop: 20, whiteSpace: "nowrap" } }, props.error)
|
|
490
|
+
: null,
|
|
408
491
|
),
|
|
409
|
-
props.error
|
|
410
|
-
? react.createElement("div", { style: { fontSize: 11, color: "#cf222e", marginTop: 20, whiteSpace: "nowrap" } }, props.error)
|
|
411
|
-
: null,
|
|
412
492
|
);
|
|
413
493
|
}
|
|
414
494
|
|
|
495
|
+
// ── auto 档边缘流光 + 浮层玻璃材质 + 重建面板样式:inline style 放不了
|
|
496
|
+
// @keyframes/@property/媒体查询,惰性注入一次性样式表(id 防重复)。
|
|
497
|
+
// dsw 主题变量参考其前端令牌:暗色走 body[data-ds-dark-theme]。 ──
|
|
498
|
+
var FLOW_STYLE_ID = "dsh-mem-flow-style";
|
|
499
|
+
function ensureFlowStyle() {
|
|
500
|
+
if (document.getElementById(FLOW_STYLE_ID)) return;
|
|
501
|
+
var el = document.createElement("style");
|
|
502
|
+
el.id = FLOW_STYLE_ID;
|
|
503
|
+
el.textContent = [
|
|
504
|
+
// conic 角度动画需要 @property 注册才能插值;不支持的浏览器优雅降级为静态渐变边框
|
|
505
|
+
"@property --dsh-mem-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }",
|
|
506
|
+
"@keyframes dshMemFlow { to { --dsh-mem-angle: 360deg; } }",
|
|
507
|
+
// 边缘流光(双层背景):border 区画旋转 conic 冷蓝光带;内部必须是【不透明】底色盖住
|
|
508
|
+
// 光带(半透明内层会让 conic 透进按钮内部,文字被光斑干扰——实测事故)。
|
|
509
|
+
// 不透明底 = 主题底混 12% 冷蓝(color-mix 出来 alpha=1),静态、随主题
|
|
510
|
+
".dsh-mem-flow {",
|
|
511
|
+
" border: 1px solid transparent;",
|
|
512
|
+
" background:",
|
|
513
|
+
" linear-gradient(",
|
|
514
|
+
" color-mix(in srgb, var(--dsw-alias-bg-layer-2, #ffffff) 88%, #3b82f6),",
|
|
515
|
+
" color-mix(in srgb, var(--dsw-alias-bg-layer-2, #ffffff) 88%, #3b82f6)",
|
|
516
|
+
" ) padding-box,",
|
|
517
|
+
" conic-gradient(from var(--dsh-mem-angle),",
|
|
518
|
+
" rgba(8,145,178,0.9), rgba(59,130,246,0.9), rgba(125,211,252,1),",
|
|
519
|
+
" rgba(99,102,241,0.9), rgba(8,145,178,0.9)) border-box;",
|
|
520
|
+
" animation: dshMemFlow 3s linear infinite;",
|
|
521
|
+
" color: #0284c7;",
|
|
522
|
+
"}",
|
|
523
|
+
"body[data-ds-dark-theme] .dsh-mem-flow { color: #7dd3fc; }",
|
|
524
|
+
"@media (prefers-reduced-motion: reduce) { .dsh-mem-flow { animation: none; } }",
|
|
525
|
+
// 浮层玻璃材质(Apple 菜单配方):材质层必须是【无 transform 的独立元素】——
|
|
526
|
+
// Chromium 中 transform 元素上的 backdrop-filter 采样异常(玻璃失效,实测)。
|
|
527
|
+
// 低不透明度基底让底下内容透出 + 顶部光泽渐变 + blur/saturate + 亮缘 + 分主题阴影
|
|
528
|
+
".dsh-mem-glass {",
|
|
529
|
+
" border-radius: 12px;",
|
|
530
|
+
" background:",
|
|
531
|
+
" linear-gradient(rgba(255,255,255,0.34), rgba(255,255,255,0.05)),",
|
|
532
|
+
" rgba(248,249,251,0.55);",
|
|
533
|
+
" -webkit-backdrop-filter: blur(32px) saturate(180%);",
|
|
534
|
+
" backdrop-filter: blur(32px) saturate(180%);",
|
|
535
|
+
" border: 1px solid rgba(255,255,255,0.55);",
|
|
536
|
+
" box-shadow:",
|
|
537
|
+
" 0 12px 40px rgba(0,0,0,0.16), 0 2px 8px rgba(0,0,0,0.07),",
|
|
538
|
+
" inset 0 1px 0 rgba(255,255,255,0.55), inset 0 -1px 0 rgba(0,0,0,0.03);",
|
|
539
|
+
"}",
|
|
540
|
+
"body[data-ds-dark-theme] .dsh-mem-glass {",
|
|
541
|
+
" background:",
|
|
542
|
+
" linear-gradient(rgba(255,255,255,0.09), rgba(255,255,255,0.015)),",
|
|
543
|
+
" rgba(30,32,40,0.55);",
|
|
544
|
+
" border-color: rgba(255,255,255,0.14);",
|
|
545
|
+
" box-shadow:",
|
|
546
|
+
" 0 16px 48px rgba(0,0,0,0.55), 0 3px 12px rgba(0,0,0,0.35),",
|
|
547
|
+
" inset 0 1px 0 rgba(255,255,255,0.12);",
|
|
548
|
+
"}",
|
|
549
|
+
"@media (prefers-reduced-transparency: reduce) {",
|
|
550
|
+
" .dsh-mem-glass { background: var(--dsw-alias-bg-layer-2, #ffffff); backdrop-filter: none; -webkit-backdrop-filter: none; }",
|
|
551
|
+
"}",
|
|
552
|
+
// ── 重建面板(Light/Dark 双主题:基底用 dsw 真实令牌 bg-layer-2/border-l2,
|
|
553
|
+
// 暗色由 body[data-ds-dark-theme] 切换;强调红/进度蓝紫双主题各调一档) ──
|
|
554
|
+
".dsh-mem-rb-card {",
|
|
555
|
+
" border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);",
|
|
556
|
+
" border-radius: 10px;",
|
|
557
|
+
" background: var(--dsw-alias-bg-layer-2, #ffffff);",
|
|
558
|
+
" padding: 12px 14px;",
|
|
559
|
+
" margin-bottom: 14px;",
|
|
560
|
+
" font-size: 13px;",
|
|
561
|
+
"}",
|
|
562
|
+
".dsh-mem-rb-btn {",
|
|
563
|
+
" padding: 5px 14px; font-size: 13px; border-radius: 6px; cursor: pointer;",
|
|
564
|
+
" border: 1px solid var(--dsw-alias-border-l2, #d0d7de);",
|
|
565
|
+
" background: var(--dsw-alias-bg-layer-2, #ffffff);",
|
|
566
|
+
" color: inherit;",
|
|
567
|
+
"}",
|
|
568
|
+
".dsh-mem-rb-btn:disabled { opacity: 0.45; cursor: not-allowed; }",
|
|
569
|
+
".dsh-mem-rb-danger { border-color: rgba(207,34,46,0.45); color: #cf222e; background: transparent; }",
|
|
570
|
+
"body[data-ds-dark-theme] .dsh-mem-rb-danger { color: #f4707b; border-color: rgba(244,112,123,0.5); }",
|
|
571
|
+
".dsh-mem-rb-primary { background: #cf222e; border-color: #cf222e; color: #fff; }",
|
|
572
|
+
"body[data-ds-dark-theme] .dsh-mem-rb-primary { background: #b62324; border-color: #b62324; }",
|
|
573
|
+
".dsh-mem-rb-bar { height: 8px; border-radius: 4px; overflow: hidden; flex: 1;",
|
|
574
|
+
" background: var(--dsw-alias-border-l2, #e8ebef); }",
|
|
575
|
+
"body[data-ds-dark-theme] .dsh-mem-rb-bar { background: rgba(255,255,255,0.12); }",
|
|
576
|
+
".dsh-mem-rb-fill { height: 100%; border-radius: 4px;",
|
|
577
|
+
" background: linear-gradient(90deg, #0969da, #8250df); transition: width .4s ease; }",
|
|
578
|
+
".dsh-mem-rb-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.35);",
|
|
579
|
+
" display: flex; align-items: center; justify-content: center; z-index: 2000; }",
|
|
580
|
+
".dsh-mem-rb-modal { width: 440px; max-width: calc(100vw - 48px); border-radius: 12px;",
|
|
581
|
+
" padding: 18px 20px; font-size: 13px; line-height: 1.6;",
|
|
582
|
+
" border: 1px solid var(--dsw-alias-border-l2, #e5e7eb);",
|
|
583
|
+
" background: var(--dsw-alias-bg-layer-2, #ffffff);",
|
|
584
|
+
" box-shadow: 0 16px 48px rgba(0,0,0,0.24); }",
|
|
585
|
+
"body[data-ds-dark-theme] .dsh-mem-rb-modal { box-shadow: 0 16px 48px rgba(0,0,0,0.6); }",
|
|
586
|
+
".dsh-mem-rb-muted { font-size: 12px; color: var(--dsw-alias-label-caption, #6e7781); }",
|
|
587
|
+
].join("\n");
|
|
588
|
+
document.head.appendChild(el);
|
|
589
|
+
}
|
|
590
|
+
|
|
415
591
|
/** 输入栏 pill:点击展开滑动选择器;props 来自 conversation.input.left 的 zone 注入。 */
|
|
416
592
|
function MemoryModePill(props) {
|
|
417
593
|
var rpc = props.rpc;
|
|
@@ -474,6 +650,31 @@ window.__ModuleLoader__.load({
|
|
|
474
650
|
if (!sessionId || !rpc) return null;
|
|
475
651
|
var info = modeInfo(mode);
|
|
476
652
|
var loaded = mode !== null;
|
|
653
|
+
var isAuto = loaded && mode === "auto";
|
|
654
|
+
|
|
655
|
+
if (isAuto) ensureFlowStyle();
|
|
656
|
+
|
|
657
|
+
// auto 档的边框/背景/文字色均由 .dsh-mem-flow 提供(双层背景画流光边 + 分主题文字),
|
|
658
|
+
// inline 不能设置这些——inline 优先级会盖掉 class 里的流光
|
|
659
|
+
var pillStyle = {
|
|
660
|
+
display: "inline-flex",
|
|
661
|
+
alignItems: "center",
|
|
662
|
+
gap: 4,
|
|
663
|
+
height: 24,
|
|
664
|
+
padding: "0 10px",
|
|
665
|
+
borderRadius: 999,
|
|
666
|
+
fontSize: 12,
|
|
667
|
+
fontWeight: 500,
|
|
668
|
+
lineHeight: "20px",
|
|
669
|
+
cursor: "pointer",
|
|
670
|
+
};
|
|
671
|
+
if (isAuto) {
|
|
672
|
+
pillStyle.boxShadow = "0 0 12px rgba(56,189,248,0.30)";
|
|
673
|
+
} else {
|
|
674
|
+
pillStyle.border = "1px solid " + (loaded ? info.color + "66" : "var(--dsw-alias-border-secondary, #ccc)");
|
|
675
|
+
pillStyle.background = loaded ? info.color + "14" : "var(--dsw-alias-bg-secondary, #f6f8fa)";
|
|
676
|
+
pillStyle.color = loaded ? info.color : "var(--dsh-alias-label-tertiary, #888)";
|
|
677
|
+
}
|
|
477
678
|
|
|
478
679
|
return react.createElement(
|
|
479
680
|
"div",
|
|
@@ -484,21 +685,8 @@ window.__ModuleLoader__.load({
|
|
|
484
685
|
type: "button",
|
|
485
686
|
title: "本会话记忆档位(点击切换)",
|
|
486
687
|
onClick: function () { setOpen(!open); },
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
alignItems: "center",
|
|
490
|
-
gap: 4,
|
|
491
|
-
height: 24,
|
|
492
|
-
padding: "0 10px",
|
|
493
|
-
borderRadius: 999,
|
|
494
|
-
fontSize: 12,
|
|
495
|
-
fontWeight: 500,
|
|
496
|
-
lineHeight: "20px",
|
|
497
|
-
cursor: "pointer",
|
|
498
|
-
border: "1px solid " + (loaded ? info.color + "66" : "var(--dsw-alias-border-secondary, #ccc)"),
|
|
499
|
-
background: loaded ? info.color + "14" : "var(--dsw-alias-bg-secondary, #f6f8fa)",
|
|
500
|
-
color: loaded ? info.color : "var(--dsh-alias-label-tertiary, #888)",
|
|
501
|
-
},
|
|
688
|
+
className: isAuto ? "dsh-mem-flow" : null,
|
|
689
|
+
style: pillStyle,
|
|
502
690
|
},
|
|
503
691
|
"记忆·",
|
|
504
692
|
react.createElement("span", null, loaded ? info.label : "…"),
|
|
@@ -513,6 +701,188 @@ window.__ModuleLoader__.load({
|
|
|
513
701
|
);
|
|
514
702
|
}
|
|
515
703
|
|
|
704
|
+
// ── 重建面板:从 L0 重导 L1/L2/L3(确认弹窗 + 进度 + 取消;Light/Dark 双主题走 class) ──
|
|
705
|
+
var RB_PHASE_LABEL = {
|
|
706
|
+
preparing: "准备中(归档旧数据 · 清空检索库)",
|
|
707
|
+
distilling: "分块蒸馏中",
|
|
708
|
+
finalizing: "收尾(强制 L2 场景 + L3 画像)",
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
function RebuildPanel(props) {
|
|
712
|
+
var rpc = props.rpc;
|
|
713
|
+
var rbState = react.useState(null);
|
|
714
|
+
var rb = rbState[0];
|
|
715
|
+
var setRb = rbState[1];
|
|
716
|
+
var confirmState = react.useState(false);
|
|
717
|
+
var confirmOpen = confirmState[0];
|
|
718
|
+
var setConfirmOpen = confirmState[1];
|
|
719
|
+
var busyState = react.useState(false);
|
|
720
|
+
var busy = busyState[0];
|
|
721
|
+
var setBusy = busyState[1];
|
|
722
|
+
var errState = react.useState(null);
|
|
723
|
+
var rbError = errState[0];
|
|
724
|
+
var setRbError = errState[1];
|
|
725
|
+
|
|
726
|
+
var refresh = react.useCallback(function () {
|
|
727
|
+
rpc("dsh-memory/rebuild-status", {})
|
|
728
|
+
.then(function (r) {
|
|
729
|
+
if (r && r.ok) setRb(r.value);
|
|
730
|
+
})
|
|
731
|
+
.catch(function () {});
|
|
732
|
+
}, [rpc]);
|
|
733
|
+
|
|
734
|
+
react.useEffect(function () { refresh(); }, [refresh]);
|
|
735
|
+
|
|
736
|
+
// 运行中 1.5s 高频轮询进度;空闲不轮询(重新打开 Tab 时挂载刷新一次)
|
|
737
|
+
var running = !!(rb && rb.running);
|
|
738
|
+
react.useEffect(function () {
|
|
739
|
+
if (!running) return;
|
|
740
|
+
var timer = setInterval(refresh, 1500);
|
|
741
|
+
return function () { clearInterval(timer); };
|
|
742
|
+
}, [running, refresh]);
|
|
743
|
+
|
|
744
|
+
if (!rb || rb.supported === false) return null;
|
|
745
|
+
ensureFlowStyle();
|
|
746
|
+
|
|
747
|
+
var start = function () {
|
|
748
|
+
setBusy(true);
|
|
749
|
+
setRbError(null);
|
|
750
|
+
rpc("dsh-memory/rebuild-start", {})
|
|
751
|
+
.then(function (r) {
|
|
752
|
+
setBusy(false);
|
|
753
|
+
if (r && r.ok) {
|
|
754
|
+
setConfirmOpen(false);
|
|
755
|
+
setRb(r.value);
|
|
756
|
+
} else {
|
|
757
|
+
setRbError(r && r.error ? r.error.message : "启动失败");
|
|
758
|
+
}
|
|
759
|
+
})
|
|
760
|
+
.catch(function (e) {
|
|
761
|
+
setBusy(false);
|
|
762
|
+
setRbError(String((e && e.message) || e));
|
|
763
|
+
});
|
|
764
|
+
};
|
|
765
|
+
var cancel = function () {
|
|
766
|
+
setBusy(true);
|
|
767
|
+
rpc("dsh-memory/rebuild-cancel", {})
|
|
768
|
+
.then(function (r) {
|
|
769
|
+
setBusy(false);
|
|
770
|
+
if (r && r.ok) setRb(r.value);
|
|
771
|
+
})
|
|
772
|
+
.catch(function () {
|
|
773
|
+
setBusy(false);
|
|
774
|
+
});
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
var empty = !running && (rb.messageCount === 0 || rb.estCalls === 0);
|
|
778
|
+
var pct = rb.total > 0 ? Math.round((rb.done / rb.total) * 100) : 0;
|
|
779
|
+
|
|
780
|
+
var lastNote = null;
|
|
781
|
+
if (!running && rb.phase === "done") {
|
|
782
|
+
lastNote =
|
|
783
|
+
"上次重建:完成(" + rb.done + "/" + rb.total + " 会话,产出 " + rb.recordsBuilt + " 条记录)" +
|
|
784
|
+
(rb.finishedAt ? " · " + fmtTime(new Date(rb.finishedAt).toISOString()) : "");
|
|
785
|
+
} else if (!running && rb.phase === "cancelled") {
|
|
786
|
+
lastNote = "上次重建:已取消(完成 " + rb.done + "/" + rb.total + " 会话,已重建部分保留)";
|
|
787
|
+
} else if (!running && rb.phase === "failed") {
|
|
788
|
+
lastNote = "上次重建:失败 — " + (rb.error || "未知错误");
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return react.createElement(
|
|
792
|
+
"div", { className: "dsh-mem-rb-card" },
|
|
793
|
+
react.createElement(
|
|
794
|
+
"div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" } },
|
|
795
|
+
react.createElement("div", { style: { fontWeight: 600, whiteSpace: "nowrap" } }, "重建记忆"),
|
|
796
|
+
react.createElement(
|
|
797
|
+
"div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 } },
|
|
798
|
+
running
|
|
799
|
+
? (RB_PHASE_LABEL[rb.phase] || rb.phase) + " · " + rb.done + "/" + rb.total + " 会话(" + pct + "%)"
|
|
800
|
+
: "从 L0 原始对话重新蒸馏 L1/L2/L3;旧数据先归档(不删除)",
|
|
801
|
+
),
|
|
802
|
+
running
|
|
803
|
+
? react.createElement("button", {
|
|
804
|
+
type: "button",
|
|
805
|
+
className: "dsh-mem-rb-btn",
|
|
806
|
+
disabled: busy || rb.cancelRequested,
|
|
807
|
+
onClick: cancel,
|
|
808
|
+
}, rb.cancelRequested ? "取消中…" : "取消重建")
|
|
809
|
+
: react.createElement("button", {
|
|
810
|
+
type: "button",
|
|
811
|
+
className: "dsh-mem-rb-btn dsh-mem-rb-danger",
|
|
812
|
+
disabled: busy || empty,
|
|
813
|
+
title: empty ? "L0 无消息,无可重建内容" : "重新蒸馏全部记忆",
|
|
814
|
+
onClick: function () { setConfirmOpen(true); },
|
|
815
|
+
}, busy ? "…" : "开始重建"),
|
|
816
|
+
),
|
|
817
|
+
running
|
|
818
|
+
? react.createElement(
|
|
819
|
+
"div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 } },
|
|
820
|
+
react.createElement(
|
|
821
|
+
"div", { className: "dsh-mem-rb-bar" },
|
|
822
|
+
react.createElement("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }),
|
|
823
|
+
),
|
|
824
|
+
react.createElement(
|
|
825
|
+
"span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" } },
|
|
826
|
+
"产出 " + rb.recordsBuilt + " 条",
|
|
827
|
+
),
|
|
828
|
+
)
|
|
829
|
+
: null,
|
|
830
|
+
lastNote
|
|
831
|
+
? react.createElement("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 } }, lastNote)
|
|
832
|
+
: null,
|
|
833
|
+
rbError
|
|
834
|
+
? react.createElement("div", { style: { marginTop: 8, fontSize: 12, color: "#cf222e" } }, rbError)
|
|
835
|
+
: null,
|
|
836
|
+
confirmOpen
|
|
837
|
+
? react.createElement(
|
|
838
|
+
"div", {
|
|
839
|
+
className: "dsh-mem-rb-overlay",
|
|
840
|
+
onClick: function (e) {
|
|
841
|
+
if (e.target === e.currentTarget) setConfirmOpen(false);
|
|
842
|
+
},
|
|
843
|
+
},
|
|
844
|
+
react.createElement(
|
|
845
|
+
"div", { className: "dsh-mem-rb-modal" },
|
|
846
|
+
react.createElement(
|
|
847
|
+
"div", { style: { fontSize: 15, fontWeight: 600, marginBottom: 10 } },
|
|
848
|
+
"确认重建全部记忆?",
|
|
849
|
+
),
|
|
850
|
+
react.createElement(
|
|
851
|
+
"div", null,
|
|
852
|
+
"将以 L0 原始对话为事实源重新蒸馏:",
|
|
853
|
+
react.createElement("b", null, rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息"),
|
|
854
|
+
",预计 ≥" + rb.estCalls + " 次蒸馏调用。",
|
|
855
|
+
),
|
|
856
|
+
react.createElement(
|
|
857
|
+
"div", { style: { marginTop: 8 } },
|
|
858
|
+
"现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。",
|
|
859
|
+
),
|
|
860
|
+
react.createElement(
|
|
861
|
+
"div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 16 } },
|
|
862
|
+
react.createElement(
|
|
863
|
+
"button", {
|
|
864
|
+
type: "button",
|
|
865
|
+
className: "dsh-mem-rb-btn",
|
|
866
|
+
onClick: function () { setConfirmOpen(false); },
|
|
867
|
+
},
|
|
868
|
+
"取消",
|
|
869
|
+
),
|
|
870
|
+
react.createElement(
|
|
871
|
+
"button", {
|
|
872
|
+
type: "button",
|
|
873
|
+
className: "dsh-mem-rb-btn dsh-mem-rb-primary",
|
|
874
|
+
disabled: busy,
|
|
875
|
+
onClick: start,
|
|
876
|
+
},
|
|
877
|
+
busy ? "启动中…" : "开始重建",
|
|
878
|
+
),
|
|
879
|
+
),
|
|
880
|
+
),
|
|
881
|
+
)
|
|
882
|
+
: null,
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
|
|
516
886
|
// ── Tab:概览(开关面板 + 计数) ──
|
|
517
887
|
function OverviewTab(props) {
|
|
518
888
|
var rpc = props.rpc;
|
|
@@ -630,11 +1000,37 @@ window.__ModuleLoader__.load({
|
|
|
630
1000
|
disabled: !master,
|
|
631
1001
|
onChange: function (v) { toggle("recall", v); },
|
|
632
1002
|
}),
|
|
1003
|
+
settingsData.effort
|
|
1004
|
+
? react.createElement(
|
|
1005
|
+
"div",
|
|
1006
|
+
{ style: S.switchRow },
|
|
1007
|
+
react.createElement(Segmented, {
|
|
1008
|
+
value: settingsData.effort.current,
|
|
1009
|
+
options: [
|
|
1010
|
+
{ key: "", label: "跟随配置" },
|
|
1011
|
+
{ key: "off", label: "off" },
|
|
1012
|
+
{ key: "high", label: "high" },
|
|
1013
|
+
{ key: "max", label: "max" },
|
|
1014
|
+
],
|
|
1015
|
+
disabled: !master,
|
|
1016
|
+
onChange: function (v) { toggle("reasoningEffort", v); },
|
|
1017
|
+
}),
|
|
1018
|
+
react.createElement("div", null,
|
|
1019
|
+
react.createElement("div", { style: S.switchLabel }, "蒸馏思考"),
|
|
1020
|
+
react.createElement(
|
|
1021
|
+
"div",
|
|
1022
|
+
{ style: S.switchDesc },
|
|
1023
|
+
"当前生效 " + (settingsData.effort.effective || "(不传,跟随模型默认)") +
|
|
1024
|
+
(settingsData.effort.current ? "" : "(来自部署配置 llm.reasoningEffort)"),
|
|
1025
|
+
)),
|
|
1026
|
+
)
|
|
1027
|
+
: null,
|
|
633
1028
|
ceilingNote
|
|
634
1029
|
? react.createElement("p", { style: S.hint }, ceilingNote)
|
|
635
1030
|
: null,
|
|
636
1031
|
)
|
|
637
1032
|
: null,
|
|
1033
|
+
react.createElement(RebuildPanel, { rpc: rpc }),
|
|
638
1034
|
error
|
|
639
1035
|
? react.createElement("div", { style: S.error }, "获取状态失败:" + error)
|
|
640
1036
|
: !stats
|