recallnest 2.5.4 → 2.6.1
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/CHANGELOG.md +37 -0
- package/README.md +34 -9
- package/README_CN.md +37 -12
- package/package.json +6 -5
- package/src/__tests__/access-tracker-novelty.test.ts +66 -0
- package/src/__tests__/api-server-security.test.ts +102 -0
- package/src/__tests__/belief-history.test.ts +220 -0
- package/src/__tests__/capture-engine.test.ts +93 -3
- package/src/__tests__/category-min-scores.test.ts +83 -0
- package/src/__tests__/cluster-consolidation.test.ts +167 -4
- package/src/__tests__/conflict-store.test.ts +46 -2
- package/src/__tests__/consolidation-engine.test.ts +97 -0
- package/src/__tests__/contracts.test.ts +46 -0
- package/src/__tests__/decay-exemption.test.ts +45 -0
- package/src/__tests__/dream-pipeline.test.ts +464 -5
- package/src/__tests__/freshness.test.ts +186 -0
- package/src/__tests__/hotness-blend.test.ts +207 -0
- package/src/__tests__/llm-client-pivot.test.ts +628 -0
- package/src/__tests__/maintenance-locks.test.ts +15 -0
- package/src/__tests__/memory-boundaries.test.ts +32 -0
- package/src/__tests__/noise-prototype-bank.test.ts +280 -0
- package/src/__tests__/pii-redact.test.ts +19 -0
- package/src/__tests__/pivot-apply.test.ts +373 -0
- package/src/__tests__/pivot-distill-supervisor.test.ts +457 -0
- package/src/__tests__/pivot-distill.test.ts +1178 -0
- package/src/__tests__/preference-matcher.test.ts +54 -2
- package/src/__tests__/pull-from-macbook-sync-only.test.ts +679 -0
- package/src/__tests__/recall-gate.test.ts +266 -0
- package/src/__tests__/resolve-db-path.test.ts +130 -0
- package/src/__tests__/resolve-tier.test.ts +64 -0
- package/src/__tests__/retrieval-eval.test.ts +163 -0
- package/src/__tests__/retriever-lazy-init-dispatch.test.ts +123 -0
- package/src/__tests__/skill-promotion.test.ts +53 -0
- package/src/__tests__/stable-context-length-contract.test.ts +62 -0
- package/src/__tests__/store-read-consistency.test.ts +122 -0
- package/src/__tests__/store-schema-migration.test.ts +87 -0
- package/src/__tests__/store-upsert.test.ts +17 -0
- package/src/__tests__/term-registry-terminal-roster.test.ts +127 -0
- package/src/__tests__/ui-server-security.test.ts +93 -0
- package/src/access-tracker.ts +53 -3
- package/src/adaptive-retrieval.ts +11 -0
- package/src/api-server.ts +9 -2
- package/src/auto-recall.ts +61 -1
- package/src/belief-history.ts +164 -0
- package/src/capture-engine.ts +88 -11
- package/src/cli.ts +109 -14
- package/src/conflict-engine.ts +24 -3
- package/src/consolidation-engine.ts +146 -12
- package/src/context-composer-stable-selection.ts +7 -1
- package/src/data-checkup.ts +1 -1
- package/src/decay-engine.ts +59 -7
- package/src/doctor.ts +4 -2
- package/src/dream-pipeline.ts +359 -11
- package/src/env-config.ts +41 -0
- package/src/eval.ts +154 -11
- package/src/freshness.ts +192 -0
- package/src/http-request-policy.ts +148 -0
- package/src/ingest.ts +277 -2
- package/src/kg-extractor.ts +7 -1
- package/src/llm-client.ts +106 -11
- package/src/mcp-server.ts +2 -1
- package/src/mcp-tools-advanced.ts +13 -0
- package/src/mcp-tools-core.ts +5 -1
- package/src/memory-boundaries.ts +23 -2
- package/src/memory-health-rebalance.ts +4 -0
- package/src/memory-output.ts +16 -2
- package/src/memory-store-port.ts +3 -0
- package/src/noise-prototype-bank.ts +408 -0
- package/src/pii-detector.ts +52 -2
- package/src/pivot-apply.ts +399 -0
- package/src/preference-matcher.ts +37 -3
- package/src/recall-gate.ts +305 -0
- package/src/retrieval-profiles.ts +46 -4
- package/src/retriever.ts +95 -18
- package/src/retroactive-boost.ts +6 -2
- package/src/runtime-config.ts +70 -5
- package/src/skill-promotion.ts +58 -2
- package/src/store.ts +54 -19
- package/src/term-registry.ts +35 -0
- package/src/ui-server.ts +7 -0
- package/src/version.ts +19 -0
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "../preference-matcher.js";
|
|
19
19
|
import type { MemoryEntry, MemorySearchResult } from "../store.js";
|
|
20
20
|
import type { LLMClient, DedupDecision } from "../llm-client.js";
|
|
21
|
+
import { parseEvolution } from "../memory-evolution.js";
|
|
21
22
|
|
|
22
23
|
// ---------------------------------------------------------------------------
|
|
23
24
|
// Helpers
|
|
@@ -37,7 +38,8 @@ function makeEntry(id: string, text: string, category = "preferences"): MemoryEn
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
function createMockStore(searchResults: MemorySearchResult[] = []) {
|
|
40
|
-
const updates: Array<{ id: string; text?: string }> = [];
|
|
41
|
+
const updates: Array<{ id: string; text?: string; metadata?: string }> = [];
|
|
42
|
+
const archived: MemoryEntry[] = [];
|
|
41
43
|
const data = new Map<string, MemoryEntry>();
|
|
42
44
|
for (const r of searchResults) {
|
|
43
45
|
data.set(r.entry.id, { ...r.entry });
|
|
@@ -45,6 +47,7 @@ function createMockStore(searchResults: MemorySearchResult[] = []) {
|
|
|
45
47
|
|
|
46
48
|
return {
|
|
47
49
|
updates,
|
|
50
|
+
archived,
|
|
48
51
|
data,
|
|
49
52
|
async vectorSearch(
|
|
50
53
|
_vector: number[],
|
|
@@ -54,18 +57,42 @@ function createMockStore(searchResults: MemorySearchResult[] = []) {
|
|
|
54
57
|
) {
|
|
55
58
|
return searchResults;
|
|
56
59
|
},
|
|
60
|
+
async getById(id: string) {
|
|
61
|
+
return data.get(id) ?? null;
|
|
62
|
+
},
|
|
63
|
+
// Belief-history rows land here rather than in `data` — merging must archive the
|
|
64
|
+
// version it replaces, so tests need to see what was written.
|
|
65
|
+
async upsert(entry: MemoryEntry) {
|
|
66
|
+
archived.push(entry);
|
|
67
|
+
return entry;
|
|
68
|
+
},
|
|
69
|
+
async store(entry: MemoryEntry) {
|
|
70
|
+
archived.push(entry);
|
|
71
|
+
return entry;
|
|
72
|
+
},
|
|
57
73
|
async update(id: string, upd: { text?: string; metadata?: string }, _scope?: string[]) {
|
|
58
74
|
const entry = data.get(id);
|
|
59
75
|
if (!entry) return null;
|
|
60
76
|
if (upd.text) {
|
|
61
77
|
entry.text = upd.text;
|
|
62
|
-
updates.push({ id, text: upd.text });
|
|
63
78
|
}
|
|
79
|
+
if (upd.metadata) {
|
|
80
|
+
entry.metadata = upd.metadata;
|
|
81
|
+
}
|
|
82
|
+
updates.push({ id, text: upd.text, metadata: upd.metadata });
|
|
64
83
|
return entry;
|
|
65
84
|
},
|
|
66
85
|
};
|
|
67
86
|
}
|
|
68
87
|
|
|
88
|
+
const mockDeps = {
|
|
89
|
+
embedder: {
|
|
90
|
+
async embedPassage(text: string) {
|
|
91
|
+
return [text.length, 1, 0];
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
69
96
|
function createMockLLM(dedupResult: DedupDecision, synthResult: string | null = "merged preference text"): LLMClient {
|
|
70
97
|
return {
|
|
71
98
|
async dedupDecision(_newText: string, _existingText: string) {
|
|
@@ -93,6 +120,22 @@ describe("matchPreference", () => {
|
|
|
93
120
|
expect(result.reason).toBe("no-similar-preferences");
|
|
94
121
|
});
|
|
95
122
|
|
|
123
|
+
it("ignores superseded belief-history rows as match candidates", async () => {
|
|
124
|
+
// store.vectorSearch() filters by scope only, so archived versions of a preference
|
|
125
|
+
// surface here alongside live ones. Matching against one would drop the incoming
|
|
126
|
+
// preference as a duplicate of a belief that is no longer held.
|
|
127
|
+
const archivedRow = makeEntry("p-old", "I prefer dark mode");
|
|
128
|
+
archivedRow.metadata = JSON.stringify({
|
|
129
|
+
evolution: { status: "superseded", validUntil: Date.now(), supersededBy: "p-live" },
|
|
130
|
+
});
|
|
131
|
+
const store = createMockStore([{ entry: archivedRow, score: 0.99 }]);
|
|
132
|
+
|
|
133
|
+
const result = await matchPreference("I prefer dark mode", vector, scope, store as any, null);
|
|
134
|
+
|
|
135
|
+
expect(result.action).toBe("create");
|
|
136
|
+
expect(result.reason).toBe("no-similar-preferences");
|
|
137
|
+
});
|
|
138
|
+
|
|
96
139
|
it("returns create when matches are non-preference category", async () => {
|
|
97
140
|
const store = createMockStore([
|
|
98
141
|
{ entry: makeEntry("e1", "some entity", "entities"), score: 0.85 },
|
|
@@ -190,6 +233,7 @@ describe("applyPreferenceMatch", () => {
|
|
|
190
233
|
{ action: "skip", reason: "duplicate" },
|
|
191
234
|
store as any,
|
|
192
235
|
"project:test",
|
|
236
|
+
mockDeps,
|
|
193
237
|
);
|
|
194
238
|
|
|
195
239
|
expect(result.handled).toBe(true);
|
|
@@ -209,12 +253,19 @@ describe("applyPreferenceMatch", () => {
|
|
|
209
253
|
},
|
|
210
254
|
store as any,
|
|
211
255
|
"project:test",
|
|
256
|
+
mockDeps,
|
|
212
257
|
);
|
|
213
258
|
|
|
214
259
|
expect(result.handled).toBe(true);
|
|
215
260
|
expect(result.entry).toBeDefined();
|
|
216
261
|
expect(store.updates.length).toBe(1);
|
|
217
262
|
expect(store.updates[0].text).toBe("merged preference text");
|
|
263
|
+
|
|
264
|
+
// Merging replaces the target's wording — the pre-merge version must survive.
|
|
265
|
+
expect(store.archived).toHaveLength(1);
|
|
266
|
+
expect(store.archived[0].text).toBe("old preference text");
|
|
267
|
+
expect(parseEvolution(store.archived[0].metadata).status).toBe("superseded");
|
|
268
|
+
expect(parseEvolution(store.updates[0].metadata).supersedes).toBe(store.archived[0].id);
|
|
218
269
|
});
|
|
219
270
|
|
|
220
271
|
it("returns not handled for create action", async () => {
|
|
@@ -223,6 +274,7 @@ describe("applyPreferenceMatch", () => {
|
|
|
223
274
|
{ action: "create", reason: "new" },
|
|
224
275
|
store as any,
|
|
225
276
|
"project:test",
|
|
277
|
+
mockDeps,
|
|
226
278
|
);
|
|
227
279
|
|
|
228
280
|
expect(result.handled).toBe(false);
|