dsh-prime-memory 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -25,13 +25,14 @@ var __defProp = Object.defineProperty;
25
25
  // client/src/entry.tsx
26
26
  var entry_exports = {};
27
27
  __export(entry_exports, {
28
+ SETTINGS_SEAT: () => SETTINGS_SEAT,
28
29
  apply: () => apply,
29
30
  inject: () => inject
30
31
  });
31
32
  module.exports = __toCommonJS(entry_exports);
32
33
 
33
34
  // client/src/panel.tsx
34
- var import_react16 = require("react");
35
+ var import_react17 = require("react");
35
36
 
36
37
  // client/src/sidebar-icon.ts
37
38
  var BOOK_ICON_SVG = '<svg data-mem-icon="1" viewBox="0 0 16 16" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex-shrink:0"><path d="M8 3.4C6.6 2.5 4.6 2.4 2.9 3.1v9.3c1.7-.7 3.7-.6 5.1.3 1.4-.9 3.4-1 5.1-.3V3.1C11.4 2.4 9.4 2.5 8 3.4Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M8 3.4v9.3" stroke="currentColor" stroke-width="1.2"/></svg>';
@@ -501,59 +502,46 @@ var __defProp = Object.defineProperty;
501
502
  document.head.appendChild(el);
502
503
  }
503
504
 
504
- // client/src/tabs/CostTab.tsx
505
+ // client/src/tabs/ConflictsTab.tsx
505
506
  var import_react2 = require("react");
506
507
 
507
- // client/src/ui/controls.tsx
508
- var import_jsx_runtime = require("react/jsx-runtime");
509
- function Switch(props) {
510
- const on = !!props.checked;
511
- const disabled = !!props.disabled;
512
- const base = { ...S.switch, ...on ? S.switchOn : S.switchOff, ...disabled ? S.switchDisabled : null };
513
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
514
- "div",
515
- {
516
- style: base,
517
- onClick: () => {
518
- if (!disabled && props.onChange) props.onChange(!on);
519
- },
520
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...S.knob, left: on ? 18 : 2 } })
521
- }
522
- );
508
+ // client/src/format.ts
509
+ var TYPE_LABELS = {
510
+ persona: "画像偏好",
511
+ episodic: "客观事件",
512
+ instruction: "全局指令",
513
+ work_fact: "工作事实",
514
+ work_task: "工作任务",
515
+ work_method: "工作方法",
516
+ work_artifact: "工作资产"
517
+ };
518
+ function fmtTime(iso) {
519
+ if (!iso) return "-";
520
+ try {
521
+ return new Date(iso).toLocaleString();
522
+ } catch {
523
+ return String(iso);
524
+ }
523
525
  }
524
- function SwitchRow(props) {
525
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: S.switchRow, children: [
526
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Switch, { checked: props.checked, disabled: props.disabled, onChange: props.onChange }),
527
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
528
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: S.switchLabel, children: props.label }),
529
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: S.switchDesc, children: props.desc || "" })
530
- ] })
531
- ] });
526
+ function fmtAgo(iso) {
527
+ if (!iso) return null;
528
+ try {
529
+ const t = new Date(iso).getTime();
530
+ if (!t) return null;
531
+ let s = Math.floor((Date.now() - t) / 1e3);
532
+ if (s < 0) s = 0;
533
+ if (s < 45) return "刚刚";
534
+ if (s < 3600) return Math.floor(s / 60) + " 分钟前";
535
+ if (s < 86400) return Math.floor(s / 3600) + " 小时前";
536
+ return Math.floor(s / 86400) + " 天前";
537
+ } catch {
538
+ return null;
539
+ }
532
540
  }
533
- function Segmented(props) {
534
- const value = props.value;
535
- const disabled = !!props.disabled;
536
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...S.seg, ...disabled ? S.switchDisabled : null }, children: props.options.map((opt, i) => {
537
- const on = opt.key === value;
538
- const optDisabled = disabled || !!opt.disabled;
539
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
540
- "span",
541
- {
542
- title: opt.disabledTitle || opt.title || "",
543
- style: {
544
- ...S.segBtn,
545
- ...on ? S.segBtnOn : null,
546
- ...i === props.options.length - 1 ? { borderRight: "none" } : null,
547
- ...optDisabled ? { cursor: "not-allowed", opacity: 0.45 } : null
548
- },
549
- onClick: () => {
550
- if (!optDisabled && !on && props.onChange) props.onChange(opt.key);
551
- },
552
- children: opt.label
553
- },
554
- opt.key
555
- );
556
- }) });
541
+ function fmtMB(bytes) {
542
+ if (!bytes || bytes <= 0) return "0MB";
543
+ if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + "KB";
544
+ return (bytes / (1024 * 1024)).toFixed(bytes < 100 * 1024 * 1024 ? 1 : 0) + "MB";
557
545
  }
558
546
 
559
547
  // client/src/ui/primitives.tsx
@@ -615,8 +603,201 @@ var __defProp = Object.defineProperty;
615
603
  );
616
604
  }
617
605
 
606
+ // client/src/tabs/ConflictsTab.tsx
607
+ var import_jsx_runtime = require("react/jsx-runtime");
608
+ var POLL_MS = 1e4;
609
+ var GONE = "(该记录已不在检索库:被合并或删除掉了)";
610
+ function ConflictsTab(props) {
611
+ const rpc = props.rpc;
612
+ const [view, setView] = (0, import_react2.useState)(null);
613
+ const [error, setError] = (0, import_react2.useState)(null);
614
+ const [note, setNote] = (0, import_react2.useState)(null);
615
+ const [busy, setBusy] = (0, import_react2.useState)(null);
616
+ const load = (0, import_react2.useCallback)(() => {
617
+ rpc("dsh-memory/conflicts", {}).then((r) => {
618
+ if (r && r.ok) {
619
+ setView(r.value);
620
+ setError(null);
621
+ } else setError(r && r.error ? r.error.message : "RPC error");
622
+ }).catch((e) => {
623
+ setError(String(e && e.message || e));
624
+ });
625
+ }, [rpc]);
626
+ (0, import_react2.useEffect)(() => {
627
+ load();
628
+ const timer = setInterval(load, POLL_MS);
629
+ return () => {
630
+ clearInterval(timer);
631
+ };
632
+ }, [load]);
633
+ const resolve = (pair, outcome) => {
634
+ const doomed = outcome === "winner" ? pair.loser_content || GONE : outcome === "loser" ? pair.winner_content || GONE : null;
635
+ if (doomed !== null) {
636
+ const ok = window.confirm(
637
+ `裁决这一对?
638
+
639
+ 将要退场的记忆:
640
+ 「${doomed}」
641
+
642
+ 它会从检索库移除(事实源保留,可从 L0 重建找回)。本操作不可覆盖。`
643
+ );
644
+ if (!ok) return;
645
+ }
646
+ setBusy(pair.pair_id);
647
+ setNote(null);
648
+ rpc("dsh-memory/conflict-resolve", { pairId: pair.pair_id, outcome }).then((r) => {
649
+ if (r && r.ok) {
650
+ const v = r.value;
651
+ setNote(v.notice ?? `已裁决 ${v.pair_id}:${v.outcome}${v.removed_record_id ? ",退场 " + v.removed_record_id : ",未移除记录"}`);
652
+ load();
653
+ } else {
654
+ setError(r && r.error ? r.error.message : "裁决失败");
655
+ }
656
+ }).catch((e) => {
657
+ setError(String(e && e.message || e));
658
+ }).finally(() => {
659
+ setBusy(null);
660
+ });
661
+ };
662
+ const items = view?.items ?? [];
663
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
664
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
665
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: S.muted, children: view === null ? "加载中…" : view.enabled ? `待裁决 ${view.total} 对` : "矛盾冻结未开启" }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: S.grow }),
667
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NButton, { onClick: load, children: "刷新" })
668
+ ] }),
669
+ error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: S.error, children: error }) : null,
670
+ note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: S.hint, children: note }) : null,
671
+ view !== null && !view.enabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: S.intro, children: [
672
+ view.notice ?? "矛盾冻结未开启。",
673
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
674
+ "矛盾冻结是**opt-in**:它把裁决权交还给人,代价是冲突会一直停着等你处理。 确认要接手这些裁决,再去「概览」打开它 —— 打开后已停放的队列会立刻显示在这里。"
675
+ ] }) : null,
676
+ view !== null && view.enabled && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: S.intro, children: "没有待裁决的冲突对。新记忆入库时若与旧记忆矛盾且冻结已开启,那一对会停到这里。" }) : null,
677
+ items.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConflictCard, { pair: p, busy: busy === p.pair_id, onResolve: resolve }, p.pair_id))
678
+ ] });
679
+ }
680
+ function ConflictCard(props) {
681
+ const p = props.pair;
682
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-mem-card", style: S.card, children: [
683
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: S.cardHead, children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: S.muted, children: "pair " + p.pair_id.slice(0, 12) }),
685
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: S.muted, children: fmtTime(p.created_at) }),
686
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: S.grow }),
687
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: S.muted, title: "产生该冻结的蒸馏批次 id(可用 memory_receipts 追这一轮判了什么)", children: "run " + p.run_id.slice(0, 12) })
688
+ ] }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
690
+ Side,
691
+ {
692
+ label: "LLM 建议:胜方",
693
+ accent: true,
694
+ id: p.winner_id,
695
+ content: p.winner_content
696
+ }
697
+ ),
698
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Side, { label: "LLM 建议:败方", id: p.loser_id, content: p.loser_content }),
699
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...S.flexRow, marginTop: 8 }, children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
701
+ NButton,
702
+ {
703
+ disabled: props.busy,
704
+ title: "判 LLM 建议的胜方为真;败方从检索库退场",
705
+ onClick: () => {
706
+ props.onResolve(p, "winner");
707
+ },
708
+ children: props.busy ? "裁决中…" : "判胜方为真"
709
+ }
710
+ ),
711
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
712
+ NButton,
713
+ {
714
+ disabled: props.busy,
715
+ title: "判败方为真;胜方从检索库退场",
716
+ onClick: () => {
717
+ props.onResolve(p, "loser");
718
+ },
719
+ children: "判败方为真"
720
+ }
721
+ ),
722
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
723
+ NButton,
724
+ {
725
+ disabled: props.busy,
726
+ title: "判两者其实是各自独立的事实(LLM 判错了);两条都保留,不删除",
727
+ onClick: () => {
728
+ props.onResolve(p, "both");
729
+ },
730
+ children: "两者都保留"
731
+ }
732
+ )
733
+ ] })
734
+ ] });
735
+ }
736
+ function Side(props) {
737
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 6 }, children: [
738
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...S.muted, fontWeight: props.accent ? 600 : void 0 }, children: props.label }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: S.content, children: props.content || GONE }),
740
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...S.muted, fontFamily: "ui-monospace, Consolas, monospace" }, children: props.id })
741
+ ] });
742
+ }
743
+
618
744
  // client/src/tabs/CostTab.tsx
745
+ var import_react3 = require("react");
746
+
747
+ // client/src/ui/controls.tsx
619
748
  var import_jsx_runtime2 = require("react/jsx-runtime");
749
+ function Switch(props) {
750
+ const on = !!props.checked;
751
+ const disabled = !!props.disabled;
752
+ const base = { ...S.switch, ...on ? S.switchOn : S.switchOff, ...disabled ? S.switchDisabled : null };
753
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
754
+ "div",
755
+ {
756
+ style: base,
757
+ onClick: () => {
758
+ if (!disabled && props.onChange) props.onChange(!on);
759
+ },
760
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { ...S.knob, left: on ? 18 : 2 } })
761
+ }
762
+ );
763
+ }
764
+ function SwitchRow(props) {
765
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: S.switchRow, children: [
766
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Switch, { checked: props.checked, disabled: props.disabled, onChange: props.onChange }),
767
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
768
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.switchLabel, children: props.label }),
769
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.switchDesc, children: props.desc || "" })
770
+ ] })
771
+ ] });
772
+ }
773
+ function Segmented(props) {
774
+ const value = props.value;
775
+ const disabled = !!props.disabled;
776
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...S.seg, ...disabled ? S.switchDisabled : null }, children: props.options.map((opt, i) => {
777
+ const on = opt.key === value;
778
+ const optDisabled = disabled || !!opt.disabled;
779
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
780
+ "span",
781
+ {
782
+ title: opt.disabledTitle || opt.title || "",
783
+ style: {
784
+ ...S.segBtn,
785
+ ...on ? S.segBtnOn : null,
786
+ ...i === props.options.length - 1 ? { borderRight: "none" } : null,
787
+ ...optDisabled ? { cursor: "not-allowed", opacity: 0.45 } : null
788
+ },
789
+ onClick: () => {
790
+ if (!optDisabled && !on && props.onChange) props.onChange(opt.key);
791
+ },
792
+ children: opt.label
793
+ },
794
+ opt.key
795
+ );
796
+ }) });
797
+ }
798
+
799
+ // client/src/tabs/CostTab.tsx
800
+ var import_jsx_runtime3 = require("react/jsx-runtime");
620
801
  function renderCostChart(buckets, models, maxY, fmtDate, fmtInt, palette) {
621
802
  const W = 600;
622
803
  const H = 200;
@@ -631,17 +812,17 @@ var __defProp = Object.defineProperty;
631
812
  const y = (v) => T + ih - v / maxY * ih;
632
813
  const yTicks = [0, maxY / 2, maxY];
633
814
  const xIdx = n > 2 ? [0, Math.floor((n - 1) / 2), n - 1] : n === 2 ? [0, 1] : [0];
634
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 " + W + " " + H, style: { width: "100%", height: "auto", display: "block" }, children: [
635
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: L, y1: y(0), x2: W - R, y2: y(0), stroke: "var(--dsh-mem-border)", strokeWidth: 1 }),
815
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { viewBox: "0 0 " + W + " " + H, style: { width: "100%", height: "auto", display: "block" }, children: [
816
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: L, y1: y(0), x2: W - R, y2: y(0), stroke: "var(--dsh-mem-border)", strokeWidth: 1 }),
636
817
  yTicks.map((v) => {
637
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x: L - 6, y: y(v) + 4, textAnchor: "end", fontSize: 10, fill: "var(--dsh-mem-text-3)", children: fmtInt(v) }, "yt" + v);
818
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { x: L - 6, y: y(v) + 4, textAnchor: "end", fontSize: 10, fill: "var(--dsh-mem-text-3)", children: fmtInt(v) }, "yt" + v);
638
819
  }),
639
820
  xIdx.map((i) => {
640
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x: x(i), y: H - 8, textAnchor: "middle", fontSize: 10, fill: "var(--dsh-mem-text-3)", children: fmtDate(buckets[i] ? buckets[i].ts : 0) }, "xt" + i);
821
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { x: x(i), y: H - 8, textAnchor: "middle", fontSize: 10, fill: "var(--dsh-mem-text-3)", children: fmtDate(buckets[i] ? buckets[i].ts : 0) }, "xt" + i);
641
822
  }),
642
823
  models.map((m, mi) => {
643
824
  const pts = buckets.map((b, i) => x(i) + "," + y(b.byModel[m] || 0)).join(" ");
644
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
825
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
645
826
  "polyline",
646
827
  {
647
828
  points: pts,
@@ -685,13 +866,13 @@ var __defProp = Object.defineProperty;
685
866
  var tdStyle = { fontSize: 12.5, color: "var(--dsh-mem-text-1)", textAlign: "right", padding: "4px 10px", fontFamily: "ui-monospace, Consolas, monospace" };
686
867
  function CostTab(props) {
687
868
  const rpc = props.rpc;
688
- const [data, setData] = (0, import_react2.useState)(null);
689
- const [error, setError] = (0, import_react2.useState)(null);
690
- const [granularity, setGranularity] = (0, import_react2.useState)("day");
691
- const [layer, setLayer] = (0, import_react2.useState)("");
692
- const [rangeDays, setRangeDays] = (0, import_react2.useState)(0);
693
- const [rangeOpen, setRangeOpen] = (0, import_react2.useState)(false);
694
- const load = (0, import_react2.useCallback)(() => {
869
+ const [data, setData] = (0, import_react3.useState)(null);
870
+ const [error, setError] = (0, import_react3.useState)(null);
871
+ const [granularity, setGranularity] = (0, import_react3.useState)("day");
872
+ const [layer, setLayer] = (0, import_react3.useState)("");
873
+ const [rangeDays, setRangeDays] = (0, import_react3.useState)(0);
874
+ const [rangeOpen, setRangeOpen] = (0, import_react3.useState)(false);
875
+ const load = (0, import_react3.useCallback)(() => {
695
876
  setError(null);
696
877
  rpc("dsh-memory/token-cost", {
697
878
  granularity,
@@ -703,7 +884,7 @@ var __defProp = Object.defineProperty;
703
884
  setError(String(e && e.message || e));
704
885
  });
705
886
  }, [rpc, granularity, rangeDays]);
706
- (0, import_react2.useEffect)(() => {
887
+ (0, import_react3.useEffect)(() => {
707
888
  load();
708
889
  const timer = setInterval(load, 5e3);
709
890
  return () => {
@@ -776,13 +957,13 @@ var __defProp = Object.defineProperty;
776
957
  });
777
958
  const cell = (lc, r, pick) => {
778
959
  const w = lc.win[r];
779
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: w ? fmtInt(pick(w)) : "0" }, r);
960
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { style: tdStyle, children: w ? fmtInt(pick(w)) : "0" }, r);
780
961
  };
781
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
782
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
783
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Segmented, { value: layer, options: LAYER_OPTS, onChange: setLayer }),
784
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Segmented, { value: granularity, options: GRAN_OPTS, onChange: setGranularity }),
785
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
962
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
963
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
964
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Segmented, { value: layer, options: LAYER_OPTS, onChange: setLayer }),
965
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Segmented, { value: granularity, options: GRAN_OPTS, onChange: setGranularity }),
966
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
786
967
  NButton,
787
968
  {
788
969
  onClick: () => {
@@ -791,12 +972,12 @@ var __defProp = Object.defineProperty;
791
972
  children: rangeDays > 0 ? "近 " + rangeDays + " 天" : "近N天"
792
973
  }
793
974
  ),
794
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.grow }),
795
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NButton, { onClick: load, children: "刷新" })
975
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.grow }),
976
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(NButton, { onClick: load, children: "刷新" })
796
977
  ] }),
