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 +10 -6
- package/lib/schema.js +1 -1
- package/lib/store.js +103 -30
- package/package.json +4 -4
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
|
|
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)
|
|
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.
|
|
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.
|
|
172
|
-
- 测试宿主:`@deepseek-ai/dsh@0.1.0-rc.8
|
|
173
|
-
- License: MIT(依赖 [TriviumDB](https://github.com/TriviumDB
|
|
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
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
if (Number(
|
|
372
|
-
|
|
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:
|
|
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) =>
|
|
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.
|
|
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
|
|
760
|
-
|
|
761
|
-
if (
|
|
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
|
|
792
|
-
|
|
793
|
-
|
|
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
|
-
|
|
796
|
-
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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
|
-
|
|
810
|
-
|
|
811
|
-
|
|
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
|
|
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) &&
|
|
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 =
|
|
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
|
+
"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.
|
|
54
|
+
"triviumdb": "^0.7.5"
|
|
55
55
|
},
|
|
56
56
|
"keywords": [
|
|
57
57
|
"dsh-plugin",
|