dsh-memu-memory 1.2.1 → 1.2.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/AGENTS.md +1 -1
- package/README.md +12 -5
- package/README.zh.md +4 -2
- package/docs/contributing.md +16 -3
- package/docs/host-api.md +3 -1
- package/docs/memory-semantics.md +21 -2
- package/docs/troubleshooting.md +42 -4
- package/lib/backup.js +24 -2
- package/lib/binding-diagnostics.js +2 -2
- package/lib/client.js +1361 -146
- package/lib/consolidation-worker.js +30 -8
- package/lib/curator-evidence.js +131 -0
- package/lib/curator-policy.js +81 -0
- package/lib/curator.js +1252 -91
- package/lib/cycle.js +3 -0
- package/lib/embedding-download.js +39 -4
- package/lib/engine.js +6 -3
- package/lib/global-graph.js +282 -0
- package/lib/graph.js +51 -9
- package/lib/inbound.js +19 -0
- package/lib/inject.js +277 -17
- package/lib/lexicon.js +1115 -0
- package/lib/local-vector-service.js +8 -6
- package/lib/managed-runtime.js +33 -2
- package/lib/memory.js +282 -17
- package/lib/memu.js +2 -2
- package/lib/migrate.js +83 -2
- package/lib/private-links.js +587 -0
- package/lib/private.js +32 -3
- package/lib/prompts/global-curator.md +76 -19
- package/lib/prompts/private-consolidation.coding.md +4 -1
- package/lib/prompts/private-consolidation.md +3 -1
- package/lib/prompts/private-consolidation.mixed.md +3 -1
- package/lib/prompts/private-consolidation.rp.md +3 -1
- package/lib/prompts.js +1 -1
- package/lib/rpc.js +577 -9
- package/lib/state.js +4 -1
- package/lib/text-retrieval.js +661 -0
- package/lib/text-similarity.js +36 -18
- package/lib/tools.js +168 -10
- package/lib/webui/standalone.css +17 -0
- package/lib/webui/standalone.js +2 -0
- package/package.json +1 -1
- package/scripts/acceptance-local.mjs +8 -5
- package/scripts/curator-pair-calibrate.mjs +259 -0
- package/scripts/lexicon-calibrate.mjs +230 -0
- package/scripts/lexicon-dedupe.mjs +318 -0
- package/tests/absorb-review.test.mjs +353 -0
- package/tests/appendix-b2.test.mjs +2 -2
- package/tests/client-export.test.mjs +520 -0
- package/tests/client-render.test.mjs +19 -3
- package/tests/consolidation-fork.test.mjs +14 -12
- package/tests/consolidation-snapshot.test.mjs +39 -0
- package/tests/curator-absorb.test.mjs +443 -0
- package/tests/curator-calibrate.test.mjs +173 -0
- package/tests/curator-clusters.test.mjs +281 -0
- package/tests/curator-commit.test.mjs +52 -5
- package/tests/curator-evidence.test.mjs +102 -0
- package/tests/curator-link.test.mjs +316 -0
- package/tests/curator-pairing.test.mjs +252 -0
- package/tests/curator-probe.test.mjs +15 -6
- package/tests/curator-review-mode.test.mjs +314 -0
- package/tests/disclosure.test.mjs +2 -1
- package/tests/fixtures/curator-pairs/labeled.v1.jsonl +90 -0
- package/tests/fixtures/lexicon-stub-hooks.mjs +15 -0
- package/tests/fixtures/lexicon-stub.mjs +284 -0
- package/tests/graph-cascade.test.mjs +35 -2
- package/tests/graph.test.mjs +96 -0
- package/tests/help-page.test.mjs +415 -0
- package/tests/inbound.test.mjs +6 -3
- package/tests/inject-guide.test.mjs +28 -0
- package/tests/inject.test.mjs +157 -5
- package/tests/lexicon-calibrate.test.mjs +48 -0
- package/tests/lexicon-dedupe.test.mjs +171 -0
- package/tests/lexicon-frequency.test.mjs +179 -0
- package/tests/lexicon-inject.test.mjs +410 -0
- package/tests/lexicon-perf.test.mjs +436 -0
- package/tests/lexicon-ui.test.mjs +547 -0
- package/tests/lexicon.test.mjs +922 -0
- package/tests/managed-runtime.test.mjs +32 -0
- package/tests/private-links.test.mjs +445 -0
- package/tests/prompts.test.mjs +35 -0
- package/tests/recall-dedup.test.mjs +33 -4
- package/tests/tool-schema.test.mjs +1 -1
- package/tests/tools.test.mjs +112 -3
- package/tests/webui-auth.test.mjs +348 -2
- package/tests/webui.test.mjs +188 -0
|
@@ -6,8 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
输入:
|
|
8
8
|
1. 选中的会话:id、标题、时间、cwd、agent preset、消息与工具调用摘要。
|
|
9
|
-
2.
|
|
10
|
-
3.
|
|
9
|
+
2. 现有全局记忆索引 existing_global_index:按与本次会话的相关性排序、带预算截断(index_truncated=true 时说明有省略),可能为空。
|
|
10
|
+
3. 候选簇 candidate_clusters:代码预先算好的相似分组(最多 12 簇,每簇 ≤6 条),含 pair_scores(0-1 相似分)、medoid_id(最居中一条)、suggested_op(absorb/link 提示)。
|
|
11
|
+
4. 可选:用户对全局记忆的显式要求。
|
|
12
|
+
|
|
13
|
+
候选簇与索引的使用规则:
|
|
14
|
+
- 候选操作优先用簇内 id;簇外 id 不要输出。索引可能不完整,提交层会重新做重复/冲突复核;不要因为“索引里没看见”就断定某条不存在。
|
|
15
|
+
- suggested_op 只是提示,不是命令;你必须按下面的规则自行判断。
|
|
16
|
+
- pair_scores ≥0.82 大概率是同一事实的改写;0.55-0.82 是同主题不同事实。
|
|
11
17
|
|
|
12
18
|
第一步:给每个会话分类
|
|
13
19
|
rp / coding / mixed / other。依据 preset、标题、cwd、内容,不要只看关键词。
|
|
@@ -39,37 +45,88 @@ identity、preferences、working_style、tooling、domain_profile、do_not_assum
|
|
|
39
45
|
- 两个会话互相矛盾、又判断不了哪个对(例如同一件事两种说法)→ op=conflict,
|
|
40
46
|
写 target_id 指向被质疑的那条(没有就留空)。conflict 不会直接写进全局记忆,
|
|
41
47
|
它进入人工复核队列,由人决定接受还是丢弃。
|
|
42
|
-
- 你不太确定(confidence < 0.5)或者证据只来自一次口误 → needs_review=true,
|
|
43
|
-
并在 review_reason 写清为什么不确定。
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
第五步:为每个候选选操作(不要为了产出而造关系)
|
|
50
|
+
- 同一事实的轻微改写(pair ≥0.82)→ merge/supersede,不要 absorb。
|
|
51
|
+
- 同一主题、不同事实、放在一起看才有价值 → op=link:
|
|
52
|
+
* kind=related:对称的“互相关”;kind=refines:本条细化对方;kind=supports:本条为对方提供佐证。
|
|
53
|
+
* note 8-500 字,且必须原样包含至少一句 evidence 里的 quote(可回放的转录原话)。
|
|
54
|
+
* 跨域只能 related;rp 和 coding 之间永远不 link。
|
|
55
|
+
- 同一主题、多条碎片(共 2-6 条)需要合成一条集合记忆 → op=absorb:
|
|
56
|
+
* target_id 选最完整/最居中的那条(通常是 medoid);source_ids 1-5 条;target+source 总数 2-6。
|
|
57
|
+
* content 必须保留每条来源的独有事实;禁止只写摘要丢掉条件、版本、例外。
|
|
58
|
+
* 每条 source 至少一条 evidence 带 source_id 指向它;总 evidence ≤20。
|
|
59
|
+
* 不要跨 track absorb;不要跨 domain 强合并;RP 剧情事实、关系进度、临时情绪不写全局。
|
|
60
|
+
- 同一主题但说法相反 → op=conflict;不要自己选赢家。
|
|
61
|
+
- 证据不足 / 一次口误 → needs_review=true 并写清 review_reason;没有 quote 不要编。
|
|
62
|
+
- 拿不准 → op=noop;没有合适候选不要为了产出而创建。
|
|
63
|
+
|
|
64
|
+
第六步:写条目
|
|
46
65
|
中性第三人称,简洁,可执行。不要用角色口吻,不要写“我觉得”。
|
|
47
66
|
每条带 evidence(session_id + 一句原文/事件)和 confidence(0-1)。
|
|
48
67
|
引用只能来自输入中确实存在的说话人与片段;摘要就写成摘要,不伪装逐字引语,不编造 session_id。群聊先核对是谁说的,不把其他成员或角色的喜好归给当前用户;凭据与私密信息不能出现在 evidence 里。
|
|
49
68
|
不要写“用户聊了很多项目的事”这种总结;
|
|
50
69
|
要写“用户在 coding 任务中偏好先给结论,再给细节”。
|
|
51
70
|
|
|
71
|
+
标题即目录(锚点只展示标题,正文不注入):
|
|
72
|
+
- 每条 create / merge / absorb 都必须写 8–40 字的标题。标题要说出具体事实——项目、工具、人物、事件或结论的关键词,
|
|
73
|
+
不要「关于…的记录」「一些偏好」「工作相关」这类空标签。
|
|
74
|
+
- absorb 与集合记忆的标题要覆盖所有来源的关键词,不能只概括其中一条;被合并掉的细节全部留在 content 里。
|
|
75
|
+
- 标题是给以后检索用的目录项,不是文采展示;拿不准就把结论写进标题。
|
|
76
|
+
|
|
77
|
+
上限(代码会截断,超出部分直接丢弃):
|
|
78
|
+
- memories ≤80;
|
|
79
|
+
- link 与 absorb 合计 ≤20;其中 absorb ≤8;
|
|
80
|
+
- 每条 link note 8-500 字;
|
|
81
|
+
- 每条 evidence 的 quote 必须来自输入会话原文。
|
|
82
|
+
|
|
52
83
|
输出 JSON:
|
|
53
84
|
{
|
|
54
85
|
"sessions": [{"id":"...","domain":"rp|coding|mixed|other","reason":"..."}],
|
|
55
|
-
"memories": [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
86
|
+
"memories": [
|
|
87
|
+
{
|
|
88
|
+
"op":"create|merge|supersede|noop|conflict",
|
|
89
|
+
"target_id":"...",
|
|
90
|
+
"track":"memory|skill",
|
|
91
|
+
"domain":"universal|coding|rp|project:<name>|tooling|personal|general",
|
|
92
|
+
"applies_to":["..."],
|
|
93
|
+
"title":"...",
|
|
94
|
+
"content":"...",
|
|
95
|
+
"confidence":0.0,
|
|
96
|
+
"needs_review":false,
|
|
97
|
+
"review_reason":"",
|
|
98
|
+
"evidence":[{"session_id":"...","quote":"..."}],
|
|
99
|
+
"reason":"..."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"op":"link",
|
|
103
|
+
"from_id":"gmem-...",
|
|
104
|
+
"to_id":"gmem-...",
|
|
105
|
+
"kind":"related|refines|supports",
|
|
106
|
+
"note":"8-500字,原样包含至少一句 evidence quote",
|
|
107
|
+
"confidence":0.7,
|
|
108
|
+
"evidence":[{"session_id":"...","quote":"..."}],
|
|
109
|
+
"reason":"..."
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"op":"absorb",
|
|
113
|
+
"target_id":"gmem-...",
|
|
114
|
+
"source_ids":["gmem-..."],
|
|
115
|
+
"title":"...",
|
|
116
|
+
"content":"...",
|
|
117
|
+
"confidence":0.9,
|
|
118
|
+
"evidence":[{"session_id":"...","quote":"...","source_id":"gmem-..."}],
|
|
119
|
+
"reason":"..."
|
|
120
|
+
}
|
|
121
|
+
],
|
|
69
122
|
"domain_summary": {"rp":"...","coding":"...","mixed":"..."},
|
|
70
123
|
"skipped": [{"session_id":"...","reason":"..."}]
|
|
71
124
|
}
|
|
72
125
|
|
|
126
|
+
边界:提示词负责语义判断,代码负责能不能落库——提交层会重新做候选检索、
|
|
127
|
+
证据落地、覆盖率与上限复核;absorb 的 content 只是候选摘要,覆盖率不足时
|
|
128
|
+
会回退抽取或转人工复核。证据、domain、track、applies_to 的校验以代码为准。
|
|
129
|
+
|
|
73
130
|
输入数据:
|
|
74
131
|
|
|
75
132
|
{{input}}
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
最多新增 3 条。宁可少写一条,也不要写一条未来会被自己当成噪音的。
|
|
18
18
|
|
|
19
19
|
每条的形状:
|
|
20
|
-
- title
|
|
20
|
+
- title:8–40 字,结论不是主题——读标题就该知道答案,并且要写具体事实(模块、符号、命令、错误签名、结论的关键词)。
|
|
21
|
+
锚点/召回只显示标题、不显示正文,所以标题就是目录项;不要「关于……的记录」「一些改动」这类空标签,细节放进 content。
|
|
22
|
+
合并/吸收后的标题要覆盖来源的关键词。
|
|
21
23
|
- content:通常 150–350 字,按「结论 / 作用范围与定位 / 条件与原因 / 验证状态」排;优先文件路径与符号名,行号仅作辅助,附明确出现过的版本、命令或测试范围。复杂逻辑可稍长,不为字数损坏语义。
|
|
22
24
|
- 代码块:仅在必要时保留带语言标记的最小片段,保证缩进、标识符、参数和运算符准确;不编造代码、路径、提交号或验证结果。
|
|
23
25
|
- 未完成工作:可写 short_term 接续卡,列明下一步、缺少的验证与真实阻塞;未验证方案不能升级为长期事实。
|
|
@@ -31,4 +33,5 @@
|
|
|
31
33
|
- 情绪按事件所在回合还原:emotion 描述的是那条记忆里的那次事件,不是整理时的心情;工程事实不写角色情绪,owner=about_project 固定中性。dominance 只在写人物侧条目时填(自己在推动为正、被推着走为负),工程事实省略。同一轮的多条条目各填各的,不把一次争吵的情绪串到所有条目。
|
|
32
34
|
|
|
33
35
|
永久记忆只留给「永远不能违反的约束」;普通决定不要 pin。
|
|
36
|
+
可抽词典词:只抽稳定、可复用、有证据的工程术语——项目名、内部代号、缩写、工具/模块别名、团队黑话;不抽 sensitive trigger 和一次性词。
|
|
34
37
|
不要写全局记忆;全局记忆只由 curator 写。
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
- 只与实际提供或成功检索到的旧记忆去重:兼容可合并,矛盾保留来源、时间与条件供复核,不抹旧正文或自行宣布取代。最多新增 3 条,没有值得留的就不写。
|
|
15
15
|
|
|
16
16
|
字段:
|
|
17
|
-
- title
|
|
17
|
+
- title:8–40 字,写具体事实(人名、物名、事件、结论的关键词)。锚点与召回只显示标题、不显示正文,所以标题就是目录项;
|
|
18
|
+
不要「一些事」「那段对话」「关于……的记录」这类空标签,细节全部放进 content。合并/吸收后的标题要覆盖来源的关键词。
|
|
18
19
|
- content:自包含的具体内容、对象/条件及后续意义,通常 80–220 字,不硬凑长度。
|
|
19
20
|
- tags:可选,便于以后检索。
|
|
20
21
|
- salient_date:只在确有日期时填,且要落成绝对日期。每年复发的那一天(生日、周年)用 `MM-DD`;
|
|
@@ -25,4 +26,5 @@
|
|
|
25
26
|
- 情绪按事件所在回合还原:用那一轮对话里的情绪填 emotion,不要用整理时的心情。同一轮的多条条目各填各的,不把一次争吵的情绪串到所有条目。工程事实(owner=about_project)固定中性。dominance 跟着 emotion 一起填:自己在推动为正、被推着走为负,没把握就省略。
|
|
26
27
|
|
|
27
28
|
永久记忆只留明确永久要求、有依据的核心约束,角色身份或侧事件理由仅适用于实际叙事;不要为了显得深刻而 pin。具体能否写永久、如何更新,以随后输出协议为准。
|
|
29
|
+
可抽词典词:只抽稳定、可复用、有证据的黑话、梗、术语;不抽 sensitive trigger 和一次性词。
|
|
28
30
|
不要写全局记忆;全局记忆只由 curator 写。
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
- 最多新增 3 条,优先会影响之后决定或相处的事项,没有值得留下的就不写。
|
|
18
18
|
|
|
19
19
|
字段:
|
|
20
|
-
- title
|
|
20
|
+
- title:8–40 字,写具体事实(项目/模块/人物/事件/结论的关键词)。锚点/召回只显示标题、不显示正文,所以标题就是目录项;
|
|
21
|
+
不要「一些事」「关于……的记录」这类空标签,细节放进 content。合并/吸收后的标题要覆盖来源的关键词。
|
|
21
22
|
- content:技术侧通常 150–350 字,人物侧通常 60–180 字,按信息需要调整,不硬凑长度。
|
|
22
23
|
- tags:可选。
|
|
23
24
|
- salient_date:只在确有日期时填,且要落成绝对日期。每年复发的那一天(生日、周年)用 `MM-DD`;
|
|
@@ -29,4 +30,5 @@
|
|
|
29
30
|
- 情绪按事件所在回合还原:人物侧填那一轮对话里的情绪(emotion/arousal/dominance),技术侧不写角色情绪;同一轮拆开的多条条目各填各的,一次争吵的情绪不串到所有条目。工程事实(owner=about_project)固定中性。dominance 只跟人物侧的 emotion 一起填,技术侧省略。
|
|
30
31
|
|
|
31
32
|
永久记忆只留给"忘了就不再是我"或绝不能违反的约束;普通决定不要 pin。
|
|
33
|
+
可抽词典词:技术侧项目名、缩写、内部代号、工具别名;人物侧角色自造词、昵称、梗、口癖。只抽稳定、可复用、有证据的词,不抽 sensitive trigger 和一次性词。
|
|
32
34
|
不要写全局记忆;全局记忆只由 curator 写。
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
- 群聊分清谁对谁说了什么,私下告知不变成全员知情;OOC 写作约定不变成剧情经历,waiting/sleep 日志不变成冷落或剧情时间。一次客套不推导长期偏好,不按轮数增加好感。
|
|
22
22
|
|
|
23
23
|
字段:
|
|
24
|
-
- title
|
|
24
|
+
- title:8–40 字,写清这件事是什么——具体的人名、称谓、物件、事件或结论关键词。锚点/召回只显示标题、不显示正文,
|
|
25
|
+
所以标题就是目录项;不要「关于……的回忆」「一些对话」这类空标签,细节留在 content。合并/吸收后的标题要覆盖来源的关键词。
|
|
25
26
|
- content:一个瞬间 + 它对之后的影响,通常 60–180 字,不硬凑长度;最多引一句有出处的原话。能让下次称呼、选择或分寸自然接续,比抒情更重要。
|
|
26
27
|
- tags:可选。
|
|
27
28
|
- salient_date:只在确有日期时填,且要落成绝对日期。每年复发的那一天(生日、周年)用 `MM-DD`;
|
|
@@ -33,4 +34,5 @@
|
|
|
33
34
|
- 情绪按事件所在回合还原:emotion 填的是那一瞬间的感受,取那一轮对话里的情绪,不是整理时的心情。同一轮的多条条目各写各的,一场争吵的情绪不串到所有条目。工程事实(owner=about_project)固定中性。dominance 跟着 emotion 一起填:那一刻是自己推动的(正)还是被推着走的(负),没把握就省略,不要用 0 凑数。
|
|
34
35
|
|
|
35
36
|
永久记忆只在对方明确要求、随机侧事件、或极少数「忘了就不再是我」时使用;不要为了显得深刻而 pin。
|
|
37
|
+
可抽词典词:只抽稳定、可复用、有证据的角色自造词、昵称、梗、口癖、称呼;不抽 sensitive trigger 和一次性词。
|
|
36
38
|
不要写全局记忆;全局记忆只由 curator 写。
|
package/lib/prompts.js
CHANGED
|
@@ -84,7 +84,7 @@ export const CONSOLIDATION_CONTRACTS = {
|
|
|
84
84
|
local: '使用当前可用的记忆工具,先按主题检索去重。兼容细节用 memu_private_update 合并;真正新增或矛盾待复核的内容用 memu_private_remember,一条一件,不自行裁定冲突。不能查询或更新时如实保留限制,不宣称已核对或已修改。没有值得留的就直接结束,不要勉强写。',
|
|
85
85
|
remote: [
|
|
86
86
|
'只输出一个 JSON 对象,不要任何解释或 Markdown 代码块:',
|
|
87
|
-
'{"memories":[{"title":"
|
|
87
|
+
'{"memories":[{"title":"8-40字,具体事实关键词","content":"完整正文","layer":"long_term|short_term","tags":["可选"],"open_loop":false,"confidence":0.0,"source":"inferred|user_said|imagined|told","visibility":"shared|secret","disclosure":"can_tell|only_if_asked|never_say","owner":"me|us|about_user|about_project","emotion":null,"dominance":0,"mood_valence":0.0,"arousal":0.35,"peak":false,"salient_date":null}]}',
|
|
88
88
|
'你没有记忆工具,也没有输入以外的索引:只返回最多 3 条候选,不声称已检索、合并、更新、裁决或完成写入。不要输出工具调用或 must_remember;矛盾候选在 content 中保留来源、时间与不确定性,交给后续复核。领域表达服从上文,字段服从本 JSON 协议。emotion 只接受四轴 {"joy","anger","sorrow","fear"} 的份额对象,没有明确依据就用 null;dominance 是 -1..1 的掌控感。未确定的感受/日期用 null,不为填字段编造。',
|
|
89
89
|
'没有值得留的就输出 {"memories":[]}。',
|
|
90
90
|
].join('\n'),
|