@max-null/dsh-memory 0.17.0 → 0.18.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/README.md +2 -0
- package/dist/index.js +62 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,6 +116,8 @@ md 文件是唯一事实源(`~/.dsh/prompt-library/*.md` 为 global;`<worksp
|
|
|
116
116
|
```
|
|
117
117
|
模型 memory_save → status: approved,立即生效;命中密钥/凭据规则则隔离(不进检索也不进注入)
|
|
118
118
|
给 injected 则同时钉住常驻(0.8.0),不受自动规则影响
|
|
119
|
+
钉成常驻时返回 `resident`(total / injected / omitted / budget)——
|
|
120
|
+
钉的那一刻就知道挤掉了几条,不必等下一轮的出局诊断行
|
|
119
121
|
memory_search → 关键词/语义召回(只搜记忆;模板走 prompt_search 通道,不会混进候选池)
|
|
120
122
|
默认最多返回 20 条,`limit: 0` 取消上限;条数等于 limit 时可能还有更多
|
|
121
123
|
命中记账只记 BM25 前 5 名——`hitCount` 是"排前"的信号,不是"被检索到"的面;
|
package/dist/index.js
CHANGED
|
@@ -99,6 +99,32 @@ const HIT_SCHEMA = {
|
|
|
99
99
|
score: { type: 'number', required: true },
|
|
100
100
|
},
|
|
101
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* `memory_save` / `memory_update` 的输出:记录本体 +(操作后仍是常驻时)预算占用快照。
|
|
104
|
+
*
|
|
105
|
+
* 单列一份而不往 {@link RECORD_SCHEMA} 里加:`memory_list` 一次返回全库,每条都带
|
|
106
|
+
* 一份占用快照既冗余,也与「这条记录本身」无关。预算快照只在**钉入/仍常驻**时出现,
|
|
107
|
+
* 因为那正是「挤掉别人」这个决定发生的那一刻——钉完再等下一轮的出局诊断行,人已经
|
|
108
|
+
* 想不起来是哪一次钉入造成的。
|
|
109
|
+
*/
|
|
110
|
+
const SAVED_RECORD_SCHEMA = {
|
|
111
|
+
type: 'object',
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
properties: {
|
|
114
|
+
...RECORD_SCHEMA.properties,
|
|
115
|
+
resident: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
additionalProperties: false,
|
|
118
|
+
description: '钉入之后的常驻注入占用(仅当该记录为常驻时出现):total 候选条数、injected 本轮实际进场、omitted 被预算挤出、budget 字符预算。',
|
|
119
|
+
properties: {
|
|
120
|
+
total: { type: 'number', required: true },
|
|
121
|
+
injected: { type: 'number', required: true },
|
|
122
|
+
omitted: { type: 'number', required: true },
|
|
123
|
+
budget: { type: 'number' },
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
};
|
|
102
128
|
/**
|
|
103
129
|
* `memory_search` 的默认返回上限(0 = 不限)。宽查询会命中大半个库(本机 279 条库实测
|
|
104
130
|
* 命中面 35%–84%),返回体随库线性增长;20 条仍覆盖"有答案价值"的部分,20 名之后
|
|
@@ -284,6 +310,21 @@ const GUIDANCE = 'Use memory tools for cross-session preferences, habits, and pr
|
|
|
284
310
|
+ 'When the library grows, call memory_sweep for a read-only health check (stale records with reasons, '
|
|
285
311
|
+ 'long-unused ones, candidates that keep being retrieved without being pinned, and budget usage). '
|
|
286
312
|
+ '库变大之后用 memory_sweep 做只读体检——失效记录(带原因)、久未命中、被反复检索却未常驻的候选、以及预算占用。';
|
|
313
|
+
/**
|
|
314
|
+
* 钉入常驻后的预算占用快照(`memory_save` / `memory_update` 输出用)。刻意复用注入侧的
|
|
315
|
+
* `renderInjection`:两处各算一套的话,「工具里显示的占用」与「下一轮实际注入」会给出
|
|
316
|
+
* 不同的数字,而人恰恰是拿前者的数字去判断要不要钉的。
|
|
317
|
+
*/
|
|
318
|
+
function residentUsage(memory, projectCwd, budget, summaryChars) {
|
|
319
|
+
const records = memory.recallRecords(projectCwd);
|
|
320
|
+
const rendered = renderInjection(records, budget, summaryChars);
|
|
321
|
+
return {
|
|
322
|
+
total: records.length,
|
|
323
|
+
injected: rendered.lines.length,
|
|
324
|
+
omitted: rendered.omitted,
|
|
325
|
+
...rendered.budget === null ? {} : { budget: rendered.budget },
|
|
326
|
+
};
|
|
327
|
+
}
|
|
287
328
|
// 0.5.1:`memory:recall` provider 可经 AssembleContext.agent 拿到当前会话
|
|
288
329
|
// 的 header.cwd——注入 = global + 当前会话工作区的 approved+injected
|
|
289
330
|
// (0.3.4 起工作区记忆就按会话 cwd 路由;provider 是同步回调,只读已
|
|
@@ -435,10 +476,11 @@ export async function apply(ctx, config) {
|
|
|
435
476
|
},
|
|
436
477
|
},
|
|
437
478
|
output: {
|
|
438
|
-
schema:
|
|
479
|
+
schema: SAVED_RECORD_SCHEMA,
|
|
439
480
|
render: (_args, value) => renderJson(value),
|
|
440
481
|
},
|
|
441
482
|
execute(args, exec) {
|
|
483
|
+
const cwd = execProjectCwd(exec);
|
|
442
484
|
return memory.remember({
|
|
443
485
|
content: args.content,
|
|
444
486
|
...args.namespace === undefined ? {} : { namespace: args.namespace },
|
|
@@ -448,7 +490,14 @@ export async function apply(ctx, config) {
|
|
|
448
490
|
...args.anchor === undefined
|
|
449
491
|
? {}
|
|
450
492
|
: { anchor: args.anchor },
|
|
451
|
-
},
|
|
493
|
+
}, cwd).then(record => {
|
|
494
|
+
const value = recordValue(record);
|
|
495
|
+
// 钉常驻的那一刻就把「挤掉了几条」交给人看:等到下一轮的出局诊断行,
|
|
496
|
+
// 人已经想不起来是哪一次钉入造成的。
|
|
497
|
+
return record.injected
|
|
498
|
+
? { ...value, resident: residentUsage(memory, cwd, injectionBudget, summaryChars) }
|
|
499
|
+
: value;
|
|
500
|
+
});
|
|
452
501
|
},
|
|
453
502
|
presentCall: args => present('Save memory', 'other', args.content),
|
|
454
503
|
}));
|
|
@@ -704,18 +753,25 @@ export async function apply(ctx, config) {
|
|
|
704
753
|
},
|
|
705
754
|
},
|
|
706
755
|
output: {
|
|
707
|
-
schema:
|
|
756
|
+
schema: SAVED_RECORD_SCHEMA,
|
|
708
757
|
render: (_args, value) => renderJson(value),
|
|
709
758
|
},
|
|
710
759
|
execute(args, exec) {
|
|
711
760
|
const cwd = execProjectCwd(exec);
|
|
712
761
|
const id = args.id;
|
|
762
|
+
const settle = (record) => {
|
|
763
|
+
const value = recordValue(record);
|
|
764
|
+
// 改内容也会改变注入占用的字符数:只要这条仍是常驻,就把占用一起交回去。
|
|
765
|
+
return record.injected
|
|
766
|
+
? { ...value, resident: residentUsage(memory, cwd, injectionBudget, summaryChars) }
|
|
767
|
+
: value;
|
|
768
|
+
};
|
|
713
769
|
// 三种动作互斥,按 retract > supersedes > update 的次序取第一个(与工具描述一致):
|
|
714
770
|
// 前两个是「标状态」,第三个才是「改内容」。同时给多个时以更重的动作为准。
|
|
715
771
|
if (args.retract !== undefined)
|
|
716
|
-
return memory.retract(id, args.retract, cwd).then(
|
|
772
|
+
return memory.retract(id, args.retract, cwd).then(settle);
|
|
717
773
|
if (args.supersedes !== undefined)
|
|
718
|
-
return memory.supersede(id, args.supersedes, cwd).then(
|
|
774
|
+
return memory.supersede(id, args.supersedes, cwd).then(settle);
|
|
719
775
|
return memory.update(id, {
|
|
720
776
|
...args.content === undefined ? {} : { content: args.content },
|
|
721
777
|
...args.keywords === undefined ? {} : { keywords: args.keywords },
|
|
@@ -724,7 +780,7 @@ export async function apply(ctx, config) {
|
|
|
724
780
|
...args.anchor === undefined
|
|
725
781
|
? {}
|
|
726
782
|
: { anchor: args.anchor },
|
|
727
|
-
}, cwd).then(
|
|
783
|
+
}, cwd).then(settle);
|
|
728
784
|
},
|
|
729
785
|
presentCall: args => present('Update memory', 'other', args.id),
|
|
730
786
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@max-null/dsh-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Cross-session plaintext memory plugin for the DeepSeek Harness — deterministic BM25 recall, writes take effect immediately, signal-driven injection, no embeddings",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|