dsh-memu-memory 1.1.3 → 1.2.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/AGENTS.md +1 -1
- package/README.md +31 -2
- package/README.zh.md +30 -2
- package/docs/active-memory-ab.md +385 -0
- package/docs/binding-lifecycle.md +99 -0
- package/docs/contributing.md +1 -1
- package/docs/emotion-model-spec.md +281 -0
- package/docs/host-api.md +2 -2
- package/docs/memory-semantics.md +12 -10
- package/docs/recall-benchmark.md +238 -0
- package/docs/troubleshooting.md +395 -395
- package/lib/active-memory.js +165 -0
- package/lib/activity-log.js +1 -1
- package/lib/binding-diagnostics.js +8 -3
- package/lib/client.js +33 -11
- package/lib/consolidation-ledger.js +347 -0
- package/lib/consolidation-receipt.js +284 -0
- package/lib/consolidation-snapshot.js +274 -0
- package/lib/consolidation-worker.js +115 -0
- package/lib/cycle.js +40 -6
- package/lib/inject.js +104 -76
- package/lib/local-embedding-manager.js +24 -6
- package/lib/memory.js +221 -19
- package/lib/mood.js +268 -39
- package/lib/preset-scope.js +1 -1
- package/lib/private.js +335 -40
- package/lib/prompts/private-consolidation.coding.md +1 -0
- package/lib/prompts/private-consolidation.md +1 -0
- package/lib/prompts/private-consolidation.mixed.md +1 -0
- package/lib/prompts/private-consolidation.rp.md +1 -0
- package/lib/prompts.js +4 -4
- package/lib/remote-summary.js +51 -25
- package/lib/rpc.js +9 -1
- package/lib/state.js +29 -12
- package/lib/tools.js +49 -2
- package/lib/vector-profile.js +27 -0
- package/package.json +2 -1
- package/scripts/acceptance-local.mjs +2 -1
- package/scripts/active-memory-ab-live.mjs +655 -0
- package/scripts/active-memory-ab.mjs +1302 -0
- package/scripts/chain-matrix.mjs +11 -1
- package/scripts/check-all.mjs +10 -1
- package/tests/activation.test.mjs +89 -0
- package/tests/active-memory-ab.test.mjs +745 -0
- package/tests/active-memory.test.mjs +129 -0
- package/tests/activity-log.test.mjs +126 -0
- package/tests/activity-wiring.test.mjs +103 -0
- package/tests/appendix-b.test.mjs +212 -0
- package/tests/appendix-b2.test.mjs +166 -0
- package/tests/audit-regression.test.mjs +272 -0
- package/tests/audit-safety.test.mjs +227 -0
- package/tests/backend-compensation.test.mjs +272 -0
- package/tests/backup.test.mjs +793 -0
- package/tests/binding-diagnostics.test.mjs +720 -0
- package/tests/browser.test.mjs +366 -0
- package/tests/client-render.test.mjs +892 -0
- package/tests/coalesce.test.mjs +113 -0
- package/tests/config.test.mjs +159 -0
- package/tests/consolidation-credential.test.mjs +320 -0
- package/tests/consolidation-fork.test.mjs +357 -0
- package/tests/consolidation-ledger.test.mjs +298 -0
- package/tests/consolidation-snapshot.test.mjs +321 -0
- package/tests/consolidation-value.test.mjs +89 -0
- package/tests/context-scope.test.mjs +40 -0
- package/tests/cue.test.mjs +44 -0
- package/tests/curator-probe.test.mjs +433 -0
- package/tests/curator.test.mjs +150 -0
- package/tests/cycle.test.mjs +411 -0
- package/tests/disclosure.test.mjs +231 -0
- package/tests/doc-drift.test.mjs +222 -0
- package/tests/embedding-catalog.test.mjs +266 -0
- package/tests/embedding-download.test.mjs +391 -0
- package/tests/embedding-runtime.test.mjs +389 -0
- package/tests/emotion-chain.test.mjs +84 -0
- package/tests/emotion-contract.test.mjs +445 -0
- package/tests/engine.test.mjs +35 -0
- package/tests/fixtures/active-memory-ab/README.md +56 -0
- package/tests/fixtures/active-memory-ab/cases/01-clean-dense-turn.json +351 -0
- package/tests/fixtures/active-memory-ab/cases/02-clean-thin-turn.json +122 -0
- package/tests/fixtures/active-memory-ab/cases/03-clean-starved-small.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/04-clean-large-thin.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/05-clean-half-step.json +166 -0
- package/tests/fixtures/active-memory-ab/cases/06-clean-duplicate-reread.json +197 -0
- package/tests/fixtures/active-memory-ab/cases/07-clean-recent-recall.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/08-global-relevant.json +111 -0
- package/tests/fixtures/active-memory-ab/cases/09-global-irrelevant-conflict.json +158 -0
- package/tests/fixtures/active-memory-ab/cases/10-no-human-turn.json +97 -0
- package/tests/fixtures/active-memory-ab/cases/11-clean-scale-100.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/12-clean-scale-1000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/13-clean-scale-5000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/14-clean-scale-20000.json +137 -0
- package/tests/fixtures/active-memory-ab/lead-ai-reviewed-reference.json +191 -0
- package/tests/fixtures/active-memory-ab/manifest.json +199 -0
- package/tests/fixtures/recall-bench/01-paraphrase.json +184 -0
- package/tests/fixtures/recall-bench/02-exact.json +153 -0
- package/tests/fixtures/recall-bench/03-negation.json +173 -0
- package/tests/fixtures/recall-bench/04-no-answer.json +162 -0
- package/tests/fixtures/recall-bench/05-conflict.json +194 -0
- package/tests/fixtures/recall-bench/06-boundary.json +273 -0
- package/tests/fixtures/recall-bench/07-secret.json +191 -0
- package/tests/fixtures/recall-bench/08-coding.json +164 -0
- package/tests/fixtures/recall-bench-gold-candidates/01-paraphrase.json +193 -0
- package/tests/fixtures/recall-bench-gold-candidates/02-exact.json +197 -0
- package/tests/fixtures/recall-bench-gold-candidates/03-negation.json +244 -0
- package/tests/fixtures/recall-bench-gold-candidates/04-no-answer.json +189 -0
- package/tests/fixtures/recall-bench-gold-candidates/05-conflict.json +245 -0
- package/tests/fixtures/recall-bench-gold-candidates/06-boundary.json +279 -0
- package/tests/fixtures/recall-bench-gold-candidates/07-secret.json +224 -0
- package/tests/fixtures/recall-bench-gold-candidates/08-coding.json +218 -0
- package/tests/fixtures/repetition-eval/01-zh-rp.json +93 -0
- package/tests/fixtures/repetition-eval/02-en.json +97 -0
- package/tests/fixtures/repetition-eval/03-code.json +91 -0
- package/tests/fixtures/repetition-eval/04-names.json +116 -0
- package/tests/fixtures/repetition-eval/05-user-quote.json +96 -0
- package/tests/fixtures/repetition-eval/06-agreement.json +86 -0
- package/tests/graph-view.test.mjs +187 -0
- package/tests/graph.test.mjs +77 -0
- package/tests/hook-order.test.mjs +72 -0
- package/tests/humanlike.test.mjs +232 -0
- package/tests/hybrid-recall.test.mjs +92 -0
- package/tests/inbound.test.mjs +393 -0
- package/tests/inject-guide.test.mjs +364 -0
- package/tests/inject.test.mjs +222 -0
- package/tests/injection-budget-settings.test.mjs +35 -0
- package/tests/injection-budget.test.mjs +64 -0
- package/tests/injection-chain.test.mjs +191 -0
- package/tests/loader-register.mjs +3 -0
- package/tests/loader.mjs +12 -0
- package/tests/local-embedding-entry.test.mjs +95 -0
- package/tests/local-embedding-manager.test.mjs +476 -0
- package/tests/local-embedding-protocol.test.mjs +95 -0
- package/tests/local-embedding-worker.test.mjs +346 -0
- package/tests/managed-memory.test.mjs +536 -0
- package/tests/managed-runtime.test.mjs +40 -0
- package/tests/media.test.mjs +132 -0
- package/tests/migration-payload.test.mjs +42 -0
- package/tests/mood.test.mjs +109 -0
- package/tests/multiprocess.test.mjs +29 -0
- package/tests/new-session-gate.test.mjs +361 -0
- package/tests/package-shipping.test.mjs +84 -0
- package/tests/preset-scope.test.mjs +212 -0
- package/tests/prompts.test.mjs +250 -0
- package/tests/react-snapshot.test.mjs +23 -0
- package/tests/recall-bench.test.mjs +306 -0
- package/tests/remote.test.mjs +140 -0
- package/tests/rename.test.mjs +30 -0
- package/tests/repetition-detector-snapshot.test.mjs +231 -0
- package/tests/repetition-eval-live.test.mjs +177 -0
- package/tests/repetition-eval.test.mjs +373 -0
- package/tests/salient-date.test.mjs +142 -0
- package/tests/settings-beat.test.mjs +221 -0
- package/tests/short-term.test.mjs +166 -0
- package/tests/sidebar-beat.test.mjs +208 -0
- package/tests/sidebar-refresh.test.mjs +123 -0
- package/tests/sidebar.test.mjs +70 -0
- package/tests/snippet.test.mjs +47 -0
- package/tests/source-kind.test.mjs +52 -0
- package/tests/state.test.mjs +150 -0
- package/tests/stats.test.mjs +112 -0
- package/tests/storage.test.mjs +125 -0
- package/tests/stubs/dsh-llm.js +5 -0
- package/tests/stubs/dsh-session.js +7 -0
- package/tests/stubs/dsh-tools.js +101 -0
- package/tests/tool-schema.test.mjs +73 -0
- package/tests/tools.test.mjs +184 -0
- package/tests/ui-defaults.test.mjs +57 -0
- package/tests/update-fields.test.mjs +138 -0
- package/tests/vector-migration.test.mjs +733 -0
- package/tests/vector-profile.test.mjs +425 -0
- package/tests/visibility-migration.test.mjs +152 -0
- package/tests/webui-auth.test.mjs +454 -0
- package/tests/webui.test.mjs +164 -0
- package/tests/windows-env.test.mjs +89 -0
package/scripts/chain-matrix.mjs
CHANGED
|
@@ -262,9 +262,19 @@ function remoteVectorRetrieve(libraryId) {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
// ------------------------------------------------------------ 宿主 ctx(fork 宿主)
|
|
265
|
+
// 加权唤醒要求真实的检查理由:多回合、有结论、有去重后的工具工作。
|
|
266
|
+
// 只有一条消息 + 一个工具调用的旧 fixture 现在会(正确地)落进 low-score。
|
|
265
267
|
const TRANSCRIPT = [
|
|
266
268
|
{ seq: 0, type: 'user/message', data: { source: { kind: 'user' }, content: [{ type: 'text', text: '帮我把这段对话里值得记的东西整理成记忆,尤其是海边的那个傍晚。' }] } },
|
|
267
|
-
{ seq: 1, type: '
|
|
269
|
+
{ seq: 1, type: 'user/message', data: { source: { kind: 'user' }, content: [{ type: 'text', text: '另外把回滚步骤和失败原因也写清楚。' }] } },
|
|
270
|
+
{ seq: 2, type: 'user/message', data: { source: { kind: 'user' }, content: [{ type: 'text', text: '最后给我一版可以直接照做的清单。' }] } },
|
|
271
|
+
{ seq: 3, type: 'assistant/message', data: { message: { content: [
|
|
272
|
+
{ type: 'text', text: '海边的傍晚那一段是这次对话里最值得留下的内容。'.repeat(120) },
|
|
273
|
+
{ type: 'tool-call', name: 'read', arguments: '{}' },
|
|
274
|
+
] } } },
|
|
275
|
+
{ seq: 4, type: 'tool/result', data: { message: { isError: false, content: [{ type: 'text', text: '回滚步骤与失败明细'.repeat(160) }] } } },
|
|
276
|
+
{ seq: 5, type: 'tool/result', data: { message: { isError: false, content: [{ type: 'text', text: '迁移账本与索引差异'.repeat(160) }] } } },
|
|
277
|
+
{ seq: 6, type: 'tool/result', data: { message: { isError: false, content: [{ type: 'text', text: '验收清单与测试输出'.repeat(160) }] } } },
|
|
268
278
|
]
|
|
269
279
|
|
|
270
280
|
function makeHost({ sessionId, cwd, onFork }) {
|
package/scripts/check-all.mjs
CHANGED
|
@@ -18,7 +18,16 @@ const check = (label, command, args) => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
for (const dir of ['lib', 'scripts', 'tests']) {
|
|
21
|
-
|
|
21
|
+
const abs = path.join(root, dir)
|
|
22
|
+
// 一个目录可以合法缺席:老版本 npm 包不发布 tests/,开发检出里才有。
|
|
23
|
+
// 以前这里直接 readdirSync,产物内 `npm run check` 会 ENOENT 崩在第一步,
|
|
24
|
+
// 而 `npm test` 因为通配符匹配不到文件反而报 0 条测试、exit 0(假绿)。
|
|
25
|
+
// 缺席就 skip 并说明,不当作失败,也不让脚本崩。
|
|
26
|
+
if (!fs.existsSync(abs)) {
|
|
27
|
+
console.log(`skip ${dir}/: directory not present in this install`)
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
for (const file of fs.readdirSync(abs, { recursive: true })) {
|
|
22
31
|
if (!/\.(js|mjs)$/.test(file)) continue
|
|
23
32
|
check(`${dir}/${file}`, process.execPath, ['--check', path.join(dir, file)])
|
|
24
33
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// The activation line is the only place that answers "is memory actually on" without
|
|
2
|
+
// a debugger, and the silent-recall bug (P0-1) would have been visible from it. It was
|
|
3
|
+
// written by hand into a doc as an acceptance step nobody could run, because the host
|
|
4
|
+
// keeps no log on disk. So the line is asserted here instead: apply() runs against a
|
|
5
|
+
// fake context and the message has to match the live settings, not a stale copy.
|
|
6
|
+
import test from 'node:test'
|
|
7
|
+
import assert from 'node:assert/strict'
|
|
8
|
+
import fs from 'node:fs'
|
|
9
|
+
import os from 'node:os'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
|
|
12
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'dsh-memu-memory-activation-'))
|
|
13
|
+
process.env.DSH_MEMU_HOME = home
|
|
14
|
+
|
|
15
|
+
const plugin = await import('../lib/index.js')
|
|
16
|
+
const { ENGINE_VERSION } = await import('../lib/engine.js')
|
|
17
|
+
const { getSettings, getMemoryBackend } = await import('../lib/state.js')
|
|
18
|
+
|
|
19
|
+
test.after(() => {
|
|
20
|
+
try { fs.rmSync(home, { recursive: true, force: true }) } catch {}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
function fakeCtx() {
|
|
24
|
+
const info = []
|
|
25
|
+
const warn = []
|
|
26
|
+
const tools = []
|
|
27
|
+
const disposers = []
|
|
28
|
+
const handlers = []
|
|
29
|
+
const scope = {
|
|
30
|
+
effect(fn, _label) { const dispose = fn(); if (typeof dispose === 'function') disposers.push(dispose) },
|
|
31
|
+
tools: { register(tool) { tools.push(tool); return () => {} } },
|
|
32
|
+
webServer: { register() { return () => {} } },
|
|
33
|
+
connection: { requestRejection: () => undefined },
|
|
34
|
+
interval() { return 1 },
|
|
35
|
+
// cordis event API: everything this plugin hangs off the agent loop arrives here.
|
|
36
|
+
on(event, handler) { handlers.push({ event, handler }); return () => {} },
|
|
37
|
+
}
|
|
38
|
+
const ctx = {
|
|
39
|
+
...scope,
|
|
40
|
+
logger: { info: (m) => info.push(m), warn: (m) => warn.push(m) },
|
|
41
|
+
inject(_deps, callback) { callback(scope) },
|
|
42
|
+
}
|
|
43
|
+
return { ctx, info, warn, tools, disposers, handlers }
|
|
44
|
+
}
|
|
45
|
+
const LOADED = /^dsh-memu-memory: loaded \(engine (\S+)\) backend=(\S+) autoInject=(\S+) anchorTokens=(\d+) turnTokens=(\d+) mustRememberCap=(\d+) unpinBudget=(\d+)$/
|
|
46
|
+
|
|
47
|
+
test('the activation line reports the live configuration', () => {
|
|
48
|
+
const { ctx, info, warn } = fakeCtx()
|
|
49
|
+
plugin.apply(ctx)
|
|
50
|
+
const line = info.find((message) => message.startsWith('dsh-memu-memory: loaded'))
|
|
51
|
+
assert.ok(line, 'apply() must log the activation line')
|
|
52
|
+
const match = LOADED.exec(line)
|
|
53
|
+
assert.ok(match, 'the line must keep the shape the docs promise: ' + line)
|
|
54
|
+
|
|
55
|
+
const settings = getSettings()
|
|
56
|
+
assert.equal(match[1], ENGINE_VERSION, 'the engine version must be the one the code expects')
|
|
57
|
+
assert.equal(match[2], getMemoryBackend(), 'the backend must be the live one')
|
|
58
|
+
assert.equal(match[3], settings.autoInject)
|
|
59
|
+
assert.equal(Number(match[4]), settings.anchorTokens, 'the budget is config, not a hard-coded number')
|
|
60
|
+
assert.equal(Number(match[5]), settings.turnTokens)
|
|
61
|
+
assert.equal(Number(match[6]), settings.mustRememberCap)
|
|
62
|
+
assert.equal(Number(match[7]), settings.unpinBudgetPerSession)
|
|
63
|
+
assert.equal(warn.filter((m) => m.includes('startup summary failed')).length, 0, 'the summary must not fall back to a warning')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('a changed budget shows up in the next activation', async () => {
|
|
67
|
+
const state = await import('../lib/state.js')
|
|
68
|
+
state.updateSettings({ anchorTokens: 512, turnTokens: 320, mustRememberCap: 7 })
|
|
69
|
+
try {
|
|
70
|
+
const { ctx, info } = fakeCtx()
|
|
71
|
+
plugin.apply(ctx)
|
|
72
|
+
const match = LOADED.exec(info.find((message) => message.startsWith('dsh-memu-memory: loaded')))
|
|
73
|
+
assert.equal(Number(match[4]), 512, 'the line reads the setting, so a tuning change is visible in the log')
|
|
74
|
+
assert.equal(Number(match[5]), 320)
|
|
75
|
+
assert.equal(Number(match[6]), 7)
|
|
76
|
+
} finally {
|
|
77
|
+
state.updateSettings({ anchorTokens: 800, turnTokens: 800, mustRememberCap: 12 })
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('a second apply() on the same context warns instead of registering twice', () => {
|
|
82
|
+
const { ctx, tools, warn } = fakeCtx()
|
|
83
|
+
plugin.apply(ctx)
|
|
84
|
+
const first = tools.length
|
|
85
|
+
const infoAfterFirst = warn.length
|
|
86
|
+
plugin.apply(ctx)
|
|
87
|
+
assert.equal(tools.length, first, 'tools must not be registered twice')
|
|
88
|
+
assert.ok(warn.slice(infoAfterFirst).some((m) => /already ran/.test(m)), 'the guard must say so')
|
|
89
|
+
})
|