@danielsimonjr/memory-mcp 9.9.0 → 10.0.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.
Files changed (70) hide show
  1. package/dist/core/EntityManager.d.ts +2 -0
  2. package/dist/core/EntityManager.d.ts.map +1 -1
  3. package/dist/core/EntityManager.js +14 -9
  4. package/dist/core/RelationManager.d.ts.map +1 -1
  5. package/dist/core/RelationManager.js +5 -4
  6. package/dist/features/CompressionManager.d.ts +3 -1
  7. package/dist/features/CompressionManager.d.ts.map +1 -1
  8. package/dist/features/CompressionManager.js +14 -5
  9. package/dist/search/BM25Search.d.ts +148 -0
  10. package/dist/search/BM25Search.d.ts.map +1 -0
  11. package/dist/search/BM25Search.js +339 -0
  12. package/dist/search/EarlyTerminationManager.d.ts +140 -0
  13. package/dist/search/EarlyTerminationManager.d.ts.map +1 -0
  14. package/dist/search/EarlyTerminationManager.js +279 -0
  15. package/dist/search/EmbeddingCache.d.ts +175 -0
  16. package/dist/search/EmbeddingCache.d.ts.map +1 -0
  17. package/dist/search/EmbeddingCache.js +246 -0
  18. package/dist/search/EmbeddingService.d.ts +108 -9
  19. package/dist/search/EmbeddingService.d.ts.map +1 -1
  20. package/dist/search/EmbeddingService.js +187 -15
  21. package/dist/search/HybridScorer.d.ts +181 -0
  22. package/dist/search/HybridScorer.d.ts.map +1 -0
  23. package/dist/search/HybridScorer.js +257 -0
  24. package/dist/search/IncrementalIndexer.d.ts +201 -0
  25. package/dist/search/IncrementalIndexer.d.ts.map +1 -0
  26. package/dist/search/IncrementalIndexer.js +342 -0
  27. package/dist/search/OptimizedInvertedIndex.d.ts +163 -0
  28. package/dist/search/OptimizedInvertedIndex.d.ts.map +1 -0
  29. package/dist/search/OptimizedInvertedIndex.js +358 -0
  30. package/dist/search/ParallelSearchExecutor.d.ts +172 -0
  31. package/dist/search/ParallelSearchExecutor.d.ts.map +1 -0
  32. package/dist/search/ParallelSearchExecutor.js +309 -0
  33. package/dist/search/QuantizedVectorStore.d.ts +171 -0
  34. package/dist/search/QuantizedVectorStore.d.ts.map +1 -0
  35. package/dist/search/QuantizedVectorStore.js +307 -0
  36. package/dist/search/QueryCostEstimator.d.ts +135 -2
  37. package/dist/search/QueryCostEstimator.d.ts.map +1 -1
  38. package/dist/search/QueryCostEstimator.js +298 -1
  39. package/dist/search/QueryPlanCache.d.ts +220 -0
  40. package/dist/search/QueryPlanCache.d.ts.map +1 -0
  41. package/dist/search/QueryPlanCache.js +379 -0
  42. package/dist/search/ReflectionManager.d.ts +49 -0
  43. package/dist/search/ReflectionManager.d.ts.map +1 -1
  44. package/dist/search/ReflectionManager.js +113 -6
  45. package/dist/search/index.d.ts +12 -3
  46. package/dist/search/index.d.ts.map +1 -1
  47. package/dist/search/index.js +20 -2
  48. package/dist/types/index.d.ts +1 -1
  49. package/dist/types/index.d.ts.map +1 -1
  50. package/dist/types/types.d.ts +41 -2
  51. package/dist/types/types.d.ts.map +1 -1
  52. package/dist/utils/BatchProcessor.d.ts +271 -0
  53. package/dist/utils/BatchProcessor.d.ts.map +1 -0
  54. package/dist/utils/BatchProcessor.js +376 -0
  55. package/dist/utils/MemoryMonitor.d.ts +176 -0
  56. package/dist/utils/MemoryMonitor.d.ts.map +1 -0
  57. package/dist/utils/MemoryMonitor.js +305 -0
  58. package/dist/utils/WorkerPoolManager.d.ts +233 -0
  59. package/dist/utils/WorkerPoolManager.d.ts.map +1 -0
  60. package/dist/utils/WorkerPoolManager.js +420 -0
  61. package/dist/utils/compressedCache.d.ts +29 -0
  62. package/dist/utils/compressedCache.d.ts.map +1 -1
  63. package/dist/utils/compressedCache.js +39 -0
  64. package/dist/utils/entityUtils.d.ts +25 -0
  65. package/dist/utils/entityUtils.d.ts.map +1 -1
  66. package/dist/utils/entityUtils.js +33 -0
  67. package/dist/utils/index.d.ts +4 -1
  68. package/dist/utils/index.d.ts.map +1 -1
  69. package/dist/utils/index.js +8 -0
  70. package/package.json +1 -1
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Query Plan Cache
3
+ *
4
+ * Phase 12 Sprint 4: Caches query analysis and planning results
5
+ * with LRU eviction for improved performance.
6
+ *
7
+ * @module search/QueryPlanCache
8
+ */
9
+ /**
10
+ * Default cache options.
11
+ */
12
+ const DEFAULT_OPTIONS = {
13
+ maxSize: 1000,
14
+ ttlMs: 5 * 60 * 1000, // 5 minutes
15
+ normalizeQueries: true,
16
+ enableStats: true,
17
+ };
18
+ /**
19
+ * Query Plan Cache with LRU eviction.
20
+ *
21
+ * Caches query analysis and planning results to avoid redundant computation.
22
+ * Uses LRU (Least Recently Used) eviction when cache is full.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const cache = new QueryPlanCache({ maxSize: 500 });
27
+ *
28
+ * // Cache an analysis
29
+ * cache.setAnalysis('Find Alice', analysis);
30
+ *
31
+ * // Retrieve cached analysis
32
+ * const cached = cache.getAnalysis('Find Alice');
33
+ * if (cached) {
34
+ * console.log('Cache hit!', cached);
35
+ * }
36
+ *
37
+ * // Get statistics
38
+ * const stats = cache.getStats();
39
+ * console.log(`Hit rate: ${(stats.hitRate * 100).toFixed(1)}%`);
40
+ * ```
41
+ */
42
+ export class QueryPlanCache {
43
+ cache;
44
+ options;
45
+ // Statistics
46
+ hits = 0;
47
+ misses = 0;
48
+ evictions = 0;
49
+ constructor(options) {
50
+ this.options = { ...DEFAULT_OPTIONS, ...options };
51
+ this.cache = new Map();
52
+ }
53
+ /**
54
+ * Get cached analysis for a query.
55
+ *
56
+ * @param query - The search query
57
+ * @returns Cached analysis or undefined if not found
58
+ */
59
+ getAnalysis(query) {
60
+ const entry = this.getEntry(query);
61
+ return entry?.analysis;
62
+ }
63
+ /**
64
+ * Get cached plan for a query.
65
+ *
66
+ * @param query - The search query
67
+ * @returns Cached plan or undefined if not found
68
+ */
69
+ getPlan(query) {
70
+ const entry = this.getEntry(query);
71
+ return entry?.plan;
72
+ }
73
+ /**
74
+ * Get full cached entry for a query.
75
+ *
76
+ * @param query - The search query
77
+ * @returns Cached entry or undefined if not found
78
+ */
79
+ getEntry(query) {
80
+ const key = this.normalizeQuery(query);
81
+ const entry = this.cache.get(key);
82
+ if (!entry) {
83
+ if (this.options.enableStats)
84
+ this.misses++;
85
+ return undefined;
86
+ }
87
+ // Check TTL
88
+ if (this.isExpired(entry)) {
89
+ this.cache.delete(key);
90
+ if (this.options.enableStats)
91
+ this.misses++;
92
+ return undefined;
93
+ }
94
+ // Update access time and count
95
+ entry.lastAccessed = Date.now();
96
+ entry.hitCount++;
97
+ if (this.options.enableStats)
98
+ this.hits++;
99
+ return entry;
100
+ }
101
+ /**
102
+ * Cache analysis results for a query.
103
+ *
104
+ * @param query - The search query
105
+ * @param analysis - The analysis result to cache
106
+ */
107
+ setAnalysis(query, analysis) {
108
+ const key = this.normalizeQuery(query);
109
+ const now = Date.now();
110
+ const existing = this.cache.get(key);
111
+ if (existing) {
112
+ // Update existing entry
113
+ existing.analysis = analysis;
114
+ existing.lastAccessed = now;
115
+ }
116
+ else {
117
+ // Evict if necessary
118
+ this.evictIfNeeded();
119
+ // Create new entry
120
+ this.cache.set(key, {
121
+ normalizedQuery: key,
122
+ originalQuery: query,
123
+ analysis,
124
+ createdAt: now,
125
+ lastAccessed: now,
126
+ hitCount: 0,
127
+ });
128
+ }
129
+ }
130
+ /**
131
+ * Cache plan results for a query.
132
+ *
133
+ * @param query - The search query
134
+ * @param analysis - The analysis result to cache
135
+ * @param plan - The plan result to cache
136
+ */
137
+ setPlan(query, analysis, plan) {
138
+ const key = this.normalizeQuery(query);
139
+ const now = Date.now();
140
+ const existing = this.cache.get(key);
141
+ if (existing) {
142
+ // Update existing entry
143
+ existing.analysis = analysis;
144
+ existing.plan = plan;
145
+ existing.lastAccessed = now;
146
+ }
147
+ else {
148
+ // Evict if necessary
149
+ this.evictIfNeeded();
150
+ // Create new entry
151
+ this.cache.set(key, {
152
+ normalizedQuery: key,
153
+ originalQuery: query,
154
+ analysis,
155
+ plan,
156
+ createdAt: now,
157
+ lastAccessed: now,
158
+ hitCount: 0,
159
+ });
160
+ }
161
+ }
162
+ /**
163
+ * Check if a query is cached.
164
+ *
165
+ * @param query - The search query
166
+ * @returns True if cached (and not expired)
167
+ */
168
+ has(query) {
169
+ const key = this.normalizeQuery(query);
170
+ const entry = this.cache.get(key);
171
+ if (!entry)
172
+ return false;
173
+ if (this.isExpired(entry)) {
174
+ this.cache.delete(key);
175
+ return false;
176
+ }
177
+ return true;
178
+ }
179
+ /**
180
+ * Invalidate a specific query from cache.
181
+ *
182
+ * @param query - The search query to invalidate
183
+ * @returns True if entry was found and removed
184
+ */
185
+ invalidate(query) {
186
+ const key = this.normalizeQuery(query);
187
+ return this.cache.delete(key);
188
+ }
189
+ /**
190
+ * Invalidate all entries matching a pattern.
191
+ *
192
+ * @param pattern - Regex pattern to match against queries
193
+ * @returns Number of entries invalidated
194
+ */
195
+ invalidatePattern(pattern) {
196
+ let count = 0;
197
+ for (const [key, entry] of this.cache) {
198
+ if (pattern.test(entry.originalQuery) || pattern.test(key)) {
199
+ this.cache.delete(key);
200
+ count++;
201
+ }
202
+ }
203
+ return count;
204
+ }
205
+ /**
206
+ * Clear all cache entries.
207
+ */
208
+ clear() {
209
+ this.cache.clear();
210
+ this.hits = 0;
211
+ this.misses = 0;
212
+ this.evictions = 0;
213
+ }
214
+ /**
215
+ * Get cache statistics.
216
+ *
217
+ * @returns Cache statistics
218
+ */
219
+ getStats() {
220
+ const now = Date.now();
221
+ let totalAge = 0;
222
+ for (const entry of this.cache.values()) {
223
+ totalAge += now - entry.createdAt;
224
+ }
225
+ const total = this.hits + this.misses;
226
+ return {
227
+ size: this.cache.size,
228
+ maxSize: this.options.maxSize,
229
+ hits: this.hits,
230
+ misses: this.misses,
231
+ hitRate: total > 0 ? this.hits / total : 0,
232
+ evictions: this.evictions,
233
+ averageEntryAgeMs: this.cache.size > 0 ? totalAge / this.cache.size : 0,
234
+ };
235
+ }
236
+ /**
237
+ * Get the current cache size.
238
+ */
239
+ get size() {
240
+ return this.cache.size;
241
+ }
242
+ /**
243
+ * Normalize a query for cache lookup.
244
+ *
245
+ * Normalization helps improve cache hit rate by treating
246
+ * similar queries as equivalent.
247
+ *
248
+ * @param query - The query to normalize
249
+ * @returns Normalized query string
250
+ */
251
+ normalizeQuery(query) {
252
+ if (!this.options.normalizeQueries) {
253
+ return query;
254
+ }
255
+ return query
256
+ .toLowerCase()
257
+ .trim()
258
+ // Normalize whitespace
259
+ .replace(/\s+/g, ' ')
260
+ // Remove punctuation that doesn't affect meaning
261
+ .replace(/[.,!?;:]+$/g, '')
262
+ // Sort operators for consistent matching
263
+ .replace(/\b(AND|OR|NOT)\b/gi, match => match.toUpperCase());
264
+ }
265
+ /**
266
+ * Check if an entry has expired.
267
+ * @private
268
+ */
269
+ isExpired(entry) {
270
+ return Date.now() - entry.createdAt > this.options.ttlMs;
271
+ }
272
+ /**
273
+ * Evict entries if cache is at capacity.
274
+ * Uses LRU (Least Recently Used) eviction.
275
+ * @private
276
+ */
277
+ evictIfNeeded() {
278
+ if (this.cache.size < this.options.maxSize) {
279
+ return;
280
+ }
281
+ // Find the least recently used entry
282
+ let oldestKey = null;
283
+ let oldestTime = Infinity;
284
+ for (const [key, entry] of this.cache) {
285
+ // Also check for expired entries during eviction
286
+ if (this.isExpired(entry)) {
287
+ this.cache.delete(key);
288
+ if (this.options.enableStats)
289
+ this.evictions++;
290
+ if (this.cache.size < this.options.maxSize)
291
+ return;
292
+ continue;
293
+ }
294
+ if (entry.lastAccessed < oldestTime) {
295
+ oldestTime = entry.lastAccessed;
296
+ oldestKey = key;
297
+ }
298
+ }
299
+ // Evict the oldest entry
300
+ if (oldestKey) {
301
+ this.cache.delete(oldestKey);
302
+ if (this.options.enableStats)
303
+ this.evictions++;
304
+ }
305
+ }
306
+ /**
307
+ * Clean up expired entries.
308
+ *
309
+ * Call this periodically to remove stale entries.
310
+ *
311
+ * @returns Number of entries removed
312
+ */
313
+ cleanup() {
314
+ let count = 0;
315
+ for (const [key, entry] of this.cache) {
316
+ if (this.isExpired(entry)) {
317
+ this.cache.delete(key);
318
+ count++;
319
+ }
320
+ }
321
+ return count;
322
+ }
323
+ /**
324
+ * Get all cache keys (for debugging).
325
+ */
326
+ keys() {
327
+ return Array.from(this.cache.keys());
328
+ }
329
+ /**
330
+ * Preload cache with common queries.
331
+ *
332
+ * @param queries - Array of query-analysis pairs to preload
333
+ */
334
+ preload(queries) {
335
+ for (const { query, analysis, plan } of queries) {
336
+ if (plan) {
337
+ this.setPlan(query, analysis, plan);
338
+ }
339
+ else {
340
+ this.setAnalysis(query, analysis);
341
+ }
342
+ }
343
+ }
344
+ /**
345
+ * Export cache entries for persistence.
346
+ *
347
+ * @returns Array of cache entries
348
+ */
349
+ export() {
350
+ const entries = [];
351
+ for (const entry of this.cache.values()) {
352
+ if (!this.isExpired(entry)) {
353
+ entries.push({ ...entry });
354
+ }
355
+ }
356
+ return entries;
357
+ }
358
+ /**
359
+ * Import cache entries from persistence.
360
+ *
361
+ * @param entries - Array of cache entries to import
362
+ * @param preserveTimestamps - Whether to preserve original timestamps
363
+ */
364
+ import(entries, preserveTimestamps = false) {
365
+ const now = Date.now();
366
+ for (const entry of entries) {
367
+ if (!preserveTimestamps) {
368
+ entry.createdAt = now;
369
+ entry.lastAccessed = now;
370
+ }
371
+ // Skip if expired
372
+ if (this.isExpired(entry))
373
+ continue;
374
+ // Evict if needed
375
+ this.evictIfNeeded();
376
+ this.cache.set(entry.normalizedQuery, entry);
377
+ }
378
+ }
379
+ }
@@ -21,6 +21,31 @@ export interface ReflectionOptions {
21
21
  minResults?: number;
22
22
  /** Hybrid search options */
23
23
  searchOptions?: Partial<HybridSearchOptions>;
24
+ /** Phase 12 Sprint 4: Progressive limit increase factor (default: 1.5) */
25
+ limitIncreaseFactor?: number;
26
+ /** Phase 12 Sprint 4: Initial search limit (default: 10) */
27
+ initialLimit?: number;
28
+ /** Phase 12 Sprint 4: Focus on specific missing info types */
29
+ focusMissingTypes?: boolean;
30
+ }
31
+ /**
32
+ * Phase 12 Sprint 4: Refinement history entry.
33
+ */
34
+ export interface RefinementHistoryEntry {
35
+ /** Iteration number (1-based) */
36
+ iteration: number;
37
+ /** Query used in this iteration */
38
+ query: string;
39
+ /** Search limit used */
40
+ limit: number;
41
+ /** Results found in this iteration */
42
+ resultsFound: number;
43
+ /** Adequacy score after this iteration */
44
+ adequacyScore: number;
45
+ /** Reason for refinement (if not final) */
46
+ refinementReason?: string;
47
+ /** Missing info types that triggered refinement */
48
+ missingInfoTypes?: string[];
24
49
  }
