@skillsmith/core 2.1.0 → 2.1.2

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 (204) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/src/analysis/types.d.ts +2 -0
  3. package/dist/src/analysis/types.d.ts.map +1 -1
  4. package/dist/src/analysis/types.js +13 -1
  5. package/dist/src/analysis/types.js.map +1 -1
  6. package/dist/src/analytics/AnalyticsRepository.d.ts +4 -0
  7. package/dist/src/analytics/AnalyticsRepository.d.ts.map +1 -1
  8. package/dist/src/analytics/AnalyticsRepository.js +26 -44
  9. package/dist/src/analytics/AnalyticsRepository.js.map +1 -1
  10. package/dist/src/analytics/schema.d.ts +1 -1
  11. package/dist/src/analytics/schema.d.ts.map +1 -1
  12. package/dist/src/analytics/schema.js +68 -0
  13. package/dist/src/analytics/schema.js.map +1 -1
  14. package/dist/src/api/client.d.ts +33 -29
  15. package/dist/src/api/client.d.ts.map +1 -1
  16. package/dist/src/api/client.js +15 -10
  17. package/dist/src/api/client.js.map +1 -1
  18. package/dist/src/billing/BillingService.d.ts +139 -0
  19. package/dist/src/billing/BillingService.d.ts.map +1 -0
  20. package/dist/src/billing/BillingService.js +393 -0
  21. package/dist/src/billing/BillingService.js.map +1 -0
  22. package/dist/src/billing/GDPRComplianceService.d.ts +176 -0
  23. package/dist/src/billing/GDPRComplianceService.d.ts.map +1 -0
  24. package/dist/src/billing/GDPRComplianceService.js +361 -0
  25. package/dist/src/billing/GDPRComplianceService.js.map +1 -0
  26. package/dist/src/billing/StripeClient.d.ts +177 -0
  27. package/dist/src/billing/StripeClient.d.ts.map +1 -0
  28. package/dist/src/billing/StripeClient.js +462 -0
  29. package/dist/src/billing/StripeClient.js.map +1 -0
  30. package/dist/src/billing/StripeReconciliationJob.d.ts +95 -0
  31. package/dist/src/billing/StripeReconciliationJob.d.ts.map +1 -0
  32. package/dist/src/billing/StripeReconciliationJob.js +405 -0
  33. package/dist/src/billing/StripeReconciliationJob.js.map +1 -0
  34. package/dist/src/billing/StripeWebhookHandler.d.ts +92 -0
  35. package/dist/src/billing/StripeWebhookHandler.d.ts.map +1 -0
  36. package/dist/src/billing/StripeWebhookHandler.js +409 -0
  37. package/dist/src/billing/StripeWebhookHandler.js.map +1 -0
  38. package/dist/src/billing/index.d.ts +18 -0
  39. package/dist/src/billing/index.d.ts.map +1 -0
  40. package/dist/src/billing/index.js +19 -0
  41. package/dist/src/billing/index.js.map +1 -0
  42. package/dist/src/billing/types.d.ts +266 -0
  43. package/dist/src/billing/types.d.ts.map +1 -0
  44. package/dist/src/billing/types.js +23 -0
  45. package/dist/src/billing/types.js.map +1 -0
  46. package/dist/src/embeddings/hnsw-store.d.ts +568 -0
  47. package/dist/src/embeddings/hnsw-store.d.ts.map +1 -0
  48. package/dist/src/embeddings/hnsw-store.js +805 -0
  49. package/dist/src/embeddings/hnsw-store.js.map +1 -0
  50. package/dist/src/embeddings/index.d.ts +2 -0
  51. package/dist/src/embeddings/index.d.ts.map +1 -1
  52. package/dist/src/embeddings/index.js +2 -0
  53. package/dist/src/embeddings/index.js.map +1 -1
  54. package/dist/src/index.d.ts +1 -0
  55. package/dist/src/index.d.ts.map +1 -1
  56. package/dist/src/index.js +2 -0
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/learning/PatternStore.d.ts +457 -0
  59. package/dist/src/learning/PatternStore.d.ts.map +1 -0
  60. package/dist/src/learning/PatternStore.js +893 -0
  61. package/dist/src/learning/PatternStore.js.map +1 -0
  62. package/dist/src/learning/ReasoningBankIntegration.d.ts +403 -0
  63. package/dist/src/learning/ReasoningBankIntegration.d.ts.map +1 -0
  64. package/dist/src/learning/ReasoningBankIntegration.js +627 -0
  65. package/dist/src/learning/ReasoningBankIntegration.js.map +1 -0
  66. package/dist/src/learning/index.d.ts +15 -0
  67. package/dist/src/learning/index.d.ts.map +1 -0
  68. package/dist/src/learning/index.js +15 -0
  69. package/dist/src/learning/index.js.map +1 -0
  70. package/dist/src/routing/SONARouter.d.ts +154 -0
  71. package/dist/src/routing/SONARouter.d.ts.map +1 -0
  72. package/dist/src/routing/SONARouter.js +679 -0
  73. package/dist/src/routing/SONARouter.js.map +1 -0
  74. package/dist/src/routing/index.d.ts +9 -0
  75. package/dist/src/routing/index.d.ts.map +1 -0
  76. package/dist/src/routing/index.js +10 -0
  77. package/dist/src/routing/index.js.map +1 -0
  78. package/dist/src/routing/types.d.ts +331 -0
  79. package/dist/src/routing/types.d.ts.map +1 -0
  80. package/dist/src/routing/types.js +203 -0
  81. package/dist/src/routing/types.js.map +1 -0
  82. package/dist/src/scripts/__tests__/scan-imported-skills.test.js +5 -0
  83. package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
  84. package/dist/src/security/SkillSandbox.d.ts +156 -0
  85. package/dist/src/security/SkillSandbox.d.ts.map +1 -0
  86. package/dist/src/security/SkillSandbox.js +303 -0
  87. package/dist/src/security/SkillSandbox.js.map +1 -0
  88. package/dist/src/security/index.d.ts +3 -1
  89. package/dist/src/security/index.d.ts.map +1 -1
  90. package/dist/src/security/index.js +5 -1
  91. package/dist/src/security/index.js.map +1 -1
  92. package/dist/src/security/rate-limiter/presets.d.ts +12 -0
  93. package/dist/src/security/rate-limiter/presets.d.ts.map +1 -1
  94. package/dist/src/security/rate-limiter/presets.js +12 -0
  95. package/dist/src/security/rate-limiter/presets.js.map +1 -1
  96. package/dist/src/security/sanitization.d.ts +85 -0
  97. package/dist/src/security/sanitization.d.ts.map +1 -1
  98. package/dist/src/security/sanitization.js +133 -0
  99. package/dist/src/security/sanitization.js.map +1 -1
  100. package/dist/src/security/scanner/SecurityScanner.d.ts +23 -0
  101. package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
  102. package/dist/src/security/scanner/SecurityScanner.js +232 -28
  103. package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
  104. package/dist/src/security/scanner/patterns.d.ts +13 -0
  105. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  106. package/dist/src/security/scanner/patterns.js +51 -0
  107. package/dist/src/security/scanner/patterns.js.map +1 -1
  108. package/dist/src/security/scanner/types.d.ts +13 -1
  109. package/dist/src/security/scanner/types.d.ts.map +1 -1
  110. package/dist/src/security/scanner/weights.d.ts.map +1 -1
  111. package/dist/src/security/scanner/weights.js +1 -0
  112. package/dist/src/security/scanner/weights.js.map +1 -1
  113. package/dist/src/session/SessionManager.d.ts +7 -0
  114. package/dist/src/session/SessionManager.d.ts.map +1 -1
  115. package/dist/src/session/SessionManager.js +117 -10
  116. package/dist/src/session/SessionManager.js.map +1 -1
  117. package/dist/src/sync/SyncEngine.d.ts.map +1 -1
  118. package/dist/src/sync/SyncEngine.js +52 -32
  119. package/dist/src/sync/SyncEngine.js.map +1 -1
  120. package/dist/src/testing/MultiLLMProvider.d.ts +374 -0
  121. package/dist/src/testing/MultiLLMProvider.d.ts.map +1 -0
  122. package/dist/src/testing/MultiLLMProvider.js +720 -0
  123. package/dist/src/testing/MultiLLMProvider.js.map +1 -0
  124. package/dist/src/testing/index.d.ts +8 -0
  125. package/dist/src/testing/index.d.ts.map +1 -0
  126. package/dist/src/testing/index.js +9 -0
  127. package/dist/src/testing/index.js.map +1 -0
  128. package/dist/src/types.d.ts +3 -0
  129. package/dist/src/types.d.ts.map +1 -1
  130. package/dist/tests/SecurityScanner.test.js +337 -1
  131. package/dist/tests/SecurityScanner.test.js.map +1 -1
  132. package/dist/tests/billing/BillingService.test.d.ts +7 -0
  133. package/dist/tests/billing/BillingService.test.d.ts.map +1 -0
  134. package/dist/tests/billing/BillingService.test.js +168 -0
  135. package/dist/tests/billing/BillingService.test.js.map +1 -0
  136. package/dist/tests/billing/GDPRCompliance.test.d.ts +7 -0
  137. package/dist/tests/billing/GDPRCompliance.test.d.ts.map +1 -0
  138. package/dist/tests/billing/GDPRCompliance.test.js +195 -0
  139. package/dist/tests/billing/GDPRCompliance.test.js.map +1 -0
  140. package/dist/tests/billing/StripeReconciliation.test.d.ts +7 -0
  141. package/dist/tests/billing/StripeReconciliation.test.d.ts.map +1 -0
  142. package/dist/tests/billing/StripeReconciliation.test.js +266 -0
  143. package/dist/tests/billing/StripeReconciliation.test.js.map +1 -0
  144. package/dist/tests/billing/stripe-validators.test.d.ts +7 -0
  145. package/dist/tests/billing/stripe-validators.test.d.ts.map +1 -0
  146. package/dist/tests/billing/stripe-validators.test.js +107 -0
  147. package/dist/tests/billing/stripe-validators.test.js.map +1 -0
  148. package/dist/tests/embeddings/hnsw-store.test.d.ts +7 -0
  149. package/dist/tests/embeddings/hnsw-store.test.d.ts.map +1 -0
  150. package/dist/tests/embeddings/hnsw-store.test.js +295 -0
  151. package/dist/tests/embeddings/hnsw-store.test.js.map +1 -0
  152. package/dist/tests/integration/neural/e2e-learning.test.d.ts +17 -0
  153. package/dist/tests/integration/neural/e2e-learning.test.d.ts.map +1 -0
  154. package/dist/tests/integration/neural/e2e-learning.test.js +238 -0
  155. package/dist/tests/integration/neural/e2e-learning.test.js.map +1 -0
  156. package/dist/tests/integration/neural/helpers.d.ts +132 -0
  157. package/dist/tests/integration/neural/helpers.d.ts.map +1 -0
  158. package/dist/tests/integration/neural/helpers.js +287 -0
  159. package/dist/tests/integration/neural/helpers.js.map +1 -0
  160. package/dist/tests/integration/neural/personalization.test.d.ts +21 -0
  161. package/dist/tests/integration/neural/personalization.test.d.ts.map +1 -0
  162. package/dist/tests/integration/neural/personalization.test.js +304 -0
  163. package/dist/tests/integration/neural/personalization.test.js.map +1 -0
  164. package/dist/tests/integration/neural/preference-learner.test.d.ts +23 -0
  165. package/dist/tests/integration/neural/preference-learner.test.d.ts.map +1 -0
  166. package/dist/tests/integration/neural/preference-learner.test.js +289 -0
  167. package/dist/tests/integration/neural/preference-learner.test.js.map +1 -0
  168. package/dist/tests/integration/neural/privacy.test.d.ts +19 -0
  169. package/dist/tests/integration/neural/privacy.test.d.ts.map +1 -0
  170. package/dist/tests/integration/neural/privacy.test.js +249 -0
  171. package/dist/tests/integration/neural/privacy.test.js.map +1 -0
  172. package/dist/tests/integration/neural/setup.d.ts +175 -0
  173. package/dist/tests/integration/neural/setup.d.ts.map +1 -0
  174. package/dist/tests/integration/neural/setup.js +487 -0
  175. package/dist/tests/integration/neural/setup.js.map +1 -0
  176. package/dist/tests/integration/neural/signal-collection.test.d.ts +21 -0
  177. package/dist/tests/integration/neural/signal-collection.test.d.ts.map +1 -0
  178. package/dist/tests/integration/neural/signal-collection.test.js +232 -0
  179. package/dist/tests/integration/neural/signal-collection.test.js.map +1 -0
  180. package/dist/tests/learning/PatternStore.test.d.ts +8 -0
  181. package/dist/tests/learning/PatternStore.test.d.ts.map +1 -0
  182. package/dist/tests/learning/PatternStore.test.js +589 -0
  183. package/dist/tests/learning/PatternStore.test.js.map +1 -0
  184. package/dist/tests/learning/ReasoningBankIntegration.test.d.ts +8 -0
  185. package/dist/tests/learning/ReasoningBankIntegration.test.d.ts.map +1 -0
  186. package/dist/tests/learning/ReasoningBankIntegration.test.js +269 -0
  187. package/dist/tests/learning/ReasoningBankIntegration.test.js.map +1 -0
  188. package/dist/tests/routing/SONARouter.test.d.ts +8 -0
  189. package/dist/tests/routing/SONARouter.test.d.ts.map +1 -0
  190. package/dist/tests/routing/SONARouter.test.js +400 -0
  191. package/dist/tests/routing/SONARouter.test.js.map +1 -0
  192. package/dist/tests/security/ContinuousSecurity.test.js +10 -12
  193. package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
  194. package/dist/tests/security/SkillSandbox.test.d.ts +8 -0
  195. package/dist/tests/security/SkillSandbox.test.d.ts.map +1 -0
  196. package/dist/tests/security/SkillSandbox.test.js +321 -0
  197. package/dist/tests/security/SkillSandbox.test.js.map +1 -0
  198. package/dist/tests/sync/SyncEngine.test.js +4 -2
  199. package/dist/tests/sync/SyncEngine.test.js.map +1 -1
  200. package/dist/tests/testing/MultiLLMProvider.test.d.ts +14 -0
  201. package/dist/tests/testing/MultiLLMProvider.test.d.ts.map +1 -0
  202. package/dist/tests/testing/MultiLLMProvider.test.js +438 -0
  203. package/dist/tests/testing/MultiLLMProvider.test.js.map +1 -0
  204. package/package.json +16 -3