797
- rangeOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
798
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: S.muted, children: "展示近 N 天(正整数,清空=默认窗口;超出保留期后端自动回退)" }),
799
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
978
+ rangeOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
979
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.muted, children: "展示近 N 天(正整数,清空=默认窗口;超出保留期后端自动回退)" }),
980
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
800
981
  NInput,
801
982
  {
802
983
  value: rangeDays === 0 ? "" : String(rangeDays),
@@ -814,100 +995,100 @@ var __defProp = Object.defineProperty;
814
995
  }
815
996
  )
816
997
  ] }) : null,
817
- error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.error, children: "成本读取失败:" + error }) : null,
818
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.panelLabel, children: "成本趋势(按模型)" }),
819
- buckets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
998
+ error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.error, children: "成本读取失败:" + error }) : null,
999
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.panelLabel, children: "成本趋势(按模型)" }),
1000
+ buckets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
820
1001
  renderCostChart(buckets, models, maxY, fmtDate, fmtInt, PALETTE),
821
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "4px 12px", margin: "6px 0 14px" }, children: models.map((m, mi) => {
822
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1002
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "4px 12px", margin: "6px 0 14px" }, children: models.map((m, mi) => {
1003
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
823
1004
  "span",
824
1005
  {
825
1006
  style: { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 12, color: "var(--dsh-mem-text-2)" },
826
1007
  children: [
827
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { width: 10, height: 10, borderRadius: 4, background: PALETTE[mi % PALETTE.length], display: "inline-block" } }),
1008
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { width: 10, height: 10, borderRadius: 4, background: PALETTE[mi % PALETTE.length], display: "inline-block" } }),
828
1009
  m
829
1010
  ]
830
1011
  },
831
1012
  "lg" + m
832
1013
  );
833
1014
  }) })
834
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: S.muted, children: data ? "暂无成本数据(触发一次蒸馏后这里会出现趋势)。" : "加载中…" }),
835
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.panelLabel, children: "层级成本(输出 token)" }),
836
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", marginBottom: 14 }, children: [
837
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
838
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thFirst, children: "层级" }),
1015
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: S.muted, children: data ? "暂无成本数据(触发一次蒸馏后这里会出现趋势)。" : "加载中…" }),
1016
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.panelLabel, children: "层级成本(输出 token)" }),
1017
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", marginBottom: 14 }, children: [
1018
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1019
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { style: thFirst, children: "层级" }),
839
1020
  RANGES.map((r) => {
840
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, children: RANGE_LABELS[r] }, r);
1021
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { style: thStyle, children: RANGE_LABELS[r] }, r);
841
1022
  })
842
1023
  ] }) }),
843
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: layerTable.map((lc) => {
844
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
845
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdFirst, children: lc.layer.toUpperCase() }),
1024
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: layerTable.map((lc) => {
1025
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1026
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { style: tdFirst, children: lc.layer.toUpperCase() }),
846
1027
  RANGES.map((r) => cell(lc, r, (w) => w.outputTokens))
847
1028
  ] }, lc.layer);
848
1029
  }) })
849
1030
  ] }),
850
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.panelLabel, children: "层级成本(单次 avg)" }),
851
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", marginBottom: 14 }, children: [
852
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
853
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thFirst, children: "层级" }),
1031
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.panelLabel, children: "层级成本(单次 avg)" }),
1032
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", marginBottom: 14 }, children: [
1033
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1034
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { style: thFirst, children: "层级" }),
854
1035
  RANGES.map((r) => {
855
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, children: RANGE_LABELS[r] + "-avg" }, r);
1036
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { style: thStyle, children: RANGE_LABELS[r] + "-avg" }, r);
856
1037
  })
857
1038
  ] }) }),
858
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: layerTable.map((lc) => {
859
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
860
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdFirst, children: lc.layer.toUpperCase() }),
1039
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: layerTable.map((lc) => {
1040
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1041
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { style: tdFirst, children: lc.layer.toUpperCase() }),
861
1042
  RANGES.map((r) => cell(lc, r, (w) => w.avgOutputTokens))
862
1043
  ] }, lc.layer);
863
1044
  }) })
864
1045
  ] }),
865
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.panelLabel, children: "层级成本(单次 median)" }),
866
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", marginBottom: 14 }, children: [
867
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
868
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thFirst, children: "层级" }),
1046
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.panelLabel, children: "层级成本(单次 median)" }),
1047
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", marginBottom: 14 }, children: [
1048
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1049
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { style: thFirst, children: "层级" }),
869
1050
  RANGES.map((r) => {
870
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, children: RANGE_LABELS[r] + "-median" }, r);
1051
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { style: thStyle, children: RANGE_LABELS[r] + "-median" }, r);
871
1052
  })
872
1053
  ] }) }),
873
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: layerTable.map((lc) => {
874
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
875
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdFirst, children: lc.layer.toUpperCase() }),
1054
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: layerTable.map((lc) => {
1055
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
1056
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { style: tdFirst, children: lc.layer.toUpperCase() }),
876
1057
  RANGES.map((r) => cell(lc, r, (w) => w.medianOutputTokens))
877
1058
  ] }, lc.layer);
878
1059
  }) })
879
1060
  ] }),
880
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.panelLabel, children: "时间窗口总览" }),
881
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.statGrid, children: windows.map((w) => {
882
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
883
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.statNum, children: fmtInt(w.outputTokens + w.reasoningTokens) }),
884
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.statLabel, children: RANGE_LABELS[w.range] + " · 总输出 token" }),
885
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.muted, children: "文字 " + fmtInt(w.outputTokens) + " · 思考 " + fmtInt(w.reasoningTokens) + " · " + w.calls + " 次调用" })
1061
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.panelLabel, children: "时间窗口总览" }),
1062
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.statGrid, children: windows.map((w) => {
1063
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
1064
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.statNum, children: fmtInt(w.outputTokens + w.reasoningTokens) }),
1065
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.statLabel, children: RANGE_LABELS[w.range] + " · 总输出 token" }),
1066
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.muted, children: "文字 " + fmtInt(w.outputTokens) + " · 思考 " + fmtInt(w.reasoningTokens) + " · " + w.calls + " 次调用" })
886
1067
  ] }, w.range);
887
1068
  }) }),
888
- byModel.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
889
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: S.panelLabel, children: "按模型(累计)" }),
1069
+ byModel.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
1070
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.panelLabel, children: "按模型(累计)" }),
890
1071
  byModel.map((m) => {
891
1072
  const label = fmtModel(m.provider, m.model);
892
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: S.infoRow, children: [
893
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: S.infoKey, children: label }),
894
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: S.infoVal, children: m.calls + " 次 · 输出 " + fmtInt(m.outputTokens) + " · 思考 " + fmtInt(m.reasoningTokens) })
1073
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.infoRow, children: [
1074
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.infoKey, children: label }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.infoVal, children: m.calls + " 次 · 输出 " + fmtInt(m.outputTokens) + " · 思考 " + fmtInt(m.reasoningTokens) })
895
1076
  ] }, "m-" + label);
896
1077
  })
897
1078
  ] }) : null,
898
- data ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: S.hint, children: "输入按字符、输出/思考按 token 计;趋势图 Y 轴为输出 token,上方可切换层级与颗粒度。" }) : null
1079
+ data ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: S.hint, children: "输入按字符、输出/思考按 token 计;趋势图 Y 轴为输出 token,上方可切换层级与颗粒度。" }) : null
899
1080
  ] });
900
1081
  }
901
1082
 
902
1083
  // client/src/tabs/LogTab.tsx
903
- var import_react3 = require("react");
904
- var import_jsx_runtime3 = require("react/jsx-runtime");
1084
+ var import_react4 = require("react");
1085
+ var import_jsx_runtime4 = require("react/jsx-runtime");
905
1086
  function LogTab(props) {
906
1087
  const rpc = props.rpc;
907
- const [lines, setLines] = (0, import_react3.useState)(null);
908
- const [error, setError] = (0, import_react3.useState)(null);
909
- const preRef = (0, import_react3.useRef)(null);
910
- const load = (0, import_react3.useCallback)(() => {
1088
+ const [lines, setLines] = (0, import_react4.useState)(null);
1089
+ const [error, setError] = (0, import_react4.useState)(null);
1090
+ const preRef = (0, import_react4.useRef)(null);
1091
+ const load = (0, import_react4.useCallback)(() => {
911
1092
  setError(null);
912
1093
  rpc("dsh-memory/log-tail", { lines: 200 }).then((r) => {
913
1094
  if (r && r.ok) setLines(r.value.lines);
@@ -916,63 +1097,24 @@ var __defProp = Object.defineProperty;
916
1097
  setError(String(e && e.message || e));
917
1098
  });
918
1099
  }, [rpc]);
919
- (0, import_react3.useEffect)(() => {
1100
+ (0, import_react4.useEffect)(() => {
920
1101
  load();
921
1102
  }, [load]);
922
- (0, import_react3.useEffect)(() => {
1103
+ (0, import_react4.useEffect)(() => {
923
1104
  if (lines && preRef.current) preRef.current.scrollTop = preRef.current.scrollHeight;
924
1105
  }, [lines]);
925
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
926
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
927
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.muted, children: error ? "加载失败" : lines === null ? "加载中…" : "最近 " + lines.length + " 行(memory.log)" }),
928
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.grow }),
929
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(NButton, { onClick: load, children: "刷新" })
1106
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1107
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: S.muted, children: error ? "加载失败" : lines === null ? "加载中…" : "最近 " + lines.length + " 行(memory.log)" }),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: S.grow }),
1110
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NButton, { onClick: load, children: "刷新" })
930
1111
  ] }),
931
- error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "日志读取失败:" + error + "(点右上“刷新”重试)" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { style: S.pre, ref: preRef, children: (lines || []).join("\n") || "(暂无日志)" })
1112
+ error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "日志读取失败:" + error + "(点右上“刷新”重试)" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: S.pre, ref: preRef, children: (lines || []).join("\n") || "(暂无日志)" })
932
1113
  ] });
933
1114
  }
934
1115
 
935
1116
  // client/src/tabs/OverviewTab.tsx
936
- var import_react12 = require("react");
937
-
938
- // client/src/format.ts
939
- var TYPE_LABELS = {
940
- persona: "画像偏好",
941
- episodic: "客观事件",
942
- instruction: "全局指令",
943
- work_fact: "工作事实",
944
- work_task: "工作任务",
945
- work_method: "工作方法",
946
- work_artifact: "工作资产"
947
- };
948
- function fmtTime(iso) {
949
- if (!iso) return "-";
950
- try {
951
- return new Date(iso).toLocaleString();
952
- } catch {
953
- return String(iso);
954
- }
955
- }
956
- function fmtAgo(iso) {
957
- if (!iso) return null;
958
- try {
959
- const t = new Date(iso).getTime();
960
- if (!t) return null;
961
- let s = Math.floor((Date.now() - t) / 1e3);
962
- if (s < 0) s = 0;
963
- if (s < 45) return "刚刚";
964
- if (s < 3600) return Math.floor(s / 60) + " 分钟前";
965
- if (s < 86400) return Math.floor(s / 3600) + " 小时前";
966
- return Math.floor(s / 86400) + " 天前";
967
- } catch {
968
- return null;
969
- }
970
- }
971
- function fmtMB(bytes) {
972
- if (!bytes || bytes <= 0) return "0MB";
973
- if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + "KB";
974
- return (bytes / (1024 * 1024)).toFixed(bytes < 100 * 1024 * 1024 ? 1 : 0) + "MB";
975
- }
1117
+ var import_react13 = require("react");
976
1118
 
977
1119
  // client/src/pill/modes.ts
978
1120
  var MODES = [
@@ -1014,11 +1156,11 @@ var __defProp = Object.defineProperty;
1014
1156
  }
1015
1157
 
1016
1158
  // client/src/tabs/DistillSettings.tsx
1017
- var import_react8 = require("react");
1159
+ var import_react9 = require("react");
1018
1160
 
1019
1161
  // client/src/tabs/BudgetInputs.tsx
1020
- var import_react4 = require("react");
1021
- var import_jsx_runtime4 = require("react/jsx-runtime");
1162
+ var import_react5 = require("react");
1163
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1022
1164
  var LAYERS = [
1023
1165
  ["extract", "抽取"],
1024
1166
  ["dedup", "去重"],
@@ -1039,7 +1181,7 @@ var __defProp = Object.defineProperty;
1039
1181
  const onError = props.onError;
1040
1182
  const scope = props.scope ?? "all";
1041
1183
  const layers = scope === "all" || scope === "input" ? LAYERS : LAYERS.filter((l) => SCOPE_KEYS[scope].includes(l[0]));
1042
- const [draft, setDraft] = (0, import_react4.useState)(null);
1184
+ const [draft, setDraft] = (0, import_react5.useState)(null);
1043
1185
  if (!data || !data.budgets) return null;
1044
1186
  const cur = data.budgets.current || {};
1045
1187
  const def = data.budgets.defaults || {};
@@ -1135,7 +1277,7 @@ var __defProp = Object.defineProperty;
1135
1277
  return false;
1136
1278
  };
1137
1279
  const inputBox = (key, _label, title, width, placeholder, onCommit) => {
1138
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1280
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1139
1281
  NInput,
1140
1282
  {
1141
1283
  type: "number",
@@ -1167,9 +1309,9 @@ var __defProp = Object.defineProperty;
1167
1309
  const effNote = layers.map((l) => eff[l[0]] || "?").join(" / ");
1168
1310
  const rowLabel = (key) => key === "extract" ? "抽取输出" : key === "dedup" ? "去重输出" : key === "l2" ? "L2 输出" : "L3 输出";
1169
1311
  const rowStyle = { display: "flex", alignItems: "center", gap: 8 };
1170
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1171
- showOutputs ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginTop: 12 }, children: [
1172
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1312
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1313
+ showOutputs ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { marginTop: 12 }, children: [
1314
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1173
1315
  "div",
1174
1316
  {
1175
1317
  style: S.switchLabel,
@@ -1177,8 +1319,8 @@ var __defProp = Object.defineProperty;
1177
1319
  children: "输出预算"
1178
1320
  }
1179
1321
  ),
1180
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: layers.map((l) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowStyle, children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: rowLabel(l[0]) }),
1322
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: layers.map((l) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: rowStyle, children: [
1323
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: rowLabel(l[0]) }),
1182
1324
  inputBox(
1183
1325
  l[0],
1184
1326
  l[1],
@@ -1187,11 +1329,11 @@ var __defProp = Object.defineProperty;
1187
1329
  def[l[0]],
1188
1330
  commitOutputs
1189
1331
  ),
1190
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "token" })
1332
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "token" })
1191
1333
  ] }, l[0])) })
1192
1334
  ] }) : null,
1193
- showInput ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginTop: 12 }, children: [
1194
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1335
+ showInput ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { marginTop: 12 }, children: [
1336
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1195
1337
  "div",
1196
1338
  {
1197
1339
  style: S.switchLabel,
@@ -1199,8 +1341,8 @@ var __defProp = Object.defineProperty;
1199
1341
  children: "输入预算"
1200
1342
  }
1201
1343
  ),
1202
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowStyle, children: [
1203
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: "单次输入" }),
1344
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: rowStyle, children: [
1345
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { width: 68, flexShrink: 0, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: "单次输入" }),
1204
1346
  inputBox(
1205
1347
  "input",
1206
1348
  "输入",
@@ -1209,15 +1351,15 @@ var __defProp = Object.defineProperty;
1209
1351
  ib.fallback,
1210
1352
  commitInput
1211
1353
  ),
1212
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "字符" })
1354
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: "字符" })
1213
1355
  ] }) })
1214
1356
  ] }) : null
1215
1357
  ] });
1216
1358
  }
1217
1359
 
1218
1360
  // client/src/tabs/ChannelEditor.tsx
1219
- var import_react5 = require("react");
1220
- var import_jsx_runtime5 = require("react/jsx-runtime");
1361
+ var import_react6 = require("react");
1362
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1221
1363
  var STY = {
1222
1364
  block: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" },
1223
1365
  head: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 6 },
@@ -1248,14 +1390,14 @@ var __defProp = Object.defineProperty;
1248
1390
  ];
