vesper-memory 0.3.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 (206) hide show
  1. package/.env.example +28 -0
  2. package/CHANGELOG.md +137 -0
  3. package/LICENSE +21 -0
  4. package/README.md +665 -0
  5. package/config/sqlite-schema.sql +413 -0
  6. package/dist/benchmark/index.d.ts +18 -0
  7. package/dist/benchmark/index.d.ts.map +1 -0
  8. package/dist/benchmark/index.js +19 -0
  9. package/dist/benchmark/index.js.map +1 -0
  10. package/dist/benchmark/metrics-collector.d.ts +90 -0
  11. package/dist/benchmark/metrics-collector.d.ts.map +1 -0
  12. package/dist/benchmark/metrics-collector.js +196 -0
  13. package/dist/benchmark/metrics-collector.js.map +1 -0
  14. package/dist/benchmark/report-generator.d.ts +35 -0
  15. package/dist/benchmark/report-generator.d.ts.map +1 -0
  16. package/dist/benchmark/report-generator.js +221 -0
  17. package/dist/benchmark/report-generator.js.map +1 -0
  18. package/dist/benchmark/runner.d.ts +30 -0
  19. package/dist/benchmark/runner.d.ts.map +1 -0
  20. package/dist/benchmark/runner.js +308 -0
  21. package/dist/benchmark/runner.js.map +1 -0
  22. package/dist/benchmark/scenarios/context-recall.d.ts +65 -0
  23. package/dist/benchmark/scenarios/context-recall.d.ts.map +1 -0
  24. package/dist/benchmark/scenarios/context-recall.js +180 -0
  25. package/dist/benchmark/scenarios/context-recall.js.map +1 -0
  26. package/dist/benchmark/scenarios/index.d.ts +34 -0
  27. package/dist/benchmark/scenarios/index.d.ts.map +1 -0
  28. package/dist/benchmark/scenarios/index.js +230 -0
  29. package/dist/benchmark/scenarios/index.js.map +1 -0
  30. package/dist/benchmark/statistics.d.ts +125 -0
  31. package/dist/benchmark/statistics.d.ts.map +1 -0
  32. package/dist/benchmark/statistics.js +520 -0
  33. package/dist/benchmark/statistics.js.map +1 -0
  34. package/dist/benchmark/types.d.ts +458 -0
  35. package/dist/benchmark/types.d.ts.map +1 -0
  36. package/dist/benchmark/types.js +297 -0
  37. package/dist/benchmark/types.js.map +1 -0
  38. package/dist/cli 2.js +583 -0
  39. package/dist/cli.d 2.ts +8 -0
  40. package/dist/cli.d.ts +8 -0
  41. package/dist/cli.d.ts 2.map +1 -0
  42. package/dist/cli.d.ts.map +1 -0
  43. package/dist/cli.js +583 -0
  44. package/dist/cli.js 2.map +1 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/config/rate-limits.d.ts +76 -0
  47. package/dist/config/rate-limits.d.ts.map +1 -0
  48. package/dist/config/rate-limits.js +161 -0
  49. package/dist/config/rate-limits.js.map +1 -0
  50. package/dist/config 2/rate-limits.d.ts +76 -0
  51. package/dist/config 2/rate-limits.d.ts.map +1 -0
  52. package/dist/config 2/rate-limits.js +161 -0
  53. package/dist/config 2/rate-limits.js.map +1 -0
  54. package/dist/consolidation/pipeline.d.ts +52 -0
  55. package/dist/consolidation/pipeline.d.ts.map +1 -0
  56. package/dist/consolidation/pipeline.js +193 -0
  57. package/dist/consolidation/pipeline.js.map +1 -0
  58. package/dist/consolidation 2/pipeline.d.ts +52 -0
  59. package/dist/consolidation 2/pipeline.d.ts.map +1 -0
  60. package/dist/consolidation 2/pipeline.js +193 -0
  61. package/dist/consolidation 2/pipeline.js.map +1 -0
  62. package/dist/embeddings/client.d.ts +95 -0
  63. package/dist/embeddings/client.d.ts.map +1 -0
  64. package/dist/embeddings/client.js +162 -0
  65. package/dist/embeddings/client.js.map +1 -0
  66. package/dist/embeddings 2/client.d.ts +94 -0
  67. package/dist/embeddings 2/client.d.ts.map +1 -0
  68. package/dist/embeddings 2/client.js +144 -0
  69. package/dist/embeddings 2/client.js.map +1 -0
  70. package/dist/memory-layers/semantic-memory.d.ts +76 -0
  71. package/dist/memory-layers/semantic-memory.d.ts.map +1 -0
  72. package/dist/memory-layers/semantic-memory.js +231 -0
  73. package/dist/memory-layers/semantic-memory.js.map +1 -0
  74. package/dist/memory-layers/skill-library.d.ts +25 -0
  75. package/dist/memory-layers/skill-library.d.ts.map +1 -0
  76. package/dist/memory-layers/skill-library.js +54 -0
  77. package/dist/memory-layers/skill-library.js.map +1 -0
  78. package/dist/memory-layers/working-memory.d.ts +57 -0
  79. package/dist/memory-layers/working-memory.d.ts.map +1 -0
  80. package/dist/memory-layers/working-memory.js +153 -0
  81. package/dist/memory-layers/working-memory.js.map +1 -0
  82. package/dist/memory-layers 2/semantic-memory.d.ts +33 -0
  83. package/dist/memory-layers 2/semantic-memory.d.ts.map +1 -0
  84. package/dist/memory-layers 2/semantic-memory.js +114 -0
  85. package/dist/memory-layers 2/semantic-memory.js.map +1 -0
  86. package/dist/memory-layers 2/skill-library.d.ts +25 -0
  87. package/dist/memory-layers 2/skill-library.d.ts.map +1 -0
  88. package/dist/memory-layers 2/skill-library.js +54 -0
  89. package/dist/memory-layers 2/skill-library.js.map +1 -0
  90. package/dist/memory-layers 2/working-memory.d.ts +57 -0
  91. package/dist/memory-layers 2/working-memory.d.ts.map +1 -0
  92. package/dist/memory-layers 2/working-memory.js +153 -0
  93. package/dist/memory-layers 2/working-memory.js.map +1 -0
  94. package/dist/middleware/auth.d.ts +287 -0
  95. package/dist/middleware/auth.d.ts.map +1 -0
  96. package/dist/middleware/auth.js +610 -0
  97. package/dist/middleware/auth.js.map +1 -0
  98. package/dist/middleware 2/auth.d.ts +287 -0
  99. package/dist/middleware 2/auth.d.ts.map +1 -0
  100. package/dist/middleware 2/auth.js +610 -0
  101. package/dist/middleware 2/auth.js.map +1 -0
  102. package/dist/monitoring/health.d.ts +241 -0
  103. package/dist/monitoring/health.d.ts.map +1 -0
  104. package/dist/monitoring/health.js +649 -0
  105. package/dist/monitoring/health.js.map +1 -0
  106. package/dist/monitoring/metrics.d.ts +153 -0
  107. package/dist/monitoring/metrics.d.ts.map +1 -0
  108. package/dist/monitoring/metrics.js +349 -0
  109. package/dist/monitoring/metrics.js.map +1 -0
  110. package/dist/monitoring 2/health.d.ts +241 -0
  111. package/dist/monitoring 2/health.d.ts.map +1 -0
  112. package/dist/monitoring 2/health.js +649 -0
  113. package/dist/monitoring 2/health.js.map +1 -0
  114. package/dist/monitoring 2/metrics.d.ts +153 -0
  115. package/dist/monitoring 2/metrics.d.ts.map +1 -0
  116. package/dist/monitoring 2/metrics.js +349 -0
  117. package/dist/monitoring 2/metrics.js.map +1 -0
  118. package/dist/retrieval/hybrid-search.d.ts +186 -0
  119. package/dist/retrieval/hybrid-search.d.ts.map +1 -0
  120. package/dist/retrieval/hybrid-search.js +330 -0
  121. package/dist/retrieval/hybrid-search.js.map +1 -0
  122. package/dist/retrieval 2/hybrid-search.d.ts +186 -0
  123. package/dist/retrieval 2/hybrid-search.d.ts.map +1 -0
  124. package/dist/retrieval 2/hybrid-search.js +327 -0
  125. package/dist/retrieval 2/hybrid-search.js.map +1 -0
  126. package/dist/router/smart-router.d.ts +157 -0
  127. package/dist/router/smart-router.d.ts.map +1 -0
  128. package/dist/router/smart-router.js +524 -0
  129. package/dist/router/smart-router.js.map +1 -0
  130. package/dist/router 2/smart-router.d.ts +111 -0
  131. package/dist/router 2/smart-router.d.ts.map +1 -0
  132. package/dist/router 2/smart-router.js +383 -0
  133. package/dist/router 2/smart-router.js.map +1 -0
  134. package/dist/security/rate-limit-middleware.d.ts +119 -0
  135. package/dist/security/rate-limit-middleware.d.ts.map +1 -0
  136. package/dist/security/rate-limit-middleware.js +193 -0
  137. package/dist/security/rate-limit-middleware.js.map +1 -0
  138. package/dist/security 2/rate-limit-middleware.d.ts +119 -0
  139. package/dist/security 2/rate-limit-middleware.d.ts.map +1 -0
  140. package/dist/security 2/rate-limit-middleware.js +193 -0
  141. package/dist/security 2/rate-limit-middleware.js.map +1 -0
  142. package/dist/server 2.js +861 -0
  143. package/dist/server-wrapper 2.js +170 -0
  144. package/dist/server-wrapper.d 2.ts +12 -0
  145. package/dist/server-wrapper.d.ts +12 -0
  146. package/dist/server-wrapper.d.ts 2.map +1 -0
  147. package/dist/server-wrapper.d.ts.map +1 -0
  148. package/dist/server-wrapper.js +170 -0
  149. package/dist/server-wrapper.js 2.map +1 -0
  150. package/dist/server-wrapper.js.map +1 -0
  151. package/dist/server.d 2.ts +14 -0
  152. package/dist/server.d.ts +14 -0
  153. package/dist/server.d.ts 2.map +1 -0
  154. package/dist/server.d.ts.map +1 -0
  155. package/dist/server.js +656 -0
  156. package/dist/server.js 2.map +1 -0
  157. package/dist/server.js.map +1 -0
  158. package/dist/synthesis/conflict-detector.d.ts +43 -0
  159. package/dist/synthesis/conflict-detector.d.ts.map +1 -0
  160. package/dist/synthesis/conflict-detector.js +125 -0
  161. package/dist/synthesis/conflict-detector.js.map +1 -0
  162. package/dist/synthesis 2/conflict-detector.d.ts +43 -0
  163. package/dist/synthesis 2/conflict-detector.d.ts.map +1 -0
  164. package/dist/synthesis 2/conflict-detector.js +125 -0
  165. package/dist/synthesis 2/conflict-detector.js.map +1 -0
  166. package/dist/utils/monitoring.d.ts +25 -0
  167. package/dist/utils/monitoring.d.ts.map +1 -0
  168. package/dist/utils/monitoring.js +41 -0
  169. package/dist/utils/monitoring.js.map +1 -0
  170. package/dist/utils/rate-limiter.d.ts +97 -0
  171. package/dist/utils/rate-limiter.d.ts.map +1 -0
  172. package/dist/utils/rate-limiter.js +166 -0
  173. package/dist/utils/rate-limiter.js.map +1 -0
  174. package/dist/utils/validation.d.ts +139 -0
  175. package/dist/utils/validation.d.ts.map +1 -0
  176. package/dist/utils/validation.js +195 -0
  177. package/dist/utils/validation.js.map +1 -0
  178. package/dist/utils 2/monitoring.d.ts +25 -0
  179. package/dist/utils 2/monitoring.d.ts.map +1 -0
  180. package/dist/utils 2/monitoring.js +41 -0
  181. package/dist/utils 2/monitoring.js.map +1 -0
  182. package/dist/utils 2/rate-limiter.d.ts +97 -0
  183. package/dist/utils 2/rate-limiter.d.ts.map +1 -0
  184. package/dist/utils 2/rate-limiter.js +166 -0
  185. package/dist/utils 2/rate-limiter.js.map +1 -0
  186. package/dist/utils 2/validation.d.ts +139 -0
  187. package/dist/utils 2/validation.d.ts.map +1 -0
  188. package/dist/utils 2/validation.js +195 -0
  189. package/dist/utils 2/validation.js.map +1 -0
  190. package/docker-compose.yml +65 -0
  191. package/embedding-service/Dockerfile +29 -0
  192. package/embedding-service/README.md +68 -0
  193. package/embedding-service/requirements.txt +6 -0
  194. package/embedding-service/server.py +110 -0
  195. package/package.json +92 -0
  196. package/scripts/FRESH_INSTALL.md +280 -0
  197. package/scripts/README.md +101 -0
  198. package/scripts/ensure-infrastructure.sh +38 -0
  199. package/scripts/fresh-install-auto.sh +96 -0
  200. package/scripts/fresh-install.sh +167 -0
  201. package/scripts/health-check.sh +72 -0
  202. package/scripts/init-qdrant.ts +201 -0
  203. package/scripts/postinstall.js +94 -0
  204. package/scripts/run-accuracy-benchmark.ts +1237 -0
  205. package/scripts/run-real-benchmark.ts +581 -0
  206. package/scripts/test-mcp-server.sh +38 -0
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Hybrid Search Engine
3
+ *
4
+ * Implements multi-index retrieval combining dense embeddings, sparse vectors,
5
+ * and BM25 full-text search. Currently implements dense search with RRF fusion
6
+ * stubs for future sparse/BM25 integration.
7
+ *
8
+ * Retrieval Pipeline:
9
+ * - Dense embeddings (BGE-large, 1024-dim)
10
+ * - Sparse vectors (SPLADE++, coming soon)
11
+ * - BM25 full-text search (coming soon)
12
+ * - ColBERT late-interaction reranking (Phase 2)
13
+ * - Reciprocal Rank Fusion (k=60)
14
+ */
15
+ /**
16
+ * Dense search result from vector similarity
17
+ */
18
+ export interface DenseSearchResult {
19
+ id: string;
20
+ score: number;
21
+ payload?: Record<string, unknown>;
22
+ }
23
+ /**
24
+ * Sparse search result from sparse embeddings
25
+ */
26
+ export interface SparseSearchResult {
27
+ id: string;
28
+ score: number;
29
+ payload?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * BM25 full-text search result
33
+ */
34
+ export interface BM25SearchResult {
35
+ id: string;
36
+ score: number;
37
+ payload?: Record<string, unknown>;
38
+ }
39
+ /**
40
+ * Unified search result after RRF fusion
41
+ */
42
+ export interface HybridSearchResult {
43
+ id: string;
44
+ denseScore?: number;
45
+ sparseScore?: number;
46
+ bm25Score?: number;
47
+ fusedScore: number;
48
+ payload?: Record<string, unknown>;
49
+ rank: number;
50
+ }
51
+ /**
52
+ * Qdrant Hybrid Search Engine
53
+ *
54
+ * Manages vector operations and retrieval across multiple index types.
55
+ * Currently focused on dense search; sparse and BM25 stubs provided for future phases.
56
+ */
57
+ export declare class HybridSearchEngine {
58
+ private client;
59
+ private collectionName;
60
+ private vectorSize;
61
+ /**
62
+ * Initialize the hybrid search engine
63
+ *
64
+ * @param qdrantUrl - Qdrant server URL (default: http://localhost:6333)
65
+ * @param collectionName - Name of the collection (default: memory-vectors)
66
+ * @param vectorSize - Dimension of dense vectors (default: 1024 for BGE-large)
67
+ * @param apiKey - Optional Qdrant API key for authentication
68
+ */
69
+ constructor(qdrantUrl?: string, collectionName?: string, vectorSize?: number, apiKey?: string);
70
+ /**
71
+ * Initialize collection with proper schema
72
+ *
73
+ * Creates a collection with:
74
+ * - Dense vectors (1024-dim, cosine similarity)
75
+ * - Payload storage for metadata
76
+ * - Future: sparse vectors, BM25 indexes
77
+ */
78
+ initializeCollection(): Promise<void>;
79
+ /**
80
+ * Dense vector search using cosine similarity
81
+ *
82
+ * Performs semantic search using dense embeddings (BGE-large, 1024-dim).
83
+ * Returns top-k results ranked by similarity score.
84
+ *
85
+ * @param queryVector - Query embedding (1024-dim array)
86
+ * @param topK - Number of results to return (default: 5)
87
+ * @returns Array of dense search results sorted by score (highest first)
88
+ */
89
+ denseSearch(queryVector: number[], topK?: number): Promise<DenseSearchResult[]>;
90
+ /**
91
+ * Sparse vector search using SPLADE++ (stub)
92
+ *
93
+ * TODO: Phase 2 implementation
94
+ * - Integrate SPLADE++ sparse embeddings
95
+ * - Query sparse index in Qdrant
96
+ * - Return top-k sparse results
97
+ *
98
+ * @param querySparseVector - Query sparse embedding
99
+ * @param topK - Number of results to return
100
+ * @returns Array of sparse search results
101
+ */
102
+ sparseSearch(_querySparseVector: Record<number, number>, _topK?: number): Promise<SparseSearchResult[]>;
103
+ /**
104
+ * BM25 full-text search (stub)
105
+ *
106
+ * TODO: Phase 2 implementation
107
+ * - Integrate BM25 index (Qdrant or external)
108
+ * - Tokenize and search query text
109
+ * - Return top-k BM25 results
110
+ *
111
+ * @param queryText - Query text for full-text search
112
+ * @param topK - Number of results to return
113
+ * @returns Array of BM25 search results
114
+ */
115
+ bm25Search(_queryText: string, _topK?: number): Promise<BM25SearchResult[]>;
116
+ /**
117
+ * Reciprocal Rank Fusion combining multiple indexes
118
+ *
119
+ * Implements RRF formula to combine rankings from dense, sparse, and BM25 indexes:
120
+ * RRF(d) = Σ 1 / (k + rank(d))
121
+ *
122
+ * where k is the fusion parameter (default 60) and rank is the position in each ranking.
123
+ *
124
+ * TODO: Phase 2 - Integrate with sparse/BM25 results once available
125
+ *
126
+ * @param denseResults - Results from dense search
127
+ * @param sparseResults - Results from sparse search
128
+ * @param bm25Results - Results from BM25 search
129
+ * @param k - RRF fusion parameter (default: 60)
130
+ * @returns Fused results sorted by RRF score
131
+ */
132
+ static rrfFusion(denseResults: DenseSearchResult[], sparseResults?: SparseSearchResult[], bm25Results?: BM25SearchResult[], k?: number): HybridSearchResult[];
133
+ /**
134
+ * Hybrid search combining all available indexes
135
+ *
136
+ * Currently implements dense search only. Will be extended to include
137
+ * sparse vectors and BM25 once those are implemented in Phase 2.
138
+ *
139
+ * Pipeline:
140
+ * 1. Dense vector search (semantic search)
141
+ * 2. Sparse vector search (keyword-level semantics)
142
+ * 3. BM25 full-text search
143
+ * 4. Reciprocal Rank Fusion
144
+ *
145
+ * @param queryVector - Query embedding (1024-dim for BGE-large)
146
+ * @param topK - Number of final results to return (default: 5)
147
+ * @returns Array of fused results ranked by combined scores
148
+ */
149
+ hybridSearch(queryVector: number[], topK?: number): Promise<HybridSearchResult[]>;
150
+ /**
151
+ * Add or update a memory record with embedding
152
+ *
153
+ * @param id - Unique identifier for the memory
154
+ * @param vector - Dense embedding (1024-dim)
155
+ * @param payload - Associated metadata (content, timestamp, source, etc.)
156
+ */
157
+ upsertMemory(id: string, vector: number[], payload?: Record<string, unknown>): Promise<void>;
158
+ /**
159
+ * Delete a memory record
160
+ *
161
+ * @param id - Unique identifier of the memory to delete
162
+ */
163
+ deleteMemory(id: string): Promise<void>;
164
+ /**
165
+ * Get collection statistics
166
+ *
167
+ * @returns Object containing collection size, vector count, etc.
168
+ */
169
+ getCollectionStats(): Promise<Record<string, unknown>>;
170
+ }
171
+ /**
172
+ * Factory function to create and initialize a hybrid search engine
173
+ *
174
+ * Usage:
175
+ * ```typescript
176
+ * const engine = await createHybridSearchEngine();
177
+ * const results = await engine.hybridSearch(queryVector);
178
+ * ```
179
+ *
180
+ * @param qdrantUrl - Qdrant server URL (default: http://localhost:6333)
181
+ * @param collectionName - Name of the collection (default: memory-vectors)
182
+ * @param vectorSize - Dimension of dense vectors (default: 1024 for BGE-large)
183
+ * @param apiKey - Optional Qdrant API key for authentication
184
+ */
185
+ export declare function createHybridSearchEngine(qdrantUrl?: string, collectionName?: string, vectorSize?: number, apiKey?: string): Promise<HybridSearchEngine>;
186
+ //# sourceMappingURL=hybrid-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../../src/retrieval/hybrid-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Hybrid Search Engine
3
+ *
4
+ * Implements multi-index retrieval combining dense embeddings, sparse vectors,
5
+ * and BM25 full-text search. Currently implements dense search with RRF fusion
6
+ * stubs for future sparse/BM25 integration.
7
+ *
8
+ * Retrieval Pipeline:
9
+ * - Dense embeddings (BGE-large, 1024-dim)
10
+ * - Sparse vectors (SPLADE++, coming soon)
11
+ * - BM25 full-text search (coming soon)
12
+ * - ColBERT late-interaction reranking (Phase 2)
13
+ * - Reciprocal Rank Fusion (k=60)
14
+ */
15
+ import { QdrantClient } from "@qdrant/js-client-rest";
16
+ import { validateVector, sanitizeCollectionName } from "../utils/validation.js";
17
+ /**
18
+ * Qdrant Hybrid Search Engine
19
+ *
20
+ * Manages vector operations and retrieval across multiple index types.
21
+ * Currently focused on dense search; sparse and BM25 stubs provided for future phases.
22
+ */
23
+ export class HybridSearchEngine {
24
+ client;
25
+ collectionName;
26
+ vectorSize;
27
+ /**
28
+ * Initialize the hybrid search engine
29
+ *
30
+ * @param qdrantUrl - Qdrant server URL (default: http://localhost:6333)
31
+ * @param collectionName - Name of the collection (default: memory-vectors)
32
+ * @param vectorSize - Dimension of dense vectors (default: 1024 for BGE-large)
33
+ * @param apiKey - Optional Qdrant API key for authentication
34
+ */
35
+ constructor(qdrantUrl = "http://localhost:6333", collectionName = "memory-vectors", vectorSize = 1024, apiKey) {
36
+ // Sanitize collection name to prevent injection attacks (SEC-012)
37
+ this.collectionName = sanitizeCollectionName(collectionName);
38
+ this.vectorSize = vectorSize;
39
+ const clientConfig = {
40
+ url: qdrantUrl,
41
+ checkCompatibility: false, // Allow client 1.16.2 with server 1.7.4
42
+ };
43
+ // Add API key if provided
44
+ if (apiKey) {
45
+ clientConfig.apiKey = apiKey;
46
+ }
47
+ this.client = new QdrantClient(clientConfig);
48
+ }
49
+ /**
50
+ * Initialize collection with proper schema
51
+ *
52
+ * Creates a collection with:
53
+ * - Dense vectors (1024-dim, cosine similarity)
54
+ * - Payload storage for metadata
55
+ * - Future: sparse vectors, BM25 indexes
56
+ */
57
+ async initializeCollection() {
58
+ try {
59
+ // Check if collection exists
60
+ const collections = await this.client.getCollections();
61
+ const collectionExists = collections.collections.some((c) => c.name === this.collectionName);
62
+ if (collectionExists) {
63
+ console.log(`Collection '${this.collectionName}' already exists`);
64
+ return;
65
+ }
66
+ // Create new collection with dense vector index
67
+ await this.client.createCollection(this.collectionName, {
68
+ vectors: {
69
+ size: this.vectorSize,
70
+ distance: "Cosine",
71
+ },
72
+ });
73
+ console.log(`Created collection '${this.collectionName}' with ${this.vectorSize}-dim vectors`);
74
+ // TODO: Phase 2 - Add sparse vector index
75
+ // TODO: Phase 2 - Add BM25 index
76
+ }
77
+ catch (error) {
78
+ console.error("Failed to initialize collection:", error instanceof Error ? error.message : error);
79
+ throw error;
80
+ }
81
+ }
82
+ /**
83
+ * Dense vector search using cosine similarity
84
+ *
85
+ * Performs semantic search using dense embeddings (BGE-large, 1024-dim).
86
+ * Returns top-k results ranked by similarity score.
87
+ *
88
+ * @param queryVector - Query embedding (1024-dim array)
89
+ * @param topK - Number of results to return (default: 5)
90
+ * @returns Array of dense search results sorted by score (highest first)
91
+ */
92
+ async denseSearch(queryVector, topK = 5) {
93
+ // Validate vector dimensions and values (SEC-005)
94
+ validateVector(queryVector, this.vectorSize);
95
+ try {
96
+ const searchResults = await this.client.search(this.collectionName, {
97
+ vector: queryVector,
98
+ limit: topK,
99
+ with_payload: true,
100
+ with_vector: false,
101
+ });
102
+ return searchResults.map((result) => ({
103
+ id: String(result.id),
104
+ score: result.score,
105
+ payload: result.payload ?? undefined,
106
+ }));
107
+ }
108
+ catch (error) {
109
+ console.error("Dense search failed:", error instanceof Error ? error.message : error);
110
+ throw error;
111
+ }
112
+ }
113
+ /**
114
+ * Sparse vector search using SPLADE++ (stub)
115
+ *
116
+ * TODO: Phase 2 implementation
117
+ * - Integrate SPLADE++ sparse embeddings
118
+ * - Query sparse index in Qdrant
119
+ * - Return top-k sparse results
120
+ *
121
+ * @param querySparseVector - Query sparse embedding
122
+ * @param topK - Number of results to return
123
+ * @returns Array of sparse search results
124
+ */
125
+ async sparseSearch(_querySparseVector, _topK = 5) {
126
+ console.warn("sparseSearch: Not yet implemented (Phase 2)");
127
+ return [];
128
+ }
129
+ /**
130
+ * BM25 full-text search (stub)
131
+ *
132
+ * TODO: Phase 2 implementation
133
+ * - Integrate BM25 index (Qdrant or external)
134
+ * - Tokenize and search query text
135
+ * - Return top-k BM25 results
136
+ *
137
+ * @param queryText - Query text for full-text search
138
+ * @param topK - Number of results to return
139
+ * @returns Array of BM25 search results
140
+ */
141
+ async bm25Search(_queryText, _topK = 5) {
142
+ console.warn("bm25Search: Not yet implemented (Phase 2)");
143
+ return [];
144
+ }
145
+ /**
146
+ * Reciprocal Rank Fusion combining multiple indexes
147
+ *
148
+ * Implements RRF formula to combine rankings from dense, sparse, and BM25 indexes:
149
+ * RRF(d) = Σ 1 / (k + rank(d))
150
+ *
151
+ * where k is the fusion parameter (default 60) and rank is the position in each ranking.
152
+ *
153
+ * TODO: Phase 2 - Integrate with sparse/BM25 results once available
154
+ *
155
+ * @param denseResults - Results from dense search
156
+ * @param sparseResults - Results from sparse search
157
+ * @param bm25Results - Results from BM25 search
158
+ * @param k - RRF fusion parameter (default: 60)
159
+ * @returns Fused results sorted by RRF score
160
+ */
161
+ static rrfFusion(denseResults, sparseResults = [], bm25Results = [], k = 60) {
162
+ // Create a map to accumulate scores
163
+ const resultMap = new Map();
164
+ // Process dense results
165
+ denseResults.forEach((result, index) => {
166
+ const rrfScore = 1 / (k + index + 1);
167
+ resultMap.set(result.id, {
168
+ id: result.id,
169
+ denseScore: result.score,
170
+ fusedScore: rrfScore,
171
+ payload: result.payload,
172
+ rank: 0, // Will be set after final sort
173
+ });
174
+ });
175
+ // Process sparse results
176
+ sparseResults.forEach((result, index) => {
177
+ const rrfScore = 1 / (k + index + 1);
178
+ const existing = resultMap.get(result.id);
179
+ if (existing) {
180
+ existing.sparseScore = result.score;
181
+ existing.fusedScore += rrfScore;
182
+ }
183
+ else {
184
+ resultMap.set(result.id, {
185
+ id: result.id,
186
+ sparseScore: result.score,
187
+ fusedScore: rrfScore,
188
+ payload: result.payload,
189
+ rank: 0,
190
+ });
191
+ }
192
+ });
193
+ // Process BM25 results
194
+ bm25Results.forEach((result, index) => {
195
+ const rrfScore = 1 / (k + index + 1);
196
+ const existing = resultMap.get(result.id);
197
+ if (existing) {
198
+ existing.bm25Score = result.score;
199
+ existing.fusedScore += rrfScore;
200
+ }
201
+ else {
202
+ resultMap.set(result.id, {
203
+ id: result.id,
204
+ bm25Score: result.score,
205
+ fusedScore: rrfScore,
206
+ payload: result.payload,
207
+ rank: 0,
208
+ });
209
+ }
210
+ });
211
+ // Sort by fused score and assign ranks
212
+ const fused = Array.from(resultMap.values())
213
+ .sort((a, b) => b.fusedScore - a.fusedScore)
214
+ .map((result, index) => {
215
+ result.rank = index + 1;
216
+ return result;
217
+ });
218
+ return fused;
219
+ }
220
+ /**
221
+ * Hybrid search combining all available indexes
222
+ *
223
+ * Currently implements dense search only. Will be extended to include
224
+ * sparse vectors and BM25 once those are implemented in Phase 2.
225
+ *
226
+ * Pipeline:
227
+ * 1. Dense vector search (semantic search)
228
+ * 2. Sparse vector search (keyword-level semantics)
229
+ * 3. BM25 full-text search
230
+ * 4. Reciprocal Rank Fusion
231
+ *
232
+ * @param queryVector - Query embedding (1024-dim for BGE-large)
233
+ * @param topK - Number of final results to return (default: 5)
234
+ * @returns Array of fused results ranked by combined scores
235
+ */
236
+ async hybridSearch(queryVector, topK = 5) {
237
+ // Phase 1: Dense search only
238
+ const denseResults = await this.denseSearch(queryVector, topK);
239
+ // Phase 2: Will add sparse and BM25
240
+ // const sparseResults = await this.sparseSearch(querySparseVector, topK);
241
+ // const bm25Results = await this.bm25Search(queryText, topK);
242
+ // Combine results with RRF
243
+ const fused = HybridSearchEngine.rrfFusion(denseResults);
244
+ return fused.slice(0, topK);
245
+ }
246
+ /**
247
+ * Add or update a memory record with embedding
248
+ *
249
+ * @param id - Unique identifier for the memory
250
+ * @param vector - Dense embedding (1024-dim)
251
+ * @param payload - Associated metadata (content, timestamp, source, etc.)
252
+ */
253
+ async upsertMemory(id, vector, payload) {
254
+ // Validate vector dimensions and values (SEC-005)
255
+ validateVector(vector, this.vectorSize);
256
+ try {
257
+ await this.client.upsert(this.collectionName, {
258
+ wait: true, // Wait for indexing to complete before returning (fixes race condition)
259
+ points: [
260
+ {
261
+ id: id,
262
+ vector: vector,
263
+ payload: payload || {},
264
+ },
265
+ ],
266
+ });
267
+ }
268
+ catch (error) {
269
+ console.error("Failed to upsert memory:", error instanceof Error ? error.message : error);
270
+ throw error;
271
+ }
272
+ }
273
+ /**
274
+ * Delete a memory record
275
+ *
276
+ * @param id - Unique identifier of the memory to delete
277
+ */
278
+ async deleteMemory(id) {
279
+ try {
280
+ await this.client.delete(this.collectionName, {
281
+ wait: true, // Wait for deletion to complete before returning
282
+ points: [id],
283
+ });
284
+ }
285
+ catch (error) {
286
+ console.error("Failed to delete memory:", error instanceof Error ? error.message : error);
287
+ throw error;
288
+ }
289
+ }
290
+ /**
291
+ * Get collection statistics
292
+ *
293
+ * @returns Object containing collection size, vector count, etc.
294
+ */
295
+ async getCollectionStats() {
296
+ try {
297
+ const info = await this.client.getCollection(this.collectionName);
298
+ return {
299
+ pointsCount: info.points_count,
300
+ indexedVectorsCount: info.indexed_vectors_count,
301
+ segmentsCount: info.segments_count,
302
+ status: info.status,
303
+ };
304
+ }
305
+ catch (error) {
306
+ console.error("Failed to get collection stats:", error instanceof Error ? error.message : error);
307
+ throw error;
308
+ }
309
+ }
310
+ }
311
+ /**
312
+ * Factory function to create and initialize a hybrid search engine
313
+ *
314
+ * Usage:
315
+ * ```typescript
316
+ * const engine = await createHybridSearchEngine();
317
+ * const results = await engine.hybridSearch(queryVector);
318
+ * ```
319
+ *
320
+ * @param qdrantUrl - Qdrant server URL (default: http://localhost:6333)
321
+ * @param collectionName - Name of the collection (default: memory-vectors)
322
+ * @param vectorSize - Dimension of dense vectors (default: 1024 for BGE-large)
323
+ * @param apiKey - Optional Qdrant API key for authentication
324
+ */
325
+ export async function createHybridSearchEngine(qdrantUrl, collectionName, vectorSize, apiKey) {
326
+ const engine = new HybridSearchEngine(qdrantUrl, collectionName, vectorSize, apiKey);
327
+ await engine.initializeCollection();
328
+ return engine;
329
+ }
330
+ //# sourceMappingURL=hybrid-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.js","sourceRoot":"","sources":["../../src/retrieval/hybrid-search.ts"],"names":[],"mappings":"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"}