25
50
  /**
26
51
  * Result of reflection-based retrieval.
@@ -31,6 +56,10 @@ export interface ReflectionResult {
31
56
  adequate: boolean;
32
57
  refinements: string[];
33
58
  adequacyScore: number;
59
+ /** Phase 12 Sprint 4: Detailed refinement history */
60
+ refinementHistory: RefinementHistoryEntry[];
61
+ /** Phase 12 Sprint 4: Final search limit used */
62
+ finalLimit: number;
34
63
  }
35
64
  /**
36
65
  * Reflection Manager for iterative retrieval refinement.
@@ -57,8 +86,28 @@ export declare class ReflectionManager {
57
86
  constructor(hybridSearch: HybridSearchManager, analyzer: QueryAnalyzer);
58
87
  /**
59
88
  * Perform retrieval with reflection-based refinement.
89
+ *
90
+ * Phase 12 Sprint 4 enhancements:
91
+ * - Progressive limit increase per round
92
+ * - Focused query refinement based on missing information
93
+ * - Detailed refinement history tracking
60
94
  */
61
95
  retrieveWithReflection(graph: ReadonlyKnowledgeGraph, query: string, options?: ReflectionOptions): Promise<ReflectionResult>;
96
+ /**
97
+ * Find missing information types based on analysis requirements.
98
+ * @private
99
+ */
100
+ private findMissingInfoTypes;
101
+ /**
102
+ * Refine query with focus on missing information types.
103
+ * @private
104
+ */
105
+ private refineQueryFocused;
106
+ /**
107
+ * Get human-readable reason for refinement.
108
+ * @private
109
+ */
110
+ private getRefinementReason;
62
111
  /**
63
112
  * Calculate result adequacy score.
64
113
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ReflectionManager.d.ts","sourceRoot":"","sources":["../../src/search/ReflectionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAEtB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,QAAQ;gBADR,YAAY,EAAE,mBAAmB,EACjC,QAAQ,EAAE,aAAa;IAGjC;;OAEG;IACG,sBAAsB,CAC1B,KAAK,EAAE,sBAAsB,EAC7B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC;IA2D5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACH,OAAO,CAAC,WAAW;CA6BpB"}
1
+ {"version":3,"file":"ReflectionManager.d.ts","sourceRoot":"","sources":["../../src/search/ReflectionManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAEtB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;IAC5C,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,QAAQ;gBADR,YAAY,EAAE,mBAAmB,EACjC,QAAQ,EAAE,aAAa;IAGjC;;;;;;;OAOG;IACG,sBAAsB,CAC1B,KAAK,EAAE,sBAAsB,EAC7B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC;IAwG5B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAqC1B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACH,OAAO,CAAC,WAAW;CA6BpB"}
@@ -34,18 +34,31 @@ export class ReflectionManager {
34
34
  }
35
35
  /**
36
36
  * Perform retrieval with reflection-based refinement.
37
+ *
38
+ * Phase 12 Sprint 4 enhancements:
39
+ * - Progressive limit increase per round
40
+ * - Focused query refinement based on missing information
41
+ * - Detailed refinement history tracking
37
42
  */