1249
1391
  function ChannelEditor(props) {
1250
1392
  const { channel, rpc, disabled } = props;
1251
- const [baseText, setBaseText] = (0, import_react5.useState)(channel.runtimeBaseURL);
1252
- const [keyText, setKeyText] = (0, import_react5.useState)("");
1253
- const baseTimer = (0, import_react5.useRef)(void 0);
1254
- const dirty = (0, import_react5.useRef)(false);
1255
- (0, import_react5.useEffect)(() => {
1393
+ const [baseText, setBaseText] = (0, import_react6.useState)(channel.runtimeBaseURL);
1394
+ const [keyText, setKeyText] = (0, import_react6.useState)("");
1395
+ const baseTimer = (0, import_react6.useRef)(void 0);
1396
+ const dirty = (0, import_react6.useRef)(false);
1397
+ (0, import_react6.useEffect)(() => {
1256
1398
  if (!dirty.current) setBaseText(channel.runtimeBaseURL);
1257
1399
  }, [channel.runtimeBaseURL]);
1258
- (0, import_react5.useEffect)(() => () => clearTimeout(baseTimer.current), []);
1400
+ (0, import_react6.useEffect)(() => () => clearTimeout(baseTimer.current), []);
1259
1401
  const commit = (patch) => {
1260
1402
  rpc("dsh-memory/settings-set", patch).catch(() => {
1261
1403
  });
@@ -1284,17 +1426,17 @@ var __defProp = Object.defineProperty;
1284
1426
  const deployedDirect = channel.deployed === "direct";
1285
1427
  const apiKeySet = channel.runtimeApiKeySet || channel.deployedApiKeySet;
1286
1428
  const showWarn = isDirect && !channel.directReady;
1287
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: STY.block, children: [
1288
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: STY.head, children: [
1289
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: STY.title, children: "蒸馏通道" }),
1290
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: isDirect ? STY.chipAccent : STY.chipMuted, children: isDirect ? "直连端点" : "复用宿主" }),
1291
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { title: "direct = 插件原生直连 OpenAI 兼容端点,与付费 API 解耦;失败自动回退宿主路由链。", style: { marginLeft: "auto", fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1429
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: STY.block, children: [
1430
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: STY.head, children: [
1431
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: STY.title, children: "蒸馏通道" }),
1432
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: isDirect ? STY.chipAccent : STY.chipMuted, children: isDirect ? "直连端点" : "复用宿主" }),
1433
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { title: "direct = 插件原生直连 OpenAI 兼容端点,与付费 API 解耦;失败自动回退宿主路由链。", style: { marginLeft: "auto", fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1292
1434
  "生效:",
1293
1435
  runtime ? runtime === "direct" ? "运行时直连" : "运行时宿主" : "跟随部署配置"
1294
1436
  ] })
1295
1437
  ] }),
1296
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: STY.desc, children: "direct 通道走插件原生 HTTP,不依赖宿主 provider 注册表;direct 失败自动回退宿主路由链作兜底安全网。" }),
1297
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1438
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: STY.desc, children: "direct 通道走插件原生 HTTP,不依赖宿主 provider 注册表;direct 失败自动回退宿主路由链作兜底安全网。" }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1298
1440
  Segmented,
1299
1441
  {
1300
1442
  value: runtime,
@@ -1303,10 +1445,10 @@ var __defProp = Object.defineProperty;
1303
1445
  onChange: (k) => commit({ distillMode: k })
1304
1446
  }
1305
1447
  ),
1306
- editing ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1307
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: STY.fieldRow, children: [
1308
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: STY.fieldLabel, children: "端点 URL" }),
1309
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1448
+ editing ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: STY.fieldRow, children: [
1450
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: STY.fieldLabel, children: "端点 URL" }),
1451
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1310
1452
  NInput,
1311
1453
  {
1312
1454
  style: STY.input,
@@ -1323,14 +1465,14 @@ var __defProp = Object.defineProperty;
1323
1465
  }
1324
1466
  }
1325
1467
  ),
1326
- deployedDirect && !channel.runtimeBaseURL ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1468
+ deployedDirect && !channel.runtimeBaseURL ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: [
1327
1469
  "部署基线:",
1328
1470
  channel.deployedBaseURL || "(空)"
1329
1471
  ] }) : null
1330
1472
  ] }),
1331
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: STY.fieldRow, children: [
1332
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: STY.fieldLabel, children: "API Key" }),
1333
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1473
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: STY.fieldRow, children: [
1474
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: STY.fieldLabel, children: "API Key" }),
1475
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1334
1476
  NInput,
1335
1477
  {
1336
1478
  style: STY.input,
@@ -1346,8 +1488,8 @@ var __defProp = Object.defineProperty;
1346
1488
  onBlur: commitKey
1347
1489
  }
1348
1490
  ),
1349
- apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: STY.chipAccent, children: "已配置" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: STY.chipMuted, children: "未配置" }),
1350
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1491
+ apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: STY.chipAccent, children: "已配置" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: STY.chipMuted, children: "未配置" }),
1492
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1351
1493
  NButton,
1352
1494
  {
1353
1495
  disabled,
@@ -1357,30 +1499,30 @@ var __defProp = Object.defineProperty;
1357
1499
  }
1358
1500
  )
1359
1501
  ] }),
1360
- showWarn ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: STY.warn, children: "⚠ direct 未配置完整:需同时有端点 URL 与模型(llm.model / 全局链主路由),否则会回退宿主路由。" }) : null
1361
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: STY.preview, children: isDirect ? "当前将直连端点:" + (channel.runtimeBaseURL || channel.deployedBaseURL || "(未配置端点)") + (apiKeySet ? " · 密钥已配置" : " · 未配置密钥") : "当前复用宿主 ctx.llm(" + (runtime === "host" ? "运行时锁定" : "跟随部署配置") + ")" })
1502
+ showWarn ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: STY.warn, children: "⚠ direct 未配置完整:需同时有端点 URL 与模型(llm.model / 全局链主路由),否则会回退宿主路由。" }) : null
1503
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: STY.preview, children: isDirect ? "当前将直连端点:" + (channel.runtimeBaseURL || channel.deployedBaseURL || "(未配置端点)") + (apiKeySet ? " · 密钥已配置" : " · 未配置密钥") : "当前复用宿主 ctx.llm(" + (runtime === "host" ? "运行时锁定" : "跟随部署配置") + ")" })
1362
1504
  ] });
1363
1505
  }
1364
1506
 
1365
1507
  // client/src/tabs/RouteChainEditor.tsx
1366
- var import_react7 = require("react");
1508
+ var import_react8 = require("react");
1367
1509
 
1368
1510
  // client/src/ui/NSel.tsx
1369
- var import_react6 = require("react");
1370
- var import_jsx_runtime6 = require("react/jsx-runtime");
1511
+ var import_react7 = require("react");
1512
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1371
1513
  function NSel(props) {
1372
1514
  const options = props.options || [];
1373
1515
  const value = props.value || "";
1374
1516
  const disabled = !!props.disabled;
1375
- const [open, setOpen] = (0, import_react6.useState)(false);
1376
- const [idx, setIdx] = (0, import_react6.useState)(-1);
1377
- const wrapRef = (0, import_react6.useRef)(null);
1378
- const listRef = (0, import_react6.useRef)(null);
1517
+ const [open, setOpen] = (0, import_react7.useState)(false);
1518
+ const [idx, setIdx] = (0, import_react7.useState)(-1);
1519
+ const wrapRef = (0, import_react7.useRef)(null);
1520
+ const listRef = (0, import_react7.useRef)(null);
1379
1521
  let selectedLabel = "";
1380
1522
  for (let si = 0; si < options.length; si++) {
1381
1523
  if (options[si].id === value) selectedLabel = options[si].label;
1382
1524
  }
1383
- (0, import_react6.useEffect)(() => {
1525
+ (0, import_react7.useEffect)(() => {
1384
1526
  if (!open) return void 0;
1385
1527
  const onDown = (e) => {
1386
1528
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -1390,7 +1532,7 @@ var __defProp = Object.defineProperty;
1390
1532
  document.removeEventListener("mousedown", onDown);
1391
1533
  };
1392
1534
  }, [open]);
1393
- (0, import_react6.useEffect)(() => {
1535
+ (0, import_react7.useEffect)(() => {
1394
1536
  if (!open || !listRef.current) return;
1395
1537
  const el = listRef.current.querySelector('[data-active="1"]');
1396
1538
  if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest" });
@@ -1453,8 +1595,8 @@ var __defProp = Object.defineProperty;
1453
1595
  const to = e.relatedTarget;
1454
1596
  if (!to || wrapRef.current && !wrapRef.current.contains(to)) setOpen(false);
1455
1597
  };
1456
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-mem-sel", style: props.style, ref: wrapRef, onKeyDown: onKey, onBlur, children: [
1457
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1598
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-mem-sel", style: props.style, ref: wrapRef, onKeyDown: onKey, onBlur, children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1458
1600
  "button",
1459
1601
  {
1460
1602
  type: "button",
@@ -1470,13 +1612,13 @@ var __defProp = Object.defineProperty;
1470
1612
  }
1471
1613
  },
1472
1614
  children: [
1473
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-mem-select-label", children: selectedLabel || props.placeholder || "(请选择)" }),
1474
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : ""), "aria-hidden": true })
1615
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-mem-select-label", children: selectedLabel || props.placeholder || "(请选择)" }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-mem-sel-chev" + (open ? " dsh-mem-sel-chev-open" : ""), "aria-hidden": true })
1475
1617
  ]
1476
1618
  }
1477
1619
  ),
1478
- open && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-mem-pop", ref: listRef, role: "listbox", children: options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-mem-pop-empty", children: "无选项" }) : options.map((o, i) => {
1479
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1620
+ open && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-mem-pop", ref: listRef, role: "listbox", children: options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-mem-pop-empty", children: "无选项" }) : options.map((o, i) => {
1621
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1480
1622
  "button",
1481
1623
  {
1482
1624
  type: "button",
@@ -1494,8 +1636,8 @@ var __defProp = Object.defineProperty;
1494
1636
  if (idx !== i) setIdx(i);
1495
1637
  },
1496
1638
  children: [
1497
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-mem-pop-opt-label", children: o.label }),
1498
- o.id === value ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-mem-pop-check", children: "✓" }) : null
1639
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-mem-pop-opt-label", children: o.label }),
1640
+ o.id === value ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-mem-pop-check", children: "✓" }) : null
1499
1641
  ]
1500
1642
  },
1501
1643
  o.id
@@ -1505,7 +1647,7 @@ var __defProp = Object.defineProperty;
1505
1647
  }
1506
1648
 
1507
1649
  // client/src/tabs/RouteChainEditor.tsx
1508
- var import_jsx_runtime7 = require("react/jsx-runtime");
1650
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1509
1651
  var modelsCache = {};
1510
1652
  var EFFORT_VOCAB = ["", "off", "none", "minimal", "low", "medium", "high", "xhigh", "max"];
1511
1653
  var STY2 = {
@@ -1534,26 +1676,26 @@ var __defProp = Object.defineProperty;
1534
1676
  const disabled = !!props.disabled;
1535
1677
  const scope = props.scope ?? "global";
1536
1678
  const isLayer = scope !== "global";
1537
- const [info, setInfo] = (0, import_react7.useState)(null);
1538
- const [rows, setRows] = (0, import_react7.useState)(null);
1539
- const [rowErrs, setRowErrs] = (0, import_react7.useState)({});
1540
- const [err, setErr] = (0, import_react7.useState)(null);
1541
- const [manual, setManual] = (0, import_react7.useState)({ idx: -1, text: "" });
1542
- const pendingWrites = (0, import_react7.useRef)(0);
1679
+ const [info, setInfo] = (0, import_react8.useState)(null);
1680
+ const [rows, setRows] = (0, import_react8.useState)(null);
1681
+ const [rowErrs, setRowErrs] = (0, import_react8.useState)({});
1682
+ const [err, setErr] = (0, import_react8.useState)(null);
1683
+ const [manual, setManual] = (0, import_react8.useState)({ idx: -1, text: "" });
1684
+ const pendingWrites = (0, import_react8.useRef)(0);
1543
1685
  function refreshInfo() {
1544
1686
  rpc("dsh-memory/llm-providers", {}).then((r) => {
1545
1687
  if (r && r.ok && pendingWrites.current === 0) setInfo(r.value);
1546
1688
  }).catch(() => {
1547
1689
  });
1548
1690
  }
1549
- (0, import_react7.useEffect)(() => {
1691
+ (0, import_react8.useEffect)(() => {
1550
1692
  refreshInfo();
1551
1693
  const timer = setInterval(refreshInfo, 5e3);
1552
1694
  return () => {
1553
1695
  clearInterval(timer);
1554
1696
  };
1555
1697
  }, [rpc]);
1556
- (0, import_react7.useEffect)(() => {
1698
+ (0, import_react8.useEffect)(() => {
1557
1699
  if (!info || !info.providers) return;
1558
1700
  info.providers.forEach((p) => {
1559
1701
  if (!p.id || modelsCache[p.id]) return;
@@ -1565,7 +1707,7 @@ var __defProp = Object.defineProperty;
1565
1707
  }, [rpc, info]);
1566
1708
  const layerView = isLayer && info && info.layerChains ? info.layerChains[scope] : null;
1567
1709
  const savedRows = isLayer ? layerView?.runtime ?? [] : info && info.chain ? info.chain.current : [];
1568
- (0, import_react7.useEffect)(() => {
1710
+ (0, import_react8.useEffect)(() => {
1569
1711
  if (rows === null && info && savedRows.length) {
1570
1712
  setRows(savedRows.map(copyRow));
1571
1713
  }
@@ -1713,17 +1855,17 @@ var __defProp = Object.defineProperty;
1713
1855
  providersById[p.id] = p;
1714
1856
  });
1715
1857
  function roRow(e, i) {
1716
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.roRow, children: [
1717
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: STY2.badge, children: i === 0 ? "主" : String(i + 1) }),
1718
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...STY2.mono, color: "var(--dsh-mem-text-2)" }, children: e.provider + " / " + e.model }),
1719
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { marginLeft: "auto", flexShrink: 0, fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: e.effort ? "档位 " + e.effort : "跟随部署配置" })
1858
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.roRow, children: [
1859
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY2.badge, children: i === 0 ? "主" : String(i + 1) }),
1860
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...STY2.mono, color: "var(--dsh-mem-text-2)" }, children: e.provider + " / " + e.model }),
1861
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { marginLeft: "auto", flexShrink: 0, fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: e.effort ? "档位 " + e.effort : "跟随部署配置" })
1720
1862
  ] }, "ro" + i);
1721
1863
  }
1722
1864
  if (info.pinned) {
1723
1865
  const effPin = isLayer ? layerView?.effectiveChain ?? [] : info.chain && info.chain.effectiveChain || [];
1724
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.wrap, children: [
1866
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.wrap, children: [
1725
1867
  effPin.map(roRow),
1726
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: STY2.note, children: "部署已锁定路由(pin),调整请修改 cordis.patch.yml 中 llm 的配置。" })
1868
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY2.note, children: "部署已锁定路由(pin),调整请修改 cordis.patch.yml 中 llm 的配置。" })
1727
1869
  ] });
1728
1870
  }
1729
1871
  if (rows === null) {
@@ -1731,21 +1873,21 @@ var __defProp = Object.defineProperty;
1731
1873
  const lv = layerView;
1732
1874
  const src = lv?.source ?? "global";
1733
1875
  if (src === "static" && lv) {
1734
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.wrap, children: [
1876
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.wrap, children: [
1735
1877
  lv.static.map((e, i) => roRow({ provider: e.provider, model: e.model, effort: e.reasoningEffort || "" }, i)),
1736
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
1878
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
1737
1879
  ] });
1738
1880
  }
1739
1881
  const previewRows = lv?.effectiveChain ?? [];
1740
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.wrap, children: [
1741
- previewRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: S.switchDesc, children: "本层跟随全局链,暂无可用路由。" }) : previewRows.map(roRow),
1742
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
1882
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.wrap, children: [
1883
+ previewRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: S.switchDesc, children: "本层跟随全局链,暂无可用路由。" }) : previewRows.map(roRow),
1884
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NButton, { onClick: forkStatic, disabled, children: "自定义本层链" }) })
1743
1885
  ] });
1744
1886
  }
1745
1887
  const effFollow = info.chain && info.chain.effectiveChain || [];
1746
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.wrap, children: [
1747
- effFollow.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: S.switchDesc, children: "蒸馏跟随默认模型,未配置回退链。" }) : effFollow.map(roRow),
1748
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NButton, { onClick: forkStatic, disabled, children: "编辑为运行时链" }) })
1888
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.wrap, children: [
1889
+ effFollow.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: S.switchDesc, children: "蒸馏跟随默认模型,未配置回退链。" }) : effFollow.map(roRow),
1890
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NButton, { onClick: forkStatic, disabled, children: "编辑为运行时链" }) })
1749
1891
  ] });
1750
1892
  }
1751
1893
  const capped = rows.length >= 8;
@@ -1786,10 +1928,10 @@ var __defProp = Object.defineProperty;
1786
1928
  const effortOptions = [{ id: "", label: "跟随部署配置" }].concat(
1787
1929
  curEfforts.filter((k) => EFFORT_VOCAB.indexOf(k) >= 0).map((k) => ({ id: k, label: k }))
1788
1930
  );
1789
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...STY2.row, ...rowErrs[i] ? STY2.rowErr : null }, children: [
1790
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.line, children: [
1791
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: STY2.badge, children: isPrimary ? "主" : String(i + 1) }),
1792
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1931
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { ...STY2.row, ...rowErrs[i] ? STY2.rowErr : null }, children: [
1932
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.line, children: [
1933
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY2.badge, children: isPrimary ? "主" : String(i + 1) }),
1934
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1793
1935
  NSel,
