@cmdoss/memwal-sdk 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/ARCHITECTURE.md +547 -547
  2. package/BENCHMARKS.md +238 -238
  3. package/README.md +310 -181
  4. package/dist/ai-sdk/tools.d.ts +2 -2
  5. package/dist/ai-sdk/tools.js +2 -2
  6. package/dist/client/ClientMemoryManager.js +2 -2
  7. package/dist/client/ClientMemoryManager.js.map +1 -1
  8. package/dist/client/PersonalDataWallet.d.ts.map +1 -1
  9. package/dist/client/SimplePDWClient.d.ts +29 -1
  10. package/dist/client/SimplePDWClient.d.ts.map +1 -1
  11. package/dist/client/SimplePDWClient.js +45 -13
  12. package/dist/client/SimplePDWClient.js.map +1 -1
  13. package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
  14. package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
  15. package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
  16. package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
  17. package/dist/client/namespaces/MemoryNamespace.js +272 -39
  18. package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
  19. package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
  20. package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
  21. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
  22. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
  23. package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
  24. package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
  25. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
  26. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
  27. package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
  28. package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
  29. package/dist/config/ConfigurationHelper.js +61 -61
  30. package/dist/config/defaults.js +2 -2
  31. package/dist/config/defaults.js.map +1 -1
  32. package/dist/graph/GraphService.js +21 -21
  33. package/dist/graph/GraphService.js.map +1 -1
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
  39. package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
  40. package/dist/infrastructure/seal/EncryptionService.js +37 -15
  41. package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
  42. package/dist/infrastructure/seal/SealService.d.ts +13 -5
  43. package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
  44. package/dist/infrastructure/seal/SealService.js +36 -34
  45. package/dist/infrastructure/seal/SealService.js.map +1 -1
  46. package/dist/langchain/createPDWRAG.js +30 -30
  47. package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
  48. package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
  49. package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
  50. package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
  51. package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
  52. package/dist/retrieval/MemoryRetrievalService.js +44 -4
  53. package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
  54. package/dist/services/CapabilityService.d.ts.map +1 -1
  55. package/dist/services/CapabilityService.js +30 -14
  56. package/dist/services/CapabilityService.js.map +1 -1
  57. package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
  58. package/dist/services/CrossContextPermissionService.js +9 -7
  59. package/dist/services/CrossContextPermissionService.js.map +1 -1
  60. package/dist/services/EmbeddingService.d.ts +28 -1
  61. package/dist/services/EmbeddingService.d.ts.map +1 -1
  62. package/dist/services/EmbeddingService.js +54 -0
  63. package/dist/services/EmbeddingService.js.map +1 -1
  64. package/dist/services/EncryptionService.d.ts.map +1 -1
  65. package/dist/services/EncryptionService.js +6 -5
  66. package/dist/services/EncryptionService.js.map +1 -1
  67. package/dist/services/GeminiAIService.js +309 -309
  68. package/dist/services/IndexManager.d.ts +5 -1
  69. package/dist/services/IndexManager.d.ts.map +1 -1
  70. package/dist/services/IndexManager.js +17 -40
  71. package/dist/services/IndexManager.js.map +1 -1
  72. package/dist/services/QueryService.js +1 -1
  73. package/dist/services/QueryService.js.map +1 -1
  74. package/dist/services/StorageService.d.ts +11 -0
  75. package/dist/services/StorageService.d.ts.map +1 -1
  76. package/dist/services/StorageService.js +73 -10
  77. package/dist/services/StorageService.js.map +1 -1
  78. package/dist/services/TransactionService.d.ts +20 -0
  79. package/dist/services/TransactionService.d.ts.map +1 -1
  80. package/dist/services/TransactionService.js +43 -0
  81. package/dist/services/TransactionService.js.map +1 -1
  82. package/dist/services/ViewService.js +2 -2
  83. package/dist/services/ViewService.js.map +1 -1
  84. package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
  85. package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
  86. package/dist/services/storage/QuiltBatchManager.js +410 -20
  87. package/dist/services/storage/QuiltBatchManager.js.map +1 -1
  88. package/dist/services/storage/index.d.ts +1 -1
  89. package/dist/services/storage/index.d.ts.map +1 -1
  90. package/dist/services/storage/index.js.map +1 -1
  91. package/dist/utils/LRUCache.d.ts +106 -0
  92. package/dist/utils/LRUCache.d.ts.map +1 -0
  93. package/dist/utils/LRUCache.js +281 -0
  94. package/dist/utils/LRUCache.js.map +1 -0
  95. package/dist/utils/index.d.ts +1 -0
  96. package/dist/utils/index.d.ts.map +1 -1
  97. package/dist/utils/index.js +2 -0
  98. package/dist/utils/index.js.map +1 -1
  99. package/dist/utils/memoryIndexOnChain.d.ts +212 -0
  100. package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
  101. package/dist/utils/memoryIndexOnChain.js +312 -0
  102. package/dist/utils/memoryIndexOnChain.js.map +1 -0
  103. package/dist/utils/rebuildIndexNode.d.ts +29 -0
  104. package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
  105. package/dist/utils/rebuildIndexNode.js +366 -98
  106. package/dist/utils/rebuildIndexNode.js.map +1 -1
  107. package/dist/vector/HnswWasmService.d.ts +20 -5
  108. package/dist/vector/HnswWasmService.d.ts.map +1 -1
  109. package/dist/vector/HnswWasmService.js +73 -40
  110. package/dist/vector/HnswWasmService.js.map +1 -1
  111. package/dist/vector/IHnswService.d.ts +10 -1
  112. package/dist/vector/IHnswService.d.ts.map +1 -1
  113. package/dist/vector/IHnswService.js.map +1 -1
  114. package/dist/vector/NodeHnswService.d.ts +16 -0
  115. package/dist/vector/NodeHnswService.d.ts.map +1 -1
  116. package/dist/vector/NodeHnswService.js +84 -5
  117. package/dist/vector/NodeHnswService.js.map +1 -1
  118. package/dist/vector/createHnswService.d.ts +1 -1
  119. package/dist/vector/createHnswService.js +1 -1
  120. package/dist/vector/index.d.ts +1 -1
  121. package/dist/vector/index.js +1 -1
  122. package/package.json +157 -157
  123. package/src/access/PermissionService.ts +635 -635
  124. package/src/aggregation/AggregationService.ts +389 -389
  125. package/src/ai-sdk/PDWVectorStore.ts +715 -715
  126. package/src/ai-sdk/index.ts +65 -65
  127. package/src/ai-sdk/tools.ts +460 -460
  128. package/src/ai-sdk/types.ts +404 -404
  129. package/src/batch/BatchManager.ts +597 -597
  130. package/src/batch/BatchingService.ts +429 -429
  131. package/src/batch/MemoryProcessingCache.ts +492 -492
  132. package/src/batch/index.ts +30 -30
  133. package/src/browser.ts +200 -200
  134. package/src/client/ClientMemoryManager.ts +987 -987
  135. package/src/client/PersonalDataWallet.ts +345 -345
  136. package/src/client/SimplePDWClient.ts +1289 -1222
  137. package/src/client/factory.ts +154 -154
  138. package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
  139. package/src/client/namespaces/BatchNamespace.ts +356 -356
  140. package/src/client/namespaces/CacheNamespace.ts +123 -123
  141. package/src/client/namespaces/CapabilityNamespace.ts +217 -217
  142. package/src/client/namespaces/ClassifyNamespace.ts +169 -169
  143. package/src/client/namespaces/ContextNamespace.ts +297 -297
  144. package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
  145. package/src/client/namespaces/EncryptionNamespace.ts +221 -221
  146. package/src/client/namespaces/GraphNamespace.ts +468 -468
  147. package/src/client/namespaces/IndexNamespace.ts +361 -361
  148. package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
  149. package/src/client/namespaces/PermissionsNamespace.ts +254 -254
  150. package/src/client/namespaces/PipelineNamespace.ts +220 -220
  151. package/src/client/namespaces/SearchNamespace.ts +1049 -1049
  152. package/src/client/namespaces/StorageNamespace.ts +458 -458
  153. package/src/client/namespaces/TxNamespace.ts +260 -260
  154. package/src/client/namespaces/WalletNamespace.ts +243 -243
  155. package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
  156. package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
  157. package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
  158. package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
  159. package/src/client/namespaces/consolidated/index.ts +39 -39
  160. package/src/client/signers/KeypairSigner.ts +108 -108
  161. package/src/client/signers/UnifiedSigner.ts +110 -110
  162. package/src/client/signers/WalletAdapterSigner.ts +159 -159
  163. package/src/client/signers/index.ts +26 -26
  164. package/src/config/ConfigurationHelper.ts +412 -412
  165. package/src/config/defaults.ts +51 -51
  166. package/src/config/index.ts +8 -8
  167. package/src/config/validation.ts +70 -70
  168. package/src/core/index.ts +14 -14
  169. package/src/core/interfaces/IService.ts +307 -307
  170. package/src/core/interfaces/index.ts +8 -8
  171. package/src/core/types/capability.ts +297 -297
  172. package/src/core/types/index.ts +870 -870
  173. package/src/core/types/wallet.ts +270 -270
  174. package/src/core/types.ts +9 -9
  175. package/src/core/wallet.ts +222 -222
  176. package/src/embedding/index.ts +19 -19
  177. package/src/embedding/types.ts +357 -357
  178. package/src/errors/index.ts +602 -602
  179. package/src/errors/recovery.ts +461 -461
  180. package/src/errors/validation.ts +567 -567
  181. package/src/generated/pdw/capability.ts +319 -319
  182. package/src/graph/GraphService.ts +887 -887
  183. package/src/graph/KnowledgeGraphManager.ts +728 -728
  184. package/src/graph/index.ts +25 -25
  185. package/src/index.ts +498 -474
  186. package/src/infrastructure/index.ts +22 -22
  187. package/src/infrastructure/seal/EncryptionService.ts +628 -603
  188. package/src/infrastructure/seal/SealService.ts +613 -615
  189. package/src/infrastructure/seal/index.ts +9 -9
  190. package/src/infrastructure/sui/BlockchainManager.ts +627 -627
  191. package/src/infrastructure/sui/SuiService.ts +888 -888
  192. package/src/infrastructure/sui/index.ts +9 -9
  193. package/src/infrastructure/walrus/StorageManager.ts +604 -604
  194. package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
  195. package/src/infrastructure/walrus/index.ts +9 -9
  196. package/src/langchain/PDWEmbeddings.ts +145 -145
  197. package/src/langchain/PDWVectorStore.ts +456 -456
  198. package/src/langchain/createPDWRAG.ts +303 -303
  199. package/src/langchain/index.ts +47 -47
  200. package/src/permissions/ConsentRepository.browser.ts +249 -249
  201. package/src/permissions/ConsentRepository.ts +364 -364
  202. package/src/pipeline/MemoryPipeline.ts +862 -862
  203. package/src/pipeline/PipelineManager.ts +683 -683
  204. package/src/pipeline/index.ts +26 -26
  205. package/src/retrieval/AdvancedSearchService.ts +629 -629
  206. package/src/retrieval/MemoryAnalyticsService.ts +711 -711
  207. package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
  208. package/src/retrieval/MemoryRetrievalService.ts +904 -830
  209. package/src/retrieval/index.ts +42 -42
  210. package/src/services/BatchService.ts +352 -352
  211. package/src/services/CapabilityService.ts +464 -448
  212. package/src/services/ClassifierService.ts +465 -465
  213. package/src/services/CrossContextPermissionService.ts +486 -484
  214. package/src/services/EmbeddingService.ts +771 -706
  215. package/src/services/EncryptionService.ts +712 -711
  216. package/src/services/GeminiAIService.ts +753 -753
  217. package/src/services/IndexManager.ts +977 -1004
  218. package/src/services/MemoryIndexService.ts +1003 -1003
  219. package/src/services/MemoryService.ts +369 -369
  220. package/src/services/QueryService.ts +890 -890
  221. package/src/services/StorageService.ts +1182 -1111
  222. package/src/services/TransactionService.ts +838 -790
  223. package/src/services/VectorService.ts +462 -462
  224. package/src/services/ViewService.ts +484 -484
  225. package/src/services/index.ts +25 -25
  226. package/src/services/storage/BlobAttributesManager.ts +333 -333
  227. package/src/services/storage/KnowledgeGraphManager.ts +425 -425
  228. package/src/services/storage/MemorySearchManager.ts +387 -387
  229. package/src/services/storage/QuiltBatchManager.ts +1130 -660
  230. package/src/services/storage/WalrusMetadataManager.ts +268 -268
  231. package/src/services/storage/WalrusStorageManager.ts +287 -287
  232. package/src/services/storage/index.ts +57 -52
  233. package/src/types/index.ts +13 -13
  234. package/src/utils/LRUCache.ts +378 -0
  235. package/src/utils/index.ts +76 -68
  236. package/src/utils/memoryIndexOnChain.ts +507 -0
  237. package/src/utils/rebuildIndex.ts +290 -290
  238. package/src/utils/rebuildIndexNode.ts +771 -424
  239. package/src/vector/BrowserHnswIndexService.ts +758 -758
  240. package/src/vector/HnswWasmService.ts +731 -679
  241. package/src/vector/IHnswService.ts +233 -224
  242. package/src/vector/NodeHnswService.ts +833 -735
  243. package/src/vector/VectorManager.ts +478 -478
  244. package/src/vector/createHnswService.ts +135 -135
  245. package/src/vector/index.ts +56 -56
  246. package/src/wallet/ContextWalletService.ts +656 -656
  247. package/src/wallet/MainWalletService.ts +317 -317