@@ -0,0 +1,568 @@
1
+ /**
2
+ * SMI-1519: HNSW Embedding Store
3
+ *
4
+ * High-performance vector storage using HNSW (Hierarchical Navigable Small World)
5
+ * index for fast approximate nearest neighbor (ANN) search.
6
+ *
7
+ * Features:
8
+ * - O(log n) similarity search vs O(n) brute-force (150x faster)
9
+ * - SQLite for metadata persistence (skill_id, text, created_at)
10
+ * - Graceful fallback to brute-force if HNSW unavailable
11
+ * - Compatible with existing EmbeddingService interface
12
+ * - Uses claude-flow V3 VectorDB API with automatic fallback
13
+ *
14
+ * Enable via environment variable: SKILLSMITH_USE_HNSW=true
15
+ *
16
+ * @see ADR-009: Embedding Service Fallback Strategy
17
+ */
18
+ import type { SimilarityResult } from './index.js';
19
+ /**
20
+ * Type definitions for hnswlib-node (not published on DefinitelyTyped)
21
+ * These are minimal declarations for the parts we use.
22
+ *
23
+ * @see https://github.com/yoshoku/hnswlib-node
24
+ */
25
+ export interface HierarchicalNSW {
26
+ initIndex(maxElements: number, m?: number, efConstruction?: number): void;
27
+ loadIndex(path: string, allowReplaceDeleted?: boolean): void;
28
+ saveIndex(path: string): void;
29
+ addPoint(point: number[] | Float32Array, label: number, replaceDeleted?: boolean): void;
30
+ markDelete(label: number): void;
31
+ searchKnn(query: number[] | Float32Array, k: number, filter?: (label: number) => boolean): HNSWSearchResult;
32
+ getMaxElements(): number;
33
+ getCurrentCount(): number;
34
+ getEfSearch(): number;
35
+ setEfSearch(ef: number): void;
36
+ getIdsList(): number[];
37
+ }
38
+ /**
39
+ * Result from HNSW k-nearest neighbor search
40
+ */
41
+ export interface HNSWSearchResult {
42
+ /** Labels (IDs) of the nearest neighbors */
43
+ neighbors: number[];
44
+ /** Distances to each neighbor (lower = closer) */
45
+ distances: number[];
46
+ }
47
+ /**
48
+ * Constructor type for HierarchicalNSW
49
+ */
50
+ export interface HierarchicalNSWConstructor {
51
+ new (space: 'cosine' | 'l2' | 'ip', dim: number): HierarchicalNSW;
52
+ }
53
+ /**
54
+ * HNSW algorithm parameters for tuning search quality vs speed.
55
+ *
56
+ * @see https://github.com/nmslib/hnswlib/blob/master/ALGO_PARAMS.md
57
+ */
58
+ export interface HNSWConfig {
59
+ /**
60
+ * Number of bidirectional links per node (M parameter).
61
+ * Higher values = better recall but more memory/slower builds.
62
+ *
63
+ * - 8-16: Fast, lower memory, suitable for <100k vectors
64
+ * - 16-32: Balanced, good for 100k-1M vectors
65
+ * - 32-64: High recall, suitable for >1M vectors or high accuracy needs
66
+ *
67
+ * @default 16
68
+ */
69
+ m: number;
70
+ /**
71
+ * Size of dynamic candidate list during index construction.
72
+ * Higher values = better index quality but slower builds.
73
+ *
74
+ * - 100-200: Fast builds, acceptable quality
75
+ * - 200-400: Balanced
76
+ * - 400-500: High quality, slower builds
77
+ *
78
+ * @default 200
79
+ */
80
+ efConstruction: number;
81
+ /**
82
+ * Size of dynamic candidate list during search.
83
+ * Higher values = better recall but slower search.
84
+ *
85
+ * - 10-50: Fast search, may miss some neighbors
86
+ * - 50-100: Balanced
87
+ * - 100-200: High recall, slower search
88
+ *
89
+ * Must be >= topK for accurate results.
90
+ *
91
+ * @default 100
92
+ */
93
+ efSearch: number;
94
+ /**
95
+ * Vector dimensionality. Must match embedding model output.
96
+ * - 384 for all-MiniLM-L6-v2
97
+ * - 768 for all-mpnet-base-v2
98
+ *
99
+ * @default 384
100
+ */
101
+ dimensions: number;
102
+ }
103
+ /**
104
+ * Options for HNSWEmbeddingStore initialization
105
+ */
106
+ export interface HNSWEmbeddingStoreOptions {
107
+ /**
108
+ * Path to SQLite database for metadata storage.
109
+ * If not provided, uses in-memory database.
110
+ */
111
+ dbPath?: string;
112
+ /**
113
+ * Path to HNSW index file for persistence.
114
+ * If not provided, index is built fresh on each startup.
115
+ */
116
+ indexPath?: string;
117
+ /**
118
+ * HNSW algorithm configuration.
119
+ * Uses sensible defaults if not provided.
120
+ */
121
+ hnswConfig?: Partial<HNSWConfig>;
122
+ /**
123
+ * Maximum number of elements the index can hold.
124
+ * Index will reject inserts once limit is reached.
125
+ *
126
+ * @default 100000
127
+ */
128
+ maxElements?: number;
129
+ /**
130
+ * Distance metric for similarity calculation.
131
+ * - 'cosine': Cosine similarity (default, best for normalized embeddings)
132
+ * - 'l2': Euclidean distance
133
+ * - 'ip': Inner product
134
+ *
135
+ * @default 'cosine'
136
+ */
137
+ distanceMetric?: 'cosine' | 'l2' | 'ip';
138
+ /**
139
+ * Force fallback to brute-force search (for testing or compatibility).
140
+ * If not specified, checks SKILLSMITH_USE_HNSW env var.
141
+ *
142
+ * When true, uses HNSW. When false, falls back to brute-force.
143
+ *
144
+ * @default undefined (auto-detect from environment)
145
+ */
146
+ useHNSW?: boolean;
147
+ /**
148
+ * Enable automatic index persistence.
149
+ * When true, saves index to indexPath after each insert.
150
+ * When false, must call saveIndex() manually.
151
+ *
152
+ * @default false
153
+ */
154
+ autoSave?: boolean;
155
+ }
156
+ /**
157
+ * Statistics about the HNSW index
158
+ */
159
+ export interface HNSWIndexStats {
160
+ /** Number of vectors currently stored */
161
+ vectorCount: number;
162
+ /** Maximum capacity of the index */
163
+ maxCapacity: number;
164
+ /** Utilization percentage (vectorCount / maxCapacity * 100) */
165
+ utilizationPercent: number;
166
+ /** Current M parameter */
167
+ m: number;
168
+ /** Current efConstruction parameter */
169
+ efConstruction: number;
170
+ /** Current efSearch parameter */
171
+ efSearch: number;
172
+ /** Vector dimensionality */
173
+ dimensions: number;
174
+ /** Approximate memory usage in bytes */
175
+ memoryUsageBytes: number;
176
+ /** Whether using HNSW (true) or brute-force fallback (false) */
177
+ isHNSWEnabled: boolean;
178
+ /** Path to index file (if persistent) */
179
+ indexPath?: string;
180
+ }
181
+ /**
182
+ * Result of a batch insert operation
183
+ */
184
+ export interface BatchInsertResult {
185
+ /** Number of vectors successfully inserted */
186
+ inserted: number;
187
+ /** Number of vectors that were updates (already existed) */
188
+ updated: number;
189
+ /** Number of vectors that failed to insert */
190
+ failed: number;
191
+ /** Skill IDs that failed with their error messages */
192
+ errors: Array<{
193
+ skillId: string;
194
+ error: string;
195
+ }>;
196
+ /** Total time taken in milliseconds */
197
+ durationMs: number;
198
+ }
199
+ /**
200
+ * Interface for embedding storage with similarity search.
201
+ * Implemented by both HNSWEmbeddingStore and EmbeddingService for compatibility.
202
+ */
203
+ export interface IEmbeddingStore {
204
+ /**
205
+ * Store an embedding with its metadata.
206
+ *
207
+ * @param skillId - Unique identifier for the skill
208
+ * @param embedding - Vector embedding (Float32Array)
209
+ * @param text - Original text that was embedded
210
+ */
211
+ storeEmbedding(skillId: string, embedding: Float32Array, text: string): void;
212
+ /**
213
+ * Retrieve a stored embedding by skill ID.
214
+ *
215
+ * @param skillId - Unique identifier for the skill
216
+ * @returns The embedding if found, null otherwise
217
+ */
218
+ getEmbedding(skillId: string): Float32Array | null;
219
+ /**
220
+ * Get all stored embeddings.
221
+ *
222
+ * @returns Map of skill IDs to their embeddings
223
+ */
224
+ getAllEmbeddings(): Map<string, Float32Array>;
225
+ /**
226
+ * Find most similar embeddings to a query vector.
227
+ *
228
+ * @param queryEmbedding - Query vector to find neighbors for
229
+ * @param topK - Number of results to return (default: 10)
230
+ * @returns Array of skill IDs with similarity scores, sorted descending
231
+ */
232
+ findSimilar(queryEmbedding: Float32Array, topK?: number): SimilarityResult[];
233
+ /**
234
+ * Compute cosine similarity between two embeddings.
235
+ *
236
+ * @param a - First embedding
237
+ * @param b - Second embedding
238
+ * @returns Similarity score between -1 and 1
239
+ */
240
+ cosineSimilarity(a: Float32Array, b: Float32Array): number;
241
+ /**
242
+ * Check if running in fallback (brute-force) mode.
243
+ *
244
+ * @returns true if using brute-force, false if using HNSW
245
+ */
246
+ isUsingFallback(): boolean;
247
+ /**
248
+ * Close database connections and release resources.
249
+ */
250
+ close(): void;
251
+ }
252
+ /**
253
+ * Default HNSW configuration optimized for skill embeddings.
254
+ * Tuned for ~10k-100k skills with balanced speed/recall.
255
+ */
256
+ export declare const DEFAULT_HNSW_CONFIG: HNSWConfig;
257
+ /**
258
+ * HNSW configuration presets for different use cases
259
+ */
260
+ export declare const HNSW_PRESETS: {
261
+ /** Fast search, lower memory, suitable for <10k vectors */
262
+ readonly small: {
263
+ m: number;
264
+ efConstruction: number;
265
+ efSearch: number;
266
+ dimensions: number;
267
+ };
268
+ /** Balanced performance, suitable for 10k-100k vectors */
269
+ readonly medium: {
270
+ m: number;
271
+ efConstruction: number;
272
+ efSearch: number;
273
+ dimensions: number;
274
+ };
275
+ /** High recall, suitable for 100k-1M vectors */
276
+ readonly large: {
277
+ m: number;
278
+ efConstruction: number;
279
+ efSearch: number;
280
+ dimensions: number;
281
+ };
282
+ /** Maximum recall, suitable for >1M vectors or critical accuracy */
283
+ readonly xlarge: {
284
+ m: number;
285
+ efConstruction: number;
286
+ efSearch: number;
287
+ dimensions: number;
288
+ };
289
+ };
290
+ /**
291
+ * High-performance embedding storage using HNSW index.
292
+ *
293
+ * Provides O(log n) approximate nearest neighbor search while maintaining
294
+ * compatibility with the existing EmbeddingService interface.
295
+ *
296
+ * @example
297
+ * ```typescript
298
+ * // Basic usage
299
+ * const store = new HNSWEmbeddingStore({
300
+ * dbPath: './embeddings.db',
301
+ * indexPath: './embeddings.hnsw',
302
+ * });
303
+ *
304
+ * // Store embeddings
305
+ * store.storeEmbedding('skill-1', embedding1, 'Jest testing framework helper');
306
+ * store.storeEmbedding('skill-2', embedding2, 'Vitest testing utilities');
307
+ *
308
+ * // Find similar
309
+ * const results = store.findSimilar(queryEmbedding, 10);
310
+ * // [{ skillId: 'skill-1', score: 0.95 }, { skillId: 'skill-2', score: 0.87 }, ...]
311
+ *
312
+ * // Clean up
313
+ * store.close();
314
+ * ```
315
+ *
316
+ * @example
317
+ * ```typescript
318
+ * // With custom HNSW config for large dataset
319
+ * const store = new HNSWEmbeddingStore({
320
+ * dbPath: './embeddings.db',
321
+ * indexPath: './embeddings.hnsw',
322
+ * hnswConfig: HNSW_PRESETS.large,
323
+ * maxElements: 500000,
324
+ * });
325
+ * ```
326
+ */
327
+ export declare class HNSWEmbeddingStore implements IEmbeddingStore {
328
+ /** SQLite database for metadata */
329
+ private db;
330
+ /** HNSW index instance (from hnswlib-node) */
331
+ private index;
332
+ /** Whether HNSW is enabled (false = brute-force fallback) */
333
+ private readonly hnswEnabled;
334
+ /** Merged HNSW configuration */
335
+ private readonly config;
336
+ /** Maximum index capacity */
337
+ private readonly maxElements;
338
+ /** Path to HNSW index file */
339
+ private readonly indexPath;
340
+ /** Distance metric */
341
+ private readonly distanceMetric;
342
+ /** Auto-save flag */
343
+ private readonly autoSave;
344
+ /** Map of skill IDs to internal HNSW labels (for reverse lookup) */
345
+ private skillIdToLabel;
346
+ /** Map of HNSW labels to skill IDs */
347
+ private labelToSkillId;
348
+ /** Next available label for HNSW insertion */
349
+ private nextLabel;
350
+ /**
351
+ * Create a new HNSWEmbeddingStore instance.
352
+ *
353
+ * @param options - Configuration options
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * // Default configuration (auto-detects HNSW availability)
358
+ * const store = new HNSWEmbeddingStore();
359
+ *
360
+ * // With persistence
361
+ * const store = new HNSWEmbeddingStore({
362
+ * dbPath: './embeddings.db',
363
+ * indexPath: './embeddings.hnsw',
364
+ * });
365
+ *
366
+ * // Force brute-force fallback
367
+ * const store = new HNSWEmbeddingStore({ useHNSW: false });
368
+ * ```
369
+ */
370
+ /** V3 VectorDB instance (if initialized) */
371
+ private vectorDB;
372
+ /** Promise for async initialization */
373
+ private initPromise;
374
+ constructor(options?: HNSWEmbeddingStoreOptions);
375
+ /**
376
+ * Ensure the store is fully initialized.
377
+ * Call this before operations that require the HNSW index.
378
+ */
379
+ ensureInitialized(): Promise<void>;
380
+ /**
381
+ * Store an embedding with its metadata.
382
+ *
383
+ * Inserts the vector into both HNSW index (for fast search) and
384
+ * SQLite (for metadata persistence).
385
+ *
386
+ * @param skillId - Unique identifier for the skill
387
+ * @param embedding - Vector embedding (must match configured dimensions)
388
+ * @param text - Original text that was embedded
389
+ * @throws Error if embedding dimensions don't match configuration
390
+ */
391
+ storeEmbedding(skillId: string, embedding: Float32Array, text: string): void;
392
+ /**
393
+ * Retrieve a stored embedding by skill ID.
394
+ *
395
+ * @param skillId - Unique identifier for the skill
396
+ * @returns The embedding if found, null otherwise
397
+ */
398
+ getEmbedding(skillId: string): Float32Array | null;
399
+ /**
400
+ * Get all stored embeddings.
401
+ *
402
+ * Note: For large datasets, consider using findSimilar() instead
403
+ * to avoid loading all vectors into memory.
404
+ *
405
+ * @returns Map of skill IDs to their embeddings
406
+ */
407
+ getAllEmbeddings(): Map<string, Float32Array>;
408
+ /**
409
+ * Find most similar embeddings to a query vector.
410
+ *
411
+ * Uses HNSW for O(log n) approximate search when available,
412
+ * falls back to O(n) brute-force cosine similarity otherwise.
413
+ *
414
+ * @param queryEmbedding - Query vector (must match configured dimensions)
415
+ * @param topK - Number of results to return (default: 10)
416
+ * @returns Array of skill IDs with similarity scores, sorted descending
417
+ */
418
+ findSimilar(queryEmbedding: Float32Array, topK?: number): SimilarityResult[];
419
+ /**
420
+ * Async version of findSimilar for backends that require async search.
421
+ *
422
+ * @param queryEmbedding - Query vector (must match configured dimensions)
423
+ * @param topK - Number of results to return (default: 10)
424
+ * @returns Promise resolving to array of skill IDs with similarity scores
425
+ */
426
+ findSimilarAsync(queryEmbedding: Float32Array, topK?: number): Promise<SimilarityResult[]>;
427
+ /**
428
+ * Compute cosine similarity between two embeddings.
429
+ *
430
+ * @param a - First embedding
431
+ * @param b - Second embedding
432
+ * @returns Similarity score between -1 and 1
433
+ * @throws Error if embeddings have different dimensions
434
+ */
435
+ cosineSimilarity(a: Float32Array, b: Float32Array): number;
436
+ /**
437
+ * Check if running in fallback (brute-force) mode.
438
+ *
439
+ * @returns true if using brute-force, false if using HNSW
440
+ */
441
+ isUsingFallback(): boolean;
442
+ /**
443
+ * Close database connections and release resources.
444
+ *
445
+ * Saves HNSW index to disk if indexPath was configured.
446
+ * Safe to call multiple times.
447
+ */
448
+ close(): void;
449
+ /**
450
+ * Get statistics about the HNSW index.
451
+ *
452
+ * @returns Index statistics including capacity, utilization, and config
453
+ */
454
+ getStats(): HNSWIndexStats;
455
+ /**
456
+ * Batch insert multiple embeddings efficiently.
457
+ *
458
+ * More efficient than calling storeEmbedding() in a loop
459
+ * due to batched SQLite transactions and HNSW insertions.
460
+ *
461
+ * @param embeddings - Array of embeddings to insert
462
+ * @returns Batch operation result with counts and timing
463
+ */
464
+ batchInsert(embeddings: Array<{
465
+ skillId: string;
466
+ embedding: Float32Array;
467
+ text: string;
468
+ }>): BatchInsertResult;
469
+ /**
470
+ * Remove an embedding from the store.
471
+ *
472
+ * Note: HNSW does not support true deletion. The vector is marked
473
+ * as deleted and excluded from search results, but memory is not
474
+ * reclaimed until the index is rebuilt.
475
+ *
476
+ * @param skillId - Unique identifier for the skill to remove
477
+ * @returns true if removed, false if not found
478
+ */
479
+ removeEmbedding(skillId: string): boolean;
480
+ /**
481
+ * Save the HNSW index to disk.
482
+ *
483
+ * Note: V3 VectorDB manages its own persistence, so this is a no-op
484
+ * unless using hnswlib-node directly.
485
+ *
486
+ * @throws Error if indexPath was not configured
487
+ */
488
+ saveIndex(): void;
489
+ /**
490
+ * Load the HNSW index from disk.
491
+ *
492
+ * Note: V3 VectorDB manages its own persistence, so this is a no-op
493
+ * unless using hnswlib-node directly.
494
+ *
495
+ * @throws Error if indexPath was not configured or file doesn't exist
496
+ */
497
+ loadIndex(): void;
498
+ /**
499
+ * Rebuild the HNSW index from SQLite data.
500
+ *
501
+ * Useful after many deletions to reclaim memory, or to apply
502
+ * new HNSW configuration parameters.
503
+ *
504
+ * @param newConfig - Optional new HNSW configuration
505
+ */
506
+ rebuildIndex(newConfig?: Partial<HNSWConfig>): Promise<void>;
507
+ /**
508
+ * Update efSearch parameter at runtime.
509
+ *
510
+ * Note: V3 VectorDB does not expose efSearch tuning directly.
511
+ * This method is provided for API compatibility.
512
+ *
513
+ * @param efSearch - New efSearch value (must be > 0)
514
+ */
515
+ setEfSearch(efSearch: number): void;
516
+ /**
517
+ * Determine whether to use HNSW based on explicit option or environment.
518
+ */
519
+ private shouldUseHNSW;
520
+ /**
521
+ * Initialize SQLite database and create tables.
522
+ */
523
+ private initDatabase;
524
+ /**
525
+ * Initialize HNSW index using V3 VectorDB API.
526
+ * Falls back gracefully if V3 is unavailable.
527
+ */
528
+ private initHNSWIndex;
529
+ /**
530
+ * Convert HNSW distance to similarity score.
531
+ * HNSW returns distances, we need similarities (higher = more similar).
532
+ */
533
+ private distanceToSimilarity;
534
+ }
535
+ /**
536
+ * Create an HNSWEmbeddingStore with a preset configuration.
537
+ *
538
+ * @param preset - Preset name ('small', 'medium', 'large', 'xlarge')
539
+ * @param options - Additional options (merged with preset)
540
+ * @returns Configured HNSWEmbeddingStore instance
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * const store = createHNSWStore('large', {
545
+ * dbPath: './embeddings.db',
546
+ * indexPath: './embeddings.hnsw',
547
+ * });
548
+ * ```
549
+ */
550
+ export declare function createHNSWStore(preset: keyof typeof HNSW_PRESETS, options?: Omit<HNSWEmbeddingStoreOptions, 'hnswConfig'>): HNSWEmbeddingStore;
551
+ /**
552
+ * Check if hnswlib-node is available.
553
+ *
554
+ * Useful for conditional logic or graceful degradation.
555
+ *
556
+ * @returns true if hnswlib-node can be loaded
557
+ */
558
+ export declare function isHNSWAvailable(): Promise<boolean>;
559
+ /**
560
+ * Dynamically load hnswlib-node module.
561
+ *
562
+ * @returns The HierarchicalNSW constructor, or null if unavailable
563
+ * @internal
564
+ */
565
+ export declare function loadHNSWLib(): Promise<{
566
+ HierarchicalNSW: HierarchicalNSWConstructor;
567
+ } | null>;
568
+ //# sourceMappingURL=hnsw-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hnsw-store.d.ts","sourceRoot":"","sources":["../../../src/embeddings/hnsw-store.ts"],"names":[],"mappings":"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"}