1794
1936
  {
1795
1937
  style: { flex: 1, minWidth: 150 },
@@ -1802,7 +1944,7 @@ var __defProp = Object.defineProperty;
1802
1944
  }
1803
1945
  }
1804
1946
  ),
1805
- !row2.provider ? null : manualInput ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1947
+ !row2.provider ? null : manualInput ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1806
1948
  NInput,
1807
1949
  {
1808
1950
  style: { flex: 1, minWidth: 150 },
@@ -1821,7 +1963,7 @@ var __defProp = Object.defineProperty;
1821
1963
  }
1822
1964
  }
1823
1965
  }
1824
- ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1966
+ ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1825
1967
  NSel,
1826
1968
  {
1827
1969
  style: { flex: 1, minWidth: 150 },
@@ -1834,7 +1976,7 @@ var __defProp = Object.defineProperty;
1834
1976
  }
1835
1977
  }
1836
1978
  ),
1837
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1979
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1838
1980
  NSel,
1839
1981
  {
1840
1982
  style: { flexShrink: 0, width: 118 },
@@ -1848,8 +1990,8 @@ var __defProp = Object.defineProperty;
1848
1990
  }
1849
1991
  )
1850
1992
  ] }),
1851
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.actions, children: [
1852
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1993
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.actions, children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1853
1995
  NButton,
1854
1996
  {
1855
1997
  style: STY2.ico,
@@ -1861,7 +2003,7 @@ var __defProp = Object.defineProperty;
1861
2003
  children: "↑"
1862
2004
  }
1863
2005
  ),
1864
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2006
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1865
2007
  NButton,
1866
2008
  {
1867
2009
  style: STY2.ico,
@@ -1873,7 +2015,7 @@ var __defProp = Object.defineProperty;
1873
2015
  children: "↓"
1874
2016
  }
1875
2017
  ),
1876
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2018
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1877
2019
  NButton,
1878
2020
  {
1879
2021
  style: STY2.ico,
@@ -1886,14 +2028,14 @@ var __defProp = Object.defineProperty;
1886
2028
  }
1887
2029
  )
1888
2030
  ] }),
1889
- isPrimary && !row2.provider ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: STY2.note, children: "跟随默认模型" + (info.default ? ":" + info.default.provider + " / " + info.default.model : "") + "(档位跟随部署配置,选定模型后可单独设置)" }) : null,
1890
- !known ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: STY2.warn, children: "⚠ 供应商 " + row2.provider + " 已不在已注册路由中:该路由调用会失败并被链跳过(不阻止保存)。" }) : null,
1891
- rowErrs[i] ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: STY2.warn, children: "✕ " + rowErrs[i] }) : null
2031
+ isPrimary && !row2.provider ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY2.note, children: "跟随默认模型" + (info.default ? ":" + info.default.provider + " / " + info.default.model : "") + "(档位跟随部署配置,选定模型后可单独设置)" }) : null,
2032
+ !known ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY2.warn, children: "⚠ 供应商 " + row2.provider + " 已不在已注册路由中:该路由调用会失败并被链跳过(不阻止保存)。" }) : null,
2033
+ rowErrs[i] ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: STY2.warn, children: "✕ " + rowErrs[i] }) : null
1892
2034
  ] }, "row" + i);
1893
2035
  });
1894
2036
  const effChain = isLayer ? layerView?.effectiveChain ?? [] : info.chain && info.chain.effectiveChain || [];
1895
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: STY2.wrap, children: [
1896
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2037
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY2.wrap, children: [
2038
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1897
2039
  "div",
1898
2040
  {
1899
2041
  style: { ...S.switchDesc, marginBottom: 8 },
@@ -1902,9 +2044,9 @@ var __defProp = Object.defineProperty;
1902
2044
  }
1903
2045
  ),
1904
2046
  rowEls,
1905
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NButton, { style: STY2.add, disabled: disabled || capped, onClick: addRow, children: capped ? "已达上限(8 条)" : "+ 添加回退路由" }),
1906
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 10 }, children: [
1907
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2047
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NButton, { style: STY2.add, disabled: disabled || capped, onClick: addRow, children: capped ? "已达上限(8 条)" : "+ 添加回退路由" }),
2048
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 10 }, children: [
2049
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1908
2050
  NButton,
1909
2051
  {
1910
2052
  style: isLayer ? { ...STY2.ghost, color: "var(--dsh-mem-danger)", border: "1px solid var(--dsh-mem-danger)" } : STY2.ghost,
@@ -1913,13 +2055,13 @@ var __defProp = Object.defineProperty;
1913
2055
  children: isLayer ? "清除自定义 · 跟随全局" : "清空并跟随部署配置"
1914
2056
  }
1915
2057
  ),
1916
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: S.grow }),
1917
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NButton, { variant: "primary", disabled, onClick: save, children: "保存" })
2058
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: S.grow }),
2059
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NButton, { variant: "primary", disabled, onClick: save, children: "保存" })
1918
2060
  ] }),
1919
- err ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...STY2.warn, marginTop: 8 }, children: "✕ " + err }) : null,
1920
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
1921
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 4 }, children: "实际链" + (dirty ? "(保存后更新;当前显示已保存值)" : "") }),
1922
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2061
+ err ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { ...STY2.warn, marginTop: 8 }, children: "✕ " + err }) : null,
2062
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" }, children: [
2063
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)", marginBottom: 4 }, children: "实际链" + (dirty ? "(保存后更新;当前显示已保存值)" : "") }),
2064
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1923
2065
  "div",
1924
2066
  {
1925
2067
  style: { fontSize: 12, color: "var(--dsh-mem-text-2)", wordBreak: "break-all", fontFamily: "ui-monospace, SFMono-Regular, Consolas, monospace" },
@@ -1931,7 +2073,7 @@ var __defProp = Object.defineProperty;
1931
2073
  }
1932
2074
 
1933
2075
  // client/src/tabs/DistillSettings.tsx
1934
- var import_jsx_runtime8 = require("react/jsx-runtime");
2076
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1935
2077
  var STY3 = {
1936
2078
  hint: { fontSize: 11, color: "var(--dsh-mem-text-3)", margin: "0 0 8px" },
1937
2079
  panelHead: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 8 },
@@ -1960,9 +2102,9 @@ var __defProp = Object.defineProperty;
1960
2102
  verticalAlign: "middle",
1961
2103
  flexShrink: 0
1962
2104
  };
1963
- if (props.kind === "runtime") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...base, background: "var(--dsh-mem-accent)" } });
1964
- if (props.kind === "static") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...base, background: "transparent", border: "1.5px solid var(--dsh-mem-text-3)" } });
1965
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...base, background: "var(--dsh-mem-track)" } });
2105
+ if (props.kind === "runtime") return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...base, background: "var(--dsh-mem-accent)" } });
2106
+ if (props.kind === "static") return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...base, background: "transparent", border: "1.5px solid var(--dsh-mem-text-3)" } });
2107
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...base, background: "var(--dsh-mem-track)" } });
1966
2108
  }
1967
2109
  var LAYER_META = {
1968
2110
  l1: { seg: "L1", title: "L1 · 抽取 / 去重" },
@@ -1972,9 +2114,9 @@ var __defProp = Object.defineProperty;
1972
2114
  function DistillSettings(props) {
1973
2115
  const rpc = props.rpc;
1974
2116
  const disabled = !!props.disabled;
1975
- const [info, setInfo] = (0, import_react8.useState)(null);
1976
- const [tab, setTab] = (0, import_react8.useState)("g");
1977
- (0, import_react8.useEffect)(() => {
2117
+ const [info, setInfo] = (0, import_react9.useState)(null);
2118
+ const [tab, setTab] = (0, import_react9.useState)("g");
2119
+ (0, import_react9.useEffect)(() => {
1978
2120
  let alive = true;
1979
2121
  const refresh = () => {
1980
2122
  rpc("dsh-memory/llm-providers", {}).then((r) => {
@@ -1997,46 +2139,67 @@ var __defProp = Object.defineProperty;
1997
2139
  ...["l1", "l2", "l3"].map((k) => ({
1998
2140
  key: k,
1999
2141
  title: LAYER_META[k].title + " · " + (dotOf(k) === "runtime" ? "运行时自定义" : dotOf(k) === "static" ? "部署 YAML 层链(只读)" : "跟随全局"),
2000
- label: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
2001
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dot, { kind: dotOf(k) }),
2142
+ label: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
2143
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dot, { kind: dotOf(k) }),
2002
2144
  LAYER_META[k].seg
2003
2145
  ] })
2004
2146
  }))
2005
2147
  ];
2006
2148
  const chipTitle = (k) => dotOf(k) === "runtime" ? "本层走设置页自定义链" : dotOf(k) === "static" ? "本层走部署 YAML 层链(UI 只读,自定义可覆盖)" : "本层未单独配置,走全局默认链";
2007
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
2008
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Segmented, { value: tab, options: segOptions, onChange: (k) => setTab(k) }),
2009
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY3.hint, children: [
2010
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dot, { kind: "runtime" }),
2149
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2150
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Segmented, { value: tab, options: segOptions, onChange: (k) => setTab(k) }),
2151
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY3.hint, children: [
2152
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dot, { kind: "runtime" }),
2011
2153
  " 自定义 · ",
2012
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dot, { kind: "static" }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dot, { kind: "static" }),
2013
2155
  " 部署 YAML · ",
2014
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dot, { kind: "global" }),
2156
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dot, { kind: "global" }),
2015
2157
  " 跟随全局",
2016
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { title: "每层实际链:运行时自定义 → 部署 YAML 层链 → 全局默认链,逐级兜底;部署 pin 时运行时编辑只读", children: "(层链优先于全局)" })
2158
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { title: "每层实际链:运行时自定义 → 部署 YAML 层链 → 全局默认链,逐级兜底;部署 pin 时运行时编辑只读", children: "(层链优先于全局)" })
2017
2159
  ] }),
2018
- tab === "g" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
2019
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY3.panelHead, children: [
2020
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY3.panelTitle, children: "全局默认链" }),
2021
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...STY3.chip, ...STY3.chipAccent }, children: "运行时 · 可编辑" }),
2022
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...STY3.inUse, marginLeft: "auto" }, children: users.length ? "在用:" + users.map((k) => LAYER_META[k].seg).join("、") : "当前无层使用" })
2160
+ tab === "g" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2161
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY3.panelHead, children: [
2162
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY3.panelTitle, children: "全局默认链" }),
2163
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...STY3.chip, ...STY3.chipAccent }, children: "运行时 · 可编辑" }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...STY3.inUse, marginLeft: "auto" }, children: users.length ? "在用:" + users.map((k) => LAYER_META[k].seg).join("、") : "当前无层使用" })
2023
2165
  ] }),
2024
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RouteChainEditor, { rpc, disabled }, "g"),
2025
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: "input" }, "g-budget"),
2026
- info?.channel ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChannelEditor, { channel: info.channel, rpc, disabled }) : null
2027
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
2028
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: STY3.panelHead, children: [
2029
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: STY3.panelTitle, children: LAYER_META[tab].title }),
2030
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { ...STY3.chip, ...dotOf(tab) === "runtime" ? STY3.chipAccent : STY3.chipMuted }, title: chipTitle(tab), children: dotOf(tab) === "runtime" ? "运行时自定义" : dotOf(tab) === "static" ? "静态 · YAML" : "跟随全局" })
2166
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RouteChainEditor, { rpc, disabled }, "g"),
2167
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: "input" }, "g-budget"),
2168
+ info?.channel ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChannelEditor, { channel: info.channel, rpc, disabled }) : null
2169
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
2170
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: STY3.panelHead, children: [
2171
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: STY3.panelTitle, children: LAYER_META[tab].title }),
2172
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...STY3.chip, ...dotOf(tab) === "runtime" ? STY3.chipAccent : STY3.chipMuted }, title: chipTitle(tab), children: dotOf(tab) === "runtime" ? "运行时自定义" : dotOf(tab) === "static" ? "静态 · YAML" : "跟随全局" })
2031
2173
  ] }),
2032
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RouteChainEditor, { rpc, disabled, scope: tab }, tab),
2033
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: tab }, tab + "-budget")
2174
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RouteChainEditor, { rpc, disabled, scope: tab }, tab),
2175
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BudgetInputs, { rpc, disabled, data: props.data, setData: props.setData, onError: props.onError, scope: tab }, tab + "-budget")
2034
2176
  ] })
2035
2177
  ] });
2036
2178
  }
2037
2179
 
2038
2180
  // client/src/tabs/EmbeddingSection.tsx
2039
- var import_react9 = require("react");
2181
+ var import_react10 = require("react");
2182
+
2183
+ // client/src/dimensions.ts
2184
+ var DIMS_MIN = 1;
2185
+ var DIMS_MAX = 1e5;
2186
+ function dimsRangeMessage() {
2187
+ return `嵌入维度须为 ${DIMS_MIN}~${DIMS_MAX} 的整数(留空 = 跟随部署配置)`;
2188
+ }
2189
+ function commitDimensions(raw, deps) {
2190
+ deps.clearDirty();
2191
+ const trimmed = raw.trim();
2192
+ if (trimmed === "") {
2193
+ deps.submit(0);
2194
+ return;
2195
+ }
2196
+ const n = Number(trimmed);
2197
+ if (!Number.isInteger(n) || n < DIMS_MIN || n > DIMS_MAX) {
2198
+ deps.reject(dimsRangeMessage());
2199
+ return;
2200
+ }
2201
+ deps.submit(n);
2202
+ }
2040
2203
 
2041
2204
  // client/src/rpc.ts
2042
2205
  function shortMethod(endpoint) {
@@ -2063,7 +2226,7 @@ var __defProp = Object.defineProperty;
2063
2226
  }
2064
2227
 
2065
2228
  // client/src/tabs/EmbeddingSection.tsx
2066
- var import_jsx_runtime9 = require("react/jsx-runtime");
2229
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2067
2230
  var RSTY = {
2068
2231
  block: { marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--dsh-mem-border)" },
2069
2232
  title: { fontSize: 12, fontWeight: 600, color: "var(--dsh-mem-text-3)", margin: "0 0 2px" },
@@ -2087,17 +2250,17 @@ var __defProp = Object.defineProperty;
2087
2250
  function EmbeddingSection(props) {
2088
2251
  const rpc = props.rpc;
2089
2252
  const loose = asLoose(rpc);
2090
- const [st, setSt] = (0, import_react9.useState)(null);
2091
- const [err, setErr] = (0, import_react9.useState)(null);
2092
- const busyPollRef = (0, import_react9.useRef)(null);
2093
- const [rBase, setRBase] = (0, import_react9.useState)("");
2094
- const [rModel, setRModel] = (0, import_react9.useState)("");
2095
- const [rDims, setRDims] = (0, import_react9.useState)("");
2096
- const [rKey, setRKey] = (0, import_react9.useState)("");
2097
- const remoteDirty = (0, import_react9.useRef)({ base: false, model: false, dims: false });
2098
- const baseTimer = (0, import_react9.useRef)(void 0);
2099
- const modelTimer = (0, import_react9.useRef)(void 0);
2100
- const load = (0, import_react9.useCallback)(() => {
2253
+ const [st, setSt] = (0, import_react10.useState)(null);
2254
+ const [err, setErr] = (0, import_react10.useState)(null);
2255
+ const busyPollRef = (0, import_react10.useRef)(null);
2256
+ const [rBase, setRBase] = (0, import_react10.useState)("");
2257
+ const [rModel, setRModel] = (0, import_react10.useState)("");
2258
+ const [rDims, setRDims] = (0, import_react10.useState)("");
2259
+ const [rKey, setRKey] = (0, import_react10.useState)("");
2260
+ const remoteDirty = (0, import_react10.useRef)({ base: false, model: false, dims: false });
2261
+ const baseTimer = (0, import_react10.useRef)(void 0);
2262
+ const modelTimer = (0, import_react10.useRef)(void 0);
2263
+ const load = (0, import_react10.useCallback)(() => {
2101
2264
  rpc("dsh-memory/embedding-state-get", {}).then((r) => {
2102
2265
  if (r && r.ok && r.value && r.value.supported !== false) {
2103
2266
  const v = r.value;
@@ -2116,10 +2279,10 @@ var __defProp = Object.defineProperty;
2116
2279
  setErr(String(e && e.message || e));
2117
2280
  });
2118
2281
  }, [rpc]);
2119
- (0, import_react9.useEffect)(() => {
2282
+ (0, import_react10.useEffect)(() => {
2120
2283
  load();
2121
2284
  }, [load]);
2122
- (0, import_react9.useEffect)(() => {
2285
+ (0, import_react10.useEffect)(() => {
2123
2286
  let stopped = false;
2124
2287
  const busyFlag = { v: false };
2125
2288
  busyPollRef.current = busyFlag;
@@ -2135,11 +2298,11 @@ var __defProp = Object.defineProperty;
2135
2298
  busyPollRef.current = null;
2136
2299
  };
2137
2300
  }, [load]);
2138
- (0, import_react9.useEffect)(() => () => {
2301
+ (0, import_react10.useEffect)(() => () => {
2139
2302
  clearTimeout(baseTimer.current);
2140
2303
  clearTimeout(modelTimer.current);
2141
2304
  }, []);
2142
- (0, import_react9.useEffect)(() => {
2305
+ (0, import_react10.useEffect)(() => {
2143
2306
  if (!st || !st.remote) return;
2144
2307
  if (!remoteDirty.current.base) setRBase(st.remote.baseURL || "");
2145
2308
  if (!remoteDirty.current.model) setRModel(st.remote.model || "");
@@ -2172,21 +2335,16 @@ var __defProp = Object.defineProperty;
2172
2335
  commitRemote({ embedRemoteModel: v.trim() });
2173
2336
  }, 600);
2174
2337
  };
2175
- const commitRemoteDims = () => {
2176
- const raw = rDims.trim();
2177
- if (raw === "") {
2338
+ const commitRemoteDims = () => commitDimensions(rDims, {
2339
+ // 复位脏标记由 commitDimensions 无条件执行(含失败路径)——**不要**在这里
2340
+ // 再加判断,那正是修复前的缺陷:失败时标记留在 true,轮询回填被永久门控,
2341
+ // 输入框卡死在非法值上。
2342
+ clearDirty: () => {
2178
2343
  remoteDirty.current.dims = false;
2179
- commitRemote({ embedRemoteDimensions: 0 });
2180
- return;
2181
- }
2182
- const n = Number(raw);
2183
- if (!Number.isInteger(n) || n <= 0 || n > 1e5) {
2184
- setErr("嵌入维度须为 1~100000 的整数(留空 = 跟随部署配置)");
2185
- return;
2186
- }
2187
- remoteDirty.current.dims = false;
2188
- commitRemote({ embedRemoteDimensions: n });
2189
- };
2344
+ },
2345
+ submit: (n) => commitRemote({ embedRemoteDimensions: n }),
2346
+ reject: (message) => setErr(message)
2347
+ });
2190
2348
  const commitRemoteKey = () => {
2191
2349
  const v = rKey.trim();
2192
2350
  if (v) commitRemote({ embedRemoteApiKey: v });
@@ -2205,15 +2363,15 @@ var __defProp = Object.defineProperty;
2205
2363
  });
2206
2364
  };
2207
2365
  if (err === "__unsupported__") {
2208
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2209
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "语义检索(嵌入)" }),
2210
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", children: "存储处于降级状态,嵌入管理不可用。" })
2366
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2367
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: "语义检索(嵌入)" }),
2368
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", children: "存储处于降级状态,嵌入管理不可用。" })
2211
2369
  ] });
2212
2370
  }
2213
2371
  if (!st) {
2214
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2215
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", children: err ? "嵌入状态读取失败:" + err : "嵌入状态读取中…" }),
2216
- err ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NButton, { style: { marginTop: 8 }, onClick: load, children: "重试" }) : null
2372
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2373
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", children: err ? "嵌入状态读取失败:" + err : "嵌入状态读取中…" }),
2374
+ err ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { style: { marginTop: 8 }, onClick: load, children: "重试" }) : null
2217
2375
  ] });
