@dshtrading/knowledge 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/knowledge-fs.js +33 -15
- package/lib/tool.js +29 -29
- package/package.json +2 -2
package/lib/knowledge-fs.js
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import { canonicalizeCardAuthor } from "./authors.js";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import {
|
|
3
|
+
import { SKIP_WRITE, transactStore } from "@dshtrading/dsh-home";
|
|
4
4
|
//#region src/knowledge-fs.ts
|
|
5
5
|
/**
|
|
6
6
|
* 文件持久化版知识卡片存储(Node.js 宿主端专用)。
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* 整表持久化经 `@dshtrading/dsh-home` 的 {@link transactStore}——跨进程排他锁 +
|
|
9
|
+
* 锁内新鲜读盘 + 原子写(2026-10-09 多进程互相覆盖事故修复)。读取面作者归一与坏
|
|
10
|
+
* 文件降级纪律不变(逐行对齐 custom-fs.ts 先例)。
|
|
9
11
|
*/
|
|
12
|
+
const LOG_PREFIX = "[dsh-trading/knowledge] failed to atomic flush knowledge cards to";
|
|
10
13
|
function createFileKnowledgeCardStore(filePath) {
|
|
11
14
|
let cache = null;
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
/**
|
|
16
|
+
* 新鲜读盘(作者别名归一、坏 JSON 降级空表);供 load 与锁内重读共用。
|
|
17
|
+
*
|
|
18
|
+
* 作者别名在读取时归一(authors.ts):历史数据即刻在 GUI/检索层表现为规范名。
|
|
19
|
+
* 读本身不写盘,但归一结果留在缓存里,会被下一次写操作的全表回写落盘——
|
|
20
|
+
* 即一次静默迁移,故这里显式 log 一次,让「改别名表 = 改历史数据」可见。
|
|
21
|
+
* 缺 source / 缺 id 的脏行原样保留(不丢数据);结构性校验只在入库发生,
|
|
22
|
+
* 但这类行仍会让 getByUrl/search/graph 的解引用抛错(既有边界,未在此收口)。
|
|
23
|
+
*/
|
|
24
|
+
async function readFromDisk() {
|
|
14
25
|
try {
|
|
15
26
|
const content = await readFile(filePath, "utf8");
|
|
16
27
|
const parsed = JSON.parse(content);
|
|
@@ -24,16 +35,20 @@ function createFileKnowledgeCardStore(filePath) {
|
|
|
24
35
|
}
|
|
25
36
|
if (healed > 0) console.warn(`[dsh-trading/knowledge] 作者别名归一:读取时治愈 ${healed} 张历史卡片(${filePath});下一次写操作会把结果落盘`);
|
|
26
37
|
}
|
|
27
|
-
cache = map;
|
|
28
38
|
return map;
|
|
29
39
|
} catch (err) {
|
|
30
40
|
if (err?.code !== "ENOENT") console.error(`[dsh-trading/knowledge] failed to read knowledge cards from ${filePath}:`, err);
|
|
31
|
-
|
|
32
|
-
return cache;
|
|
41
|
+
return /* @__PURE__ */ new Map();
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
|
-
async function
|
|
36
|
-
|
|
44
|
+
async function load() {
|
|
45
|
+
if (cache !== null) return cache;
|
|
46
|
+
cache = await readFromDisk();
|
|
47
|
+
return cache;
|
|
48
|
+
}
|
|
49
|
+
async function commit(mutate) {
|
|
50
|
+
cache = await transactStore(filePath, readFromDisk, mutate, (table) => [...table.values()], LOG_PREFIX);
|
|
51
|
+
return cache;
|
|
37
52
|
}
|
|
38
53
|
return {
|
|
39
54
|
async list() {
|
|
@@ -48,14 +63,17 @@ function createFileKnowledgeCardStore(filePath) {
|
|
|
48
63
|
for (const card of map.values()) if (card.source.url.trim() === trimmed) return card;
|
|
49
64
|
},
|
|
50
65
|
async save(card) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
await commit((onDisk) => {
|
|
67
|
+
onDisk.set(card.id, canonicalizeCardAuthor({ ...card }));
|
|
68
|
+
return onDisk;
|
|
69
|
+
});
|
|
54
70
|
},
|
|
55
71
|
async delete(id) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
let existed = false;
|
|
73
|
+
await commit((onDisk) => {
|
|
74
|
+
existed = onDisk.delete(id);
|
|
75
|
+
return existed ? onDisk : SKIP_WRITE;
|
|
76
|
+
});
|
|
59
77
|
return existed;
|
|
60
78
|
}
|
|
61
79
|
};
|
package/lib/tool.js
CHANGED
|
@@ -30,72 +30,72 @@ function createKnowledgeIngestTool(store, options = {}) {
|
|
|
30
30
|
const { onWritten } = options;
|
|
31
31
|
return defineTool({
|
|
32
32
|
name: "knowledge_ingest",
|
|
33
|
-
description: "
|
|
33
|
+
description: "Ingest one fact-checked knowledge card (a Content Insight product) into the local knowledge base. Duplicate source URLs are detected automatically: an existing card with the same URL is updated in place and keeps its id. Related-card references are validated.",
|
|
34
34
|
parameters: {
|
|
35
35
|
title: {
|
|
36
36
|
type: "string",
|
|
37
37
|
required: true,
|
|
38
|
-
description: "
|
|
38
|
+
description: "Card subject, e.g. the defensive logic of high-dividend strategies in a low-rate environment."
|
|
39
39
|
},
|
|
40
40
|
summary: {
|
|
41
41
|
type: "string",
|
|
42
42
|
required: true,
|
|
43
|
-
description: "2-4
|
|
43
|
+
description: "One-sentence overview merging the 2-4 core claims; shown in the graph hover and quick read."
|
|
44
44
|
},
|
|
45
45
|
sourceType: {
|
|
46
46
|
type: "string",
|
|
47
47
|
required: true,
|
|
48
|
-
description: "
|
|
48
|
+
description: "Source kind: \"bilibili\" | \"wechat\" | \"manual\"."
|
|
49
49
|
},
|
|
50
50
|
sourceUrl: {
|
|
51
51
|
type: "string",
|
|
52
52
|
required: true,
|
|
53
|
-
description: "
|
|
53
|
+
description: "Source link or dedup key, e.g. a Bilibili BV link or a WeChat article link."
|
|
54
54
|
},
|
|
55
55
|
sourceAuthor: {
|
|
56
56
|
type: "string",
|
|
57
57
|
required: true,
|
|
58
|
-
description: "
|
|
58
|
+
description: "Source author, channel or account name."
|
|
59
59
|
},
|
|
60
60
|
publishedAt: {
|
|
61
61
|
type: "string",
|
|
62
|
-
description: "
|
|
62
|
+
description: "Optional source publish date, ISO format such as 2026-08-30."
|
|
63
63
|
},
|
|
64
64
|
credibility: {
|
|
65
65
|
type: "string",
|
|
66
66
|
required: true,
|
|
67
|
-
description: "
|
|
67
|
+
description: "Overall fact-check grade: \"high\" | \"medium\" | \"low\"."
|
|
68
68
|
},
|
|
69
69
|
coreClaimsJson: {
|
|
70
70
|
type: "string",
|
|
71
71
|
required: true,
|
|
72
|
-
description: "JSON
|
|
72
|
+
description: "JSON string array of core claims, preserving the author's reasoning chain, e.g. '[\"claim1\", \"claim2\"]'."
|
|
73
73
|
},
|
|
74
74
|
factCheckJson: {
|
|
75
75
|
type: "string",
|
|
76
76
|
required: true,
|
|
77
|
-
description: "JSON
|
|
77
|
+
description: "JSON object with the three fact-check buckets, e.g. '{\"verified\":[\"...\"],\"discrepancies\":[\"...\"],\"unverifiable\":[]}'."
|
|
78
78
|
},
|
|
79
79
|
takeawaysJson: {
|
|
80
80
|
type: "string",
|
|
81
|
-
description: "
|
|
81
|
+
description: "Optional JSON string array of reusable analysis frameworks and lessons."
|
|
82
82
|
},
|
|
83
83
|
boundariesJson: {
|
|
84
84
|
type: "string",
|
|
85
|
-
description: "
|
|
85
|
+
description: "Optional JSON string array of applicability boundaries, invalidation cases and pitfalls."
|
|
86
86
|
},
|
|
87
87
|
tagsJson: {
|
|
88
88
|
type: "string",
|
|
89
89
|
required: true,
|
|
90
|
-
description: "JSON
|
|
90
|
+
description: "JSON string array of controlled topic tags, e.g. '[\"宏观\", \"高股息\", \"红利策略\"]'."
|
|
91
91
|
},
|
|
92
92
|
tickersJson: {
|
|
93
93
|
type: "string",
|
|
94
|
-
description: "
|
|
94
|
+
description: "Optional JSON string array of related instrument codes, e.g. '[\"BTCUSDT\", \"600519.SH\"]'."
|
|
95
95
|
},
|
|
96
96
|
relatedJson: {
|
|
97
97
|
type: "string",
|
|
98
|
-
description: "
|
|
98
|
+
description: "Optional JSON string array of related card ids already in the library, e.g. '[\"kc_01j...\", \"kc_01k...\"]'."
|
|
99
99
|
}
|
|
100
100
|
},
|
|
101
101
|
output: {
|
|
@@ -196,40 +196,40 @@ function createKnowledgeIngestTool(store, options = {}) {
|
|
|
196
196
|
function createKnowledgeSearchTool(store) {
|
|
197
197
|
return defineTool({
|
|
198
198
|
name: "knowledge_search",
|
|
199
|
-
description: "
|
|
199
|
+
description: "Search knowledge cards in the local library. With a keyword the results rank by field hit weight (tags > title > core claims > summary/author); without one they come newest-updated first. Filters: cluster (the graph clustering key, pair with knowledge_graph for two-stage retrieval), author, source kind and credibility. detail=\"full\" also returns core claims, the fact-check buckets and reusable lessons (capped at 20 cards).",
|
|
200
200
|
parameters: {
|
|
201
201
|
query: {
|
|
202
202
|
type: "string",
|
|
203
|
-
description: "
|
|
203
|
+
description: "Search keyword, fuzzy-matched against title, summary, core claims and tags."
|
|
204
204
|
},
|
|
205
205
|
tags: {
|
|
206
206
|
type: "string",
|
|
207
|
-
description: "
|
|
207
|
+
description: "Comma-separated tag filter, e.g. \"宏观,高股息\"; matches any one of them."
|
|
208
208
|
},
|
|
209
209
|
cluster: {
|
|
210
210
|
type: "string",
|
|
211
|
-
description: "
|
|
211
|
+
description: "Exact subject filter (subject = graph clustering key = the card first tag). Second stage of a two-stage retrieval: call knowledge_graph for the subject distribution, then drill in here."
|
|
212
212
|
},
|
|
213
213
|
author: {
|
|
214
214
|
type: "string",
|
|
215
|
-
description: "
|
|
215
|
+
description: "Author/channel filter (substring match)."
|
|
216
216
|
},
|
|
217
217
|
sourceType: {
|
|
218
218
|
type: "string",
|
|
219
|
-
description: "
|
|
219
|
+
description: "Source kind filter: \"bilibili\" | \"wechat\" | \"manual\"."
|
|
220
220
|
},
|
|
221
221
|
credibility: {
|
|
222
222
|
type: "string",
|
|
223
|
-
description: "
|
|
223
|
+
description: "Credibility filter: \"high\" | \"medium\" | \"low\"."
|
|
224
224
|
},
|
|
225
225
|
limit: {
|
|
226
226
|
type: "number",
|
|
227
|
-
description: "
|
|
227
|
+
description: "Maximum results to return (default 20).",
|
|
228
228
|
default: 20
|
|
229
229
|
},
|
|
230
230
|
detail: {
|
|
231
231
|
type: "string",
|
|
232
|
-
description: "
|
|
232
|
+
description: "Detail level: \"summary\" (default) | \"full\" (adds core claims, fact check, lessons and boundaries).",
|
|
233
233
|
default: "summary"
|
|
234
234
|
}
|
|
235
235
|
},
|
|
@@ -302,11 +302,11 @@ function createKnowledgeSearchTool(store) {
|
|
|
302
302
|
function createKnowledgeGetTool(store) {
|
|
303
303
|
return defineTool({
|
|
304
304
|
name: "knowledge_get",
|
|
305
|
-
description: "
|
|
305
|
+
description: "Read one knowledge card in full by id: core claims, the three fact-check buckets, reusable lessons and applicability boundaries. Ids come from knowledge_search results or citation markers in earlier analyses.",
|
|
306
306
|
parameters: { id: {
|
|
307
307
|
type: "string",
|
|
308
308
|
required: true,
|
|
309
|
-
description: "
|
|
309
|
+
description: "Knowledge card id (kc_...)."
|
|
310
310
|
} },
|
|
311
311
|
output: {
|
|
312
312
|
schema: { type: "string" },
|
|
@@ -337,16 +337,16 @@ function createKnowledgeDeleteTool(store, options = {}) {
|
|
|
337
337
|
const { onWritten } = options;
|
|
338
338
|
return defineTool({
|
|
339
339
|
name: "knowledge_delete",
|
|
340
|
-
description: "
|
|
340
|
+
description: "Delete (retire) one knowledge card from the local library, for a claim disproved by evidence, a retracted source or a duplicate card. Other cards' related references to it are cleaned up automatically, and the deleted title and core claims are echoed as a trail. Record the disproof itself separately in the trading journal or the conversation.",
|
|
341
341
|
parameters: {
|
|
342
342
|
id: {
|
|
343
343
|
type: "string",
|
|
344
344
|
required: true,
|
|
345
|
-
description: "
|
|
345
|
+
description: "Knowledge card id to delete (kc_...). Confirm the id with knowledge_search first; never delete from vague memory."
|
|
346
346
|
},
|
|
347
347
|
reason: {
|
|
348
348
|
type: "string",
|
|
349
|
-
description: "
|
|
349
|
+
description: "Deletion reason, echoed in the result as a trail."
|
|
350
350
|
}
|
|
351
351
|
},
|
|
352
352
|
output: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dshtrading/knowledge",
|
|
3
3
|
"description": "Knowledge base data plane for dsh-trading: KnowledgeCard data model, validation, graph builder, atomic file store, and knowledge_ingest / knowledge_search agent tools.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@deepseek-ai/dsh-tools": "0.2.0-rc.2",
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
30
|
-
"@dshtrading/dsh-home": "^0.
|
|
30
|
+
"@dshtrading/dsh-home": "^0.6.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@deepseek-ai/cordis": ">=4.0.0"
|