@max-null/dsh-memory 0.4.1 → 0.5.2
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 +31 -12
- package/client.js +195 -150
- package/dist/bm25.d.ts +25 -1
- package/dist/bm25.js +99 -20
- package/dist/engine.d.ts +47 -3
- package/dist/engine.js +192 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +45 -12
- package/dist/injection.d.ts +34 -0
- package/dist/injection.js +52 -0
- package/dist/remote.d.ts +9 -5
- package/dist/remote.js +11 -4
- package/dist/routes.js +12 -2
- package/dist/self.js +2 -2
- package/package.json +13 -13
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 注入渲染(0.5.2):`memory:recall` 与面板「注入预览」共用的确定性
|
|
3
|
+
* 渲染——摘要化 + 预算截断。纯函数、无模型调用:注入行 = 每条记忆的
|
|
4
|
+
* 单行摘要(内容过长取首行截断),超出预算(字符数)时按「最近更新
|
|
5
|
+
* 优先」贪心保留,省略计数返回给 UI 提示。
|
|
6
|
+
*/
|
|
7
|
+
/** 摘要截断上限(字符):中英混合场景下 ~40-60 token。 */
|
|
8
|
+
export const DEFAULT_SUMMARY_CHARS = 80;
|
|
9
|
+
/** 注入预算(字符):0.5.2 起默认开启,防常驻注入随记忆增长膨胀上下文。 */
|
|
10
|
+
export const DEFAULT_INJECTION_BUDGET = 1500;
|
|
11
|
+
/** 单条注入行的固定标记开销(不含摘要本体)。 */
|
|
12
|
+
const LINE_OVERHEAD = 27;
|
|
13
|
+
/**
|
|
14
|
+
* 确定性摘要:取首行,超过 maxChars 截断加省略号。
|
|
15
|
+
* 空内容/空首行回退为去掉换行后的前 maxChars(保证 any 内容有摘要)。
|
|
16
|
+
*/
|
|
17
|
+
export function deriveSummary(content, maxChars) {
|
|
18
|
+
const firstLine = content.split('\n')[0].trim();
|
|
19
|
+
if (firstLine !== '') {
|
|
20
|
+
return firstLine.length <= maxChars ? firstLine : `${firstLine.slice(0, maxChars)}…`;
|
|
21
|
+
}
|
|
22
|
+
const collapsed = content.replace(/\s+/g, ' ').trim();
|
|
23
|
+
if (collapsed === '')
|
|
24
|
+
return content;
|
|
25
|
+
return collapsed.length <= maxChars ? collapsed : `${collapsed.slice(0, maxChars)}…`;
|
|
26
|
+
}
|
|
27
|
+
/** 一条注入行的渲染文本(与面板预览完全一致)。 */
|
|
28
|
+
export function injectionLine(record, summaryChars) {
|
|
29
|
+
return `- [memory:${String(record.id).slice(0, 8)}:${record.namespace}] ${deriveSummary(record.content, summaryChars)}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 由候选记录渲染注入行:按使用序降序(lastUsedAt 优先、缺省回退
|
|
33
|
+
* updatedAt——最近使用/更新的记忆最先),逐条累加开销直到预算用尽;
|
|
34
|
+
* 预算为 null 或非正数时全量注入(不过滤)。
|
|
35
|
+
*/
|
|
36
|
+
export function renderInjection(records, budget, summaryChars) {
|
|
37
|
+
const ordered = [...records].sort((left, right) => (right.lastUsedAt ?? right.updatedAt) - (left.lastUsedAt ?? left.updatedAt));
|
|
38
|
+
const lines = [];
|
|
39
|
+
let chars = 0;
|
|
40
|
+
let omitted = 0;
|
|
41
|
+
for (const record of ordered) {
|
|
42
|
+
const text = injectionLine(record, summaryChars);
|
|
43
|
+
const cost = text.length + LINE_OVERHEAD;
|
|
44
|
+
if (budget !== null && budget > 0 && chars + cost > budget) {
|
|
45
|
+
omitted++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
lines.push(text);
|
|
49
|
+
chars += cost;
|
|
50
|
+
}
|
|
51
|
+
return { lines, budget: budget ?? null, omitted, chars };
|
|
52
|
+
}
|
package/dist/remote.d.ts
CHANGED
|
@@ -29,12 +29,16 @@ export declare class MemoryGateway extends TypertRemoteService {
|
|
|
29
29
|
/** Force-reload storage files (external edits; JsonStorageBackend has no watch). */
|
|
30
30
|
reload(cwd?: string): Promise<MemoryRecord[]>;
|
|
31
31
|
/**
|
|
32
|
-
* 注入预览(0.3.5):开发者查看当前注入到 system prompt
|
|
33
|
-
*
|
|
32
|
+
* 注入预览(0.3.5 + 0.5.2):开发者查看当前注入到 system prompt 的记忆
|
|
33
|
+
* 内容——self 自述 + 当前会话工作区(cwd)的 approved+injected 记忆,
|
|
34
|
+
* 经摘要化 + 预算截断(与 memory:recall 同源渲染)。
|
|
34
35
|
*/
|
|
35
|
-
injectionPreview(): {
|
|
36
|
+
injectionPreview(cwd?: string, budget?: number | null, summaryChars?: number): Promise<{
|
|
36
37
|
self: string;
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
lines: string[];
|
|
39
|
+
budget: number | null;
|
|
40
|
+
omitted: number;
|
|
41
|
+
chars: number;
|
|
42
|
+
}>;
|
|
39
43
|
}
|
|
40
44
|
export default MemoryGateway;
|
package/dist/remote.js
CHANGED
|
@@ -43,6 +43,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
43
43
|
import { TypertRemoteService, Remote } from '@deepseek-ai/dsh-typert-protocol';
|
|
44
44
|
import { MemoryId } from "./engine.js";
|
|
45
45
|
import { SELF_DESCRIPTION } from "./self.js";
|
|
46
|
+
import { DEFAULT_INJECTION_BUDGET, DEFAULT_SUMMARY_CHARS, renderInjection } from "./injection.js";
|
|
46
47
|
/** Client-callable memory surface; registered as the `memory` Typert namespace. */
|
|
47
48
|
let MemoryGateway = (() => {
|
|
48
49
|
let _classSuper = TypertRemoteService;
|
|
@@ -109,11 +110,17 @@ let MemoryGateway = (() => {
|
|
|
109
110
|
return this.ctx.memory.list({}, cwd);
|
|
110
111
|
}
|
|
111
112
|
/**
|
|
112
|
-
* 注入预览(0.3.5):开发者查看当前注入到 system prompt
|
|
113
|
-
*
|
|
113
|
+
* 注入预览(0.3.5 + 0.5.2):开发者查看当前注入到 system prompt 的记忆
|
|
114
|
+
* 内容——self 自述 + 当前会话工作区(cwd)的 approved+injected 记忆,
|
|
115
|
+
* 经摘要化 + 预算截断(与 memory:recall 同源渲染)。
|
|
114
116
|
*/
|
|
115
|
-
injectionPreview() {
|
|
116
|
-
|
|
117
|
+
async injectionPreview(cwd, budget, summaryChars) {
|
|
118
|
+
if (cwd !== undefined)
|
|
119
|
+
await this.ctx.memory.ensureProjectOpen(cwd);
|
|
120
|
+
return {
|
|
121
|
+
self: SELF_DESCRIPTION,
|
|
122
|
+
...renderInjection(this.ctx.memory.recallRecords(cwd), budget ?? DEFAULT_INJECTION_BUDGET, summaryChars ?? DEFAULT_SUMMARY_CHARS),
|
|
123
|
+
};
|
|
117
124
|
}
|
|
118
125
|
};
|
|
119
126
|
})();
|
package/dist/routes.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { SELF_DESCRIPTION } from "./self.js";
|
|
3
|
+
import { DEFAULT_INJECTION_BUDGET, DEFAULT_SUMMARY_CHARS, renderInjection } from "./injection.js";
|
|
3
4
|
const require = createRequire(import.meta.url);
|
|
4
5
|
/** Body size bound of one JSON request. */
|
|
5
6
|
const MAX_BODY_BYTES = 1 << 20;
|
|
@@ -168,11 +169,20 @@ export function mountMemoryApi(ctx) {
|
|
|
168
169
|
...record.keywords === undefined ? {} : { keywords: record.keywords },
|
|
169
170
|
}, cwdOf(record));
|
|
170
171
|
},
|
|
171
|
-
'injectionPreview': () => {
|
|
172
|
+
'injectionPreview': async (payload) => {
|
|
172
173
|
const memory = ctx.get('memory');
|
|
173
174
|
if (memory === undefined)
|
|
174
175
|
throw new MemoryApiError('service-unavailable', 'memory service unavailable', 503);
|
|
175
|
-
|
|
176
|
+
const record = payload;
|
|
177
|
+
const cwd = cwdOf(record);
|
|
178
|
+
if (cwd !== undefined)
|
|
179
|
+
await memory.ensureProjectOpen(cwd);
|
|
180
|
+
// 0.5.2:预览与真实注入同源(renderInjection)——摘要化 + 预算截断一致
|
|
181
|
+
const budget = typeof record?.budget === 'number' && record.budget > 0
|
|
182
|
+
? record.budget
|
|
183
|
+
: record?.budget === null ? null : DEFAULT_INJECTION_BUDGET;
|
|
184
|
+
const summaryChars = typeof record?.summaryChars === 'number' && record.summaryChars > 0 ? record.summaryChars : DEFAULT_SUMMARY_CHARS;
|
|
185
|
+
return { self: SELF_DESCRIPTION, ...renderInjection(memory.recallRecords(cwd), budget, summaryChars) };
|
|
176
186
|
},
|
|
177
187
|
};
|
|
178
188
|
const fence = (req) => isTrusted(req, webRuntime.trustedHosts);
|
package/dist/self.js
CHANGED
|
@@ -18,8 +18,8 @@ const SELF_VERSION = (() => {
|
|
|
18
18
|
export const SELF_DESCRIPTION = `[记忆系统自述] 当前环境内置跨会话记忆服务(dsh-memory v${SELF_VERSION})。`
|
|
19
19
|
+ '工作机制:①记忆以明文 JSON 存储(global→$DSH_HOME/storages、工作区→会话工作区 .dsh/storages 随 git 分享);'
|
|
20
20
|
+ '②模型写入即 suggested(待审核),仅人工审核(memory_confirm)后才 approved;'
|
|
21
|
-
+ '③每轮注入 system prompt
|
|
22
|
-
+ '
|
|
21
|
+
+ '③每轮注入 system prompt 的 = 「global 的 approved + injected」+「当前会话工作区的 approved + injected」,逐条为单行摘要(内容全文靠 memory_search 检索),并受注入预算限制(超预算按最近更新优先,省略条数在面板「注入预览」可见;常驻注入由用户控制,审核≠注入);'
|
|
22
|
+
+ '④工作区记忆按会话工作区路由(存储跟随仓库),memory_search 为 BM25 检索(中文 2-gram + 关键词加权,可配置语义融合),可检索任意状态(含待审核条目,可先评估再引用);'
|
|
23
23
|
+ '⑤修正过时内容用 memory_update(改动重置待审核,注入开关保留)。'
|
|
24
24
|
+ `可用记忆工具共 6 个:memory_save / memory_list / memory_search / memory_confirm / memory_forget / memory_update。`
|
|
25
25
|
+ '使用建议:相关历史上下文先 memory_search 检索再引用;新习惯/约定用 memory_save 写入(落在待审核)。'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@max-null/dsh-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Cross-session plaintext memory plugin for the DeepSeek Harness — deterministic BM25 recall, human-owned, no embeddings",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -61,22 +61,22 @@
|
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
64
|
-
"@deepseek-ai/dsh-storage": "
|
|
65
|
-
"@deepseek-ai/dsh-storage-domain": "
|
|
66
|
-
"@deepseek-ai/dsh-storage-json": "
|
|
67
|
-
"@deepseek-ai/dsh-system-prompt": "
|
|
68
|
-
"@deepseek-ai/dsh-tools": "
|
|
69
|
-
"@deepseek-ai/dsh-typert-protocol": "
|
|
64
|
+
"@deepseek-ai/dsh-storage": "^0.1.1-rc.1",
|
|
65
|
+
"@deepseek-ai/dsh-storage-domain": "^0.1.1-rc.1",
|
|
66
|
+
"@deepseek-ai/dsh-storage-json": "^0.1.1-rc.1",
|
|
67
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.1",
|
|
68
|
+
"@deepseek-ai/dsh-tools": "^0.1.1-rc.1",
|
|
69
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.1"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
73
73
|
"@deepseek-ai/cordis-plugin-loader": "^1.0.2",
|
|
74
|
-
"@deepseek-ai/dsh-storage": "
|
|
75
|
-
"@deepseek-ai/dsh-storage-domain": "
|
|
76
|
-
"@deepseek-ai/dsh-storage-json": "
|
|
77
|
-
"@deepseek-ai/dsh-system-prompt": "
|
|
78
|
-
"@deepseek-ai/dsh-tools": "
|
|
79
|
-
"@deepseek-ai/dsh-typert-protocol": "
|
|
74
|
+
"@deepseek-ai/dsh-storage": "^0.1.1-rc.1",
|
|
75
|
+
"@deepseek-ai/dsh-storage-domain": "^0.1.1-rc.1",
|
|
76
|
+
"@deepseek-ai/dsh-storage-json": "^0.1.1-rc.1",
|
|
77
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.1",
|
|
78
|
+
"@deepseek-ai/dsh-tools": "^0.1.1-rc.1",
|
|
79
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.1",
|
|
80
80
|
"@types/node": "^26.2.0",
|
|
81
81
|
"tsx": "^4.0.0",
|
|
82
82
|
"typescript": "^5.5.0",
|