2218
2376
  }
2219
2377
  const switchConfirm = "切换嵌入源后将按新模型重建向量索引(期间语义检索暂退化为关键词匹配,不影响对话)。确定切换?";
@@ -2239,40 +2397,40 @@ var __defProp = Object.defineProperty;
2239
2397
  const remote = st.remote;
2240
2398
  let runtimeRow = null;
2241
2399
  if (rt.phase === "installing") {
2242
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginTop: 8, fontSize: 12 }, children: [
2243
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: S.flexRow, children: [
2244
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "安装推理运行时中… 已耗时 " + Math.round(rt.elapsedMs / 1e3) + "s(约 100~200MB,视网络)" }),
2245
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: S.grow }),
2246
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-runtime-cancel", {}), children: "取消" })
2400
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { marginTop: 8, fontSize: 12 }, children: [
2401
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: S.flexRow, children: [
2402
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "安装推理运行时中… 已耗时 " + Math.round(rt.elapsedMs / 1e3) + "s(约 100~200MB,视网络)" }),
2403
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.grow }),
2404
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-runtime-cancel", {}), children: "取消" })
2247
2405
  ] }),
2248
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("pre", { style: { ...S.pre, maxHeight: 68, marginTop: 6, fontSize: 11, opacity: 0.85 }, children: (rt.lastLines || []).join("\n") || "等待 npm 输出…" })
2406
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { style: { ...S.pre, maxHeight: 68, marginTop: 6, fontSize: 11, opacity: 0.85 }, children: (rt.lastLines || []).join("\n") || "等待 npm 输出…" })
2249
2407
  ] });
2250
2408
  } else if (rt.phase === "error") {
2251
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "运行时安装失败:" + (rt.error || "未知") + "(重新切换嵌入源可重试)" });
2409
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "运行时安装失败:" + (rt.error || "未知") + "(重新切换嵌入源可重试)" });
2252
2410
  } else if (rt.phase === "ready") {
2253
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "推理运行时就绪(transformers.js v" + rt.installedVersion + ")" });
2411
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "推理运行时就绪(transformers.js v" + rt.installedVersion + ")" });
2254
2412
  } else if (st.source === "local") {
2255
- runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "首次启用本地嵌入时会自动安装推理运行时(约 100~200MB)。" });
2413
+ runtimeRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "首次启用本地嵌入时会自动安装推理运行时(约 100~200MB)。" });
2256
2414
  }
2257
2415
  let applyRow = null;
2258
2416
  if (ap.phase === "warming") {
2259
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "加载嵌入模型中…(首次需数秒)" });
2417
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "加载嵌入模型中…(首次需数秒)" });
2260
2418
  } else if (ap.phase === "switching") {
2261
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "切换嵌入源中…" });
2419
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: "切换嵌入源中…" });
2262
2420
  } else if (ap.phase === "error") {
2263
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "切换失败:" + ap.message + "(已保存的嵌入源不变,重启后仍按原源运行)" });
2421
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "切换失败:" + ap.message + "(已保存的嵌入源不变,重启后仍按原源运行)" });
2264
2422
  } else if (st.reindex && st.reindex.running) {
2265
2423
  const rj = st.reindex;
2266
2424
  const rDone = rj.l1Done + rj.l0Done;
2267
2425
  const rTotal = rj.l1Total + rj.l0Total;
2268
2426
  const rPct = rTotal > 0 ? Math.round(rDone / rTotal * 100) : 0;
2269
- applyRow = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { marginTop: 8 }, children: [
2270
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: S.flexRow, children: [
2271
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-rb-muted", children: "重嵌入中 L1 " + rj.l1Done + "/" + rj.l1Total + " · L0 " + rj.l0Done + "/" + rj.l0Total + "(" + rPct + "%)" }),
2272
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: S.grow }),
2273
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-reindex-cancel", {}), children: "取消" })
2427
+ applyRow = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { marginTop: 8 }, children: [
2428
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: S.flexRow, children: [
2429
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-rb-muted", children: "重嵌入中 L1 " + rj.l1Done + "/" + rj.l1Total + " · L0 " + rj.l0Done + "/" + rj.l0Total + "(" + rPct + "%)" }),
2430
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.grow }),
2431
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-reindex-cancel", {}), children: "取消" })
2274
2432
  ] }),
2275
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: rPct + "%" } }) }) })
2433
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: rPct + "%" } }) }) })
2276
2434
  ] });
2277
2435
  }
2278
2436
  const modelCards = st.models.map((m) => {
@@ -2281,24 +2439,24 @@ var __defProp = Object.defineProperty;
2281
2439
  const pct = mDl && dl.overallTotal > 0 ? Math.round(dl.overallReceived / dl.overallTotal * 100) : 0;
2282
2440
  let action;
2283
2441
  if (mDl) {
2284
- action = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { flex: 1, minWidth: 200 }, children: [
2285
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: S.flexRow, children: [
2286
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: (dl.phase === "verifying" ? "校验中 " : "") + fmtMB(dl.overallReceived) + " / " + fmtMB(dl.overallTotal) + "(文件 " + dl.fileIndex + "/" + dl.fileCount + "," + pct + "%" + (dl.speedBps > 0 && dl.phase === "downloading" ? "," + fmtMB(dl.speedBps) + "/s" : "") + ")" }),
2287
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: S.grow }),
2288
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-download-cancel", {}), children: "取消" })
2442
+ action = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { flex: 1, minWidth: 200 }, children: [
2443
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: S.flexRow, children: [
2444
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: (dl.phase === "verifying" ? "校验中 " : "") + fmtMB(dl.overallReceived) + " / " + fmtMB(dl.overallTotal) + "(文件 " + dl.fileIndex + "/" + dl.fileCount + "," + pct + "%" + (dl.speedBps > 0 && dl.phase === "downloading" ? "," + fmtMB(dl.speedBps) + "/s" : "") + ")" }),
2445
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.grow }),
2446
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { onClick: () => call("dsh-memory/embedding-download-cancel", {}), children: "取消" })
2289
2447
  ] }),
2290
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }) })
2448
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { ...S.flexRow, marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }) })
2291
2449
  ] });
2292
2450
  } else if (isActive) {
2293
- action = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: S.flexRow, children: [
2294
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-task", children: "使用中" }),
2295
- localInfo && localInfo.state === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-rb-muted", children: "模型加载中…" }) : null,
2296
- localInfo && localInfo.state === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "加载失败:" + (localInfo.error || "") }) : null,
2297
- localInfo && localInfo.state === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-mem-rb-muted", children: "已就绪" }) : null
2451
+ action = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: S.flexRow, children: [
2452
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-task", children: "使用中" }),
2453
+ localInfo && localInfo.state === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-rb-muted", children: "模型加载中…" }) : null,
2454
+ localInfo && localInfo.state === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "加载失败:" + (localInfo.error || "") }) : null,
2455
+ localInfo && localInfo.state === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-rb-muted", children: "已就绪" }) : null
2298
2456
  ] });
2299
2457
  } else if (m.state === "downloaded") {
2300
- action = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: S.flexRow, children: [
2301
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2458
+ action = /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: S.flexRow, children: [
2459
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2302
2460
  NButton,
2303
2461
  {
2304
2462
  disabled: ap.busy,
@@ -2306,7 +2464,7 @@ var __defProp = Object.defineProperty;
2306
2464
  children: "启用"
2307
2465
  }
2308
2466
  ),
2309
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2467
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2310
2468
  NButton,
2311
2469
  {
2312
2470
  disabled: dlActive,
@@ -2316,7 +2474,7 @@ var __defProp = Object.defineProperty;
2316
2474
  )
2317
2475
  ] });
2318
2476
  } else {
2319
- action = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2477
+ action = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2320
2478
  NButton,
2321
2479
  {
2322
2480
  disabled: dlActive || !st.ceilings.local,
@@ -2326,27 +2484,27 @@ var __defProp = Object.defineProperty;
2326
2484
  }
2327
2485
  );
2328
2486
  }
2329
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2487
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2330
2488
  "div",
2331
2489
  {
2332
2490
  style: { ...S.flexRow, padding: "8px 0", borderBottom: "1px solid var(--dsh-mem-border)", flexWrap: "wrap" },
2333
2491
  children: [
2334
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { minWidth: 150 }, children: [
2335
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { fontWeight: 600 }, children: m.name }),
2336
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", children: m.tags.join(" · ") + " · " + m.dims + " 维 · 上下文 " + m.contextTokens })
2492
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { minWidth: 150 }, children: [
2493
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { fontWeight: 600 }, children: m.name }),
2494
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", children: m.tags.join(" · ") + " · " + m.dims + " 维 · 上下文 " + m.contextTokens })
2337
2495
  ] }),
2338
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: m.description }),
2496
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, minWidth: 180, fontSize: 12, color: "var(--dsh-mem-text-2)" }, children: m.description }),
2339
2497
  action
2340
2498
  ]
2341
2499
  },
2342
2500
  m.id
2343
2501
  );
2344
2502
  });
2345
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2346
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: S.flexRow, children: [
2347
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "语义检索(嵌入源)" }),
2348
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: S.grow }),
2349
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2503
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2504
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: S.flexRow, children: [
2505
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "语义检索(嵌入源)" }),
2506
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.grow }),
2507
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2350
2508
  Segmented,
2351
2509
  {
2352
2510
  value: st.source,
@@ -2359,18 +2517,18 @@ var __defProp = Object.defineProperty;
2359
2517
  }
2360
2518
  )
2361
2519
  ] }),
2362
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 4 }, children: st.source === "off" ? "当前:关键词(BM25)检索,不做向量嵌入" : st.source === "remote" ? "当前:远程嵌入(" + (remote.model || "未配置模型") + (remote.baseURL ? " · " + remote.baseURL : "") + ")" : "当前:本地嵌入" + (st.activeModel ? "(" + st.activeModel + ")" : "") }),
2363
- st.activeNote ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginTop: 4, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: st.activeNote }) : null,
2364
- err && err !== "__unsupported__" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null,
2365
- dl && dl.phase === "error" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "下载失败:" + (dl.error || "") }) : null,
2520
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 4 }, children: st.source === "off" ? "当前:关键词(BM25)检索,不做向量嵌入" : st.source === "remote" ? "当前:远程嵌入(" + (remote.model || "未配置模型") + (remote.baseURL ? " · " + remote.baseURL : "") + ")" : "当前:本地嵌入" + (st.activeModel ? "(" + st.activeModel + ")" : "") }),
2521
+ st.activeNote ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 4, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: st.activeNote }) : null,
2522
+ err && err !== "__unsupported__" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: err }) : null,
2523
+ dl && dl.phase === "error" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 6, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: "下载失败:" + (dl.error || "") }) : null,
2366
2524
  runtimeRow,
2367
2525
  applyRow,
2368
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: RSTY.block, children: [
2369
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: RSTY.title, children: "远程连接(生效值;运行时覆盖优先于部署 YAML)" }),
2370
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: RSTY.note, children: "生效端点 " + (remote.baseURL || "(未配置)") + " · 模型 " + (remote.model || "(未配置)") + " · " + (remote.dimensions > 0 ? remote.dimensions + " 维" : "维度跟随部署") + (remote.apiKeySet ? " · 密钥已设置" : " · 密钥未设置") }),
2371
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: RSTY.row, children: [
2372
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: RSTY.label, children: "端点 URL" }),
2373
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2526
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: RSTY.block, children: [
2527
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: RSTY.title, children: "远程连接(生效值;运行时覆盖优先于部署 YAML)" }),
2528
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: RSTY.note, children: "生效端点 " + (remote.baseURL || "(未配置)") + " · 模型 " + (remote.model || "(未配置)") + " · " + (remote.dimensions > 0 ? remote.dimensions + " 维" : "维度跟随部署") + (remote.apiKeySet ? " · 密钥已设置" : " · 密钥未设置") }),
2529
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: RSTY.row, children: [
2530
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: RSTY.label, children: "端点 URL" }),
2531
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2374
2532
  NInput,
2375
2533
  {
2376
2534
  style: RSTY.input,
@@ -2387,9 +2545,9 @@ var __defProp = Object.defineProperty;
2387
2545
  }
2388
2546
  )
2389
2547
  ] }),
2390
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: RSTY.row, children: [
2391
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: RSTY.label, children: "模型名" }),
2392
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2548
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: RSTY.row, children: [
2549
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: RSTY.label, children: "模型名" }),
2550
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2393
2551
  NInput,
2394
2552
  {
2395
2553
  style: RSTY.input,
@@ -2405,8 +2563,8 @@ var __defProp = Object.defineProperty;
2405
2563
  }
2406
2564
  }
2407
2565
  ),
2408
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: RSTY.label, children: "维度" }),
2409
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2566
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: RSTY.label, children: "维度" }),
2567
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2410
2568
  NInput,
2411
2569
  {
2412
2570
  style: { width: 90, minWidth: 0, flex: "0 1 90px" },
@@ -2426,9 +2584,9 @@ var __defProp = Object.defineProperty;
2426
2584
  }
2427
2585
  )
2428
2586
  ] }),
2429
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: RSTY.row, children: [
2430
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: RSTY.label, children: "API Key" }),
2431
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2587
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: RSTY.row, children: [
2588
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: RSTY.label, children: "API Key" }),
2589
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2432
2590
  NInput,
2433
2591
  {
2434
2592
  style: RSTY.input,
@@ -2443,8 +2601,8 @@ var __defProp = Object.defineProperty;
2443
2601
  onBlur: commitRemoteKey
2444
2602
  }
2445
2603
  ),
2446
- remote.apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: RSTY.chipAccent, children: "已设置" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: RSTY.chipMuted, children: "未设置" }),
2447
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2604
+ remote.apiKeySet ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: RSTY.chipAccent, children: "已设置" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: RSTY.chipMuted, children: "未设置" }),
2605
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2448
2606
  NButton,
2449
2607
  {
2450
2608
  title: "写入空串清除运行时密钥(部署 YAML 的密钥不受影响)",
@@ -2454,14 +2612,14 @@ var __defProp = Object.defineProperty;
2454
2612
  )
2455
2613
  ] })
2456
2614
  ] }),
2457
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: S.panelLabel, children: "本地模型目录(下载后离线可用,不随插件分发)" }),
2615
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: S.panelLabel, children: "本地模型目录(下载后离线可用,不随插件分发)" }),
2458
2616
  modelCards
2459
2617
  ] });
2460
2618
  }
2461
2619
 
2462
2620
  // client/src/tabs/RebuildPanel.tsx
