@dshtrading/knowledge 0.1.5 → 0.2.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/lib/graph.js +54 -1
- package/lib/knowledge-fs.js +3 -23
- package/lib/plugin.d.ts +1 -1
- package/lib/plugin.js +8 -8
- package/package.json +3 -2
package/lib/graph.js
CHANGED
|
@@ -141,5 +141,58 @@ function buildGraph(cards, options = {}) {
|
|
|
141
141
|
links
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* 只计数的图概要(knowledge_graph 工具专用):与默认模式 buildGraph 的
|
|
146
|
+
* { nodes.length, links.length } 严格同值,但不物化节点/边对象——
|
|
147
|
+
* related 边 O(E) 键去重、co-author 边按作者分组 Σk(k-1)/2(同作者对唯一)、
|
|
148
|
+
* co-tag 边按标签索引逐标签枚举对并全局去重 O(Σ k_t²)。工具只要规模数字时
|
|
149
|
+
* 避免全配对边的对象分配(215 卡 ≈ 2 万+边对象的构建与丢弃)。
|
|
150
|
+
*/
|
|
151
|
+
function countGraphSummary(cards) {
|
|
152
|
+
if (!cards || cards.length === 0) return {
|
|
153
|
+
nodeCount: 0,
|
|
154
|
+
edgeCount: 0
|
|
155
|
+
};
|
|
156
|
+
const ids = /* @__PURE__ */ new Set();
|
|
157
|
+
for (const c of cards) ids.add(c.id);
|
|
158
|
+
const related = /* @__PURE__ */ new Set();
|
|
159
|
+
for (const card of cards) {
|
|
160
|
+
if (!Array.isArray(card.related)) continue;
|
|
161
|
+
for (const targetId of card.related) {
|
|
162
|
+
if (!ids.has(targetId) || targetId === card.id) continue;
|
|
163
|
+
const [a, b] = card.id < targetId ? [card.id, targetId] : [targetId, card.id];
|
|
164
|
+
related.add(`${a}:${b}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const byTag = /* @__PURE__ */ new Map();
|
|
168
|
+
for (const card of cards) {
|
|
169
|
+
const seen = /* @__PURE__ */ new Set();
|
|
170
|
+
for (const tag of card.tags) {
|
|
171
|
+
if (seen.has(tag)) continue;
|
|
172
|
+
seen.add(tag);
|
|
173
|
+
const members = byTag.get(tag);
|
|
174
|
+
if (members === void 0) byTag.set(tag, [card.id]);
|
|
175
|
+
else members.push(card.id);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const coTag = /* @__PURE__ */ new Set();
|
|
179
|
+
for (const members of byTag.values()) for (let i = 0; i < members.length; i++) for (let j = i + 1; j < members.length; j++) {
|
|
180
|
+
const a = members[i];
|
|
181
|
+
const b = members[j];
|
|
182
|
+
coTag.add(a < b ? `${a}:${b}` : `${b}:${a}`);
|
|
183
|
+
}
|
|
184
|
+
const byAuthor = /* @__PURE__ */ new Map();
|
|
185
|
+
for (const card of cards) {
|
|
186
|
+
const author = card.source.author.trim();
|
|
187
|
+
if (!author || author === "manual" || author === "手工") continue;
|
|
188
|
+
byAuthor.set(author, (byAuthor.get(author) ?? 0) + 1);
|
|
189
|
+
}
|
|
190
|
+
let coAuthor = 0;
|
|
191
|
+
for (const k of byAuthor.values()) coAuthor += k * (k - 1) / 2;
|
|
192
|
+
return {
|
|
193
|
+
nodeCount: cards.length,
|
|
194
|
+
edgeCount: related.size + coTag.size + coAuthor
|
|
195
|
+
};
|
|
196
|
+
}
|
|
144
197
|
//#endregion
|
|
145
|
-
export { buildGraph };
|
|
198
|
+
export { buildGraph, countGraphSummary };
|
package/lib/knowledge-fs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { writeJsonAtomic } from "@dshtrading/dsh-home";
|
|
3
3
|
//#region src/knowledge-fs.ts
|
|
4
4
|
/**
|
|
5
5
|
* 文件持久化版知识卡片存储(Node.js 宿主端专用)。
|
|
@@ -26,27 +26,7 @@ function createFileKnowledgeCardStore(filePath) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
async function flush(map) {
|
|
29
|
-
|
|
30
|
-
const tmpPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
31
|
-
const data = JSON.stringify([...map.values()], null, 2);
|
|
32
|
-
try {
|
|
33
|
-
await mkdir(dir, { recursive: true });
|
|
34
|
-
await writeFile(tmpPath, data, "utf8");
|
|
35
|
-
let lastError;
|
|
36
|
-
for (let attempt = 0; attempt < 3; attempt++) try {
|
|
37
|
-
await rename(tmpPath, filePath);
|
|
38
|
-
return;
|
|
39
|
-
} catch (err) {
|
|
40
|
-
if (err?.code !== "EPERM" && err?.code !== "EBUSY") throw err;
|
|
41
|
-
lastError = err;
|
|
42
|
-
await new Promise((resolve) => setTimeout(resolve, 25 * (attempt + 1)));
|
|
43
|
-
}
|
|
44
|
-
throw lastError;
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error(`[dsh-trading/knowledge] failed to atomic flush knowledge cards to ${filePath}:`, error);
|
|
47
|
-
await unlink(tmpPath).catch(() => {});
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
29
|
+
await writeJsonAtomic(filePath, [...map.values()], "[dsh-trading/knowledge] failed to atomic flush knowledge cards to");
|
|
50
30
|
}
|
|
51
31
|
return {
|
|
52
32
|
async list() {
|
package/lib/plugin.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ declare const TRADING_KNOWLEDGE_CARDS_KEY = "tradingKnowledgeCards";
|
|
|
12
12
|
interface TradingEventsPublisher {
|
|
13
13
|
emit(store: 'knowledge'): void;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
15
|
+
/** 默认存储路径:$DSH_HOME/knowledge/cards.json(缺省 ~/.dsh;与 client-ui-trading 同源解析)。 */
|
|
16
16
|
declare function defaultStorePath(): string;
|
|
17
17
|
interface KnowledgeGraphToolOptions {
|
|
18
18
|
store: KnowledgeCardStore;
|
package/lib/plugin.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { countGraphSummary } from "./graph.js";
|
|
2
2
|
import { createFileKnowledgeCardStore } from "./knowledge-fs.js";
|
|
3
3
|
import { createKnowledgeDeleteTool, createKnowledgeGetTool, createKnowledgeIngestTool, createKnowledgeSearchTool } from "./tool.js";
|
|
4
4
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
5
|
-
import
|
|
5
|
+
import { dshHomeDir } from "@dshtrading/dsh-home";
|
|
6
6
|
import { Service } from "@deepseek-ai/cordis";
|
|
7
|
-
import
|
|
7
|
+
import path from "node:path";
|
|
8
8
|
//#region src/plugin.ts
|
|
9
9
|
/** Cordis 插件名 = patch 行 id(TEMPLATES §8)。 */
|
|
10
10
|
const name = "dsh-trading-knowledge";
|
|
@@ -12,9 +12,9 @@ const name = "dsh-trading-knowledge";
|
|
|
12
12
|
const inject = [];
|
|
13
13
|
/** SDK 服务键:知识卡片 store 单实例。 */
|
|
14
14
|
const TRADING_KNOWLEDGE_CARDS_KEY = "tradingKnowledgeCards";
|
|
15
|
-
/**
|
|
15
|
+
/** 默认存储路径:$DSH_HOME/knowledge/cards.json(缺省 ~/.dsh;与 client-ui-trading 同源解析)。 */
|
|
16
16
|
function defaultStorePath() {
|
|
17
|
-
return path.join(
|
|
17
|
+
return path.join(dshHomeDir(), "knowledge", "cards.json");
|
|
18
18
|
}
|
|
19
19
|
/** knowledge_graph 工厂(issue #33 新增;只读结构概要,不倾倒全量 label)。 */
|
|
20
20
|
function createKnowledgeGraphTool(options) {
|
|
@@ -32,7 +32,7 @@ function createKnowledgeGraphTool(options) {
|
|
|
32
32
|
},
|
|
33
33
|
async execute() {
|
|
34
34
|
const cards = await store.list();
|
|
35
|
-
const data =
|
|
35
|
+
const data = countGraphSummary(cards);
|
|
36
36
|
const clusterCounts = /* @__PURE__ */ new Map();
|
|
37
37
|
const credibility = {
|
|
38
38
|
high: 0,
|
|
@@ -51,8 +51,8 @@ function createKnowledgeGraphTool(options) {
|
|
|
51
51
|
return JSON.stringify({
|
|
52
52
|
ok: true,
|
|
53
53
|
cards: cards.length,
|
|
54
|
-
nodeCount: data.
|
|
55
|
-
edgeCount: data.
|
|
54
|
+
nodeCount: data.nodeCount,
|
|
55
|
+
edgeCount: data.edgeCount,
|
|
56
56
|
clusters,
|
|
57
57
|
credibility
|
|
58
58
|
});
|
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.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@deepseek-ai/dsh-tools": "^0.1.2-alpha.2",
|
|
29
|
-
"@deepseek-ai/schemastery": "^3.18.2"
|
|
29
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
30
|
+
"@dshtrading/dsh-home": "^0.2.0"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|
|
32
33
|
"@deepseek-ai/cordis": ">=4.0.0"
|