@@ -1,462 +1,462 @@
1
- /**
2
- * VectorService - Unified Vector Operations
3
- *
4
- * Consolidated service combining embedding generation and HNSW indexing
5
- * with smart caching and Walrus persistence.
6
- *
7
- * Uses hybrid HNSW implementation:
8
- * - Browser: hnswlib-wasm
9
- * - Node.js: hnswlib-node
10
- *
11
- * Replaces: HnswIndexService + VectorManager
12
- */
13
-
14
- import { createHnswService, isBrowser, isNode } from '../vector/createHnswService';
15
- import type { IHnswService, HnswServiceConfig } from '../vector/IHnswService';
16
- import { EmbeddingService } from './EmbeddingService';
17
- import { StorageService } from './StorageService';
18
- import {
19
- VectorEmbedding,
20
- EmbeddingConfig,
21
- HNSWIndexConfig,
22
- BatchConfig,
23
- VectorSearchOptions,
24
- VectorSearchResult
25
- } from '../embedding/types';
26
- import type { MemoryMetadata } from './StorageService';
27
-
28
- // Local VectorError class implementation
29
- class VectorErrorImpl extends Error {
30
- constructor(message: string) {
31
- super(message);
32
- this.name = 'VectorError';
33
- }
34
- }
35
-
36
- export interface VectorServiceConfig {
37
- embedding: EmbeddingConfig;
38
- index?: Partial<HNSWIndexConfig>;
39
- batch?: Partial<BatchConfig>;
40
- enableAutoIndex?: boolean;
41
- enableMemoryCache?: boolean;
42
- /** Pre-initialized HNSW service instance (shared singleton) */
43
- hnswService?: IHnswService;
44
- }
45
-
46
- interface IndexCacheEntry {
47
- lastModified: Date;
48
- pendingVectors: Map<number, number[]>;
49
- isDirty: boolean;
50
- version: number;
51
- metadata: Map<number, any>;
52
- /** Cached vectors for serialization (vectorId -> vector) */
53
- vectors: Map<number, number[]>;
54
- }
55
-
56
- /**
57
- * VectorService provides unified vector operations including:
58
- * - Embedding generation via EmbeddingService
59
- * - HNSW vector indexing and search (hybrid: hnswlib-wasm for browser, hnswlib-node for Node.js)
60
- * - Intelligent batching and caching
61
- * - Persistence via Walrus storage
62
- */
63
- export class VectorService {
64
- private embeddingService: EmbeddingService;
65
- private storageService: StorageService;
66
- private indexCache: Map<string, IndexCacheEntry> = new Map();
67
- private hnswService: IHnswService | null = null;
68
- private hnswServicePromise: Promise<IHnswService> | null = null;
69
-
70
- constructor(
71
- private config: VectorServiceConfig,
72
- embeddingService?: EmbeddingService,
73
- storageService?: StorageService
74
- ) {
75
- this.embeddingService = embeddingService || new EmbeddingService(config.embedding);
76
- this.storageService = storageService || new StorageService({ packageId: '' }); // Will be properly configured
77
-
78
- // Use pre-initialized HNSW service if provided (shared singleton pattern)
79
- if (config.hnswService) {
80
- this.hnswService = config.hnswService;
81
- console.log('✅ VectorService using shared HNSW service instance');
82
- } else {
83
- const envType = isBrowser() ? 'browser (hnswlib-wasm)' : isNode() ? 'Node.js (hnswlib-node)' : 'unknown';
84
- console.log(`✅ VectorService initializing with hybrid HNSW (${envType})`);
85
- }
86
- }
87
-
88
- /**
89
- * Get the HNSW service, initializing it if needed
90
- */
91
- private async getHnswService(): Promise<IHnswService> {
92
- if (this.hnswService) {
93
- return this.hnswService;
94
- }
95
- if (this.hnswServicePromise) {
96
- return this.hnswServicePromise;
97
- }
98
- throw new VectorErrorImpl('HNSW service not initialized. Call initialize() first.');
99
- }
100
-
101
- /**
102
- * Initialize the HNSW service (must be called before using any index operations)
103
- * If a shared HNSW service was provided in config, this is a no-op.
104
- */
105
- async initialize(): Promise<void> {
106
- if (this.hnswService) {
107
- return; // Already initialized (or using shared instance)
108
- }
109
-
110
- if (this.hnswServicePromise) {
111
- await this.hnswServicePromise;
112
- return;
113
- }
114
-
115
- // Create own HNSW service only if not provided externally
116
- this.hnswServicePromise = createHnswService({
117
- indexConfig: {
118
- dimension: this.config.index?.dimension || 3072,
119
- maxElements: this.config.index?.maxElements || 10000,
120
- efConstruction: this.config.index?.efConstruction || 200,
121
- m: this.config.index?.m || 16
122
- },
123
- batchConfig: this.config.batch
124
- });
125
-
126
- try {
127
- this.hnswService = await this.hnswServicePromise;
128
- console.log('✅ VectorService HNSW service initialized successfully');
129
- } catch (error) {
130
- this.hnswServicePromise = null;
131
- console.error('❌ Failed to initialize VectorService HNSW service:', error);
132
- throw error;
133
- }
134
- }
135
-
136
- /**
137
- * Generate embeddings for text content
138
- */
139
- async generateEmbedding(text: string): Promise<VectorEmbedding> {
140
- const result = await this.embeddingService.embedText({ text });
141
- return {
142
- vector: result.vector,
143
- dimension: result.dimension,
144
- model: result.model
145
- };
146
- }
147
-
148
- /**
149
- * Create or get HNSW index for a specific space
150
- */
151
- async createIndex(spaceId: string, dimension?: number, config?: Partial<HNSWIndexConfig>): Promise<void> {
152
- await this.initialize();
153
- const hnswService = await this.getHnswService();
154
-
155
- // Use IHnswService.getOrCreateIndex to create the index
156
- await hnswService.getOrCreateIndex(spaceId);
157
-
158
- // Initialize local cache entry for metadata tracking
159
- if (!this.indexCache.has(spaceId)) {
160
- this.indexCache.set(spaceId, {
161
- lastModified: new Date(),
162
- pendingVectors: new Map(),
163
- isDirty: false,
164
- version: 1,
165
- metadata: new Map(),
166
- vectors: new Map()
167
- });
168
- }
169
- }
170
-
171
- /**
172
- * Add vector to index
173
- */
174
- async addVector(spaceId: string, vectorId: number, vector: number[], metadata?: any): Promise<void> {
175
- const hnswService = await this.getHnswService();
176
-
177
- // Add to HNSW index
178
- await hnswService.addVector(spaceId, vectorId, vector, metadata);
179
-
180
- // Update local cache entry for metadata tracking
181
- let entry = this.indexCache.get(spaceId);
182
- if (!entry) {
183
- entry = {
184
- lastModified: new Date(),
185
- pendingVectors: new Map(),
186
- isDirty: true,
187
- version: 1,
188
- metadata: new Map(),
189
- vectors: new Map()
190
- };
191
- this.indexCache.set(spaceId, entry);
192
- }
193
-
194
- if (metadata) {
195
- entry.metadata.set(vectorId, metadata);
196
- }
197
- // Cache vector for serialization
198
- entry.vectors.set(vectorId, vector);
199
- entry.isDirty = true;
200
- entry.lastModified = new Date();
201
- }
202
-
203
- /**
204
- * Get cached vector by ID
205
- */
206
- getVector(spaceId: string, vectorId: number): number[] | undefined {
207
- const entry = this.indexCache.get(spaceId);
208
- return entry?.vectors.get(vectorId);
209
- }
210
-
211
- /**
212
- * Get all cached vectors
213
- */
214
- getAllCachedVectors(spaceId: string): Map<number, number[]> {
215
- const entry = this.indexCache.get(spaceId);
216
- return entry?.vectors || new Map();
217
- }
218
-
219
- /**
220
- * Search vectors in index
221
- */
222
- async searchVectors(
223
- spaceId: string,
224
- queryVector: number[],
225
- options?: Partial<VectorSearchOptions>
226
- ): Promise<VectorSearchResult> {
227
- const hnswService = await this.getHnswService();
228
- const entry = this.indexCache.get(spaceId);
229
-
230
- const k = options?.k || 10;
231
- const startTime = performance.now();
232
-
233
- // Use IHnswService.search
234
- const searchResults = await hnswService.search(spaceId, queryVector, {
235
- k,
236
- ef: options?.efSearch || 50
237
- });
238
-
239
- const searchTime = performance.now() - startTime;
240
-
241
- // Get metadata - prefer HNSW service metadata (loaded from disk) over local cache
242
- return {
243
- results: searchResults.map((result) => ({
244
- memoryId: result.vectorId.toString(),
245
- vectorId: result.vectorId,
246
- similarity: result.score,
247
- distance: result.distance,
248
- metadata: result.metadata || entry?.metadata.get(result.vectorId)
249
- })),
250
- searchStats: {
251
- searchTime,
252
- nodesVisited: searchResults.length,
253
- exactMatches: searchResults.length,
254
- approximateMatches: 0,
255
- cacheHits: 0,
256
- indexSize: 0 // TODO: Get from IHnswService
257
- }
258
- };
259
- }
260
-
261
- /**
262
- * Save index to Walrus storage
263
- */
264
- async saveIndex(spaceId: string): Promise<string> {
265
- const hnswService = await this.getHnswService();
266
- const entry = this.indexCache.get(spaceId);
267
-
268
- // Use IHnswService.saveIndex to save the index
269
- await hnswService.saveIndex(spaceId);
270
-
271
- // Also save metadata to Walrus for persistence
272
- if (entry) {
273
- const indexData = {
274
- spaceId,
275
- version: entry.version,
276
- metadata: Array.from(entry.metadata.entries()),
277
- vectors: Array.from(entry.vectors.entries()),
278
- lastModified: entry.lastModified.toISOString()
279
- };
280
-
281
- const serializedData = JSON.stringify(indexData);
282
- const metadata: MemoryMetadata = {
283
- contentType: 'application/json',
284
- contentSize: serializedData.length,
285
- contentHash: '',
286
- category: 'vector-index',
287
- topic: spaceId,
288
- importance: 8,
289
- embeddingDimension: 3072,
290
- createdTimestamp: Date.now(),
291
- customMetadata: {
292
- type: 'hnsw-index',
293
- spaceId,
294
- version: entry.version.toString()
295
- }
296
- };
297
-
298
- const result = await this.storageService.upload(serializedData, metadata);
299
- entry.isDirty = false;
300
- return result.blobId;
301
- }
302
-
303
- return '';
304
- }
305
-
306
- /**
307
- * Load index from persistent storage or Walrus
308
- * @param spaceId - Index space identifier
309
- * @param blobId - Optional blob ID for Walrus storage (if provided, loads metadata from Walrus)
310
- */
311
- async loadIndex(spaceId: string, blobId?: string): Promise<void> {
312
- const hnswService = await this.getHnswService();
313
-
314
- // Load the HNSW index using IHnswService (from local IndexedDB/filesystem)
315
- await hnswService.loadIndex(spaceId);
316
-
317
- // If blobId provided, also load metadata from Walrus
318
- if (blobId) {
319
- try {
320
- const result = await this.storageService.retrieve(blobId);
321
- const indexData = JSON.parse(new TextDecoder().decode(result.content));
322
-
323
- // Initialize or update local cache entry
324
- const entry = this.indexCache.get(spaceId) || {
325
- lastModified: new Date(),
326
- pendingVectors: new Map(),
327
- isDirty: false,
328
- version: 1,
329
- metadata: new Map(),
330
- vectors: new Map()
331
- };
332
-
333
- entry.version = indexData.version || 1;
334
- entry.metadata = new Map(indexData.metadata || []);
335
- entry.vectors = new Map(indexData.vectors || []);
336
- entry.lastModified = new Date(indexData.lastModified || Date.now());
337
- entry.isDirty = false;
338
-
339
- this.indexCache.set(spaceId, entry);
340
-
341
- // Re-add vectors to HNSW index from cached vectors
342
- for (const [vectorId, vector] of entry.vectors.entries()) {
343
- await hnswService.addVector(spaceId, vectorId, vector, entry.metadata.get(vectorId));
344
- }
345
- } catch (error) {
346
- console.warn(`Failed to load metadata from Walrus for ${blobId}:`, error);
347
- // Index is still loaded via IHnswService, just without local metadata
348
- }
349
- }
350
- }
351
-
352
- /**
353
- * Process text to vector pipeline
354
- */
355
- async processText(spaceId: string, text: string, vectorId: number, metadata?: any): Promise<VectorEmbedding> {
356
- // Generate embedding
357
- const embedding = await this.generateEmbedding(text);
358
-
359
- // Add to index
360
- await this.addVector(spaceId, vectorId, embedding.vector, metadata);
361
-
362
- return embedding;
363
- }
364
-
365
- /**
366
- * Search by text query
367
- */
368
- async searchByText(
369
- spaceId: string,
370
- query: string,
371
- options?: Partial<VectorSearchOptions>
372
- ): Promise<VectorSearchResult> {
373
- // Generate query embedding
374
- const queryEmbedding = await this.generateEmbedding(query);
375
-
376
- // Search vectors
377
- return await this.searchVectors(spaceId, queryEmbedding.vector, options);
378
- }
379
-
380
- /**
381
- * Get index statistics
382
- */
383
- getIndexStats(spaceId: string): any {
384
- const entry = this.indexCache.get(spaceId);
385
- if (!entry) {
386
- return null;
387
- }
388
-
389
- return {
390
- spaceId,
391
- version: entry.version,
392
- currentElements: entry.metadata.size,
393
- maxElements: this.config.index?.maxElements || 10000,
394
- isDirty: entry.isDirty,
395
- lastModified: entry.lastModified,
396
- metadataCount: entry.metadata.size,
397
- vectorCount: entry.vectors.size
398
- };
399
- }
400
-
401
- /**
402
- * Get all vectors matching a category filter
403
- *
404
- * @param spaceId - Index space identifier
405
- * @param category - Category to filter by
406
- * @returns Array of metadata objects matching the category
407
- */
408
- getVectorsByCategory(spaceId: string, category: string): Array<{ vectorId: number; metadata: any }> {
409
- const entry = this.indexCache.get(spaceId);
410
- if (!entry) {
411
- return [];
412
- }
413
-
414
- const results: Array<{ vectorId: number; metadata: any }> = [];
415
- for (const [vectorId, metadata] of entry.metadata.entries()) {
416
- if (metadata?.category === category) {
417
- results.push({ vectorId, metadata });
418
- }
419
- }
420
- return results;
421
- }
422
-
423
- /**
424
- * Get all vectors with their metadata
425
- *
426
- * @param spaceId - Index space identifier
427
- * @returns Array of all vectors with metadata
428
- */
429
- getAllVectors(spaceId: string): Array<{ vectorId: number; metadata: any }> {
430
- const entry = this.indexCache.get(spaceId);
431
- if (!entry) {
432
- return [];
433
- }
434
-
435
- const results: Array<{ vectorId: number; metadata: any }> = [];
436
- for (const [vectorId, metadata] of entry.metadata.entries()) {
437
- results.push({ vectorId, metadata });
438
- }
439
- return results;
440
- }
441
-
442
- /**
443
- * Clean up resources
444
- */
445
- async cleanup(): Promise<void> {
446
- // Save all dirty indices
447
- for (const [spaceId, entry] of this.indexCache.entries()) {
448
- if (entry.isDirty) {
449
- await this.saveIndex(spaceId);
450
- }
451
- }
452
-
453
- // Destroy HNSW service
454
- if (this.hnswService) {
455
- this.hnswService.destroy();
456
- this.hnswService = null;
457
- this.hnswServicePromise = null;
458
- }
459
-
460
- this.indexCache.clear();
461
- }
462
- }
1
+ /**
2
+ * VectorService - Unified Vector Operations
3
+ *
4
+ * Consolidated service combining embedding generation and HNSW indexing
5
+ * with smart caching and Walrus persistence.
6
+ *
7
+ * Uses hybrid HNSW implementation:
8
+ * - Browser: hnswlib-wasm
9
+ * - Node.js: hnswlib-node
10
+ *
11
+ * Replaces: HnswIndexService + VectorManager
12
+ */
13
+
14
+ import { createHnswService, isBrowser, isNode } from '../vector/createHnswService';
15
+ import type { IHnswService, HnswServiceConfig } from '../vector/IHnswService';
16
+ import { EmbeddingService } from './EmbeddingService';
17
+ import { StorageService } from './StorageService';
18
+ import {
19
+ VectorEmbedding,
20
+ EmbeddingConfig,
21
+ HNSWIndexConfig,
22
+ BatchConfig,
23
+ VectorSearchOptions,
24
+ VectorSearchResult
25
+ } from '../embedding/types';
26
+ import type { MemoryMetadata } from './StorageService';
27
+
28
+ // Local VectorError class implementation
29
+ class VectorErrorImpl extends Error {
30
+ constructor(message: string) {
31
+ super(message);
32
+ this.name = 'VectorError';
33
+ }
34
+ }
35
+
36
+ export interface VectorServiceConfig {
37
+ embedding: EmbeddingConfig;
38
+ index?: Partial<HNSWIndexConfig>;
39
+ batch?: Partial<BatchConfig>;
40
+ enableAutoIndex?: boolean;
41
+ enableMemoryCache?: boolean;
42
+ /** Pre-initialized HNSW service instance (shared singleton) */
43
+ hnswService?: IHnswService;
44
+ }
45
+
46
+ interface IndexCacheEntry {
47
+ lastModified: Date;
48
+ pendingVectors: Map<number, number[]>;
49
+ isDirty: boolean;
50
+ version: number;
51
+ metadata: Map<number, any>;
52
+ /** Cached vectors for serialization (vectorId -> vector) */
53
+ vectors: Map<number, number[]>;
54
+ }
55
+
56
+ /**
57
+ * VectorService provides unified vector operations including:
58
+ * - Embedding generation via EmbeddingService
59
+ * - HNSW vector indexing and search (hybrid: hnswlib-wasm for browser, hnswlib-node for Node.js)
60
+ * - Intelligent batching and caching
61
+ * - Persistence via Walrus storage
62
+ */
63
+ export class VectorService {
64
+ private embeddingService: EmbeddingService;
65
+ private storageService: StorageService;
66
+ private indexCache: Map<string, IndexCacheEntry> = new Map();
67
+ private hnswService: IHnswService | null = null;
68
+ private hnswServicePromise: Promise<IHnswService> | null = null;
69
+
70
+ constructor(
71
+ private config: VectorServiceConfig,
72
+ embeddingService?: EmbeddingService,
73
+ storageService?: StorageService
74
+ ) {
75
+ this.embeddingService = embeddingService || new EmbeddingService(config.embedding);
76
+ this.storageService = storageService || new StorageService({ packageId: '' }); // Will be properly configured
77
+
78
+ // Use pre-initialized HNSW service if provided (shared singleton pattern)
79
+ if (config.hnswService) {
80
+ this.hnswService = config.hnswService;
81
+ console.log('✅ VectorService using shared HNSW service instance');
82
+ } else {
83
+ const envType = isBrowser() ? 'browser (hnswlib-wasm)' : isNode() ? 'Node.js (hnswlib-node)' : 'unknown';
84
+ console.log(`✅ VectorService initializing with hybrid HNSW (${envType})`);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Get the HNSW service, initializing it if needed
90
+ */
91
+ private async getHnswService(): Promise<IHnswService> {
92
+ if (this.hnswService) {
93
+ return this.hnswService;
94
+ }
95
+ if (this.hnswServicePromise) {
96
+ return this.hnswServicePromise;
97
+ }
98
+ throw new VectorErrorImpl('HNSW service not initialized. Call initialize() first.');
99
+ }
100
+
101
+ /**
102
+ * Initialize the HNSW service (must be called before using any index operations)
103
+ * If a shared HNSW service was provided in config, this is a no-op.
104
+ */
105
+ async initialize(): Promise<void> {
106
+ if (this.hnswService) {
107
+ return; // Already initialized (or using shared instance)
108
+ }
109
+
110
+ if (this.hnswServicePromise) {
111
+ await this.hnswServicePromise;
112
+ return;
113
+ }
114
+
115
+ // Create own HNSW service only if not provided externally
116
+ this.hnswServicePromise = createHnswService({
117
+ indexConfig: {
118
+ dimension: this.config.index?.dimension || 3072,
119
+ maxElements: this.config.index?.maxElements || 10000,
120
+ efConstruction: this.config.index?.efConstruction || 200,
121
+ m: this.config.index?.m || 16
122
+ },
123
+ batchConfig: this.config.batch
124
+ });
125
+
126
+ try {
127
+ this.hnswService = await this.hnswServicePromise;
128
+ console.log('✅ VectorService HNSW service initialized successfully');
129
+ } catch (error) {
130
+ this.hnswServicePromise = null;
131
+ console.error('❌ Failed to initialize VectorService HNSW service:', error);
132
+ throw error;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Generate embeddings for text content
138
+ */
139
+ async generateEmbedding(text: string): Promise<VectorEmbedding> {
140
+ const result = await this.embeddingService.embedText({ text });
141
+ return {
142
+ vector: result.vector,
143
+ dimension: result.dimension,
144
+ model: result.model
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Create or get HNSW index for a specific space
150
+ */
151
+ async createIndex(spaceId: string, dimension?: number, config?: Partial<HNSWIndexConfig>): Promise<void> {
152
+ await this.initialize();
153
+ const hnswService = await this.getHnswService();
154
+
155
+ // Use IHnswService.getOrCreateIndex to create the index
156
+ await hnswService.getOrCreateIndex(spaceId);
157
+
158
+ // Initialize local cache entry for metadata tracking
159
+ if (!this.indexCache.has(spaceId)) {
160
+ this.indexCache.set(spaceId, {
161
+ lastModified: new Date(),
162
+ pendingVectors: new Map(),
163
+ isDirty: false,
164
+ version: 1,
165
+ metadata: new Map(),
166
+ vectors: new Map()
167
+ });
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Add vector to index
173
+ */
174
+ async addVector(spaceId: string, vectorId: number, vector: number[], metadata?: any): Promise<void> {
175
+ const hnswService = await this.getHnswService();
176
+
177
+ // Add to HNSW index
178
+ await hnswService.addVector(spaceId, vectorId, vector, metadata);
179
+
180
+ // Update local cache entry for metadata tracking
181
+ let entry = this.indexCache.get(spaceId);
182
+ if (!entry) {
183
+ entry = {
184
+ lastModified: new Date(),
185
+ pendingVectors: new Map(),
186
+ isDirty: true,
187
+ version: 1,
188
+ metadata: new Map(),
189
+ vectors: new Map()
190
+ };
191
+ this.indexCache.set(spaceId, entry);
192
+ }
193
+
194
+ if (metadata) {
195
+ entry.metadata.set(vectorId, metadata);
196
+ }
197
+ // Cache vector for serialization
198
+ entry.vectors.set(vectorId, vector);
199
+ entry.isDirty = true;
200
+ entry.lastModified = new Date();
201
+ }
202
+
203
+ /**
204
+ * Get cached vector by ID
205
+ */
206
+ getVector(spaceId: string, vectorId: number): number[] | undefined {
207
+ const entry = this.indexCache.get(spaceId);
208
+ return entry?.vectors.get(vectorId);
209
+ }
210
+
211
+ /**
212
+ * Get all cached vectors
213
+ */
214
+ getAllCachedVectors(spaceId: string): Map<number, number[]> {
215
+ const entry = this.indexCache.get(spaceId);
216
+ return entry?.vectors || new Map();
217
+ }
218
+
219
+ /**
220
+ * Search vectors in index
221
+ */
222
+ async searchVectors(
223
+ spaceId: string,
224
+ queryVector: number[],
225
+ options?: Partial<VectorSearchOptions>
226
+ ): Promise<VectorSearchResult> {
227
+ const hnswService = await this.getHnswService();
228
+ const entry = this.indexCache.get(spaceId);
229
+
230
+ const k = options?.k || 10;
231
+ const startTime = performance.now();
232
+
233
+ // Use IHnswService.search
234
+ const searchResults = await hnswService.search(spaceId, queryVector, {
235
+ k,
236
+ ef: options?.efSearch || 50
237
+ });
238
+
239
+ const searchTime = performance.now() - startTime;
240
+
241
+ // Get metadata - prefer HNSW service metadata (loaded from disk) over local cache
242
+ return {
243
+ results: searchResults.map((result) => ({
244
+ memoryId: result.vectorId.toString(),
245
+ vectorId: result.vectorId,
246
+ similarity: result.score,
247
+ distance: result.distance,
248
+ metadata: result.metadata || entry?.metadata.get(result.vectorId)
249
+ })),
250
+ searchStats: {
251
+ searchTime,
252
+ nodesVisited: searchResults.length,
253
+ exactMatches: searchResults.length,
254
+ approximateMatches: 0,
255
+ cacheHits: 0,
256
+ indexSize: 0 // TODO: Get from IHnswService
257
+ }
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Save index to Walrus storage
263
+ */
264
+ async saveIndex(spaceId: string): Promise<string> {
265
+ const hnswService = await this.getHnswService();
266
+ const entry = this.indexCache.get(spaceId);
267
+
268
+ // Use IHnswService.saveIndex to save the index
269
+ await hnswService.saveIndex(spaceId);
270
+
271
+ // Also save metadata to Walrus for persistence
272
+ if (entry) {
273
+ const indexData = {
274
+ spaceId,
275
+ version: entry.version,
276
+ metadata: Array.from(entry.metadata.entries()),
277
+ vectors: Array.from(entry.vectors.entries()),
278
+ lastModified: entry.lastModified.toISOString()
279
+ };
280
+
281
+ const serializedData = JSON.stringify(indexData);
282
+ const metadata: MemoryMetadata = {
283
+ contentType: 'application/json',
284
+ contentSize: serializedData.length,
285
+ contentHash: '',
286
+ category: 'vector-index',
287
+ topic: spaceId,
288
+ importance: 8,
289
+ embeddingDimension: 3072,
290
+ createdTimestamp: Date.now(),
291
+ customMetadata: {
292
+ type: 'hnsw-index',
293
+ spaceId,
294
+ version: entry.version.toString()
295
+ }
296
+ };
297
+
298
+ const result = await this.storageService.upload(serializedData, metadata);
299
+ entry.isDirty = false;
300
+ return result.blobId;
301
+ }
302
+
303
+ return '';
304
+ }
305
+
306
+ /**
307
+ * Load index from persistent storage or Walrus
308
+ * @param spaceId - Index space identifier
309
+ * @param blobId - Optional blob ID for Walrus storage (if provided, loads metadata from Walrus)
310
+ */
311
+ async loadIndex(spaceId: string, blobId?: string): Promise<void> {
312
+ const hnswService = await this.getHnswService();
313
+
314
+ // Load the HNSW index using IHnswService (from local IndexedDB/filesystem)
315
+ await hnswService.loadIndex(spaceId);
316
+
317
+ // If blobId provided, also load metadata from Walrus
318
+ if (blobId) {
319
+ try {
320
+ const result = await this.storageService.retrieve(blobId);
321
+ const indexData = JSON.parse(new TextDecoder().decode(result.content));
322
+
323
+ // Initialize or update local cache entry
324
+ const entry = this.indexCache.get(spaceId) || {
325
+ lastModified: new Date(),
326
+ pendingVectors: new Map(),
327
+ isDirty: false,
328
+ version: 1,
329
+ metadata: new Map(),
330
+ vectors: new Map()
331
+ };
332
+
333
+ entry.version = indexData.version || 1;
334
+ entry.metadata = new Map(indexData.metadata || []);
335
+ entry.vectors = new Map(indexData.vectors || []);
336
+ entry.lastModified = new Date(indexData.lastModified || Date.now());
337
+ entry.isDirty = false;
338
+
339
+ this.indexCache.set(spaceId, entry);
340
+
341
+ // Re-add vectors to HNSW index from cached vectors
342
+ for (const [vectorId, vector] of entry.vectors.entries()) {
343
+ await hnswService.addVector(spaceId, vectorId, vector, entry.metadata.get(vectorId));
344
+ }
345
+ } catch (error) {
346
+ console.warn(`Failed to load metadata from Walrus for ${blobId}:`, error);
347
+ // Index is still loaded via IHnswService, just without local metadata
348
+ }
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Process text to vector pipeline
354
+ */
355
+ async processText(spaceId: string, text: string, vectorId: number, metadata?: any): Promise<VectorEmbedding> {
356
+ // Generate embedding
357
+ const embedding = await this.generateEmbedding(text);
358
+
359
+ // Add to index
360
+ await this.addVector(spaceId, vectorId, embedding.vector, metadata);
361
+
362
+ return embedding;
363
+ }
364
+
365
+ /**
366
+ * Search by text query
367
+ */
368
+ async searchByText(
369
+ spaceId: string,
370
+ query: string,
371
+ options?: Partial<VectorSearchOptions>
372
+ ): Promise<VectorSearchResult> {
373
+ // Generate query embedding
374
+ const queryEmbedding = await this.generateEmbedding(query);
375
+
376
+ // Search vectors
377
+ return await this.searchVectors(spaceId, queryEmbedding.vector, options);
378
+ }
379
+
380
+ /**
381
+ * Get index statistics
382
+ */
383
+ getIndexStats(spaceId: string): any {
384
+ const entry = this.indexCache.get(spaceId);
385
+ if (!entry) {
386
+ return null;
387
+ }
388
+
389
+ return {
390
+ spaceId,
391
+ version: entry.version,
392
+ currentElements: entry.metadata.size,
393
+ maxElements: this.config.index?.maxElements || 10000,
394
+ isDirty: entry.isDirty,
395
+ lastModified: entry.lastModified,
396
+ metadataCount: entry.metadata.size,
397
+ vectorCount: entry.vectors.size
398
+ };
399
+ }
400
+
401
+ /**
402
+ * Get all vectors matching a category filter
403
+ *
404
+ * @param spaceId - Index space identifier
405
+ * @param category - Category to filter by
406
+ * @returns Array of metadata objects matching the category
407
+ */
408
+ getVectorsByCategory(spaceId: string, category: string): Array<{ vectorId: number; metadata: any }> {
409
+ const entry = this.indexCache.get(spaceId);
410
+ if (!entry) {
411
+ return [];
412
+ }
413
+
414
+ const results: Array<{ vectorId: number; metadata: any }> = [];
415
+ for (const [vectorId, metadata] of entry.metadata.entries()) {
416
+ if (metadata?.category === category) {
417
+ results.push({ vectorId, metadata });
418
+ }
419
+ }
420
+ return results;
421
+ }
422
+
423
+ /**
424
+ * Get all vectors with their metadata
425
+ *
426
+ * @param spaceId - Index space identifier
427
+ * @returns Array of all vectors with metadata
428
+ */
429
+ getAllVectors(spaceId: string): Array<{ vectorId: number; metadata: any }> {
430
+ const entry = this.indexCache.get(spaceId);
431
+ if (!entry) {
432
+ return [];
433
+ }
434
+
435
+ const results: Array<{ vectorId: number; metadata: any }> = [];
436
+ for (const [vectorId, metadata] of entry.metadata.entries()) {
437
+ results.push({ vectorId, metadata });
438
+ }
439
+ return results;
440
+ }
441
+
442
+ /**
443
+ * Clean up resources
444
+ */
445
+ async cleanup(): Promise<void> {
446
+ // Save all dirty indices
447
+ for (const [spaceId, entry] of this.indexCache.entries()) {
448
+ if (entry.isDirty) {
449
+ await this.saveIndex(spaceId);
450
+ }
451
+ }
452
+
453
+ // Destroy HNSW service
454
+ if (this.hnswService) {
455
+ this.hnswService.destroy();
456
+ this.hnswService = null;
457
+ this.hnswServicePromise = null;
458
+ }
459
+
460
+ this.indexCache.clear();
461
+ }
462
+ }