2463
- var import_react10 = require("react");
2464
- var import_jsx_runtime10 = require("react/jsx-runtime");
2621
+ var import_react11 = require("react");
2622
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2465
2623
  var RB_PHASE_LABEL = {
2466
2624
  preparing: "准备中(归档旧数据 · 清空检索库)",
2467
2625
  distilling: "分块蒸馏中",
@@ -2469,21 +2627,21 @@ var __defProp = Object.defineProperty;
2469
2627
  };
2470
2628
  function RebuildPanel(props) {
2471
2629
  const rpc = props.rpc;
2472
- const [rbRaw, setRb] = (0, import_react10.useState)(null);
2473
- const [confirmOpen, setConfirmOpen] = (0, import_react10.useState)(false);
2474
- const [busy, setBusy] = (0, import_react10.useState)(false);
2475
- const [rbError, setRbError] = (0, import_react10.useState)(null);
2476
- const refresh = (0, import_react10.useCallback)(() => {
2630
+ const [rbRaw, setRb] = (0, import_react11.useState)(null);
2631
+ const [confirmOpen, setConfirmOpen] = (0, import_react11.useState)(false);
2632
+ const [busy, setBusy] = (0, import_react11.useState)(false);
2633
+ const [rbError, setRbError] = (0, import_react11.useState)(null);
2634
+ const refresh = (0, import_react11.useCallback)(() => {
2477
2635
  rpc("dsh-memory/rebuild-status", {}).then((r) => {
2478
2636
  if (r && r.ok) setRb(r.value);
2479
2637
  }).catch(() => {
2480
2638
  });
2481
2639
  }, [rpc]);
2482
- (0, import_react10.useEffect)(() => {
2640
+ (0, import_react11.useEffect)(() => {
2483
2641
  refresh();
2484
2642
  }, [refresh]);
2485
2643
  const running = !!(rbRaw && rbRaw.running);
2486
- (0, import_react10.useEffect)(() => {
2644
+ (0, import_react11.useEffect)(() => {
2487
2645
  if (!running) return;
2488
2646
  const timer = setInterval(refresh, 1500);
2489
2647
  return () => {
@@ -2528,11 +2686,11 @@ var __defProp = Object.defineProperty;
2528
2686
  } else if (!running && rb.phase === "failed") {
2529
2687
  lastNote = "上次重建:失败:" + (rb.error || "未知错误");
2530
2688
  }
2531
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2532
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
2533
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "重建记忆" }),
2534
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RB_PHASE_LABEL[rb.phase] || rb.phase) + " · " + rb.done + "/" + rb.total + " 会话(" + pct + "%)" : "从 L0 原始对话重新蒸馏 L1/L2/L3;旧数据先归档(不删除)" }),
2535
- running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { disabled: busy || rb.cancelRequested, onClick: cancel, children: rb.cancelRequested ? "取消中…" : "取消重建" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2689
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
2691
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "重建记忆" }),
2692
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RB_PHASE_LABEL[rb.phase] || rb.phase) + " · " + rb.done + "/" + rb.total + " 会话(" + pct + "%)" : "从 L0 原始对话重新蒸馏 L1/L2/L3;旧数据先归档(不删除)" }),
2693
+ running ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { disabled: busy || rb.cancelRequested, onClick: cancel, children: rb.cancelRequested ? "取消中…" : "取消重建" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2536
2694
  NButton,
2537
2695
  {
2538
2696
  disabled: busy || empty,
@@ -2545,13 +2703,13 @@ var __defProp = Object.defineProperty;
2545
2703
  }
2546
2704
  )
2547
2705
  ] }),
2548
- running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
2549
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }),
2550
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rb.recordsBuilt + " 条" })
2706
+ running ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
2707
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: pct + "%" } }) }),
2708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rb.recordsBuilt + " 条" })
2551
2709
  ] }) : null,
2552
- lastNote ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
2553
- rbError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rbError }) : null,
2554
- confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2710
+ lastNote ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
2711
+ rbError ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rbError }) : null,
2712
+ confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2555
2713
  NModal,
2556
2714
  {
2557
2715
  open: true,
@@ -2560,7 +2718,7 @@ var __defProp = Object.defineProperty;
2560
2718
  },
2561
2719
  title: "确认重建全部记忆?",
2562
2720
  footer: [
2563
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2721
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2564
2722
  NButton,
2565
2723
  {
2566
2724
  onClick: () => {
@@ -2570,15 +2728,15 @@ var __defProp = Object.defineProperty;
2570
2728
  },
2571
2729
  "cancel"
2572
2730
  ),
2573
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "开始重建" }, "confirm")
2731
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "开始重建" }, "confirm")
2574
2732
  ],
2575
2733
  children: [
2576
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2734
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { children: [
2577
2735
  "将以 L0 原始对话为事实源重新蒸馏:",
2578
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
2736
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("b", { children: rb.sessionCount + " 个会话 · " + rb.messageCount + " 条消息" }),
2579
2737
  ",预计 ≥" + rb.estCalls + " 次蒸馏调用。"
2580
2738
  ] }),
2581
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
2739
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 8 }, children: "现有 L1 记忆 / L2 场景 / L3 画像会整体归档(*.bak.时间戳,可手工找回),随后清空重建;重建期间可正常对话,新对话的蒸馏优先进行;中途可取消,已重建部分保留。" })
2582
2740
  ]
2583
2741
  }
2584
2742
  ) : null
@@ -2586,8 +2744,8 @@ var __defProp = Object.defineProperty;
2586
2744
  }
2587
2745
 
2588
2746
  // client/src/tabs/RuminatePanel.tsx
2589
- var import_react11 = require("react");
2590
- var import_jsx_runtime11 = require("react/jsx-runtime");
2747
+ var import_react12 = require("react");
2748
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2591
2749
  var RM_PHASE_LABEL = {
2592
2750
  refreshing: "轻量刷新中",
2593
2751
  distilling: "L1 蒸馏中",
@@ -2597,27 +2755,27 @@ var __defProp = Object.defineProperty;
2597
2755
  var RM_RUNNING_PHASES = ["refreshing", "distilling", "consolidating", "updating"];
2598
2756
  function RuminatePanel(props) {
2599
2757
  const rpc = props.rpc;
2600
- const [rmRaw, setRm] = (0, import_react11.useState)(null);
2601
- const [confirmOpen, setConfirmOpen] = (0, import_react11.useState)(false);
2602
- const [busy, setBusy] = (0, import_react11.useState)(false);
2603
- const [rmError, setRmError] = (0, import_react11.useState)(null);
2604
- const refresh = (0, import_react11.useCallback)(() => {
2758
+ const [rmRaw, setRm] = (0, import_react12.useState)(null);
2759
+ const [confirmOpen, setConfirmOpen] = (0, import_react12.useState)(false);
2760
+ const [busy, setBusy] = (0, import_react12.useState)(false);
2761
+ const [rmError, setRmError] = (0, import_react12.useState)(null);
2762
+ const refresh = (0, import_react12.useCallback)(() => {
2605
2763
  rpc("dsh-memory/ruminate-status", {}).then((r) => {
2606
2764
  if (r && r.ok) setRm(r.value);
2607
2765
  }).catch(() => {
2608
2766
  });
2609
2767
  }, [rpc]);
2610
- (0, import_react11.useEffect)(() => {
2768
+ (0, import_react12.useEffect)(() => {
2611
2769
  refresh();
2612
2770
  }, [refresh]);
2613
2771
  const running = !!(rmRaw && (rmRaw.running || RM_RUNNING_PHASES.indexOf(rmRaw.phase) >= 0));
2614
- (0, import_react11.useEffect)(() => {
2772
+ (0, import_react12.useEffect)(() => {
2615
2773
  if (!running) return;
2616
2774
  const timer = setInterval(refresh, 1500);
2617
2775
  return () => clearInterval(timer);
2618
2776
  }, [running, refresh]);
2619
- const [, setTick] = (0, import_react11.useState)(0);
2620
- (0, import_react11.useEffect)(() => {
2777
+ const [, setTick] = (0, import_react12.useState)(0);
2778
+ (0, import_react12.useEffect)(() => {
2621
2779
  if (!running) return;
2622
2780
  const timer = setInterval(() => setTick((n) => n + 1), 1e3);
2623
2781
  return () => clearInterval(timer);
@@ -2664,11 +2822,11 @@ var __defProp = Object.defineProperty;
2664
2822
  }
2665
2823
  const unit = rm.phase === "refreshing" ? "步" : "会话";
2666
2824
  const progressText = rm.total > 0 ? rm.done + "/" + rm.total + " " + unit + "(" + pct + "%)" : "进行中…";
2667
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2668
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
2669
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "反刍整理" }),
2670
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RM_PHASE_LABEL[rm.phase] || rm.phase) + " · " + progressText + (elapsedText ? " · 已用 " + elapsedText : "") : "冲刷未蒸馏缓冲,跑一轮 L1→L2→L3 消化;不清库不改 L0" }),
2671
- running ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { disabled: busy || rm.cancelRequested, onClick: cancel, children: rm.cancelRequested ? "取消中…" : "取消整理" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2825
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dsh-mem-rb-card", children: [
2826
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
2827
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { fontWeight: 600, whiteSpace: "nowrap" }, children: "反刍整理" }),
2828
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { flex: 1, minWidth: 180 }, children: running ? (RM_PHASE_LABEL[rm.phase] || rm.phase) + " · " + progressText + (elapsedText ? " · 已用 " + elapsedText : "") : "冲刷未蒸馏缓冲,跑一轮 L1→L2→L3 消化;不清库不改 L0" }),
2829
+ running ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NButton, { disabled: busy || rm.cancelRequested, onClick: cancel, children: rm.cancelRequested ? "取消中…" : "取消整理" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2672
2830
  NButton,
2673
2831
  {
2674
2832
  disabled: busy,
@@ -2681,21 +2839,21 @@ var __defProp = Object.defineProperty;
2681
2839
  }
2682
2840
  )
2683
2841
  ] }),
2684
- running ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
2685
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: (rm.total > 0 ? pct : 100) + "%" } }) }),
2686
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rm.recordsBuilt + " 条" })
2842
+ running ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, marginTop: 10 }, children: [
2843
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-bar", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-fill", style: { width: (rm.total > 0 ? pct : 100) + "%" } }) }),
2844
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dsh-mem-rb-muted", style: { whiteSpace: "nowrap" }, children: "产出 " + rm.recordsBuilt + " 条" })
2687
2845
  ] }) : null,
2688
- running && rm.detail ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 6, whiteSpace: "normal" }, children: "当前:" + rm.detail }) : null,
2689
- lastNote ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
2690
- rmError ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rmError }) : null,
2691
- confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2846
+ running && rm.detail ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 6, whiteSpace: "normal" }, children: "当前:" + rm.detail }) : null,
2847
+ lastNote ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dsh-mem-rb-muted", style: { marginTop: 8 }, children: lastNote }) : null,
2848
+ rmError ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 8, fontSize: 12, color: "var(--dsh-mem-danger)" }, children: rmError }) : null,
2849
+ confirmOpen ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2692
2850
  NModal,
2693
2851
  {
2694
2852
  open: true,
2695
2853
  onClose: () => setConfirmOpen(false),
2696
2854
  title: "确认反刍整理?",
2697
2855
  footer: [
2698
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2856
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2699
2857
  NButton,
2700
2858
  {
2701
2859
  onClick: () => setConfirmOpen(false),
@@ -2703,11 +2861,11 @@ var __defProp = Object.defineProperty;
2703
2861
  },
2704
2862
  "cancel"
2705
2863
  ),
2706
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "反刍整理" }, "confirm")
2864
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NButton, { variant: "primary", disabled: busy, onClick: start, children: busy ? "启动中…" : "反刍整理" }, "confirm")
2707
2865
  ],
2708
2866
  children: [
2709
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: "将扫描未蒸馏缓冲,按会话逐个跑蒸馏管线,完成后强制 L2 场景整合与 L3 画像更新。" }),
2710
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 8 }, children: "与重建不同:不清空 L1 检索库、不归档旧产物、不改 L0;仅消化攒而未蒸馏的切片,无缓冲时做轻量 L2/L3 刷新。" })
2867
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "将扫描未蒸馏缓冲,按会话逐个跑蒸馏管线,完成后强制 L2 场景整合与 L3 画像更新。" }),
2868
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 8 }, children: "与重建不同:不清空 L1 检索库、不归档旧产物、不改 L0;仅消化攒而未蒸馏的切片,无缓冲时做轻量 L2/L3 刷新。" })
2711
2869
  ]
2712
2870
  }
2713
2871
  ) : null
@@ -2715,13 +2873,13 @@ var __defProp = Object.defineProperty;
2715
2873
  }
2716
2874
 
2717
2875
  // client/src/tabs/OverviewTab.tsx
2718
- var import_jsx_runtime12 = require("react/jsx-runtime");
2876
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2719
2877
  function OverviewTab(props) {
2720
2878
  const rpc = props.rpc;
2721
- const [stats, setStats] = (0, import_react12.useState)(null);
2722
- const [settingsData, setSettingsData] = (0, import_react12.useState)(null);
2723
- const [error, setError] = (0, import_react12.useState)(null);
2724
- const load = (0, import_react12.useCallback)(() => {
2879
+ const [stats, setStats] = (0, import_react13.useState)(null);
2880
+ const [settingsData, setSettingsData] = (0, import_react13.useState)(null);
2881
+ const [error, setError] = (0, import_react13.useState)(null);
2882
+ const load = (0, import_react13.useCallback)(() => {
2725
2883
  rpc("dsh-memory/stats", {}).then((r) => {
2726
2884
  if (r && r.ok) setStats(r.value);
2727
2885
  else setError(r && r.error ? r.error.message : "RPC error");
@@ -2733,7 +2891,7 @@ var __defProp = Object.defineProperty;
2733
2891
  }).catch(() => {
2734
2892
  });
2735
2893
  }, [rpc]);
2736
- (0, import_react12.useEffect)(() => {
2894
+ (0, import_react13.useEffect)(() => {
2737
2895
  load();
2738
2896
  const timer = setInterval(load, 5e3);
2739
2897
  return () => {
@@ -2788,10 +2946,10 @@ var __defProp = Object.defineProperty;
2788
2946
  if (off.length > 0) ceilingNote = "注意:部署配置已停用 " + off.join("、") + "(运行时开关无法开启)";
2789
2947
  }
2790
2948
  const mutate = settingsData && settingsData.settings ? !!settingsData.settings.memoryMutate : false;
2791
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2792
- settingsData && settingsData.supported === false ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: S.hint, children: "settings 服务不可用,记忆模式开关未启用(记忆保持全开)。" }) : settingsData ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.switchPanel, children: [
2793
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
2794
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2949
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
2950
+ settingsData && settingsData.supported === false ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: S.hint, children: "settings 服务不可用,记忆模式开关未启用(记忆保持全开)。" }) : settingsData ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.switchPanel, children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "记忆模式" }),
2952
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2795
2953
  SwitchRow,
2796
2954
  {
2797
2955
  label: "记忆模式",
@@ -2802,7 +2960,7 @@ var __defProp = Object.defineProperty;
2802
2960
  }
2803
2961
  }
2804
2962
  ),
2805
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2963
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2806
2964
  SwitchRow,
2807
2965
  {
2808
2966
  label: "捕获",
@@ -2814,7 +2972,7 @@ var __defProp = Object.defineProperty;
2814
2972
  }
2815
2973
  }
2816
2974
  ),
2817
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2975
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2818
2976
  SwitchRow,
2819
2977
  {
2820
2978
  label: "蒸馏",
@@ -2826,7 +2984,7 @@ var __defProp = Object.defineProperty;
2826
2984
  }
2827
2985
  }
2828
2986
  ),
2829
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2987
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2830
2988
  SwitchRow,
2831
2989
  {
2832
2990
  label: "召回",
@@ -2838,8 +2996,8 @@ var __defProp = Object.defineProperty;
2838
2996
  }
2839
2997
  }
2840
2998
  ),
2841
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
2842
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2999
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "高权限模式" }),
3000
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2843
3001
  SwitchRow,
2844
3002
  {
2845
3003
  label: "高权限模式",
@@ -2850,42 +3008,42 @@ var __defProp = Object.defineProperty;
2850
3008
  }
2851
3009
  }
2852
3010
  ),
2853
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
2854
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
2855
- ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: S.hint, children: ceilingNote }) : null
3011
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "蒸馏参数" }),
3012
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DistillSettings, { rpc, disabled: !master, data: settingsData, setData: setSettingsData, onError: setError }),
3013
+ ceilingNote ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: S.hint, children: ceilingNote }) : null
2856
3014
  ] }) : null,
2857
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EmbeddingSection, { rpc }),
2858
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RebuildPanel, { rpc }),
2859
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RuminatePanel, { rpc }),
2860
- degraded ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
2861
- error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.error, children: "获取状态失败:" + error }) : !stats ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: S.intro, children: "正在读取记忆状态…" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
2862
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
2863
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
2864
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
2865
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.statNum, children: t.num }),
2866
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.statLabel, children: t.label })
3015
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EmbeddingSection, { rpc }),
3016
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RebuildPanel, { rpc }),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RuminatePanel, { rpc }),
3018
+ degraded ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "⚠ " + stats.message + "。上方数据为最后一次成功读取的值,记忆功能当前未工作。" }) : null,
3019
+ error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.error, children: "获取状态失败:" + error }) : !stats ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: S.intro, children: "正在读取记忆状态…" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
3020
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "记忆概况" }),
3021
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.statGrid, children: tiles.map((t) => {
3022
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "dsh-mem-card", style: S.statTile, children: [
3023
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.statNum, children: t.num }),
3024
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.statLabel, children: t.label })
2867
3025
  ] }, t.label);
