squish-memory 0.7.2 → 0.8.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.
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Hybrid Search - Combines BM25 keyword search with vector semantic search
3
+ * Uses Reciprocal Rank Fusion (RRF) for intelligent result merging
4
+ *
5
+ * Based on research showing 40-60% improvement over pure vector search:
6
+ * - BM25 excels at exact keyword matches
7
+ * - Vector search captures semantic similarity
8
+ * - RRF merges both without score calibration issues
9
+ */
10
+ import { getDb } from '../../db/index.js';
11
+ import { createDatabaseClient } from '../../core/database.js';
12
+ import { getEmbedding } from '../../core/embeddings.js';
13
+ import { getProjectByPath } from '../../core/projects.js';
14
+ import { fromSqliteTags, normalizeTags } from './serialization.js';
15
+ import { isDatabaseUnavailableError } from '../../core/utils.js';
16
+ /**
17
+ * Reciprocal Rank Fusion (RRF) constant
18
+ * Higher values = more influence from lower-ranked items
19
+ * 60 is the standard value used in research
20
+ */
21
+ const RRF_K = 60;
22
+ /**
23
+ * Main hybrid search function - combines BM25 and vector search with RRF
24
+ */
25
+ export async function hybridSearch(input, options = {}) {
26
+ const limit = options.limit ?? input.limit ?? 10;
27
+ const bm25Weight = options.bm25Weight ?? 0.5;
28
+ const vectorWeight = options.vectorWeight ?? 0.5;
29
+ // Run both searches in parallel
30
+ const [bm25Results, vectorResults] = await Promise.all([
31
+ bm25Search(input, { ...options, limit: limit * 2 }),
32
+ vectorSearch(input, { ...options, limit: limit * 2 }),
33
+ ]);
34
+ // Apply RRF to merge results
35
+ return reciprocalRankFusion(bm25Results, vectorResults, { limit, bm25Weight, vectorWeight });
36
+ }
37
+ /**
38
+ * BM25 keyword search using SQLite FTS5
39
+ */
40
+ async function bm25Search(input, options) {
41
+ try {
42
+ const db = createDatabaseClient(await getDb());
43
+ const sqlite = db.$client;
44
+ const limit = options.limit ?? 10;
45
+ const tags = normalizeTags(options.tags ?? input.tags);
46
+ // Build FTS5 query with proper escaping
47
+ const ftsQuery = buildFtsQuery(input.query);
48
+ // Build WHERE conditions
49
+ const conditions = ['memories_fts MATCH ?'];
50
+ const params = [ftsQuery];
51
+ if (input.type) {
52
+ conditions.push('m.type = ?');
53
+ params.push(input.type);
54
+ }
55
+ if (tags.length) {
56
+ conditions.push('(' + tags.map(() => 'm.tags LIKE ?').join(' OR ') + ')');
57
+ params.push(...tags.map((tag) => `%${tag}%`));
58
+ }
59
+ let projectId = null;
60
+ if (input.project) {
61
+ const project = await getProjectByPath(input.project);
62
+ if (project) {
63
+ projectId = project.id;
64
+ conditions.push('m.project_id = ?');
65
+ params.push(project.id);
66
+ }
67
+ }
68
+ const whereClause = conditions.join(' AND ');
69
+ // FTS5 search with BM25 ranking
70
+ // Note: SQLite doesn't allow rowid access in subquery, so we use direct join
71
+ const statement = sqlite.prepare(`
72
+ SELECT
73
+ m.id as id,
74
+ m.project_id as projectId,
75
+ m.type as type,
76
+ m.content as content,
77
+ m.summary as summary,
78
+ m.tags as tags,
79
+ m.metadata as metadata,
80
+ bm25(memories_fts) as bm25Score,
81
+ m.created_at as createdAt
82
+ FROM memories m
83
+ INNER JOIN memories_fts ON m.rowid = memories_fts.rowid
84
+ WHERE ${whereClause}
85
+ ORDER BY bm25(memories_fts)
86
+ LIMIT ?
87
+ `);
88
+ const rows = statement.all(...params, limit * 3);
89
+ // Return as ranked results (lower BM25 score = better rank)
90
+ return rows.map((row, index) => ({
91
+ id: row.id,
92
+ rank: index + 1,
93
+ score: row.bm25Score,
94
+ result: {
95
+ id: row.id,
96
+ projectId: row.projectId,
97
+ type: row.type,
98
+ content: row.content,
99
+ summary: row.summary ?? undefined,
100
+ tags: fromSqliteTags(row.tags ?? null),
101
+ metadata: row.metadata ? JSON.parse(row.metadata) : null,
102
+ createdAt: row.createdAt ? new Date((Number(row.createdAt) || 0) * 1000).toISOString() : undefined,
103
+ },
104
+ }));
105
+ }
106
+ catch (error) {
107
+ if (isDatabaseUnavailableError(error)) {
108
+ return [];
109
+ }
110
+ throw error;
111
+ }
112
+ }
113
+ /**
114
+ * Vector semantic search using cosine similarity
115
+ */
116
+ async function vectorSearch(input, options) {
117
+ try {
118
+ const db = createDatabaseClient(await getDb());
119
+ const sqlite = db.$client;
120
+ const limit = options.limit ?? 10;
121
+ const tags = normalizeTags(options.tags ?? input.tags);
122
+ // Get query embedding
123
+ const queryEmbedding = await getEmbedding(input.query);
124
+ if (!queryEmbedding) {
125
+ return [];
126
+ }
127
+ // Build WHERE conditions
128
+ const conditions = [];
129
+ const params = [];
130
+ if (input.type) {
131
+ conditions.push('m.type = ?');
132
+ params.push(input.type);
133
+ }
134
+ if (tags.length) {
135
+ conditions.push('(' + tags.map(() => 'm.tags LIKE ?').join(' OR ') + ')');
136
+ params.push(...tags.map((tag) => `%${tag}%`));
137
+ }
138
+ let projectId = null;
139
+ if (input.project) {
140
+ const project = await getProjectByPath(input.project);
141
+ if (project) {
142
+ projectId = project.id;
143
+ conditions.push('m.project_id = ?');
144
+ params.push(project.id);
145
+ }
146
+ }
147
+ const whereClause = conditions.length > 0
148
+ ? 'WHERE ' + conditions.join(' AND ')
149
+ : '';
150
+ // Fetch candidates for vector search
151
+ const statement = sqlite.prepare(`
152
+ SELECT
153
+ m.id as id,
154
+ m.project_id as projectId,
155
+ m.type as type,
156
+ m.content as content,
157
+ m.summary as summary,
158
+ m.tags as tags,
159
+ m.metadata as metadata,
160
+ m.embedding as embedding,
161
+ m.embedding_json as embeddingJson,
162
+ m.created_at as createdAt
163
+ FROM memories m
164
+ ${whereClause}
165
+ ORDER BY m.created_at DESC
166
+ LIMIT ?
167
+ `);
168
+ const rows = statement.all(...params, limit * 3);
169
+ // Calculate cosine similarity for each result
170
+ const scored = rows
171
+ .map((row) => {
172
+ const embedding = parseEmbedding(row.embedding) ?? parseEmbedding(row.embeddingJson);
173
+ if (!embedding)
174
+ return null;
175
+ const similarity = cosineSimilarity(queryEmbedding, embedding);
176
+ return {
177
+ id: row.id,
178
+ projectId: row.projectId,
179
+ type: row.type,
180
+ content: row.content,
181
+ summary: row.summary,
182
+ tags: row.tags,
183
+ metadata: row.metadata,
184
+ createdAt: row.createdAt,
185
+ similarity,
186
+ };
187
+ })
188
+ .filter((item) => item !== null);
189
+ // Sort by similarity (descending) and return as ranked results
190
+ scored.sort((a, b) => b.similarity - a.similarity);
191
+ return scored.slice(0, limit * 2).map((item, index) => ({
192
+ id: item.id,
193
+ rank: index + 1,
194
+ score: item.similarity,
195
+ result: {
196
+ id: item.id,
197
+ projectId: item.projectId,
198
+ type: item.type,
199
+ content: item.content,
200
+ summary: item.summary ?? undefined,
201
+ tags: fromSqliteTags(item.tags ?? null),
202
+ metadata: item.metadata ? JSON.parse(item.metadata) : null,
203
+ createdAt: item.createdAt ? new Date((Number(item.createdAt) || 0) * 1000).toISOString() : undefined,
204
+ similarity: item.similarity,
205
+ },
206
+ }));
207
+ }
208
+ catch (error) {
209
+ if (isDatabaseUnavailableError(error)) {
210
+ return [];
211
+ }
212
+ throw error;
213
+ }
214
+ }
215
+ /**
216
+ * Reciprocal Rank Fusion (RRF) - merges ranked lists without score calibration
217
+ *
218
+ * RRF Formula: score(item) = sum(weight_i / (k + rank_i))
219
+ * Where k is a constant (typically 60) that prevents high ranks from dominating
220
+ *
221
+ * Benefits:
222
+ * - No need to calibrate different scoring systems (BM25 vs cosine similarity)
223
+ * - Handles items that appear in only one list
224
+ * - Proven to outperform weighted score fusion in most cases
225
+ */
226
+ function reciprocalRankFusion(bm25Results, vectorResults, options) {
227
+ const { limit, bm25Weight, vectorWeight } = options;
228
+ const scores = new Map();
229
+ // Process BM25 results
230
+ for (const item of bm25Results) {
231
+ const rrfScore = (bm25Weight * 2) / (RRF_K + item.rank);
232
+ const existing = scores.get(item.id);
233
+ if (existing) {
234
+ existing.score += rrfScore;
235
+ }
236
+ else {
237
+ scores.set(item.id, { score: rrfScore, result: item.result });
238
+ }
239
+ }
240
+ // Process vector results
241
+ for (const item of vectorResults) {
242
+ const rrfScore = (vectorWeight * 2) / (RRF_K + item.rank);
243
+ const existing = scores.get(item.id);
244
+ if (existing) {
245
+ existing.score += rrfScore;
246
+ }
247
+ else {
248
+ scores.set(item.id, { score: rrfScore, result: item.result });
249
+ }
250
+ }
251
+ // Sort by RRF score (descending) and return top results
252
+ return Array.from(scores.values())
253
+ .sort((a, b) => b.score - a.score)
254
+ .slice(0, limit)
255
+ .map((item) => ({
256
+ ...item.result,
257
+ similarity: item.result.similarity ?? 0,
258
+ }));
259
+ }
260
+ /**
261
+ * Build FTS5 query string from user input
262
+ * Handles phrase searches, AND/OR operators, and special characters
263
+ */
264
+ function buildFtsQuery(query) {
265
+ // Remove special characters that could break FTS5 syntax
266
+ let cleaned = query.replace(/[^\w\s"'-]/g, ' ');
267
+ // If query contains quotes, preserve as phrase search
268
+ if (cleaned.includes('"')) {
269
+ return cleaned;
270
+ }
271
+ // Split into terms and join with AND for better precision
272
+ const terms = cleaned.trim().split(/\s+/).filter((t) => t.length > 0);
273
+ if (terms.length === 0) {
274
+ return '""'; // Empty query
275
+ }
276
+ // For multi-word queries, use NEAR operator for proximity search
277
+ if (terms.length > 1) {
278
+ return terms.join(' ');
279
+ }
280
+ return terms[0];
281
+ }
282
+ /**
283
+ * Parse embedding from SQLite storage
284
+ */
285
+ function parseEmbedding(embeddingData) {
286
+ if (!embeddingData)
287
+ return null;
288
+ if (Array.isArray(embeddingData))
289
+ return embeddingData;
290
+ if (embeddingData instanceof Uint8Array || Buffer.isBuffer(embeddingData)) {
291
+ try {
292
+ const json = JSON.parse(embeddingData.toString());
293
+ if (Array.isArray(json))
294
+ return json;
295
+ }
296
+ catch {
297
+ try {
298
+ const floatArray = new Float32Array(embeddingData.buffer || embeddingData);
299
+ return Array.from(floatArray);
300
+ }
301
+ catch {
302
+ return null;
303
+ }
304
+ }
305
+ }
306
+ if (typeof embeddingData === 'string') {
307
+ try {
308
+ const parsed = JSON.parse(embeddingData);
309
+ if (Array.isArray(parsed))
310
+ return parsed;
311
+ }
312
+ catch {
313
+ return null;
314
+ }
315
+ }
316
+ return null;
317
+ }
318
+ /**
319
+ * Calculate cosine similarity between two vectors
320
+ */
321
+ function cosineSimilarity(a, b) {
322
+ if (a.length !== b.length)
323
+ return 0;
324
+ let dotProduct = 0;
325
+ let normA = 0;
326
+ let normB = 0;
327
+ for (let i = 0; i < a.length; i++) {
328
+ dotProduct += a[i] * b[i];
329
+ normA += a[i] * a[i];
330
+ normB += b[i] * b[i];
331
+ }
332
+ if (normA === 0 || normB === 0)
333
+ return 0;
334
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
335
+ }
336
+ //# sourceMappingURL=hybrid-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.js","sourceRoot":"","sources":["../../../core/memory/hybrid-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Importance Scoring System
3
+ *
4
+ * Calculates and manages memory importance scores (0-100) with temporal decay.
5
+ * Based on research from Mnemosyne architecture and ReMe (Memory Replay).
6
+ *
7
+ * Scoring factors:
8
+ * - Base score: 50 (neutral)
9
+ * - Recency boost: decays over time (exponential decay)
10
+ * - Access frequency: more frequently accessed = higher importance
11
+ * - Type weighting: decisions > facts > preferences > context > observations
12
+ * - User flags: pinned/protected memories get maximum importance
13
+ */
14
+ import type { Memory } from '../../drizzle/schema.js';
15
+ export interface ImportanceScore {
16
+ score: number;
17
+ components: {
18
+ base: number;
19
+ recency: number;
20
+ accessFrequency: number;
21
+ typeWeight: number;
22
+ userFlags: number;
23
+ };
24
+ explanation: string;
25
+ }
26
+ /**
27
+ * Calculate importance score for a memory
28
+ *
29
+ * Formula: base + recency + accessFrequency + typeWeight + userFlags
30
+ * All values are clamped to 0-100 range
31
+ */
32
+ export declare function calculateImportance(memory: Partial<Memory>): ImportanceScore;
33
+ /**
34
+ * Update importance score for a memory
35
+ * Used when memory is accessed or modified
36
+ */
37
+ export declare function updateImportanceScore(memoryId: string, incrementAccess?: boolean): Promise<number>;
38
+ /**
39
+ * Decay importance scores for old memories
40
+ * Should be run periodically (e.g., daily) to reduce scores of stale memories
41
+ *
42
+ * This function applies exponential decay to all memories that haven't been
43
+ * recalculated recently, keeping the system's importance scores current.
44
+ */
45
+ export declare function decayImportanceScores(projectId?: string): Promise<number>;
46
+ /**
47
+ * Get low-importance memories that are candidates for consolidation
48
+ * These are old, rarely accessed memories with low importance scores
49
+ */
50
+ export declare function getLowImportanceMemories(projectId: string, options?: {
51
+ minAge?: number;
52
+ maxImportance?: number;
53
+ limit?: number;
54
+ }): Promise<any[]>;
55
+ /**
56
+ * Set importance score manually (for user override)
57
+ */
58
+ export declare function setImportanceScore(memoryId: string, score: number): Promise<void>;
59
+ /**
60
+ * Pin a memory to prevent decay and consolidation
61
+ */
62
+ export declare function pinMemory(memoryId: string, pinned?: boolean): Promise<void>;
63
+ /**
64
+ * Calculate cosine similarity between two vectors
65
+ * Re-exported for use in consolidation
66
+ */
67
+ export declare function cosineSimilarity(vecA: number[], vecB: number[]): number;
68
+ //# sourceMappingURL=importance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importance.d.ts","sourceRoot":"","sources":["../../../core/memory/importance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAMtD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;CACrB;AAcD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,eAAe,CA2B5E;AAgHD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,eAAe,GAAE,OAAe,GAC/B,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgD/E;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CACX,GACL,OAAO,CAAC,GAAG,EAAE,CAAC,CA0ChB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,OAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAavF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAuBvE"}