dsh-prime-memory 0.11.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/CHANGELOG.en.md +28 -0
- package/CHANGELOG.ja.md +30 -0
- package/CHANGELOG.ko.md +30 -0
- package/CHANGELOG.md +1220 -0
- package/ENGINEERING-NOTES.md +452 -0
- package/INSTALL.en.md +92 -0
- package/INSTALL.ja.md +92 -0
- package/INSTALL.ko.md +92 -0
- package/INSTALL.md +92 -0
- package/LICENSE +21 -0
- package/README.en.md +458 -0
- package/README.ja.md +306 -0
- package/README.ko.md +306 -0
- package/README.md +425 -0
- package/assets/changelog/0.8.10/01-write-only-pill.png +0 -0
- package/assets/changelog/0.8.9/01-panel.png +0 -0
- package/assets/changelog/0.8.9/02-halo.png +0 -0
- package/assets/changelog/0.8.9/03-layer-segmented-panel.png +0 -0
- package/assets/changelog/0.8.9/04-layer-l1-panel.png +0 -0
- package/assets/img/EmbeddingSource.png +0 -0
- package/assets/img/Hero.png +0 -0
- package/assets/img/Layers.png +0 -0
- package/assets/img/MemoryTools.png +0 -0
- package/assets/img/Modes.png +0 -0
- package/assets/img/ToolTrajectory.png +0 -0
- package/assets/img/ui-dark.jpg +0 -0
- package/assets/img/ui-light.jpg +0 -0
- package/assets/readme/bench-dialog.svg +70 -0
- package/assets/readme/bench-workflow.svg +79 -0
- package/assets/readme/flow.svg +189 -0
- package/assets/readme/storage.svg +115 -0
- package/cordis.patch.yml +16 -0
- package/dist/bench-control.d.ts +34 -0
- package/dist/bench-control.js +16 -0
- package/dist/client.js +4293 -0
- package/dist/config.d.ts +683 -0
- package/dist/config.js +129 -0
- package/dist/contract.d.ts +820 -0
- package/dist/contract.js +1 -0
- package/dist/embedding-worker.cjs +176 -0
- package/dist/graph/apply.d.ts +37 -0
- package/dist/graph/apply.js +270 -0
- package/dist/graph/constraints.d.ts +47 -0
- package/dist/graph/constraints.js +38 -0
- package/dist/graph/search.d.ts +16 -0
- package/dist/graph/search.js +115 -0
- package/dist/graph/types.d.ts +142 -0
- package/dist/graph/types.js +14 -0
- package/dist/hooks/capture.d.ts +32 -0
- package/dist/hooks/capture.js +194 -0
- package/dist/hooks/recall.d.ts +63 -0
- package/dist/hooks/recall.js +429 -0
- package/dist/index.d.ts +534 -0
- package/dist/index.js +344 -0
- package/dist/llm-usage.d.ts +26 -0
- package/dist/llm-usage.js +37 -0
- package/dist/llm.d.ts +153 -0
- package/dist/llm.js +530 -0
- package/dist/pipeline/graph.d.ts +35 -0
- package/dist/pipeline/graph.js +104 -0
- package/dist/pipeline/l1.d.ts +19 -0
- package/dist/pipeline/l1.js +271 -0
- package/dist/pipeline/l2.d.ts +13 -0
- package/dist/pipeline/l2.js +83 -0
- package/dist/pipeline/l3.d.ts +15 -0
- package/dist/pipeline/l3.js +78 -0
- package/dist/pipeline/rebuild.d.ts +61 -0
- package/dist/pipeline/rebuild.js +307 -0
- package/dist/pipeline/ruminate.d.ts +89 -0
- package/dist/pipeline/ruminate.js +298 -0
- package/dist/pipeline/runner.d.ts +167 -0
- package/dist/pipeline/runner.js +638 -0
- package/dist/pipeline/trigger.d.ts +40 -0
- package/dist/pipeline/trigger.js +75 -0
- package/dist/prompts/graph-projection.d.ts +70 -0
- package/dist/prompts/graph-projection.js +167 -0
- package/dist/prompts/l1-dedup.d.ts +22 -0
- package/dist/prompts/l1-dedup.js +251 -0
- package/dist/prompts/l1-extraction.d.ts +22 -0
- package/dist/prompts/l1-extraction.js +457 -0
- package/dist/prompts/persona.d.ts +23 -0
- package/dist/prompts/persona.js +240 -0
- package/dist/prompts/scene.d.ts +32 -0
- package/dist/prompts/scene.js +414 -0
- package/dist/runtime-package-lock.json +982 -0
- package/dist/settings.d.ts +50 -0
- package/dist/settings.js +355 -0
- package/dist/stats.d.ts +109 -0
- package/dist/stats.js +929 -0
- package/dist/store/bm25.d.ts +19 -0
- package/dist/store/bm25.js +63 -0
- package/dist/store/cost-ledger.d.ts +75 -0
- package/dist/store/cost-ledger.js +171 -0
- package/dist/store/download-queue.d.ts +79 -0
- package/dist/store/download-queue.js +424 -0
- package/dist/store/embedding-source.d.ts +118 -0
- package/dist/store/embedding-source.js +443 -0
- package/dist/store/embedding.d.ts +90 -0
- package/dist/store/embedding.js +206 -0
- package/dist/store/graph-store.d.ts +94 -0
- package/dist/store/graph-store.js +641 -0
- package/dist/store/l0.d.ts +40 -0
- package/dist/store/l0.js +197 -0
- package/dist/store/l1.d.ts +93 -0
- package/dist/store/l1.js +297 -0
- package/dist/store/local-embedding.d.ts +89 -0
- package/dist/store/local-embedding.js +227 -0
- package/dist/store/model-catalog.d.ts +48 -0
- package/dist/store/model-catalog.js +81 -0
- package/dist/store/occupancy.d.ts +30 -0
- package/dist/store/occupancy.js +134 -0
- package/dist/store/pending.d.ts +36 -0
- package/dist/store/pending.js +103 -0
- package/dist/store/persona.d.ts +15 -0
- package/dist/store/persona.js +60 -0
- package/dist/store/recall-dedupe.d.ts +26 -0
- package/dist/store/recall-dedupe.js +138 -0
- package/dist/store/runtime-installer.d.ts +59 -0
- package/dist/store/runtime-installer.js +243 -0
- package/dist/store/scenes.d.ts +24 -0
- package/dist/store/scenes.js +160 -0
- package/dist/store/search-utils.d.ts +38 -0
- package/dist/store/search-utils.js +100 -0
- package/dist/store/session-modes.d.ts +35 -0
- package/dist/store/session-modes.js +144 -0
- package/dist/store/sqlite.d.ts +246 -0
- package/dist/store/sqlite.js +1491 -0
- package/dist/store/state.d.ts +41 -0
- package/dist/store/state.js +72 -0
- package/dist/token-cost.d.ts +23 -0
- package/dist/token-cost.js +185 -0
- package/dist/tools/index.d.ts +34 -0
- package/dist/tools/index.js +758 -0
- package/dist/types.d.ts +139 -0
- package/dist/types.js +38 -0
- package/dist/util/context-occupancy.d.ts +68 -0
- package/dist/util/context-occupancy.js +92 -0
- package/dist/util/filelog.d.ts +6 -0
- package/dist/util/filelog.js +108 -0
- package/dist/util/io.d.ts +18 -0
- package/dist/util/io.js +97 -0
- package/dist/util/recall-budget.d.ts +31 -0
- package/dist/util/recall-budget.js +84 -0
- package/dist/util/sanitize.d.ts +11 -0
- package/dist/util/sanitize.js +67 -0
- package/dist/util/text.d.ts +16 -0
- package/dist/util/text.js +61 -0
- package/dist/util/tokenizer.d.ts +9 -0
- package/dist/util/tokenizer.js +50 -0
- package/dsh.plugin.json +22 -0
- package/package.json +118 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 召回预算与超时(ADR-0001 / 规格 A 节)。
|
|
3
|
+
*
|
|
4
|
+
* 预算:单条记忆截断上限 + 整轮总量上限——超限截断并以后缀引导模型用记忆工具
|
|
5
|
+
* 查全文(截断是引流而不是损失:工具路径返回完整记录);总量超限按融合排名丢尾部。
|
|
6
|
+
* 超时:召回是增强能力,超时跳过本轮注入、绝不阻塞对话(CONTEXT.md「召回超时」语义
|
|
7
|
+
* 在本模块以 raceRecallTimeout 落地)。
|
|
8
|
+
*/
|
|
9
|
+
/** 截断后缀:显式告诉模型全文在工具侧(引导主动深挖)。注入字符串,逐字为契约。 */
|
|
10
|
+
export const RECALL_TRUNCATION_SUFFIX = '…(已截断;可用 memory_search 或 conversation_search 查看详情)';
|
|
11
|
+
/** 剩余预算小于该值时整条丢弃(截出比后缀还短的行没有意义)。 */
|
|
12
|
+
const MIN_TRUNCATED_RECALL_LINE_CHARS = 40;
|
|
13
|
+
function normalizeLimit(value) {
|
|
14
|
+
if (value == null || !Number.isFinite(value) || value <= 0)
|
|
15
|
+
return undefined;
|
|
16
|
+
return Math.floor(value);
|
|
17
|
+
}
|
|
18
|
+
/** 按 code point 计数截断(不劈开代理对),带引导后缀。 */
|
|
19
|
+
export function truncateRecallLine(line, maxChars) {
|
|
20
|
+
const cps = Array.from(line);
|
|
21
|
+
if (cps.length <= maxChars)
|
|
22
|
+
return line;
|
|
23
|
+
if (maxChars <= RECALL_TRUNCATION_SUFFIX.length) {
|
|
24
|
+
return cps.slice(0, maxChars).join('');
|
|
25
|
+
}
|
|
26
|
+
return `${cps.slice(0, maxChars - RECALL_TRUNCATION_SUFFIX.length).join('').trimEnd()}${RECALL_TRUNCATION_SUFFIX}`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 对召回行施加预算:先逐条截断,再按总量预算装填——装不下的尾部整条丢弃。
|
|
30
|
+
* 输入行应按相关性降序(低分先丢)。行间换行符计入总量预算。
|
|
31
|
+
*/
|
|
32
|
+
export function applyRecallBudget(lines, limits) {
|
|
33
|
+
const maxCharsPerMemory = normalizeLimit(limits.maxCharsPerMemory);
|
|
34
|
+
const maxTotalRecallChars = normalizeLimit(limits.maxTotalRecallChars);
|
|
35
|
+
if (!maxCharsPerMemory && !maxTotalRecallChars)
|
|
36
|
+
return lines;
|
|
37
|
+
const budgeted = [];
|
|
38
|
+
let usedChars = 0;
|
|
39
|
+
for (let i = 0; i < lines.length; i++) {
|
|
40
|
+
const line = lines[i];
|
|
41
|
+
const perBounded = maxCharsPerMemory ? truncateRecallLine(line, maxCharsPerMemory) : line;
|
|
42
|
+
if (!maxTotalRecallChars) {
|
|
43
|
+
budgeted.push(perBounded);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const separatorChars = budgeted.length > 0 ? 1 : 0;
|
|
47
|
+
const remaining = maxTotalRecallChars - usedChars - separatorChars;
|
|
48
|
+
if (remaining <= 0)
|
|
49
|
+
break;
|
|
50
|
+
if (perBounded.length > remaining) {
|
|
51
|
+
const canFit = remaining >= MIN_TRUNCATED_RECALL_LINE_CHARS;
|
|
52
|
+
if (canFit)
|
|
53
|
+
budgeted.push(truncateRecallLine(perBounded, remaining));
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
budgeted.push(perBounded);
|
|
57
|
+
usedChars += separatorChars + perBounded.length;
|
|
58
|
+
}
|
|
59
|
+
return budgeted;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 召回总预算:超时返回 undefined(调用方跳过本轮注入),正常 resolve 返回原值。
|
|
63
|
+
* resolve 为空结果(空数组)与超时(undefined)语义不同,调用方据此区分日志。
|
|
64
|
+
*/
|
|
65
|
+
export async function raceRecallTimeout(promise, timeoutMs) {
|
|
66
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
67
|
+
return promise;
|
|
68
|
+
let timer;
|
|
69
|
+
try {
|
|
70
|
+
return await Promise.race([
|
|
71
|
+
promise,
|
|
72
|
+
new Promise((resolve) => {
|
|
73
|
+
timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
74
|
+
}),
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
if (timer)
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** 召回路径嵌入调用的内层钳制(固定值):给 FTS 降级留出总预算内的时间。
|
|
83
|
+
* 远程作用于 HTTP fetch;本地作用于 worker 代理的等待(race 放弃、迟到回复丢弃)。 */
|
|
84
|
+
export const RECALL_EMBED_CAP_MS = 3_000;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L0 捕获文本清洗。
|
|
3
|
+
* 保证:清除我们注入的召回标签(防反馈循环)、框架元数据块、媒体标记等。
|
|
4
|
+
* 正则清单即行为契约——漏一条,注入物就会经 L0→L1 反复自我强化。
|
|
5
|
+
*/
|
|
6
|
+
/** 剥离注入的记忆标签 + 框架元数据块 + 媒体标记。 */
|
|
7
|
+
export declare function sanitizeText(text: string): string;
|
|
8
|
+
/** 剥离助手回复中的围栏代码块(保留解释性文本)。 */
|
|
9
|
+
export declare function stripCodeBlocks(text: string): string;
|
|
10
|
+
/** L0 捕获过滤——宽松:只丢弃结构性无用消息。 */
|
|
11
|
+
export declare function shouldCaptureL0(text: string): boolean;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L0 捕获文本清洗。
|
|
3
|
+
* 保证:清除我们注入的召回标签(防反馈循环)、框架元数据块、媒体标记等。
|
|
4
|
+
* 正则清单即行为契约——漏一条,注入物就会经 L0→L1 反复自我强化。
|
|
5
|
+
*/
|
|
6
|
+
/** 剥离注入的记忆标签 + 框架元数据块 + 媒体标记。 */
|
|
7
|
+
export function sanitizeText(text) {
|
|
8
|
+
let cleaned = text;
|
|
9
|
+
// 注入的记忆上下文标签(防止再捕获时反馈循环)
|
|
10
|
+
cleaned = cleaned.replace(/<relevant-memories>[\s\S]*?<\/relevant-memories>/g, '');
|
|
11
|
+
cleaned = cleaned.replace(/<user-persona>[\s\S]*?<\/user-persona>/g, '');
|
|
12
|
+
cleaned = cleaned.replace(/<relevant-scenes>[\s\S]*?<\/relevant-scenes>/g, '');
|
|
13
|
+
cleaned = cleaned.replace(/<scene-navigation>[\s\S]*?<\/scene-navigation>/g, '');
|
|
14
|
+
cleaned = cleaned.replace(/<memory-tools-guide>[\s\S]*?<\/memory-tools-guide>/g, '');
|
|
15
|
+
// 任务上下文注入块
|
|
16
|
+
cleaned = cleaned.replace(/<current_task_context>[\s\S]*?<\/current_task_context>/g, '');
|
|
17
|
+
cleaned = cleaned.replace(/<history_task_context[\s\S]*?<\/history_task_context>/g, '');
|
|
18
|
+
// 框架注入的入站元数据块(label + ```json ... ```)
|
|
19
|
+
cleaned = cleaned.replace(/(?:Conversation info|Sender|Thread starter|Replied message|Forwarded message context|Chat history since last reply)\s*\(untrusted[\s\S]*?\):\s*```json\s*[\s\S]*?```/g, '');
|
|
20
|
+
// 旧版会话元数据 JSON 块
|
|
21
|
+
cleaned = cleaned.replace(/```json\s*\{[\s\S]*?"session[\s\S]*?\}\s*```/g, '');
|
|
22
|
+
// 回复指令标签
|
|
23
|
+
cleaned = cleaned.replace(/\[\[reply_to[^\]]*\]\]\s*/g, '');
|
|
24
|
+
// Skill 选择包裹符
|
|
25
|
+
cleaned = cleaned.replace(/¥¥\[[\s\S]*?\]¥¥/g, '');
|
|
26
|
+
// 行首时间戳
|
|
27
|
+
cleaned = cleaned.replace(/^\[[\w\d\-:+ ]+\]\s*/gm, '');
|
|
28
|
+
// 媒体附件标记
|
|
29
|
+
cleaned = cleaned.replace(/\[media attached:[^\]]*\]\s*/g, '');
|
|
30
|
+
// 图片回复指令
|
|
31
|
+
cleaned = cleaned.replace(/To send an image back,[\s\S]*?(?:Keep caption in the text body\.)\s*/g, '');
|
|
32
|
+
// 系统执行块
|
|
33
|
+
cleaned = cleaned.replace(/^System:\s*\[[\s\S]*?$/gm, '');
|
|
34
|
+
// 内联 base64 图片
|
|
35
|
+
cleaned = cleaned.replace(/data:image\/[a-z+]+;base64,[A-Za-z0-9+/=]+/gi, '');
|
|
36
|
+
// 空字符 + 折叠空白
|
|
37
|
+
cleaned = cleaned.replace(/\0/g, '').replace(/\n{3,}/g, '\n\n').trim();
|
|
38
|
+
return cleaned;
|
|
39
|
+
}
|
|
40
|
+
/** 剥离助手回复中的围栏代码块(保留解释性文本)。 */
|
|
41
|
+
export function stripCodeBlocks(text) {
|
|
42
|
+
return text.replace(/```[^\n]*\n[\s\S]*?```/g, '').replace(/\n{3,}/g, '\n\n').trim();
|
|
43
|
+
}
|
|
44
|
+
/** L0 捕获过滤——宽松:只丢弃结构性无用消息。 */
|
|
45
|
+
export function shouldCaptureL0(text) {
|
|
46
|
+
if (!text || !text.trim())
|
|
47
|
+
return false;
|
|
48
|
+
if (isFrameworkNoise(text))
|
|
49
|
+
return false;
|
|
50
|
+
if (text.startsWith('/'))
|
|
51
|
+
return false;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function isFrameworkNoise(text) {
|
|
55
|
+
const t = text.trim();
|
|
56
|
+
if (t === '(session bootstrap)')
|
|
57
|
+
return true;
|
|
58
|
+
if (t.startsWith('A new session was started via'))
|
|
59
|
+
return true;
|
|
60
|
+
if (/^✅\s*New session started/.test(t))
|
|
61
|
+
return true;
|
|
62
|
+
if (t.startsWith('Pre-compaction memory flush'))
|
|
63
|
+
return true;
|
|
64
|
+
if (/^NO_REPLY\s*$/.test(t))
|
|
65
|
+
return true;
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 中英混排分词:jieba 词元 ∪ 拉丁词 ∪ CJK 二元组,按首次出现顺序去重。
|
|
3
|
+
*
|
|
4
|
+
* 分词结果是 FTS 索引内容的定义——token 序列必须与既有索引构建算法严格一致,
|
|
5
|
+
* 否则旧库检索错位(这是格式级契约,不是可自由重设计项):
|
|
6
|
+
* - 词元给 BM25 提供高精度整词命中("负载均衡"作为词,idf 远高于碎片二元组);
|
|
7
|
+
* - 二元组保住子词召回底线:查询"负载"仍能命中只含"负载均衡"词元的行,且旧库
|
|
8
|
+
* 纯二元组索引无需迁移即可被新查询命中(新查询仍含二元组 token);
|
|
9
|
+
* - 去重防 2 字词与其自身二元组重复计数(FTS tf / 词频被同一出现双计);
|
|
10
|
+
* - jieba 加载失败时 jiebaCut 返回 undefined,自动退化为纯二元组。
|
|
11
|
+
*/
|
|
12
|
+
import type { ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
13
|
+
/** 把消息的 ContentBlock[] 展平成纯文本(仅 text 与 reasoning 块,换行连接)。 */
|
|
14
|
+
export declare function blocksToText(blocks: readonly ContentBlock[] | undefined): string;
|
|
15
|
+
/** FTS / BM25 共用分词入口(输入内部统一小写)。 */
|
|
16
|
+
export declare function tokenize(text: string): string[];
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jiebaCut } from './tokenizer.js';
|
|
2
|
+
/** 把消息的 ContentBlock[] 展平成纯文本(仅 text 与 reasoning 块,换行连接)。 */
|
|
3
|
+
export function blocksToText(blocks) {
|
|
4
|
+
if (!blocks)
|
|
5
|
+
return '';
|
|
6
|
+
const parts = [];
|
|
7
|
+
for (const b of blocks) {
|
|
8
|
+
if (b.type === 'text')
|
|
9
|
+
parts.push(b.text);
|
|
10
|
+
else if (b.type === 'reasoning')
|
|
11
|
+
parts.push(b.text);
|
|
12
|
+
}
|
|
13
|
+
return parts.join('\n');
|
|
14
|
+
}
|
|
15
|
+
const CJK_RE = /[\u3400-\u9fff\uf900-\ufaff]/;
|
|
16
|
+
const WORD_RE = /[a-zA-Z0-9][a-zA-Z0-9_-]{1,}/g;
|
|
17
|
+
/** token 里至少要有一个字母/数字/CJK 字(输入已小写;滤掉 jieba 切出的纯标点 token)。 */
|
|
18
|
+
const TOKEN_KEEP_RE = /[a-z0-9\u3400-\u9fff\uf900-\ufaff]/;
|
|
19
|
+
/** CJK 连续段二元组(首尾单字成 token;jieba 失败回退时的唯一分词,也是并集模式的子词召回底线)。 */
|
|
20
|
+
function cjkBigrams(text) {
|
|
21
|
+
const tokens = [];
|
|
22
|
+
const cjk = text.replace(/[^\u3400-\u9fff\uf900-\ufaff]/g, ' ');
|
|
23
|
+
let i = 0;
|
|
24
|
+
while (i < cjk.length) {
|
|
25
|
+
const ch = cjk[i];
|
|
26
|
+
if (CJK_RE.test(ch)) {
|
|
27
|
+
const next = cjk[i + 1];
|
|
28
|
+
if (next && CJK_RE.test(next))
|
|
29
|
+
tokens.push(ch + next);
|
|
30
|
+
else
|
|
31
|
+
tokens.push(ch);
|
|
32
|
+
}
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
return tokens;
|
|
36
|
+
}
|
|
37
|
+
/** FTS / BM25 共用分词入口(输入内部统一小写)。 */
|
|
38
|
+
export function tokenize(text) {
|
|
39
|
+
const lower = text.toLowerCase();
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
const tokens = [];
|
|
42
|
+
const push = (t) => {
|
|
43
|
+
if (t.length >= 2 && TOKEN_KEEP_RE.test(t) && !seen.has(t)) {
|
|
44
|
+
seen.add(t);
|
|
45
|
+
tokens.push(t);
|
|
46
|
+
}
|
|
47
|
+
else if (t.length === 1 && CJK_RE.test(t) && !seen.has(t)) {
|
|
48
|
+
seen.add(t);
|
|
49
|
+
tokens.push(t);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const words = jiebaCut(lower);
|
|
53
|
+
if (words)
|
|
54
|
+
for (const w of words)
|
|
55
|
+
push(w.trim());
|
|
56
|
+
for (const m of lower.matchAll(WORD_RE))
|
|
57
|
+
push(m[0]);
|
|
58
|
+
for (const bg of cjkBigrams(lower))
|
|
59
|
+
push(bg);
|
|
60
|
+
return tokens;
|
|
61
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type TokenizerMode = 'jieba' | 'bigram';
|
|
2
|
+
/** 启动期主动初始化并返回模式(MemoryDb 记日志用)。 */
|
|
3
|
+
export declare function ensureTokenizer(): TokenizerMode;
|
|
4
|
+
/** FTS 分词器版本戳(存 embedding_meta 表,键 fts_tokenizer)。 */
|
|
5
|
+
export declare function tokenizerStamp(): string;
|
|
6
|
+
/** 模式描述(日志用)。 */
|
|
7
|
+
export declare function describeTokenizer(): string;
|
|
8
|
+
/** jieba 切词(回退模式下返回 undefined,调用方走二元组路径)。 */
|
|
9
|
+
export declare function jiebaCut(text: string): string[] | undefined;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分词器装配:jieba 词级分词(@node-rs/jieba,Rust napi 预编译二进制)优先,
|
|
3
|
+
* 加载失败(平台无预编译二进制等)永久回退 CJK 二元组。
|
|
4
|
+
*
|
|
5
|
+
* - 惰性单例:首次调用即定死本进程的分词模式,运行中不漂移——FTS 读写两侧共用
|
|
6
|
+
* 同一实例,索引/查询天然对齐;
|
|
7
|
+
* - require 走 createRequire(与原生模块装配同款):失败只降级不抛出,由 MemoryDb
|
|
8
|
+
* 启动时主动 ensure 并记录模式日志;
|
|
9
|
+
* - 分词器版本戳 jieba-v1/bigram-v1 是 FTS 重建的触发键:戳 ≠ 索引构建时的戳,
|
|
10
|
+
* FTS 表 drop 后从源表全量回灌——戳必须如实反映"构建当前 FTS 内容的分词器"。
|
|
11
|
+
*/
|
|
12
|
+
import { createRequire } from 'node:module';
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
let mode;
|
|
15
|
+
let cutFn;
|
|
16
|
+
/** 惰性初始化(永不抛出)。词典约 5MB,首次加载 ~100ms。 */
|
|
17
|
+
function ensure() {
|
|
18
|
+
if (mode !== undefined)
|
|
19
|
+
return mode;
|
|
20
|
+
try {
|
|
21
|
+
const { Jieba } = require('@node-rs/jieba');
|
|
22
|
+
const { dict } = require('@node-rs/jieba/dict');
|
|
23
|
+
const jieba = Jieba.withDict(dict);
|
|
24
|
+
cutFn = (text) => jieba.cut(text, true);
|
|
25
|
+
mode = 'jieba';
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
cutFn = undefined;
|
|
29
|
+
mode = 'bigram';
|
|
30
|
+
}
|
|
31
|
+
return mode;
|
|
32
|
+
}
|
|
33
|
+
/** 启动期主动初始化并返回模式(MemoryDb 记日志用)。 */
|
|
34
|
+
export function ensureTokenizer() {
|
|
35
|
+
return ensure();
|
|
36
|
+
}
|
|
37
|
+
/** FTS 分词器版本戳(存 embedding_meta 表,键 fts_tokenizer)。 */
|
|
38
|
+
export function tokenizerStamp() {
|
|
39
|
+
return ensure() === 'jieba' ? 'jieba-v1' : 'bigram-v1';
|
|
40
|
+
}
|
|
41
|
+
/** 模式描述(日志用)。 */
|
|
42
|
+
export function describeTokenizer() {
|
|
43
|
+
return ensure() === 'jieba'
|
|
44
|
+
? 'jieba 词级分词(@node-rs/jieba)+ CJK 二元组并集'
|
|
45
|
+
: 'jieba 加载失败,回退 CJK 二元组分词(子词召回降级)';
|
|
46
|
+
}
|
|
47
|
+
/** jieba 切词(回退模式下返回 undefined,调用方走二元组路径)。 */
|
|
48
|
+
export function jiebaCut(text) {
|
|
49
|
+
return ensure() === 'jieba' ? cutFn(text) : undefined;
|
|
50
|
+
}
|
package/dsh.plugin.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dsh-prime-memory",
|
|
3
|
+
"name": "dsh-prime-memory",
|
|
4
|
+
"version": "0.11.0",
|
|
5
|
+
"description": {
|
|
6
|
+
"en": "Layered distilled memory plugin (L0 capture → L1 atomic memory → L2 scenes → L3 persona) with automatic recall injection before each model step.",
|
|
7
|
+
"zh": "L0~L3 分层蒸馏记忆插件:自动捕获对话、抽取原子记忆、整合场景块、蒸馏核心画像,并在模型步骤前自动召回注入。"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/drscrewdriver/dsh-prime-memory",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/drscrewdriver/dsh-prime-memory.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"engines": {
|
|
16
|
+
"dsh": ">=0.1.1-rc.2 <0.2.0-0"
|
|
17
|
+
},
|
|
18
|
+
"components": {
|
|
19
|
+
"host": "dist/index.js",
|
|
20
|
+
"client": "dist/client.js"
|
|
21
|
+
}
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-prime-memory",
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "L0~L3 分层蒸馏记忆插件 for DeepSeek Harness:自动捕获对话(L0)、抽取原子记忆(L1)、整合场景块(L2)、蒸馏核心画像/团队方法论(L3),并在模型步骤前自动召回注入。移植自 MemoryCore (TencentDB Agent Memory) 的管线设计。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./client": "./dist/client.js",
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"dsh": {
|
|
17
|
+
"bundle": {
|
|
18
|
+
"patch": "./cordis.patch.yml"
|
|
19
|
+
},
|
|
20
|
+
"client": {
|
|
21
|
+
"inject": [
|
|
22
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
23
|
+
"@deepseek-ai/dsh-client-connection"
|
|
24
|
+
],
|
|
25
|
+
"platform": "web"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"assets",
|
|
31
|
+
"cordis.patch.yml",
|
|
32
|
+
"dsh.plugin.json",
|
|
33
|
+
"README.md",
|
|
34
|
+
"README.en.md",
|
|
35
|
+
"README.ja.md",
|
|
36
|
+
"README.ko.md",
|
|
37
|
+
"INSTALL.md",
|
|
38
|
+
"INSTALL.en.md",
|
|
39
|
+
"INSTALL.ja.md",
|
|
40
|
+
"INSTALL.ko.md",
|
|
41
|
+
"CHANGELOG.md",
|
|
42
|
+
"CHANGELOG.en.md",
|
|
43
|
+
"CHANGELOG.ja.md",
|
|
44
|
+
"CHANGELOG.ko.md",
|
|
45
|
+
"ENGINEERING-NOTES.md"
|
|
46
|
+
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc -p tsconfig.json && node scripts/build-client.mjs && node scripts/copy-client.mjs",
|
|
49
|
+
"smoke": "npm run build:smoke && node dist-smoke/smoke.js",
|
|
50
|
+
"verify-catalog": "npm run build && node scripts/verify-catalog.mjs",
|
|
51
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit && tsc -p tsconfig.test.json",
|
|
52
|
+
"build:smoke": "tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop",
|
|
53
|
+
"lint": "eslint src client/src scripts tests",
|
|
54
|
+
"test": "vitest run"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=22.16.0"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"dsh",
|
|
61
|
+
"deepseek-harness",
|
|
62
|
+
"memory",
|
|
63
|
+
"agent-memory",
|
|
64
|
+
"cordis-plugin"
|
|
65
|
+
],
|
|
66
|
+
"repository": {
|
|
67
|
+
"type": "git",
|
|
68
|
+
"url": "git+https://github.com/drscrewdriver/dsh-prime-memory.git"
|
|
69
|
+
},
|
|
70
|
+
"author": "drscrewdriver <597093681@qq.com>",
|
|
71
|
+
"license": "MIT",
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@deepseek-ai/schemastery": "3.18.1",
|
|
74
|
+
"@node-rs/jieba": "^2.0.2",
|
|
75
|
+
"sqlite-vec": "^0.1.7-alpha.2",
|
|
76
|
+
"undici": "^7.29.0"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
80
|
+
"@deepseek-ai/dsh-agent": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2",
|
|
82
|
+
"@deepseek-ai/dsh-llm": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2",
|
|
83
|
+
"@deepseek-ai/dsh-session": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2",
|
|
84
|
+
"@deepseek-ai/dsh-settings": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2",
|
|
85
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2",
|
|
86
|
+
"@deepseek-ai/dsh-tools": "^0.1.1-rc.2 || ^0.1.2-rc.1 || ^0.1.3-rc.1 || ^0.1.5-rc.2"
|
|
87
|
+
},
|
|
88
|
+
"peerDependenciesMeta": {
|
|
89
|
+
"@deepseek-ai/dsh-agent": { "optional": true },
|
|
90
|
+
"@deepseek-ai/dsh-home-paths": { "optional": true },
|
|
91
|
+
"@deepseek-ai/dsh-llm": { "optional": true },
|
|
92
|
+
"@deepseek-ai/dsh-session": { "optional": true },
|
|
93
|
+
"@deepseek-ai/dsh-settings": { "optional": true },
|
|
94
|
+
"@deepseek-ai/dsh-system-prompt": { "optional": true },
|
|
95
|
+
"@deepseek-ai/dsh-tools": { "optional": true }
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
99
|
+
"@deepseek-ai/dsh-agent": "0.1.1-rc.2",
|
|
100
|
+
"@deepseek-ai/dsh-agent-default-model": "0.1.1-rc.2",
|
|
101
|
+
"@deepseek-ai/dsh-client-connection": "0.1.1-rc.2",
|
|
102
|
+
"@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
|
|
103
|
+
"@deepseek-ai/dsh-llm": "0.1.1-rc.2",
|
|
104
|
+
"@deepseek-ai/dsh-session": "0.1.1-rc.2",
|
|
105
|
+
"@deepseek-ai/dsh-settings": "0.1.1-rc.2",
|
|
106
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
|
|
107
|
+
"@deepseek-ai/dsh-tools": "0.1.1-rc.2",
|
|
108
|
+
"@eslint/js": "^10.0.1",
|
|
109
|
+
"@types/node": "^22.0.0",
|
|
110
|
+
"@types/react": "^19.2.18",
|
|
111
|
+
"esbuild": "^0.28.2",
|
|
112
|
+
"eslint": "^10.9.1",
|
|
113
|
+
"globals": "^17.12.0",
|
|
114
|
+
"typescript": "^5.6.0",
|
|
115
|
+
"typescript-eslint": "^8.69.0",
|
|
116
|
+
"vitest": "^4.1.11"
|
|
117
|
+
}
|
|
118
|
+
}
|