2868
3026
  }) }),
2869
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
3027
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.panelLabel, children: "运行状态" }),
2870
3028
  infos.map((row2) => {
2871
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: S.infoRow, children: [
2872
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: S.infoKey, children: row2[0] }),
2873
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: S.infoVal, children: row2[1] })
3029
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: S.infoRow, children: [
3030
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: S.infoKey, children: row2[0] }),
3031
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: S.infoVal, children: row2[1] })
2874
3032
  ] }, row2[0]);
2875
3033
  })
2876
3034
  ] }),
2877
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
3035
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: S.hint, children: "浏览各层记忆内容请切换上方 Tab;原始对话(L0)不入浏览器,可由模型侧 conversation_search 工具查询。" })
2878
3036
  ] });
2879
3037
  }
2880
3038
 
2881
3039
  // client/src/tabs/PersonaTab.tsx
2882
- var import_react13 = require("react");
2883
- var import_jsx_runtime13 = require("react/jsx-runtime");
3040
+ var import_react14 = require("react");
3041
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2884
3042
  function PersonaTab(props) {
2885
3043
  const rpc = props.rpc;
2886
- const [content, setContent] = (0, import_react13.useState)(null);
2887
- const [error, setError] = (0, import_react13.useState)(null);
2888
- const load = (0, import_react13.useCallback)(() => {
3044
+ const [content, setContent] = (0, import_react14.useState)(null);
3045
+ const [error, setError] = (0, import_react14.useState)(null);
3046
+ const load = (0, import_react14.useCallback)(() => {
2889
3047
  setError(null);
2890
3048
  rpc("dsh-memory/persona", {}).then((r) => {
2891
3049
  if (r && r.ok) setContent(r.value.content);
@@ -2894,23 +3052,23 @@ var __defProp = Object.defineProperty;
2894
3052
  setError(String(e && e.message || e));
2895
3053
  });
2896
3054
  }, [rpc]);
2897
- (0, import_react13.useEffect)(() => {
3055
+ (0, import_react14.useEffect)(() => {
2898
3056
  load();
2899
3057
  }, [load]);
2900
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
2901
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
2902
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
2903
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: S.grow }),
2904
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(NButton, { onClick: load, children: "刷新" })
3058
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3059
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3060
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.muted, children: error ? "加载失败" : content === null ? "加载中…" : content ? content.length + " 字符" : "未生成画像" }),
3061
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.grow }),
3062
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { onClick: load, children: "刷新" })
2905
3063
  ] }),
2906
- error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
2907
- content ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { style: S.pre, children: content }) : content === null ? null : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: S.intro, children: "画像尚未生成;蒸馏若干记忆后 L3 会自动产出。" })
3064
+ error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { ...S.error, marginBottom: 10 }, children: "画像读取失败:" + error + "(点右上“刷新”重试)" }) : null,
3065
+ content ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { style: S.pre, children: content }) : content === null ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: S.intro, children: "画像尚未生成;蒸馏若干记忆后 L3 会自动产出。" })
2908
3066
  ] });
2909
3067
  }
2910
3068
 
2911
3069
  // client/src/tabs/RecordsTab.tsx
2912
- var import_react14 = require("react");
2913
- var import_jsx_runtime14 = require("react/jsx-runtime");
3070
+ var import_react15 = require("react");
3071
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2914
3072
  var TYPE_CHOICES = [
2915
3073
  "persona",
2916
3074
  "episodic",
@@ -2932,24 +3090,24 @@ var __defProp = Object.defineProperty;
2932
3090
  function RecordsTab(props) {
2933
3091
  const rpc = props.rpc;
2934
3092
  const limit = 50;
2935
- const [items, setItems] = (0, import_react14.useState)([]);
2936
- const [hasMore, setHasMore] = (0, import_react14.useState)(false);
2937
- const [total, setTotal] = (0, import_react14.useState)(null);
2938
- const [sceneOptions, setSceneOptions] = (0, import_react14.useState)([]);
2939
- const [loading, setLoading] = (0, import_react14.useState)(false);
2940
- const [truncated, setTruncated] = (0, import_react14.useState)(false);
2941
- const [error, setError] = (0, import_react14.useState)(null);
2942
- const [expandedId, setExpandedId] = (0, import_react14.useState)(null);
2943
- const [sel, setSel] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
2944
- const [hiPriv, setHiPriv] = (0, import_react14.useState)(false);
2945
- const [hiPrivBusy, setHiPrivBusy] = (0, import_react14.useState)(false);
2946
- const [query, setQuery] = (0, import_react14.useState)("");
2947
- const [typeFilter, setTypeFilter] = (0, import_react14.useState)("");
2948
- const [sceneFilter, setSceneFilter] = (0, import_react14.useState)("");
2949
- const [hallFilter, setHallFilter] = (0, import_react14.useState)("");
2950
- const [last, setLast] = (0, import_react14.useState)({ query: "", type: "", scene: "", hall: "" });
2951
- const seqRef = (0, import_react14.useRef)(0);
2952
- const fetchPage = (0, import_react14.useCallback)(
3093
+ const [items, setItems] = (0, import_react15.useState)([]);
3094
+ const [hasMore, setHasMore] = (0, import_react15.useState)(false);
3095
+ const [total, setTotal] = (0, import_react15.useState)(null);
3096
+ const [sceneOptions, setSceneOptions] = (0, import_react15.useState)([]);
3097
+ const [loading, setLoading] = (0, import_react15.useState)(false);
3098
+ const [truncated, setTruncated] = (0, import_react15.useState)(false);
3099
+ const [error, setError] = (0, import_react15.useState)(null);
3100
+ const [expandedId, setExpandedId] = (0, import_react15.useState)(null);
3101
+ const [sel, setSel] = (0, import_react15.useState)(/* @__PURE__ */ new Set());
3102
+ const [hiPriv, setHiPriv] = (0, import_react15.useState)(false);
3103
+ const [hiPrivBusy, setHiPrivBusy] = (0, import_react15.useState)(false);
3104
+ const [query, setQuery] = (0, import_react15.useState)("");
3105
+ const [typeFilter, setTypeFilter] = (0, import_react15.useState)("");
3106
+ const [sceneFilter, setSceneFilter] = (0, import_react15.useState)("");
3107
+ const [hallFilter, setHallFilter] = (0, import_react15.useState)("");
3108
+ const [last, setLast] = (0, import_react15.useState)({ query: "", type: "", scene: "", hall: "" });
3109
+ const seqRef = (0, import_react15.useRef)(0);
3110
+ const fetchPage = (0, import_react15.useCallback)(
2953
3111
  (conds, offset, append) => {
2954
3112
  setLoading(true);
2955
3113
  setError(null);
@@ -2986,16 +3144,16 @@ var __defProp = Object.defineProperty;
2986
3144
  setLast(conds);
2987
3145
  fetchPage(conds, 0, false);
2988
3146
  };
2989
- (0, import_react14.useEffect)(() => {
3147
+ (0, import_react15.useEffect)(() => {
2990
3148
  fetchPage({ query: "", type: "", scene: "", hall: "" }, 0, false);
2991
3149
  }, [fetchPage]);
2992
- const loadHiPriv = (0, import_react14.useCallback)(() => {
3150
+ const loadHiPriv = (0, import_react15.useCallback)(() => {
2993
3151
  rpc("dsh-memory/settings-get", {}).then((r) => {
2994
3152
  if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
2995
3153
  }).catch(() => {
2996
3154
  });
2997
3155
  }, [rpc]);
2998
- (0, import_react14.useEffect)(() => {
3156
+ (0, import_react15.useEffect)(() => {
2999
3157
  loadHiPriv();
3000
3158
  }, [loadHiPriv]);
3001
3159
  const toggleHiPriv = () => {
@@ -3056,9 +3214,9 @@ var __defProp = Object.defineProperty;
3056
3214
  };
3057
3215
  const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
3058
3216
  const selCount = sel.size;
3059
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
3060
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.toolbar, children: [
3061
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3217
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
3218
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.toolbar, children: [
3219
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3062
3220
  NInput,
3063
3221
  {
3064
3222
  style: { flex: 1, minWidth: 160 },
@@ -3072,7 +3230,7 @@ var __defProp = Object.defineProperty;
3072
3230
  }
3073
3231
  }
3074
3232
  ),
3075
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3233
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3076
3234
  NSel,
3077
3235
  {
3078
3236
  style: { maxWidth: 200 },
@@ -3085,7 +3243,7 @@ var __defProp = Object.defineProperty;
3085
3243
  onChange: setTypeFilter
3086
3244
  }
3087
3245
  ),
3088
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3246
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3089
3247
  NSel,
3090
3248
  {
3091
3249
  style: { maxWidth: 220 },
@@ -3098,7 +3256,7 @@ var __defProp = Object.defineProperty;
3098
3256
  onChange: setSceneFilter
3099
3257
  }
3100
3258
  ),
3101
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3259
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3102
3260
  NSel,
3103
3261
  {
3104
3262
  style: { maxWidth: 150 },
@@ -3111,8 +3269,8 @@ var __defProp = Object.defineProperty;
3111
3269
  onChange: setHallFilter
3112
3270
  }
3113
3271
  ),
3114
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NButton, { onClick: search, children: "搜索" }),
3115
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3272
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NButton, { onClick: search, children: "搜索" }),
3273
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3116
3274
  NButton,
3117
3275
  {
3118
3276
  style: {
@@ -3126,9 +3284,9 @@ var __defProp = Object.defineProperty;
3126
3284
  }
3127
3285
  )
3128
3286
  ] }),
3129
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3130
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
3131
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3287
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3288
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
3289
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3132
3290
  NButton,
3133
3291
  {
3134
3292
  style: selCount > 0 ? { color: "var(--dsh-mem-danger)" } : void 0,
@@ -3138,7 +3296,7 @@ var __defProp = Object.defineProperty;
3138
3296
  children: "删除选中" + (selCount > 0 ? "(" + selCount + ")" : "")
3139
3297
  }
3140
3298
  ),
3141
- selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3299
+ selCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3142
3300
  NButton,
3143
3301
  {
3144
3302
  onClick: () => {
@@ -3147,8 +3305,8 @@ var __defProp = Object.defineProperty;
3147
3305
  children: "清空选择"
3148
3306
  }
3149
3307
  ) : null,
3150
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.grow }),
3151
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3308
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
3309
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3152
3310
  NButton,
3153
3311
  {
3154
3312
  onClick: () => {
@@ -3158,13 +3316,13 @@ var __defProp = Object.defineProperty;
3158
3316
  }
3159
3317
  )
3160
3318
  ] }),
3161
- !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
3162
- error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.error, children: error }) : null,
3163
- truncated ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
3164
- items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
3319
+ !hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.hint, children: "提示:删除记忆需先开启高权限模式(右上开关或概览页「高权限模式」),关闭时删除按钮不可用。" }) : null,
3320
+ error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.error, children: error }) : null,
3321
+ truncated ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.hint, children: "搜索分页已达检索上限(200 条),更早的结果未显示。请用更精确的关键词或类型/情境过滤。" }) : null,
3322
+ items.length === 0 && !loading && !error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.intro, children: "暂无记忆。对话几轮后,蒸馏管线会自动抽取记忆。" }) : items.map((m) => {
3165
3323
  const open = expandedId === m.id;
3166
3324
  const checked = sel.has(m.id);
3167
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3325
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3168
3326
  "div",
3169
3327
  {
3170
3328
  className: "dsh-mem-card dsh-mem-card-hover",
@@ -3173,8 +3331,8 @@ var __defProp = Object.defineProperty;
3173
3331
  setExpandedId(open ? null : m.id);
3174
3332
  },
3175
3333
  children: [
3176
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.cardHead, children: [
3177
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3334
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.cardHead, children: [
3335
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3178
3336
  "input",
3179
3337
  {
3180
3338
  type: "checkbox",
@@ -3189,13 +3347,13 @@ var __defProp = Object.defineProperty;
3189
3347
  }
3190
3348
  }
3191
3349
  ),
3192
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + m.type, children: TYPE_LABELS[m.type] || m.type }),
3193
- m.hall ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-fact", children: "Hall · " + (HALL_LABEL[m.hall] || m.hall) }) : null,
3194
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
3195
- m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
3196
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.grow }),
3197
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
3198
- hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3350
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + m.type, children: TYPE_LABELS[m.type] || m.type }),
3351
+ m.hall ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-work-fact", children: "Hall · " + (HALL_LABEL[m.hall] || m.hall) }) : null,
3352
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
3353
+ m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
3354
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
3355
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
3356
+ hiPriv ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3199
3357
  NButton,
3200
3358
  {
3201
3359
  style: { padding: "0 7px", minWidth: 26, height: 26, fontSize: 12, color: "var(--dsh-mem-danger)" },
@@ -3208,16 +3366,16 @@ var __defProp = Object.defineProperty;
3208
3366
  }
3209
3367
  ) : null
3210
3368
  ] }),
3211
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.content, children: m.content }),
3212
- open ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.detail, children: "id: " + m.id + "\n情境: " + (m.scene || "-") + "\n版本: v" + m.version + "(去重合并次数 " + m.version + ")\n创建: " + fmtTime(m.createdAt) + "\n活跃时间: " + (m.timestamps && m.timestamps.length > 0 ? m.timestamps.map(fmtTime).join(" → ") : "-") + "\n" + (m.sourceMessageIds && m.sourceMessageIds.length > 0 ? "来源消息: " + m.sourceMessageIds.join(", ") : "来源消息: -") }) : null
3369
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.content, children: m.content }),
3370
+ open ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.detail, children: "id: " + m.id + "\n情境: " + (m.scene || "-") + "\n版本: v" + m.version + "(去重合并次数 " + m.version + ")\n创建: " + fmtTime(m.createdAt) + "\n活跃时间: " + (m.timestamps && m.timestamps.length > 0 ? m.timestamps.map(fmtTime).join(" → ") : "-") + "\n" + (m.sourceMessageIds && m.sourceMessageIds.length > 0 ? "来源消息: " + m.sourceMessageIds.join(", ") : "来源消息: -") }) : null
3213
3371
  ]
3214
3372
  },
3215
3373
  m.id
3216
3374
  );
3217
3375
  }),
3218
- hasMore ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.flexRow, children: [
3219
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.grow }),
3220
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3376
+ hasMore ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.flexRow, children: [
3377
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
3378
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3221
3379
  NButton,
3222
3380
  {
3223
3381
  disabled: loading,
@@ -3232,13 +3390,13 @@ var __defProp = Object.defineProperty;
3232
3390
  }
3233
3391
 
3234
3392
  // client/src/tabs/ScenesTab.tsx
3235
- var import_react15 = require("react");
3236
- var import_jsx_runtime15 = require("react/jsx-runtime");
3393
+ var import_react16 = require("react");
3394
+ var import_jsx_runtime16 = require("react/jsx-runtime");
3237
3395
  function SceneCard(props) {
3238
3396
  const s = props.s;
3239
- const [open, setOpen] = (0, import_react15.useState)(false);
3240
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
3241
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
3397
+ const [open, setOpen] = (0, import_react16.useState)(false);
3398
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
3399
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3242
3400
  "div",
3243
3401
  {
3244
3402
  style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
@@ -3246,23 +3404,23 @@ var __defProp = Object.defineProperty;
3246
3404
  setOpen(!open);
3247
3405
  },
3248
3406
  children: [
3249
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
3250
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.sceneTitle, children: s.path }),
3251
- s.heat ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
3252
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
3253
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
3407
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
3408
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.sceneTitle, children: s.path }),
3409
+ s.heat ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
3410
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
3411
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
3254
3412
  ]
3255
3413
  }
3256
3414
  ),
3257
- s.summary ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
3258
- open ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
3415
+ s.summary ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
3416
+ open ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
3259
3417
  ] });
3260
3418
  }
3261
3419
  function ScenesTab(props) {
3262
3420
  const rpc = props.rpc;
3263
- const [items, setItems] = (0, import_react15.useState)(null);
3264
- const [error, setError] = (0, import_react15.useState)(null);
3265
- const load = (0, import_react15.useCallback)(() => {
3421
+ const [items, setItems] = (0, import_react16.useState)(null);
3422
+ const [error, setError] = (0, import_react16.useState)(null);
3423
+ const load = (0, import_react16.useCallback)(() => {
3266
3424
  rpc("dsh-memory/scenes", {}).then((r) => {
3267
3425
  if (r && r.ok) {
3268
3426
  setItems(r.value.items);
@@ -3272,28 +3430,29 @@ var __defProp = Object.defineProperty;
3272
3430
  setError(String(e && e.message || e));
3273
3431
  });
3274
3432
  }, [rpc]);
3275
- (0, import_react15.useEffect)(() => {
3433
+ (0, import_react16.useEffect)(() => {
3276
3434
  load();
3277
3435
  }, [load]);
3278
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
3279
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3280
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
3281
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
3282
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(NButton, { onClick: load, children: "刷新" })
3436
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
3437
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
3438
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
3439
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
3440
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { onClick: load, children: "刷新" })
3283
3441
  ] }),
3284
- error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.error, children: error }) : null,
3285
- items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
3442
+ error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.error, children: error }) : null,
3443
+ items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
3286
3444
  (items || []).map((s) => {
3287
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SceneCard, { s }, s.path);
3445
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SceneCard, { s }, s.path);
3288
3446
  })
