dsh-trivium 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ DeepSeek Harness 的跨会话图记忆插件:按节点和边记,默认少注
8
8
 
9
9
  ## 安装
10
10
 
11
- > 前提:已安装 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 并至少启动过一次 `dsh web`。当前测试宿主:`@deepseek-ai/dsh@0.1.0-rc.8`(从 rc.6 跟过来:设置里的「Trivium 记忆」、新会话短地图、跨会话 `ctx_find`、会话图标签均可用)。
11
+ > 前提:已安装 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 并至少启动过一次 `dsh web`。当前测试宿主:`@deepseek-ai/dsh@0.1.1-rc.2`(`dsh-llm` / `dsh-tools` peer 兼容 `0.1.0-rc.8` 与 `0.1.1-rc.2`)。设置里的「Trivium 记忆」、新会话短地图、跨会话 `ctx_find`、会话图标签均可用。
12
12
 
13
13
  ```sh
14
14
  dsh plugin --profile web add dsh-trivium
@@ -20,7 +20,7 @@ dsh plugin --profile web add dsh-trivium
20
20
  <workspace>/.dsh/trivium.tdb
21
21
  ```
22
22
 
23
- 用 [Dsh_BatStart](https://github.com/QWQcool/Dsh_BatStart) 的(启动器已钉 `0.1.0-rc.8`),双击启动就会装上,不必再执行上面这条。
23
+ 用 [Dsh_BatStart](https://github.com/QWQcool/Dsh_BatStart) 的,双击启动就会装上,不必再执行上面这条。
24
24
 
25
25
  本地跟源码联调:
26
26
 
@@ -113,7 +113,7 @@ dsh plugin --profile web add dsh-trivium
113
113
 
114
114
  ## 界面截图
115
115
 
116
- 以下入口在本机 DSH Web(`0.1.0-rc.8`)上仍在。截图摄于较早的 rc.6 界面。
116
+ 以下入口在本机 DSH Web(`0.1.1-rc.2`)上仍在。截图摄于较早的 rc.6 界面。
117
117
 
118
118
  ### 会话 — `ctx_find("鉴权")`
119
119
 
@@ -155,6 +155,10 @@ dsh plugin --profile web add dsh-trivium
155
155
 
156
156
  ## 更新说明
157
157
 
158
+ **0.4.5** — 宿主 peer 放宽到 `0.1.0-rc.8` 与 `0.1.1-rc.2`,不再嵌一套旧 `dsh-llm` / `dsh-tools`。
159
+
160
+ **0.4.4** — 依赖 `triviumdb@0.7.5`:入边、按 label 扩邻、按 label 删边走引擎 API,不再全表扫边。find / 会话图行为不变。
161
+
158
162
  **0.4.3** — 会话图「更新检查点」:把当前对话里 DSH 已有的压缩标记和侧边栏 fork 补进图,给装插件之前的旧会话用。没压过的会话仍然只有「后续」。
159
163
 
160
164
  **0.4.2** — 会话图芯片条可新增(整段粘贴一条)、批量归档 / 删除。自动抽取仍偏严;芯片新增按你写的入库。
@@ -168,6 +172,6 @@ dsh plugin --profile web add dsh-trivium
168
172
  ## 发布信息
169
173
 
170
174
  - GitHub: https://github.com/QWQcool/dsh-trivium
171
- - npm: [`dsh-trivium@0.4.3`](https://www.npmjs.com/package/dsh-trivium)
172
- - 测试宿主:`@deepseek-ai/dsh@0.1.0-rc.8`
173
- - License: MIT(依赖 [TriviumDB](https://github.com/TriviumDB/triviumdb) 为 Apache-2.0)
175
+ - npm: [`dsh-trivium@0.4.5`](https://www.npmjs.com/package/dsh-trivium)
176
+ - 测试宿主:`@deepseek-ai/dsh@0.1.1-rc.2`(兼 `0.1.0-rc.8`)
177
+ - License: MIT(依赖 [TriviumDB](https://github.com/YoKONCy/TriviumDB) 为 Apache-2.0)
package/lib/schema.js CHANGED
@@ -25,7 +25,7 @@ export const EDGE_LABELS = Object.freeze({
25
25
 
26
26
  export const BUSINESS_EDGES = Object.freeze(["about", "decided", "broke", "fixed"]);
27
27
 
28
- /** Weights written on link(). Engine expand currently ignores labels; we still persist them. */
28
+ /** Weights written on link(). Engine neighbors / expandLabels can whitelist labels; we still persist weights. */
29
29
  export const EDGE_WEIGHTS = Object.freeze({
30
30
  about: 1,
31
31
  decided: 1,
package/lib/store.js CHANGED
@@ -135,6 +135,42 @@ function normalizeTql(rows) {
135
135
  .filter(Boolean);
136
136
  }
137
137
 
138
+ function edgeTarget(e) {
139
+ return Number(e?.targetId ?? e?.target_id);
140
+ }
141
+
142
+ function edgeSource(e) {
143
+ return Number(e?.sourceId ?? e?.source_id ?? e?.fromId);
144
+ }
145
+
146
+ /** Native incoming edges when triviumdb >= 0.7.5; otherwise null so callers can scan. */
147
+ function nativeIncoming(db, id, label) {
148
+ if (typeof db.getIncomingEdges !== "function") return null;
149
+ try {
150
+ const rows = label
151
+ ? db.getIncomingEdges(Number(id), label)
152
+ : db.getIncomingEdges(Number(id));
153
+ return Array.isArray(rows) ? rows : [];
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+
159
+ function nativeLabeledNeighbors(db, id, labels) {
160
+ if (typeof db.neighbors !== "function") return null;
161
+ try {
162
+ const rows = db.neighbors(Number(id), 1, [...labels]);
163
+ return Array.isArray(rows) ? rows.map(Number).filter(Number.isFinite) : [];
164
+ } catch {
165
+ try {
166
+ const rows = db.neighbors(Number(id), 1);
167
+ return Array.isArray(rows) ? rows.map(Number).filter(Number.isFinite) : null;
168
+ } catch {
169
+ return null;
170
+ }
171
+ }
172
+ }
173
+
138
174
  function indexNode(db, id, payload) {
139
175
  const text = indexTextFor(payload);
140
176
  try {
@@ -364,12 +400,18 @@ export function mergeNodes(db, keepId, dropId) {
364
400
  if (pa.status === "archived" || pb.status === "archived") {
365
401
  return { ok: false, message: "archived" };
366
402
  }
367
- for (const other of db.allNodeIds?.() || []) {
368
- if (Number(other) === drop) continue;
369
- const n = db.get(other);
370
- for (const e of n?.edges || []) {
371
- if (Number(e.targetId ?? e.target_id) === drop) {
372
- ensureLink(db, other, keep, e.label);
403
+ const inbound = nativeIncoming(db, drop);
404
+ if (inbound) {
405
+ for (const e of inbound) {
406
+ const from = edgeSource(e);
407
+ if (Number.isFinite(from) && from !== keep) ensureLink(db, from, keep, e.label);
408
+ }
409
+ } else {
410
+ for (const other of db.allNodeIds?.() || []) {
411
+ if (Number(other) === drop) continue;
412
+ const n = db.get(other);
413
+ for (const e of n?.edges || []) {
414
+ if (edgeTarget(e) === drop) ensureLink(db, other, keep, e.label);
373
415
  }
374
416
  }
375
417
  }
@@ -402,7 +444,7 @@ export function exportGraph(db, cwd = "") {
402
444
  for (const e of node.edges || []) {
403
445
  edges.push({
404
446
  from: Number(id),
405
- to: Number(e.targetId ?? e.target_id),
447
+ to: edgeTarget(e),
406
448
  label: e.label || "",
407
449
  weight: e.weight ?? null,
408
450
  });
@@ -474,11 +516,11 @@ export function importGraph(db, graph) {
474
516
  export function hasEdge(db, from, to, label) {
475
517
  const node = db.get(Number(from));
476
518
  return (node?.edges || []).some(
477
- (e) => Number(e.targetId ?? e.target_id) === Number(to) && (!label || e.label === label),
519
+ (e) => edgeTarget(e) === Number(to) && (!label || e.label === label),
478
520
  );
479
521
  }
480
522
 
481
- /** Link once for a (from, to, label) triple. Engine unlink cannot drop a single label. */
523
+ /** Link once for a (from, to, label) triple. */
482
524
  export function ensureLink(db, from, to, label) {
483
525
  const src = Number(from);
484
526
  const dst = Number(to);
@@ -489,6 +531,22 @@ export function ensureLink(db, from, to, label) {
489
531
  return true;
490
532
  }
491
533
 
534
+ /** Drop one labeled edge when the engine supports unlink(src, dst, label). */
535
+ export function dropLink(db, from, to, label) {
536
+ const src = Number(from);
537
+ const dst = Number(to);
538
+ if (!Number.isFinite(src) || !Number.isFinite(dst)) return false;
539
+ if (!hasEdge(db, src, dst, label)) return false;
540
+ try {
541
+ if (label) db.unlink(src, dst, label);
542
+ else db.unlink(src, dst);
543
+ db.flush();
544
+ return true;
545
+ } catch {
546
+ return false;
547
+ }
548
+ }
549
+
492
550
  function pickMergedText(oldText, incomingText) {
493
551
  const a = String(oldText || "").trim();
494
552
  const b = String(incomingText || "").trim();
@@ -756,10 +814,9 @@ function entityAnchorIds(db, query) {
756
814
  const q = String(query || "").trim().toLowerCase();
757
815
  if (!q) return [];
758
816
  const ids = [];
759
- for (const id of db.allNodeIds?.() || []) {
760
- const node = db.get(id);
761
- if (node?.payload?.status === "archived" || node?.payload?.type === "episode") continue;
762
- if (entityAnchorScore(node?.payload, q) > 0) ids.push(Number(id));
817
+ for (const n of findByType(db, "entity")) {
818
+ if (n.payload?.status === "archived") continue;
819
+ if (entityAnchorScore(n.payload, q) > 0) ids.push(Number(n.id));
763
820
  }
764
821
  return ids;
765
822
  }
@@ -788,16 +845,27 @@ function primaryScore(payload, query, now) {
788
845
  function scanBusinessNeighbors(db, id) {
789
846
  const ids = new Set();
790
847
  const want = new Set(BUSINESS_EDGES);
791
- const node = db.get(Number(id));
792
- for (const e of node?.edges || []) {
793
- if (want.has(e.label)) ids.add(Number(e.targetId ?? e.target_id));
848
+ const nid = Number(id);
849
+ const labeled = nativeLabeledNeighbors(db, nid, BUSINESS_EDGES);
850
+ if (labeled) {
851
+ for (const other of labeled) ids.add(other);
852
+ } else {
853
+ const node = db.get(nid);
854
+ for (const e of node?.edges || []) {
855
+ if (want.has(e.label)) ids.add(edgeTarget(e));
856
+ }
794
857
  }
795
- for (const other of db.allNodeIds?.() || []) {
796
- if (Number(other) === Number(id)) continue;
797
- const n = db.get(other);
798
- for (const e of n?.edges || []) {
799
- if (want.has(e.label) && Number(e.targetId ?? e.target_id) === Number(id)) {
800
- ids.add(Number(other));
858
+ const inbound = nativeIncoming(db, nid);
859
+ if (inbound) {
860
+ for (const e of inbound) {
861
+ if (want.has(e.label)) ids.add(edgeSource(e));
862
+ }
863
+ } else {
864
+ for (const other of db.allNodeIds?.() || []) {
865
+ if (Number(other) === nid) continue;
866
+ const n = db.get(other);
867
+ for (const e of n?.edges || []) {
868
+ if (want.has(e.label) && edgeTarget(e) === nid) ids.add(Number(other));
801
869
  }
802
870
  }
803
871
  }
@@ -806,9 +874,11 @@ function scanBusinessNeighbors(db, id) {
806
874
 
807
875
  export function businessNeighborIds(db, id) {
808
876
  const ids = scanBusinessNeighbors(db, id);
809
- const viaTql = tqlBusinessNeighbors(db, id);
810
- if (viaTql) {
811
- for (const nid of viaTql) ids.add(Number(nid));
877
+ if (typeof db.getIncomingEdges !== "function") {
878
+ const viaTql = tqlBusinessNeighbors(db, id);
879
+ if (viaTql) {
880
+ for (const nid of viaTql) ids.add(Number(nid));
881
+ }
812
882
  }
813
883
  return [...ids].filter((n) => Number.isFinite(n));
814
884
  }
@@ -885,7 +955,7 @@ function nodeLabel(db, id) {
885
955
  function sameAsTarget(db, id) {
886
956
  const node = db.get(Number(id));
887
957
  for (const e of node?.edges || []) {
888
- if (e.label === EDGE_LABELS.sameAs) return Number(e.targetId ?? e.target_id);
958
+ if (e.label === EDGE_LABELS.sameAs) return edgeTarget(e);
889
959
  }
890
960
  return null;
891
961
  }
@@ -913,6 +983,11 @@ function incomingBusinessEdges(db, id, { query = "", now, hideStale = false } =
913
983
  seen.add(key);
914
984
  found.push({ fromId: src, label, payload: srcNode.payload });
915
985
  };
986
+ const inbound = nativeIncoming(db, nid);
987
+ if (inbound) {
988
+ for (const e of inbound) add(edgeSource(e), e.label);
989
+ return found;
990
+ }
916
991
  if (typeof db.tql === "function") {
917
992
  try {
918
993
  for (const label of BUSINESS_EDGES) {
@@ -928,9 +1003,7 @@ function incomingBusinessEdges(db, id, { query = "", now, hideStale = false } =
928
1003
  const n = db.get(other);
929
1004
  if (!n || n.payload?.status === "archived") continue;
930
1005
  for (const e of n.edges || []) {
931
- if (want.has(e.label) && Number(e.targetId ?? e.target_id) === nid) {
932
- add(other, e.label);
933
- }
1006
+ if (want.has(e.label) && edgeTarget(e) === nid) add(other, e.label);
934
1007
  }
935
1008
  }
936
1009
  return found;
@@ -976,7 +1049,7 @@ export function listOutgoingBusiness(db, id) {
976
1049
  const seen = new Set();
977
1050
  for (const e of node?.edges || []) {
978
1051
  if (!want.has(e.label)) continue;
979
- const tid = Number(e.targetId ?? e.target_id);
1052
+ const tid = edgeTarget(e);
980
1053
  if (!Number.isFinite(tid)) continue;
981
1054
  const key = `${e.label}:${tid}`;
982
1055
  if (seen.has(key)) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-trivium",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "In-process graph memory and session map for DeepSeek Harness, backed by TriviumDB.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -47,11 +47,11 @@
47
47
  "node": "^22.19.0 || >=24"
48
48
  },
49
49
  "peerDependencies": {
50
- "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
51
- "@deepseek-ai/dsh-tools": "0.1.0-rc.8"
50
+ "@deepseek-ai/dsh-llm": ">=0.1.0-rc.8 <0.1.1 || >=0.1.1-rc.2 <0.2.0",
51
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.8 <0.1.1 || >=0.1.1-rc.2 <0.2.0"
52
52
  },
53
53
  "dependencies": {
54
- "triviumdb": "^0.7.4"
54
+ "triviumdb": "^0.7.5"
55
55
  },
56
56
  "keywords": [
57
57
  "dsh-plugin",