dsh-lite-memory 0.18.1 → 0.18.19
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 +13 -13
- package/TRIGGERS.md +1 -1
- package/client.js +184 -34
- package/docs/RELEASE-0.18.10.md +25 -0
- package/docs/RELEASE-0.18.11.md +48 -0
- package/docs/RELEASE-0.18.12.md +27 -0
- package/docs/RELEASE-0.18.13.md +13 -0
- package/docs/RELEASE-0.18.14.md +13 -0
- package/docs/RELEASE-0.18.15.md +5 -0
- package/docs/RELEASE-0.18.2.md +21 -0
- package/docs/RELEASE-0.18.3.md +16 -0
- package/docs/RELEASE-0.18.4.md +15 -0
- package/docs/RELEASE-0.18.5.md +21 -0
- package/docs/RELEASE-0.18.6.md +18 -0
- package/docs/RELEASE-0.18.7.md +23 -0
- package/docs/RELEASE-0.18.8.md +18 -0
- package/docs/RELEASE-0.18.9.md +24 -0
- package/index.js +347 -123
- package/learning.js +65 -6
- package/package.json +3 -3
- package/state.js +47 -6
- package/store.js +180 -18
- package/test/client.test.mjs +47 -25
- package/test/contract.test.mjs +221 -86
- package/test/control.test.mjs +2 -2
- package/test/eval-seed.test.mjs +113 -0
- package/test/evolution-read.test.mjs +10 -10
- package/test/ha.test.mjs +55 -5
- package/test/layer-read.test.mjs +293 -0
- package/test/learning.test.mjs +80 -0
- package/test/palace.test.mjs +2 -0
- package/test/recall.test.mjs +67 -9
- package/test/state.test.mjs +57 -1
- package/test/store.test.mjs +49 -5
- package/test/view.test.mjs +3 -0
- package/view.js +85 -12
package/test/client.test.mjs
CHANGED
|
@@ -28,7 +28,7 @@ assert.equal(panel.name, 'shell.overlay');
|
|
|
28
28
|
assert.equal(panel.order, 30);
|
|
29
29
|
|
|
30
30
|
const EMPTY_CHILDREN = [];
|
|
31
|
-
const { metaOf, citationOf, citationsOfMeta, citationsOfTurn, dedupe, undoRefOf, graphOf, ruleGraphOf, processingStatusOf, currentBodyOf, historyDiffsOf, MemoryPanel, MemoryGraph, displayKeyOf, readDisplaySettings, writeDisplaySettings, graphViewOf, viewModeOf, filterRecords, projectionOf, failureStateOf, evidenceTextOf, evidenceMetaOf, MemoryPalace, palaceRoomsOf, palaceRoomPageOf, palacePageWindow, palaceToggleOf, palaceMotionOf, palaceRoomIdOf, TurnMemory, refMetaOf, explainKeyOf, explainModeOf, setExplainMode, agoLabel, checkupOf, titleCountsOf } = seen;
|
|
31
|
+
const { metaOf, citationOf, citationsOfMeta, citationsOfTurn, dedupe, undoRefOf, graphOf, ruleGraphOf, processingStatusOf, currentBodyOf, historyDiffsOf, MemoryPanel, MemoryGraph, displayKeyOf, readDisplaySettings, writeDisplaySettings, graphViewOf, viewModeOf, filterRecords, projectionOf, failureStateOf, evidenceTextOf, evidenceMetaOf, MemoryPalace, palaceRoomsOf, palaceRoomPageOf, palacePageWindow, palaceToggleOf, palaceMotionOf, palaceRoomIdOf, TurnMemory, refMetaOf, explainKeyOf, explainModeOf, setExplainMode, recallLineOf, agoLabel, checkupOf, titleCountsOf, rowKeyOf, rowKeepFlags } = seen;
|
|
32
32
|
|
|
33
33
|
// 图谱只按真实数据画:共享标签成枢纽,显式关联成边,位置由 id 决定。
|
|
34
34
|
const graph = graphOf([
|
|
@@ -96,23 +96,24 @@ assert.equal(metaOf(settled(null)), null);
|
|
|
96
96
|
assert.equal(metaOf(settled([{ kind: 'memory-read' }])), null);
|
|
97
97
|
|
|
98
98
|
// 保存只在真的改了时进引用;正文保存不冒充引用。
|
|
99
|
-
const save = citationOf({ kind: 'memory-save',
|
|
99
|
+
const save = citationOf({ kind: 'memory-save', title: 'A', scope: 'project', revision: 3, changed: false, mode: 'unchanged' }, 'memory-save');
|
|
100
100
|
assert.equal(save, null);
|
|
101
|
-
const changed = citationOf({ kind: 'memory-save',
|
|
101
|
+
const changed = citationOf({ kind: 'memory-save', title: 'A', scope: 'global', revision: 2, changed: true, mode: 'updated' }, 'memory-save');
|
|
102
102
|
assert.equal(changed.exposure, 'update');
|
|
103
103
|
assert.equal(changed.scope, 'global');
|
|
104
104
|
|
|
105
105
|
// 没有真改动、缺版本、缺工作目录的写入行不产生撤销入口。
|
|
106
|
-
assert.equal(undoRefOf({ kind: 'memory-save',
|
|
107
|
-
assert.equal(undoRefOf({ kind: 'memory-save',
|
|
108
|
-
assert.equal(undoRefOf({ kind: 'memory-save',
|
|
109
|
-
assert.equal(undoRefOf({ kind: 'memory-save',
|
|
106
|
+
assert.equal(undoRefOf({ kind: 'memory-save', title: 'A', revision: 3, changed: false }, '/tmp/p'), null);
|
|
107
|
+
assert.equal(undoRefOf({ kind: 'memory-save', title: 'A', revision: 3 }, '/tmp/p'), null);
|
|
108
|
+
assert.equal(undoRefOf({ kind: 'memory-save', title: 'A', revision: 3, changed: true }, ''), null);
|
|
109
|
+
assert.equal(undoRefOf({ kind: 'memory-save', revision: 2, changed: true }, '/tmp/p'), null);
|
|
110
|
+
assert.equal(undoRefOf({ kind: 'memory-save', title: 'A', revision: 2, changed: true }, '/tmp/p').revision, 2);
|
|
110
111
|
|
|
111
112
|
// 搜索的多条引用按 refs 展开;删除/归档状态原样保留。
|
|
112
113
|
const refs = citationsOfMeta({ kind: 'memory-search', refs: [
|
|
113
|
-
{
|
|
114
|
-
{
|
|
115
|
-
{
|
|
114
|
+
{ title: 'A', scope: 'project', revision: 1, status: 'ok' },
|
|
115
|
+
{ title: 'B', scope: 'global', revision: 4, status: 'archived' },
|
|
116
|
+
{ title: '', scope: 'global', revision: 1, status: 'ok' },
|
|
116
117
|
] });
|
|
117
118
|
assert.equal(refs.length, 2);
|
|
118
119
|
assert.equal(refs[1].status, 'archived');
|
|
@@ -121,17 +122,17 @@ assert.equal(refs[0].exposure, 'reference');
|
|
|
121
122
|
// 一轮里 PTC 子结果也算;同 id 同用途只留一条,位置不变、内容取最新。
|
|
122
123
|
const nodes = [
|
|
123
124
|
{ root: settled({ kind: 'memory-search', refs: [
|
|
124
|
-
{
|
|
125
|
+
{ title: 'A', scope: 'project', revision: 1, status: 'ok' },
|
|
125
126
|
] }) },
|
|
126
|
-
{ root: settled({ kind: 'memory-read',
|
|
127
|
-
{ root: settled({ kind: 'memory-read',
|
|
127
|
+
{ root: settled({ kind: 'memory-read', title: 'A', scope: 'project', revision: 2, status: 'ok' }, { subCalls: [settled({ kind: 'memory-read', title: 'A', scope: 'project', revision: 2, status: 'ok' })] }) },
|
|
128
|
+
{ root: settled({ kind: 'memory-read', title: 'B', scope: 'global', revision: 1, status: 'ok' }) },
|
|
128
129
|
];
|
|
129
130
|
const turn = dedupe(citationsOfTurn(nodes));
|
|
130
131
|
assert.equal(turn.length, 2);
|
|
131
|
-
assert.equal(turn[0].
|
|
132
|
+
assert.equal(turn[0].title, 'A');
|
|
132
133
|
assert.equal(turn[0].revision, 2);
|
|
133
|
-
assert.equal(turn[
|
|
134
|
-
assert.equal(turn[
|
|
134
|
+
assert.equal(turn[1].title, 'B');
|
|
135
|
+
assert.equal('id' in turn[0], false);
|
|
135
136
|
|
|
136
137
|
// 旧行没有元数据:什么也不产出,绝不从文案猜 id。
|
|
137
138
|
assert.deepEqual(citationsOfTurn([{ root: null }, { root: { kind: 'tool-result', content: [{ type: 'text', text: 'memory · saved "A" mem_aaaaaaaa' }] } }]), []);
|
|
@@ -280,16 +281,17 @@ assert.equal(palacePicked, 'mem_a');
|
|
|
280
281
|
const palaceEmpty = MemoryPalace({ records: [], selectedId: '', onPick: () => {}, emptyText: '这个项目还没有记忆' });
|
|
281
282
|
assert.equal(expandNodes(palaceEmpty).some((node) => node.children.includes('这个项目还没有记忆')), true);
|
|
282
283
|
|
|
283
|
-
//
|
|
284
|
-
const typedSearch = citationOf({
|
|
284
|
+
// 引用行只标层与来源:类型留在数据里给检索用,不上会话界面。
|
|
285
|
+
const typedSearch = citationOf({ title: 'A', scope: 'global', revision: 1, status: 'ok', kind: 'preference' }, 'memory-search');
|
|
285
286
|
assert.equal(typedSearch.entryKind, 'preference');
|
|
286
|
-
assert.equal(refMetaOf(typedSearch), '
|
|
287
|
-
assert.equal(citationOf({ kind: 'memory-read',
|
|
288
|
-
assert.equal(refMetaOf({ scope: 'project', origin: 'user_explicit' }), '项目
|
|
289
|
-
|
|
290
|
-
|
|
287
|
+
assert.equal(refMetaOf(typedSearch), '[全局]');
|
|
288
|
+
assert.equal(citationOf({ kind: 'memory-read', title: 'P', recordKind: 'procedure', scope: 'project', revision: 2 }, 'memory-read').entryKind, 'procedure');
|
|
289
|
+
assert.equal(refMetaOf({ scope: 'project', origin: 'user_explicit' }), '[项目]');
|
|
290
|
+
assert.equal(refMetaOf({ scope: 'global', origin: 'project_evolution' }), '[全局][自进化]');
|
|
291
|
+
/** 更新距今照旧,只是不再拼类型与「你记的」。 */
|
|
292
|
+
const aged = citationOf({ kind: 'preference', title: 'C', scope: 'global', revision: 1, updated: new Date(Date.now() - 3 * 86_400_000).toISOString() }, 'memory-search');
|
|
291
293
|
assert.equal(aged.entryKind, 'preference');
|
|
292
|
-
assert.equal(refMetaOf(aged), '
|
|
294
|
+
assert.equal(refMetaOf(aged), '[全局] · 3 天前更新');
|
|
293
295
|
assert.equal(agoLabel(''), '');
|
|
294
296
|
assert.equal(agoLabel(new Date(Date.now() - 40 * 86_400_000).toISOString()), '');
|
|
295
297
|
|
|
@@ -320,5 +322,25 @@ assert.deepEqual(filterRecords(checkupRows, '', { kind: 'unread' }).map((row) =>
|
|
|
320
322
|
assert.deepEqual(filterRecords(checkupRows, '', { kind: 'noWhen' }).map((row) => row.id), ['mem_c0000001']);
|
|
321
323
|
assert.deepEqual([...titleCountsOf(checkupRows).values()], [2, 1]);
|
|
322
324
|
assert.equal(checkupOf([], [], false).globalEntries, null);
|
|
323
|
-
|
|
325
|
+
// 两条一模一样的拦截结果在同一轮里只展示一行:拦截结果没有 id,只能按曝光类型 + 文案 + 正文认。
|
|
326
|
+
const blockedBlock = (text) => ({ kind: 'tool-result', callId: 'call-a', content: [{ type: 'text', text }], subCalls: [] });
|
|
327
|
+
const blockedText = 'memory · 这条记忆的适用条件还没确认,先说明当前任务再读';
|
|
328
|
+
assert.equal(blockedText.includes('mem_'), false);
|
|
329
|
+
const blockedKeys = [rowKeyOf('memory_read', blockedBlock(blockedText)), rowKeyOf('memory_read', blockedBlock(blockedText))];
|
|
330
|
+
assert.equal(blockedKeys[0].length > 0, true);
|
|
331
|
+
assert.deepEqual(rowKeepFlags(blockedKeys), [true, false]);
|
|
332
|
+
assert.equal(blockedKeys.filter((_key, at) => rowKeepFlags(blockedKeys)[at]).length, 1);
|
|
333
|
+
assert.deepEqual(rowKeepFlags([rowKeyOf('memory_search', blockedBlock(blockedText)), rowKeyOf('memory_read', blockedBlock(blockedText))]), [true, true]);
|
|
334
|
+
assert.deepEqual(rowKeepFlags([rowKeyOf('memory_read', blockedBlock('memory · stopped'))]), [true]);
|
|
335
|
+
// 面板要能回答「为什么这次没提醒我」:只给结论和条数,不露原因码。
|
|
336
|
+
assert.equal(recallLineOf(null), '');
|
|
337
|
+
assert.equal(recallLineOf({ reason: 'hit', cards: 1, matched: 1 }), '上次自动提醒 1 条');
|
|
338
|
+
assert.equal(recallLineOf({ reason: 'budget', cards: 0, matched: 2 }), '上次没提醒,2 条相关记忆,本轮自动提醒已用满');
|
|
339
|
+
assert.equal(recallLineOf({ reason: 'needs_context', cards: 0, matched: 1 }), '上次没提醒,1 条相关记忆,适用条件未确认');
|
|
340
|
+
assert.equal(recallLineOf({ reason: 'no_overlap', cards: 0, matched: 0 }), '上次没提醒,没有匹配的记忆');
|
|
341
|
+
assert.equal(recallLineOf({ reason: 'memory_off', cards: 0, matched: 0 }), '上次没提醒,记忆已关闭');
|
|
342
|
+
assert.equal(recallLineOf({ reason: 'tools_only', cards: 0, matched: 0 }), '上次没提醒,只在你问时检索');
|
|
343
|
+
assert.equal(recallLineOf({ reason: 'made_up', cards: 0, matched: 0 }), '');
|
|
344
|
+
assert.doesNotMatch(recallLineOf({ reason: 'needs_context', cards: 0, matched: 1 }), /needs_context|reasonCode/);
|
|
345
|
+
console.log('client.test.mjs: 22 passed + palace');
|
|
324
346
|
|