3289
3447
  ] });
3290
3448
  }
3291
3449
 
3292
3450
  // client/src/panel.tsx
3293
- var import_jsx_runtime16 = require("react/jsx-runtime");
3451
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3294
3452
  var TABS = [
3295
3453
  ["overview", "概览"],
3296
3454
  ["records", "记忆"],
3455
+ ["conflicts", "冲突"],
3297
3456
  ["scenes", "场景"],
3298
3457
  ["persona", "画像"],
3299
3458
  ["cost", "成本"],
@@ -3301,23 +3460,24 @@ var __defProp = Object.defineProperty;
3301
3460
  ];
3302
3461
  function MemoryPanel(props) {
3303
3462
  const rpc = props.rpc;
3304
- const [tab, setTab] = (0, import_react16.useState)("overview");
3463
+ const [tab, setTab] = (0, import_react17.useState)("overview");
3305
3464
  ensureThemeStyle();
3306
- (0, import_react16.useEffect)(() => {
3465
+ (0, import_react17.useEffect)(() => {
3307
3466
  watchSidebarIcon();
3308
3467
  }, []);
3309
3468
  let body;
3310
- if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(OverviewTab, { rpc });
3311
- else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RecordsTab, { rpc });
3312
- else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ScenesTab, { rpc });
3313
- else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PersonaTab, { rpc });
3314
- else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CostTab, { rpc });
3315
- else body = /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LogTab, { rpc });
3316
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
3317
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
3318
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
3319
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
3320
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3469
+ if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(OverviewTab, { rpc });
3470
+ else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RecordsTab, { rpc });
3471
+ else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ConflictsTab, { rpc });
3472
+ else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ScenesTab, { rpc });
3473
+ else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PersonaTab, { rpc });
3474
+ else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CostTab, { rpc });
3475
+ else body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(LogTab, { rpc });
3476
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
3477
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
3478
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
3479
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
3480
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3321
3481
  "button",
3322
3482
  {
3323
3483
  className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
@@ -3334,7 +3494,7 @@ var __defProp = Object.defineProperty;
3334
3494
  }
3335
3495
 
3336
3496
  // client/src/pill/MemoryModePill.tsx
3337
- var import_react19 = require("react");
3497
+ var import_react20 = require("react");
3338
3498
 
3339
3499
  // src/util/context-occupancy.ts
3340
3500
  var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
@@ -3650,23 +3810,23 @@ var __defProp = Object.defineProperty;
3650
3810
  }
3651
3811
 
3652
3812
  // client/src/pill/ModeSlider.tsx
3653
- var import_react18 = require("react");
3813
+ var import_react19 = require("react");
3654
3814
 
3655
3815
  // client/src/pill/SessionInfoArea.tsx
3656
- var import_react17 = require("react");
3657
- var import_jsx_runtime17 = require("react/jsx-runtime");
3816
+ var import_react18 = require("react");
3817
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3658
3818
  function sinfoCell(val, label, title) {
3659
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { title: title || void 0, children: [
3660
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
3661
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
3819
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { title: title || void 0, children: [
3820
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
3821
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
3662
3822
  ] });
3663
3823
  }
3664
3824
  function SessionInfoArea(props) {
3665
3825
  const rpc = props.rpc;
3666
3826
  const sessionId = props.sessionId;
3667
- const [stats, setStats] = (0, import_react17.useState)(void 0);
3668
- const busyRef = (0, import_react17.useRef)(false);
3669
- (0, import_react17.useEffect)(() => {
3827
+ const [stats, setStats] = (0, import_react18.useState)(void 0);
3828
+ const busyRef = (0, import_react18.useRef)(false);
3829
+ (0, import_react18.useEffect)(() => {
3670
3830
  if (!rpc || !sessionId) return void 0;
3671
3831
  let alive = true;
3672
3832
  let timer = null;
@@ -3699,7 +3859,7 @@ var __defProp = Object.defineProperty;
3699
3859
  }, [rpc, sessionId]);
3700
3860
  if (stats === null) return null;
3701
3861
  if (stats === void 0) {
3702
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
3862
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
3703
3863
  sinfoCell("…", "召回命中"),
3704
3864
  sinfoCell("…", "攒批进度"),
3705
3865
  sinfoCell("…", "本会话记忆"),
@@ -3748,27 +3908,27 @@ var __defProp = Object.defineProperty;
3748
3908
  else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
3749
3909
  }
3750
3910
  const ago = fmtAgo(gl.lastExtractAt);
3751
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-sinfo", children: [
3752
- warn ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
3753
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
3911
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-sinfo", children: [
3912
+ warn ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
3913
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
3754
3914
  sinfoCell(rcVal, rcLabel, rcTitle),
3755
3915
  sinfoCell(dVal, dLabel, dTitle),
3756
3916
  sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
3757
3917
  sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
3758
3918
  ] }),
3759
- note ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
3760
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
3919
+ note ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
3920
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
3761
3921
  ] });
3762
3922
  }
3763
3923
 
3764
3924
  // client/src/pill/ModeSlider.tsx
3765
- var import_jsx_runtime18 = require("react/jsx-runtime");
3925
+ var import_jsx_runtime19 = require("react/jsx-runtime");
3766
3926
  function ModeSlider(props) {
3767
3927
  ensureThemeStyle();
3768
- const trackRef = (0, import_react18.useRef)(null);
3769
- const [drag, setDrag] = (0, import_react18.useState)(null);
3770
- const canvasRef = (0, import_react18.useRef)(null);
3771
- const geoRef = (0, import_react18.useRef)(null);
3928
+ const trackRef = (0, import_react19.useRef)(null);
3929
+ const [drag, setDrag] = (0, import_react19.useState)(null);
3930
+ const canvasRef = (0, import_react19.useRef)(null);
3931
+ const geoRef = (0, import_react19.useRef)(null);
3772
3932
  const clampX = (x) => {
3773
3933
  if (x < 0) return 0;
3774
3934
  if (x > INNER_W) return INNER_W;
@@ -3816,7 +3976,7 @@ var __defProp = Object.defineProperty;
3816
3976
  // 与填充显隐同源
3817
3977
  dragging: drag !== null
3818
3978
  };
3819
- (0, import_react18.useEffect)(() => {
3979
+ (0, import_react19.useEffect)(() => {
3820
3980
  const canvas = canvasRef.current;
3821
3981
  if (!canvas) return void 0;
3822
3982
  const ctx = canvas.getContext && canvas.getContext("2d");
@@ -3922,10 +4082,10 @@ var __defProp = Object.defineProperty;
3922
4082
  themeObs.disconnect();
3923
4083
  };
3924
4084
  }, []);
3925
- const popRef = (0, import_react18.useRef)(null);
3926
- const shiftRef = (0, import_react18.useRef)(0);
3927
- const [shiftX, setShiftX] = (0, import_react18.useState)(0);
3928
- (0, import_react18.useLayoutEffect)(() => {
4085
+ const popRef = (0, import_react19.useRef)(null);
4086
+ const shiftRef = (0, import_react19.useRef)(0);
4087
+ const [shiftX, setShiftX] = (0, import_react19.useState)(0);
4088
+ (0, import_react19.useLayoutEffect)(() => {
3929
4089
  const clamp = () => {
3930
4090
  const el = popRef.current;
3931
4091
  if (!el) return;
@@ -3955,7 +4115,7 @@ var __defProp = Object.defineProperty;
3955
4115
  for (let i = 0; i < MODES.length; i++) {
3956
4116
  const stopLeft = i / (MODES.length - 1) * INNER_W + THUMB / 2;
3957
4117
  stops.push(
3958
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4118
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3959
4119
  "div",
3960
4120
  {
3961
4121
  style: {
@@ -3974,7 +4134,7 @@ var __defProp = Object.defineProperty;
3974
4134
  )
3975
4135
  );
3976
4136
  }
3977
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4137
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3978
4138
  "div",
3979
4139
  {
3980
4140
  ref: popRef,
@@ -3985,13 +4145,13 @@ var __defProp = Object.defineProperty;
3985
4145
  transform: "translateX(calc(-50% + " + shiftX + "px))",
3986
4146
  zIndex: 1e3
3987
4147
  },
3988
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4148
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
3989
4149
  "div",
3990
4150
  {
3991
4151
  className: "dsh-mem-popover",
3992
4152
  style: { position: "relative", padding: "14px 16px" },
3993
4153
  children: [
3994
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4154
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
3995
4155
  "div",
3996
4156
  {
3997
4157
  ref: trackRef,
@@ -4011,7 +4171,7 @@ var __defProp = Object.defineProperty;
4011
4171
  onPointerUp,
4012
4172
  onPointerCancel: onPointerUp,
4013
4173
  children: [
4014
- activeIdx > 0 || drag !== null ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4174
+ activeIdx > 0 || drag !== null ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4015
4175
  "div",
4016
4176
  {
4017
4177
  style: {
@@ -4029,7 +4189,7 @@ var __defProp = Object.defineProperty;
4029
4189
  }
4030
4190
  ) : null,
4031
4191
  stops,
4032
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4192
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4033
4193
  "canvas",
4034
4194
  {
4035
4195
  ref: canvasRef,
@@ -4046,7 +4206,7 @@ var __defProp = Object.defineProperty;
4046
4206
  }
4047
4207
  }
4048
4208
  ),
4049
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4209
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4050
4210
  "div",
4051
4211
  {
4052
4212
  style: {
@@ -4065,12 +4225,12 @@ var __defProp = Object.defineProperty;
4065
4225
  }
4066
4226
  }
4067
4227
  ),
4068
- drag !== null ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-bubble", style: { left: thumbLeft + THUMB / 2, zIndex: 4 }, children: info.label }) : null
4228
+ drag !== null ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "dsh-mem-bubble", style: { left: thumbLeft + THUMB / 2, zIndex: 4 }, children: info.label }) : null
4069
4229
  ]
4070
4230
  }
4071
4231
  ),
4072
- props.error ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 10, whiteSpace: "nowrap" }, children: props.error }) : null,
4073
- props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
4232
+ props.error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 10, whiteSpace: "nowrap" }, children: props.error }) : null,
4233
+ props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4074
4234
  "div",
4075
4235
  {
4076
4236
  style: {
@@ -4083,8 +4243,8 @@ var __defProp = Object.defineProperty;
4083
4243
  gap: 8
4084
4244
  },
4085
4245
  children: [
4086
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: "注入" }),
4087
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4246
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: "注入" }),
4247
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4088
4248
  Segmented,
4089
4249
  {
4090
4250
  value: props.recall === null ? "follow" : props.recall ? "on" : "off",
@@ -4100,7 +4260,7 @@ var __defProp = Object.defineProperty;
4100
4260
  ]
4101
4261
  }
4102
4262
  ) : null,
4103
- props.rpc && props.sessionId ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId }) : null
4263
+ props.rpc && props.sessionId ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId }) : null
4104
4264
  ]
4105
4265
  }
4106
4266
  )
@@ -4109,18 +4269,18 @@ var __defProp = Object.defineProperty;
4109
4269
  }
4110
4270
 
4111
4271
  // client/src/pill/MemoryModePill.tsx
4112
- var import_jsx_runtime19 = require("react/jsx-runtime");
4272
+ var import_jsx_runtime20 = require("react/jsx-runtime");
4113
4273
  function MemoryModePill(props) {
4114
4274
  const rpc = props.rpc;
4115
4275
  const sessionId = props.sessionId || props.session && props.session.sessionId;
4116
- const [mode, setMode] = (0, import_react19.useState)(null);
4117
- const [recall, setRecall] = (0, import_react19.useState)(null);
4118
- const [recallResolved, setRecallResolved] = (0, import_react19.useState)(true);
4119
- const [error, setError] = (0, import_react19.useState)(null);
4120
- const [open, setOpen] = (0, import_react19.useState)(false);
4121
- const wrapRef = (0, import_react19.useRef)(null);
4122
- const seqRef = (0, import_react19.useRef)(0);
4123
- const load = (0, import_react19.useCallback)(() => {
4276
+ const [mode, setMode] = (0, import_react20.useState)(null);
4277
+ const [recall, setRecall] = (0, import_react20.useState)(null);
4278
+ const [recallResolved, setRecallResolved] = (0, import_react20.useState)(true);
4279
+ const [error, setError] = (0, import_react20.useState)(null);
4280
+ const [open, setOpen] = (0, import_react20.useState)(false);
4281
+ const wrapRef = (0, import_react20.useRef)(null);
4282
+ const seqRef = (0, import_react20.useRef)(0);
4283
+ const load = (0, import_react20.useCallback)(() => {
4124
4284
  if (!sessionId || !rpc) return;
4125
4285
  const token = ++seqRef.current;
4126
4286
  setError(null);
@@ -4136,13 +4296,13 @@ var __defProp = Object.defineProperty;
4136
4296
  setError(String(e && e.message || e));
4137
4297
  });
4138
4298
  }, [sessionId, rpc]);
4139
- (0, import_react19.useEffect)(() => {
4299
+ (0, import_react20.useEffect)(() => {
4140
4300
  load();
4141
4301
  }, [load]);
4142
- (0, import_react19.useEffect)(() => {
4302
+ (0, import_react20.useEffect)(() => {
4143
4303
  watchSidebarIcon();
4144
4304
  }, []);
4145
- (0, import_react19.useEffect)(() => {
4305
+ (0, import_react20.useEffect)(() => {
4146
4306
  initOccupancyIndicator(
4147
4307
  (endpoint, payload) => rpc(endpoint, payload)
4148
4308
  );
@@ -4150,7 +4310,7 @@ var __defProp = Object.defineProperty;
4150
4310
  watchContextMeter();
4151
4311
  noteOccupancySession(sessionId ?? null);
4152
4312
  }, [sessionId, rpc]);
4153
- (0, import_react19.useEffect)(() => {
4313
+ (0, import_react20.useEffect)(() => {
4154
4314
  if (!open) return;
4155
4315
  const onDown = (e) => {
4156
4316
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -4236,8 +4396,8 @@ var __defProp = Object.defineProperty;
4236
4396
  pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
4237
4397
  pillStyle["--dsh-mem-pill-tint"] = info.color;
4238
4398
  }
4239
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
4240
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
4399
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
4400
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4241
4401
  "button",
4242
4402
  {
4243
4403
  type: "button",
@@ -4250,11 +4410,11 @@ var __defProp = Object.defineProperty;
4250
4410
  style: pillStyle,
4251
4411
  children: [
4252
4412
  "记忆 · ",
4253
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: faceLabel })
4413
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: faceLabel })
4254
4414
  ]
4255
4415
  }
4256
4416
  ),
4257
- open ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4417
+ open ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4258
4418
  ModeSlider,
4259
4419
  {
4260
4420
  mode: mode || "auto",
@@ -4271,25 +4431,36 @@ var __defProp = Object.defineProperty;
4271
4431
 
4272
4432
  // client/src/entry.tsx
4273
4433
  var inject = ["slots"];
4434
+ var SETTINGS_SEAT = "settings.section";
4435
+ var SEAT_PROBE_MS = 3e3;
4274
4436
  function apply(ctx) {
4275
4437
  const rpc = makeRpc(ctx);
4276
4438
  console.info("[dsh-prime-memory] client apply: slots 注入就绪,注册 UI 槽位");
4439
+ const SETTINGS_SEAT2 = "settings.section";
4440
+ let cardSeatLive = false;
4277
4441
  try {
4278
- ctx.slots.inject("settings.section", () => {
4279
- return ctx.slots.register(
4280
- {
4281
- name: "settings.section",
4282
- id: "dsh-memory",
4283
- order: 200,
4284
- label: "记忆",
4285
- inject: () => ({ rpc })
4286
- },
4287
- MemoryPanel
4288
- );
4442
+ ctx.slots.inject(SETTINGS_SEAT2, () => {
4443
+ cardSeatLive = true;
4444
+ try {
4445
+ return ctx.slots.register(
4446
+ { name: SETTINGS_SEAT2, id: "dsh-memory", order: 200, label: "记忆", inject: () => ({ rpc }) },
4447
+ MemoryPanel
4448
+ );
4449
+ } catch (err) {
4450
+ console.warn(`[dsh-prime-memory] ${SETTINGS_SEAT2} 注册失败:`, err);
4451
+ return () => {
4452
+ };
4453
+ }
4289
4454
  });
4290
4455
  } catch (err) {
4291
- console.warn("[dsh-prime-memory] settings.section 注册失败(新宿主已收编):", err);
4456
+ console.warn(`[dsh-prime-memory] ${SETTINGS_SEAT2} 槽位未声明:`, err);
4292
4457
  }
4458
+ setTimeout(() => {
4459
+ if (cardSeatLive) return;
4460
+ console.warn(
4461
+ `[dsh-prime-memory] 宿主未声明 ${SETTINGS_SEAT2}:设置里的「记忆」面板不会出现。(0.1.5 的座位集合本机未验证,请在真机上确认。)`
4462
+ );
4463
+ }, SEAT_PROBE_MS);
4293
4464
  try {
4294
4465
  ctx.slots.inject("conversation.input.left", () => {
4295
4466
  return ctx.slots.register(