38
43
  async retrieveWithReflection(graph, query, options = {}) {
39
- const { maxIterations = 3, adequacyThreshold = 0.7, minResults = 3, searchOptions = {}, } = options;
44
+ const { maxIterations = 3, adequacyThreshold = 0.7, minResults = 3, searchOptions = {}, limitIncreaseFactor = 1.5, initialLimit = 10, focusMissingTypes = true, } = options;
40
45
  const allResults = [];
41
46
  const refinements = [];
47
+ const refinementHistory = [];
42
48
  let currentQuery = query;
43
49
  let iteration = 0;
44
50
  let adequacyScore = 0;
51
+ let currentLimit = initialLimit;
52
+ // Get initial analysis for tracking
53
+ const analysis = this.analyzer.analyze(query);
45
54
  while (iteration < maxIterations) {
46
55
  iteration++;
47
- // Execute search
48
- const results = await this.hybridSearch.searchWithEntities(graph, currentQuery, searchOptions);
56
+ // Calculate current limit with progressive increase
57
+ currentLimit = Math.round(initialLimit * Math.pow(limitIncreaseFactor, iteration - 1));
58
+ // Execute search with current limit
59
+ const results = await this.hybridSearch.searchWithEntities(graph, currentQuery, { ...searchOptions, limit: currentLimit });
60
+ // Track results found this iteration (before deduplication)
61
+ const newResultsCount = results.filter(r => !allResults.some(existing => existing.entity.name === r.entity.name)).length;
49
62
  // Add new results (deduplicated)
50
63
  for (const result of results) {
51
64
  if (!allResults.some(r => r.entity.name === result.entity.name)) {
@@ -53,17 +66,36 @@ export class ReflectionManager {
53
66
  }
54
67
  }
55
68
  // Check adequacy
56
- const analysis = this.analyzer.analyze(query);
57
- adequacyScore = this.calculateAdequacy(allResults, analysis, minResults);
69
+ const iterAnalysis = this.analyzer.analyze(currentQuery);
70
+ adequacyScore = this.calculateAdequacy(allResults, iterAnalysis, minResults);
71
+ // Determine missing info types
72
+ const missingInfoTypes = this.findMissingInfoTypes(allResults, analysis);
73
+ // Record history entry
74
+ const historyEntry = {
75
+ iteration,
76
+ query: currentQuery,
77
+ limit: currentLimit,
78
+ resultsFound: newResultsCount,
79
+ adequacyScore,
80
+ };
58
81
  if (adequacyScore >= adequacyThreshold) {
82
+ refinementHistory.push(historyEntry);
59
83
  break;
60
84
  }
61
85
  // Refine query if not adequate
62
- const refinedQuery = this.refineQuery(currentQuery, allResults, analysis);
86
+ const refinedQuery = focusMissingTypes && missingInfoTypes.length > 0
87
+ ? this.refineQueryFocused(currentQuery, allResults, analysis, missingInfoTypes)
88
+ : this.refineQuery(currentQuery, allResults, analysis);
63
89
  if (refinedQuery === currentQuery) {
64
90
  // No refinement possible
91
+ historyEntry.refinementReason = 'No further refinement possible';
92
+ refinementHistory.push(historyEntry);
65
93
  break;
66
94
  }
95
+ // Record refinement details in history
96
+ historyEntry.refinementReason = this.getRefinementReason(currentQuery, refinedQuery, missingInfoTypes);
97
+ historyEntry.missingInfoTypes = missingInfoTypes;
98
+ refinementHistory.push(historyEntry);
67
99
  refinements.push(refinedQuery);
68
100
  currentQuery = refinedQuery;
69
101
  }
@@ -73,8 +105,83 @@ export class ReflectionManager {
73
105
  adequate: adequacyScore >= adequacyThreshold,
74
106
  refinements,
75
107
  adequacyScore,
108
+ refinementHistory,
109
+ finalLimit: currentLimit,
76
110
  };
77
111
  }
112
+ /**
113
+ * Find missing information types based on analysis requirements.
114
+ * @private
115
+ */
116
+ findMissingInfoTypes(results, analysis) {
117
+ const coveredTypes = new Set();
118
+ for (const result of results) {
119
+ const entityType = result.entity.entityType.toLowerCase();
120
+ coveredTypes.add(entityType);
121
+ // Map entity types to info types
122
+ if (['person', 'people', 'user', 'employee'].includes(entityType)) {
123
+ coveredTypes.add('person');
124
+ }
125
+ if (['location', 'place', 'city', 'country', 'address'].includes(entityType)) {
126
+ coveredTypes.add('location');
127
+ }
128
+ if (result.entity.createdAt || result.entity.lastModified) {
129
+ coveredTypes.add('temporal');
130
+ }
131
+ // Entity type covers 'entity' requirement
132
+ coveredTypes.add('entity');
133
+ }
134
+ // Find which required types are missing
135
+ return analysis.requiredInfoTypes.filter(type => !coveredTypes.has(type));
136
+ }
137
+ /**
138
+ * Refine query with focus on missing information types.
139
+ * @private
140
+ */
141
+ refineQueryFocused(query, results, analysis, missingInfoTypes) {
142
+ const additions = [];
143
+ for (const missingType of missingInfoTypes) {
144
+ switch (missingType) {
145
+ case 'person':
146
+ additions.push('person people who');
147
+ break;
148
+ case 'location':
149
+ additions.push('location place where');
150
+ break;
151
+ case 'temporal':
152
+ additions.push('when date time');
153
+ break;
154
+ case 'quantity':
155
+ additions.push('count number how many');
156
+ break;
157
+ case 'reason':
158
+ additions.push('reason why because');
159
+ break;
160
+ }
161
+ }
162
+ if (additions.length > 0) {
163
+ // Add relevant keywords to query
164
+ return `${query} ${additions.slice(0, 2).join(' ')}`;
165
+ }
166
+ // Fallback to standard refinement
167
+ return this.refineQuery(query, results, analysis);
168
+ }
169
+ /**
170
+ * Get human-readable reason for refinement.
171
+ * @private
172
+ */
173
+ getRefinementReason(_originalQuery, refinedQuery, missingInfoTypes) {
174
+ if (missingInfoTypes.length > 0) {
175
+ return `Added keywords for missing info types: ${missingInfoTypes.join(', ')}`;
176
+ }
177
+ if (refinedQuery.includes('person people')) {
178
+ return 'Expanded query to find person-related entities';
179
+ }
180
+ if (refinedQuery.includes('recent history timeline')) {
181
+ return 'Added temporal context to query';
182
+ }
183
+ return 'Broadened query by removing constraints';
184
+ }
78
185
  /**
79
186
  * Calculate result adequacy score.
80
187
  */
@@ -12,15 +12,24 @@ export { SearchSuggestions } from './SearchSuggestions.js';
12
12
  export { SavedSearchManager } from './SavedSearchManager.js';
13
13
  export { SearchManager } from './SearchManager.js';
14
14
  export { SearchFilterChain, type SearchFilters, type ValidatedPagination } from './SearchFilterChain.js';
15
- export { OpenAIEmbeddingService, LocalEmbeddingService, MockEmbeddingService, createEmbeddingService, } from './EmbeddingService.js';
15
+ export { OpenAIEmbeddingService, LocalEmbeddingService, MockEmbeddingService, createEmbeddingService, l2Normalize, QUERY_PREFIX, DOCUMENT_PREFIX, type EmbeddingProgressCallback, } from './EmbeddingService.js';
16
+ export { EmbeddingCache, DEFAULT_EMBEDDING_CACHE_OPTIONS, type EmbeddingCacheStats, type EmbeddingCacheOptions, } from './EmbeddingCache.js';
17
+ export { IncrementalIndexer, DEFAULT_INDEXER_OPTIONS, type IndexOperationType, type IndexOperation, type IncrementalIndexerOptions, type FlushResult, } from './IncrementalIndexer.js';
16
18
  export { InMemoryVectorStore, SQLiteVectorStore, createVectorStore, cosineSimilarity, type SQLiteStorageWithEmbeddings, } from './VectorStore.js';
17
19
  export { SemanticSearch, entityToText, } from './SemanticSearch.js';
18
20
  export { TFIDFIndexManager } from './TFIDFIndexManager.js';
19
21
  export { TFIDFEventSync } from './TFIDFEventSync.js';
20
- export { QueryCostEstimator } from './QueryCostEstimator.js';
22
+ export { QueryCostEstimator, type SearchLayer, type ExtendedQueryCostEstimate, type LayerRecommendationOptions, type TokenEstimationOptions, type AdaptiveDepthConfig, } from './QueryCostEstimator.js';
21
23
  export { SymbolicSearch, type SymbolicResult } from './SymbolicSearch.js';
22
24
  export { HybridSearchManager, DEFAULT_HYBRID_WEIGHTS } from './HybridSearchManager.js';
23
25
  export { QueryAnalyzer } from './QueryAnalyzer.js';
24
26
  export { QueryPlanner } from './QueryPlanner.js';
25
- export { ReflectionManager, type ReflectionOptions, type ReflectionResult, } from './ReflectionManager.js';
27
+ export { ReflectionManager, type ReflectionOptions, type ReflectionResult, type RefinementHistoryEntry, } from './ReflectionManager.js';
28
+ export { BM25Search, STOPWORDS, DEFAULT_BM25_CONFIG, type BM25DocumentEntry, type BM25Index, type BM25Config, } from './BM25Search.js';
29
+ export { OptimizedInvertedIndex, type IndexMemoryUsage, type PostingListResult, } from './OptimizedInvertedIndex.js';
30
+ export { HybridScorer, DEFAULT_SCORER_WEIGHTS, type SemanticSearchResult, type LexicalSearchResult, type SymbolicSearchResult, type ScoredResult, type HybridWeights, type HybridScorerOptions, } from './HybridScorer.js';
31
+ export { ParallelSearchExecutor, type LayerTiming, type ParallelSearchResult, type ParallelSearchOptions, } from './ParallelSearchExecutor.js';
32
+ export { EarlyTerminationManager, type AdequacyCheck, type EarlyTerminationOptions, type EarlyTerminationResult, } from './EarlyTerminationManager.js';
33
+ export { QueryPlanCache, type CachedQueryEntry, type QueryPlanCacheStats, type QueryPlanCacheOptions, } from './QueryPlanCache.js';
34
+ export { QuantizedVectorStore, type QuantizationParams, type QuantizedVectorStoreStats, type QuantizedSearchResult, type QuantizedVectorStoreOptions, } from './QuantizedVectorStore.js';
26
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAGzG,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,2BAA2B,GACjC,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,cAAc,EACd,YAAY,GACb,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGvF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EACL,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"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"}