@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.
- package/ARCHITECTURE.md +547 -547
- package/BENCHMARKS.md +238 -238
- package/README.md +310 -181
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/client/ClientMemoryManager.js +2 -2
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/PersonalDataWallet.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +29 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +45 -13
- package/dist/client/SimplePDWClient.js.map +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +272 -39
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
- package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/config/ConfigurationHelper.js +61 -61
- package/dist/config/defaults.js +2 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/graph/GraphService.js +21 -21
- package/dist/graph/GraphService.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
- package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.js +37 -15
- package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
- package/dist/infrastructure/seal/SealService.d.ts +13 -5
- package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
- package/dist/infrastructure/seal/SealService.js +36 -34
- package/dist/infrastructure/seal/SealService.js.map +1 -1
- package/dist/langchain/createPDWRAG.js +30 -30
- package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.js +44 -4
- package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
- package/dist/services/CapabilityService.d.ts.map +1 -1
- package/dist/services/CapabilityService.js +30 -14
- package/dist/services/CapabilityService.js.map +1 -1
- package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
- package/dist/services/CrossContextPermissionService.js +9 -7
- package/dist/services/CrossContextPermissionService.js.map +1 -1
- package/dist/services/EmbeddingService.d.ts +28 -1
- package/dist/services/EmbeddingService.d.ts.map +1 -1
- package/dist/services/EmbeddingService.js +54 -0
- package/dist/services/EmbeddingService.js.map +1 -1
- package/dist/services/EncryptionService.d.ts.map +1 -1
- package/dist/services/EncryptionService.js +6 -5
- package/dist/services/EncryptionService.js.map +1 -1
- package/dist/services/GeminiAIService.js +309 -309
- package/dist/services/IndexManager.d.ts +5 -1
- package/dist/services/IndexManager.d.ts.map +1 -1
- package/dist/services/IndexManager.js +17 -40
- package/dist/services/IndexManager.js.map +1 -1
- package/dist/services/QueryService.js +1 -1
- package/dist/services/QueryService.js.map +1 -1
- package/dist/services/StorageService.d.ts +11 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +73 -10
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/TransactionService.d.ts +20 -0
- package/dist/services/TransactionService.d.ts.map +1 -1
- package/dist/services/TransactionService.js +43 -0
- package/dist/services/TransactionService.js.map +1 -1
- package/dist/services/ViewService.js +2 -2
- package/dist/services/ViewService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +410 -20
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/services/storage/index.d.ts +1 -1
- package/dist/services/storage/index.d.ts.map +1 -1
- package/dist/services/storage/index.js.map +1 -1
- package/dist/utils/LRUCache.d.ts +106 -0
- package/dist/utils/LRUCache.d.ts.map +1 -0
- package/dist/utils/LRUCache.js +281 -0
- package/dist/utils/LRUCache.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/memoryIndexOnChain.d.ts +212 -0
- package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
- package/dist/utils/memoryIndexOnChain.js +312 -0
- package/dist/utils/memoryIndexOnChain.js.map +1 -0
- package/dist/utils/rebuildIndexNode.d.ts +29 -0
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +366 -98
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/HnswWasmService.d.ts +20 -5
- package/dist/vector/HnswWasmService.d.ts.map +1 -1
- package/dist/vector/HnswWasmService.js +73 -40
- package/dist/vector/HnswWasmService.js.map +1 -1
- package/dist/vector/IHnswService.d.ts +10 -1
- package/dist/vector/IHnswService.d.ts.map +1 -1
- package/dist/vector/IHnswService.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts +16 -0
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +84 -5
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/dist/vector/createHnswService.d.ts +1 -1
- package/dist/vector/createHnswService.js +1 -1
- package/dist/vector/index.d.ts +1 -1
- package/dist/vector/index.js +1 -1
- package/package.json +157 -157
- package/src/access/PermissionService.ts +635 -635
- package/src/aggregation/AggregationService.ts +389 -389
- package/src/ai-sdk/PDWVectorStore.ts +715 -715
- package/src/ai-sdk/index.ts +65 -65
- package/src/ai-sdk/tools.ts +460 -460
- package/src/ai-sdk/types.ts +404 -404
- package/src/batch/BatchManager.ts +597 -597
- package/src/batch/BatchingService.ts +429 -429
- package/src/batch/MemoryProcessingCache.ts +492 -492
- package/src/batch/index.ts +30 -30
- package/src/browser.ts +200 -200
- package/src/client/ClientMemoryManager.ts +987 -987
- package/src/client/PersonalDataWallet.ts +345 -345
- package/src/client/SimplePDWClient.ts +1289 -1222
- package/src/client/factory.ts +154 -154
- package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
- package/src/client/namespaces/BatchNamespace.ts +356 -356
- package/src/client/namespaces/CacheNamespace.ts +123 -123
- package/src/client/namespaces/CapabilityNamespace.ts +217 -217
- package/src/client/namespaces/ClassifyNamespace.ts +169 -169
- package/src/client/namespaces/ContextNamespace.ts +297 -297
- package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
- package/src/client/namespaces/EncryptionNamespace.ts +221 -221
- package/src/client/namespaces/GraphNamespace.ts +468 -468
- package/src/client/namespaces/IndexNamespace.ts +361 -361
- package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
- package/src/client/namespaces/PermissionsNamespace.ts +254 -254
- package/src/client/namespaces/PipelineNamespace.ts +220 -220
- package/src/client/namespaces/SearchNamespace.ts +1049 -1049
- package/src/client/namespaces/StorageNamespace.ts +458 -458
- package/src/client/namespaces/TxNamespace.ts +260 -260
- package/src/client/namespaces/WalletNamespace.ts +243 -243
- package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
- package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
- package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
- package/src/client/namespaces/consolidated/index.ts +39 -39
- package/src/client/signers/KeypairSigner.ts +108 -108
- package/src/client/signers/UnifiedSigner.ts +110 -110
- package/src/client/signers/WalletAdapterSigner.ts +159 -159
- package/src/client/signers/index.ts +26 -26
- package/src/config/ConfigurationHelper.ts +412 -412
- package/src/config/defaults.ts +51 -51
- package/src/config/index.ts +8 -8
- package/src/config/validation.ts +70 -70
- package/src/core/index.ts +14 -14
- package/src/core/interfaces/IService.ts +307 -307
- package/src/core/interfaces/index.ts +8 -8
- package/src/core/types/capability.ts +297 -297
- package/src/core/types/index.ts +870 -870
- package/src/core/types/wallet.ts +270 -270
- package/src/core/types.ts +9 -9
- package/src/core/wallet.ts +222 -222
- package/src/embedding/index.ts +19 -19
- package/src/embedding/types.ts +357 -357
- package/src/errors/index.ts +602 -602
- package/src/errors/recovery.ts +461 -461
- package/src/errors/validation.ts +567 -567
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +887 -887
- package/src/graph/KnowledgeGraphManager.ts +728 -728
- package/src/graph/index.ts +25 -25
- package/src/index.ts +498 -474
- package/src/infrastructure/index.ts +22 -22
- package/src/infrastructure/seal/EncryptionService.ts +628 -603
- package/src/infrastructure/seal/SealService.ts +613 -615
- package/src/infrastructure/seal/index.ts +9 -9
- package/src/infrastructure/sui/BlockchainManager.ts +627 -627
- package/src/infrastructure/sui/SuiService.ts +888 -888
- package/src/infrastructure/sui/index.ts +9 -9
- package/src/infrastructure/walrus/StorageManager.ts +604 -604
- package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
- package/src/infrastructure/walrus/index.ts +9 -9
- package/src/langchain/PDWEmbeddings.ts +145 -145
- package/src/langchain/PDWVectorStore.ts +456 -456
- package/src/langchain/createPDWRAG.ts +303 -303
- package/src/langchain/index.ts +47 -47
- package/src/permissions/ConsentRepository.browser.ts +249 -249
- package/src/permissions/ConsentRepository.ts +364 -364
- package/src/pipeline/MemoryPipeline.ts +862 -862
- package/src/pipeline/PipelineManager.ts +683 -683
- package/src/pipeline/index.ts +26 -26
- package/src/retrieval/AdvancedSearchService.ts +629 -629
- package/src/retrieval/MemoryAnalyticsService.ts +711 -711
- package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
- package/src/retrieval/MemoryRetrievalService.ts +904 -830
- package/src/retrieval/index.ts +42 -42
- package/src/services/BatchService.ts +352 -352
- package/src/services/CapabilityService.ts +464 -448
- package/src/services/ClassifierService.ts +465 -465
- package/src/services/CrossContextPermissionService.ts +486 -484
- package/src/services/EmbeddingService.ts +771 -706
- package/src/services/EncryptionService.ts +712 -711
- package/src/services/GeminiAIService.ts +753 -753
- package/src/services/IndexManager.ts +977 -1004
- package/src/services/MemoryIndexService.ts +1003 -1003
- package/src/services/MemoryService.ts +369 -369
- package/src/services/QueryService.ts +890 -890
- package/src/services/StorageService.ts +1182 -1111
- package/src/services/TransactionService.ts +838 -790
- package/src/services/VectorService.ts +462 -462
- package/src/services/ViewService.ts +484 -484
- package/src/services/index.ts +25 -25
- package/src/services/storage/BlobAttributesManager.ts +333 -333
- package/src/services/storage/KnowledgeGraphManager.ts +425 -425
- package/src/services/storage/MemorySearchManager.ts +387 -387
- package/src/services/storage/QuiltBatchManager.ts +1130 -660
- package/src/services/storage/WalrusMetadataManager.ts +268 -268
- package/src/services/storage/WalrusStorageManager.ts +287 -287
- package/src/services/storage/index.ts +57 -52
- package/src/types/index.ts +13 -13
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +76 -68
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndex.ts +290 -290
- package/src/utils/rebuildIndexNode.ts +771 -424
- package/src/vector/BrowserHnswIndexService.ts +758 -758
- package/src/vector/HnswWasmService.ts +731 -679
- package/src/vector/IHnswService.ts +233 -224
- package/src/vector/NodeHnswService.ts +833 -735
- package/src/vector/VectorManager.ts +478 -478
- package/src/vector/createHnswService.ts +135 -135
- package/src/vector/index.ts +56 -56
- package/src/wallet/ContextWalletService.ts +656 -656
- package/src/wallet/MainWalletService.ts +317 -317
|
@@ -1,479 +1,479 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VectorManager - High-level Vector Operations Orchestrator
|
|
3
|
-
*
|
|
4
|
-
* Provides a unified interface for vector operations combining
|
|
5
|
-
* embedding generation and HNSW indexing with smart caching.
|
|
6
|
-
* Uses hybrid HNSW implementation (browser: wasm, node: native).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { EmbeddingService, EmbeddingOptions, EmbeddingResult, BatchEmbeddingResult } from '../services/EmbeddingService';
|
|
10
|
-
import { createHnswService, isBrowser, isNode } from './createHnswService';
|
|
11
|
-
import type { IHnswService } from './IHnswService';
|
|
12
|
-
import {
|
|
13
|
-
VectorEmbedding,
|
|
14
|
-
EmbeddingConfig,
|
|
15
|
-
HNSWIndexConfig,
|
|
16
|
-
BatchConfig,
|
|
17
|
-
VectorSearchOptions,
|
|
18
|
-
VectorSearchResult,
|
|
19
|
-
VectorSearchMatch,
|
|
20
|
-
HNSWSearchResult
|
|
21
|
-
} from '../embedding/types';
|
|
22
|
-
|
|
23
|
-
export interface VectorManagerConfig {
|
|
24
|
-
embedding: EmbeddingConfig;
|
|
25
|
-
index?: Partial<HNSWIndexConfig>;
|
|
26
|
-
batch?: Partial<BatchConfig>;
|
|
27
|
-
enableAutoIndex?: boolean;
|
|
28
|
-
enableMemoryCache?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface VectorOperationResult {
|
|
32
|
-
success: boolean;
|
|
33
|
-
vectorId?: number;
|
|
34
|
-
embedding?: VectorEmbedding;
|
|
35
|
-
indexBlobId?: string;
|
|
36
|
-
processingTime: number;
|
|
37
|
-
error?: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface VectorSearchStats {
|
|
41
|
-
searchTime: number;
|
|
42
|
-
embeddingTime: number;
|
|
43
|
-
indexSearchTime: number;
|
|
44
|
-
totalResults: number;
|
|
45
|
-
cacheHits: number;
|
|
46
|
-
indexSize: number;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Unified vector operations manager
|
|
51
|
-
*/
|
|
52
|
-
export class VectorManager {
|
|
53
|
-
private embeddingService: EmbeddingService;
|
|
54
|
-
private indexService: IHnswService | null = null;
|
|
55
|
-
private indexServicePromise: Promise<IHnswService> | null = null;
|
|
56
|
-
private vectorIdCounter = new Map<string, number>(); // userAddress -> nextVectorId
|
|
57
|
-
private memoryCache = new Map<string, VectorEmbedding>(); // text hash -> embedding
|
|
58
|
-
private config: VectorManagerConfig;
|
|
59
|
-
|
|
60
|
-
constructor(config: VectorManagerConfig) {
|
|
61
|
-
this.config = config;
|
|
62
|
-
|
|
63
|
-
// Initialize embedding service
|
|
64
|
-
this.embeddingService = new EmbeddingService(config.embedding);
|
|
65
|
-
|
|
66
|
-
// Initialize HNSW index service asynchronously using factory
|
|
67
|
-
this.indexServicePromise = this.initializeIndexService();
|
|
68
|
-
|
|
69
|
-
const envType = isBrowser() ? 'browser (hnswlib-wasm)' : isNode() ? 'Node.js (hnswlib-node)' : 'unknown';
|
|
70
|
-
console.log(`✅ VectorManager initializing with hybrid HNSW (${envType})`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Initialize HNSW service using factory
|
|
75
|
-
*/
|
|
76
|
-
private async initializeIndexService(): Promise<IHnswService> {
|
|
77
|
-
try {
|
|
78
|
-
const service = await createHnswService({
|
|
79
|
-
indexConfig: {
|
|
80
|
-
dimension: this.config.index?.dimension || 3072,
|
|
81
|
-
maxElements: this.config.index?.maxElements || 10000,
|
|
82
|
-
efConstruction: this.config.index?.efConstruction || 200,
|
|
83
|
-
m: this.config.index?.m || 16
|
|
84
|
-
},
|
|
85
|
-
batchConfig: this.config.batch
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
this.indexService = service;
|
|
89
|
-
console.log('✅ VectorManager HNSW service initialized successfully');
|
|
90
|
-
return service;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error('❌ Failed to initialize HNSW service:', error);
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get HNSW service (waits for initialization if needed)
|
|
99
|
-
*/
|
|
100
|
-
private async getIndexService(): Promise<IHnswService> {
|
|
101
|
-
if (this.indexService) {
|
|
102
|
-
return this.indexService;
|
|
103
|
-
}
|
|
104
|
-
if (this.indexServicePromise) {
|
|
105
|
-
return this.indexServicePromise;
|
|
106
|
-
}
|
|
107
|
-
throw new Error('HNSW service not initialized');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Add text content to vector index (embed + index)
|
|
112
|
-
*/
|
|
113
|
-
async addTextToIndex(
|
|
114
|
-
userAddress: string,
|
|
115
|
-
text: string,
|
|
116
|
-
options: {
|
|
117
|
-
vectorId?: number;
|
|
118
|
-
metadata?: any;
|
|
119
|
-
embeddingType?: 'content' | 'metadata' | 'query';
|
|
120
|
-
enableCache?: boolean;
|
|
121
|
-
} = {}
|
|
122
|
-
): Promise<VectorOperationResult> {
|
|
123
|
-
const startTime = Date.now();
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
// Generate or get cached embedding
|
|
127
|
-
let embedding: VectorEmbedding;
|
|
128
|
-
const textHash = this.hashText(text);
|
|
129
|
-
|
|
130
|
-
if (options.enableCache !== false && this.config.enableMemoryCache && this.memoryCache.has(textHash)) {
|
|
131
|
-
embedding = this.memoryCache.get(textHash)!;
|
|
132
|
-
console.debug(`Using cached embedding for text hash: ${textHash.substring(0, 8)}`);
|
|
133
|
-
} else {
|
|
134
|
-
// Generate new embedding
|
|
135
|
-
const embeddingResult = await this.embeddingService.embedText({
|
|
136
|
-
text,
|
|
137
|
-
type: options.embeddingType || 'content'
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
embedding = {
|
|
141
|
-
vector: embeddingResult.vector,
|
|
142
|
-
dimension: embeddingResult.dimension,
|
|
143
|
-
model: embeddingResult.model,
|
|
144
|
-
metadata: {
|
|
145
|
-
contentType: 'text/plain',
|
|
146
|
-
timestamp: Date.now(),
|
|
147
|
-
source: 'vector-manager',
|
|
148
|
-
...options.metadata
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
// Cache if enabled
|
|
153
|
-
if (this.config.enableMemoryCache) {
|
|
154
|
-
this.memoryCache.set(textHash, embedding);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Get vector ID
|
|
159
|
-
const vectorId = options.vectorId || this.getNextVectorId(userAddress);
|
|
160
|
-
|
|
161
|
-
// Add to HNSW index
|
|
162
|
-
if (this.config.enableAutoIndex !== false) {
|
|
163
|
-
const indexService = await this.getIndexService();
|
|
164
|
-
await indexService.addVector(
|
|
165
|
-
userAddress,
|
|
166
|
-
vectorId,
|
|
167
|
-
embedding.vector,
|
|
168
|
-
{ text, ...options.metadata }
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
success: true,
|
|
174
|
-
vectorId,
|
|
175
|
-
embedding,
|
|
176
|
-
processingTime: Date.now() - startTime
|
|
177
|
-
};
|
|
178
|
-
} catch (error) {
|
|
179
|
-
return {
|
|
180
|
-
success: false,
|
|
181
|
-
processingTime: Date.now() - startTime,
|
|
182
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Search for similar texts using vector similarity
|
|
189
|
-
*/
|
|
190
|
-
async searchSimilarTexts(
|
|
191
|
-
userAddress: string,
|
|
192
|
-
queryText: string,
|
|
193
|
-
options: {
|
|
194
|
-
k?: number;
|
|
195
|
-
threshold?: number;
|
|
196
|
-
efSearch?: number;
|
|
197
|
-
category?: string;
|
|
198
|
-
metadata?: any;
|
|
199
|
-
includeEmbeddings?: boolean;
|
|
200
|
-
} = {}
|
|
201
|
-
): Promise<{
|
|
202
|
-
results: VectorSearchMatch[];
|
|
203
|
-
stats: VectorSearchStats;
|
|
204
|
-
}> {
|
|
205
|
-
const totalStartTime = Date.now();
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
// Generate query embedding
|
|
209
|
-
const embeddingStartTime = Date.now();
|
|
210
|
-
const queryEmbedding = await this.embeddingService.embedText({
|
|
211
|
-
text: queryText,
|
|
212
|
-
type: 'query'
|
|
213
|
-
});
|
|
214
|
-
const embeddingTime = Date.now() - embeddingStartTime;
|
|
215
|
-
|
|
216
|
-
// Search in HNSW index
|
|
217
|
-
const indexStartTime = Date.now();
|
|
218
|
-
const indexService = await this.getIndexService();
|
|
219
|
-
const searchResults = await indexService.search(
|
|
220
|
-
userAddress,
|
|
221
|
-
queryEmbedding.vector,
|
|
222
|
-
{
|
|
223
|
-
k: options.k || 10,
|
|
224
|
-
ef: options.efSearch || 50,
|
|
225
|
-
filter: options.metadata ? (meta) => this.matchesMetadata(meta, options.metadata!) : undefined
|
|
226
|
-
}
|
|
227
|
-
);
|
|
228
|
-
const indexSearchTime = Date.now() - indexStartTime;
|
|
229
|
-
|
|
230
|
-
// Convert HNSW results to VectorSearchMatch format
|
|
231
|
-
const results: VectorSearchMatch[] = [];
|
|
232
|
-
for (const result of searchResults) {
|
|
233
|
-
const vectorId = result.vectorId;
|
|
234
|
-
const distance = result.distance;
|
|
235
|
-
const similarity = result.score;
|
|
236
|
-
|
|
237
|
-
// Apply threshold filter
|
|
238
|
-
if (options.threshold && similarity < options.threshold) {
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const match: VectorSearchMatch = {
|
|
243
|
-
memoryId: `memory_${vectorId}`, // TODO: Map to actual memory ID
|
|
244
|
-
vectorId,
|
|
245
|
-
similarity,
|
|
246
|
-
distance,
|
|
247
|
-
metadata: {} // TODO: Get metadata from index
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
if (options.includeEmbeddings) {
|
|
251
|
-
match.embedding = {
|
|
252
|
-
vector: [], // TODO: Store and retrieve vectors
|
|
253
|
-
dimension: queryEmbedding.dimension,
|
|
254
|
-
model: queryEmbedding.model
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
results.push(match);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const stats: VectorSearchStats = {
|
|
262
|
-
searchTime: Date.now() - totalStartTime,
|
|
263
|
-
embeddingTime,
|
|
264
|
-
indexSearchTime,
|
|
265
|
-
totalResults: results.length,
|
|
266
|
-
cacheHits: 0, // TODO: Track cache hits
|
|
267
|
-
indexSize: 0 // TODO: Get from index service
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
return { results, stats };
|
|
271
|
-
} catch (error) {
|
|
272
|
-
throw new Error(`Vector search failed: ${error}`);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Batch add multiple texts to index
|
|
278
|
-
*/
|
|
279
|
-
async addTextsBatch(
|
|
280
|
-
userAddress: string,
|
|
281
|
-
texts: Array<{
|
|
282
|
-
text: string;
|
|
283
|
-
metadata?: any;
|
|
284
|
-
embeddingType?: 'content' | 'metadata' | 'query';
|
|
285
|
-
}>,
|
|
286
|
-
options: {
|
|
287
|
-
batchSize?: number;
|
|
288
|
-
enableCache?: boolean;
|
|
289
|
-
} = {}
|
|
290
|
-
): Promise<{
|
|
291
|
-
results: VectorOperationResult[];
|
|
292
|
-
stats: {
|
|
293
|
-
totalTime: number;
|
|
294
|
-
embeddingTime: number;
|
|
295
|
-
indexingTime: number;
|
|
296
|
-
successCount: number;
|
|
297
|
-
failureCount: number;
|
|
298
|
-
};
|
|
299
|
-
}> {
|
|
300
|
-
const startTime = Date.now();
|
|
301
|
-
const batchSize = options.batchSize || 10;
|
|
302
|
-
const results: VectorOperationResult[] = [];
|
|
303
|
-
|
|
304
|
-
// Extract texts for batch embedding
|
|
305
|
-
const textContents = texts.map(t => t.text);
|
|
306
|
-
|
|
307
|
-
// Generate embeddings in batch
|
|
308
|
-
const embeddingStartTime = Date.now();
|
|
309
|
-
const batchEmbeddings = await this.embeddingService.embedBatch(textContents);
|
|
310
|
-
const embeddingTime = Date.now() - embeddingStartTime;
|
|
311
|
-
|
|
312
|
-
// Add to index
|
|
313
|
-
const indexingStartTime = Date.now();
|
|
314
|
-
for (let i = 0; i < texts.length; i++) {
|
|
315
|
-
try {
|
|
316
|
-
const text = texts[i];
|
|
317
|
-
const vector = batchEmbeddings.vectors[i];
|
|
318
|
-
const vectorId = this.getNextVectorId(userAddress);
|
|
319
|
-
|
|
320
|
-
const embedding: VectorEmbedding = {
|
|
321
|
-
vector,
|
|
322
|
-
dimension: batchEmbeddings.dimension,
|
|
323
|
-
model: batchEmbeddings.model,
|
|
324
|
-
metadata: {
|
|
325
|
-
contentType: 'text/plain',
|
|
326
|
-
timestamp: Date.now(),
|
|
327
|
-
...text.metadata
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
// Add to index
|
|
332
|
-
if (this.config.enableAutoIndex !== false) {
|
|
333
|
-
const indexService = await this.getIndexService();
|
|
334
|
-
await indexService.addVector(
|
|
335
|
-
userAddress,
|
|
336
|
-
vectorId,
|
|
337
|
-
vector,
|
|
338
|
-
text.metadata
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Cache embedding
|
|
343
|
-
if (this.config.enableMemoryCache && options.enableCache !== false) {
|
|
344
|
-
const textHash = this.hashText(text.text);
|
|
345
|
-
this.memoryCache.set(textHash, embedding);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
results.push({
|
|
349
|
-
success: true,
|
|
350
|
-
vectorId,
|
|
351
|
-
embedding,
|
|
352
|
-
processingTime: 0 // Individual timing not tracked in batch
|
|
353
|
-
});
|
|
354
|
-
} catch (error) {
|
|
355
|
-
results.push({
|
|
356
|
-
success: false,
|
|
357
|
-
processingTime: 0,
|
|
358
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const indexingTime = Date.now() - indexingStartTime;
|
|
364
|
-
const totalTime = Date.now() - startTime;
|
|
365
|
-
|
|
366
|
-
return {
|
|
367
|
-
results,
|
|
368
|
-
stats: {
|
|
369
|
-
totalTime,
|
|
370
|
-
embeddingTime,
|
|
371
|
-
indexingTime,
|
|
372
|
-
successCount: results.filter(r => r.success).length,
|
|
373
|
-
failureCount: results.filter(r => !r.success).length
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Load user's vector index from storage
|
|
380
|
-
*/
|
|
381
|
-
async loadUserIndex(userAddress: string, indexBlobId?: string): Promise<void> {
|
|
382
|
-
const indexService = await this.getIndexService();
|
|
383
|
-
await indexService.loadIndex(userAddress);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Save user's vector index to storage
|
|
388
|
-
*/
|
|
389
|
-
async saveUserIndex(userAddress: string): Promise<void> {
|
|
390
|
-
const indexService = await this.getIndexService();
|
|
391
|
-
await indexService.saveIndex(userAddress);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Force flush pending vectors for a user
|
|
396
|
-
*/
|
|
397
|
-
async forceFlushUser(userAddress: string): Promise<void> {
|
|
398
|
-
const indexService = await this.getIndexService();
|
|
399
|
-
await indexService.flushBatch(userAddress);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Get vector processing statistics
|
|
404
|
-
*/
|
|
405
|
-
async getStats() {
|
|
406
|
-
const embeddingStats = this.embeddingService.getStats();
|
|
407
|
-
|
|
408
|
-
let indexStats = null;
|
|
409
|
-
if (this.indexService) {
|
|
410
|
-
indexStats = this.indexService.getBatchStats();
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return {
|
|
414
|
-
index: indexStats,
|
|
415
|
-
embedding: embeddingStats,
|
|
416
|
-
cache: {
|
|
417
|
-
memoryCache: {
|
|
418
|
-
size: this.memoryCache.size,
|
|
419
|
-
enabled: this.config.enableMemoryCache
|
|
420
|
-
},
|
|
421
|
-
vectorIdCounters: Object.fromEntries(this.vectorIdCounter)
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Clear cache and reset state for a user
|
|
428
|
-
*/
|
|
429
|
-
async clearUserData(userAddress: string): Promise<void> {
|
|
430
|
-
const indexService = await this.getIndexService();
|
|
431
|
-
await indexService.deleteIndex(userAddress);
|
|
432
|
-
this.vectorIdCounter.delete(userAddress);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Cleanup resources
|
|
437
|
-
*/
|
|
438
|
-
destroy(): void {
|
|
439
|
-
if (this.indexService) {
|
|
440
|
-
this.indexService.destroy();
|
|
441
|
-
}
|
|
442
|
-
this.indexService = null;
|
|
443
|
-
this.indexServicePromise = null;
|
|
444
|
-
this.memoryCache.clear();
|
|
445
|
-
this.vectorIdCounter.clear();
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// ==================== PRIVATE METHODS ====================
|
|
449
|
-
|
|
450
|
-
private getNextVectorId(userAddress: string): number {
|
|
451
|
-
const current = this.vectorIdCounter.get(userAddress) || 0;
|
|
452
|
-
const next = current + 1;
|
|
453
|
-
this.vectorIdCounter.set(userAddress, next);
|
|
454
|
-
return next;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
private hashText(text: string): string {
|
|
458
|
-
// Simple hash function for text caching
|
|
459
|
-
let hash = 0;
|
|
460
|
-
for (let i = 0; i < text.length; i++) {
|
|
461
|
-
const char = text.charCodeAt(i);
|
|
462
|
-
hash = ((hash << 5) - hash) + char;
|
|
463
|
-
hash = hash & hash; // Convert to 32-bit integer
|
|
464
|
-
}
|
|
465
|
-
return Math.abs(hash).toString(36);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
private matchesMetadata(metadata: any, filter: any): boolean {
|
|
469
|
-
if (!metadata || !filter) return true;
|
|
470
|
-
|
|
471
|
-
for (const [key, value] of Object.entries(filter)) {
|
|
472
|
-
if (metadata[key] !== value) return false;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
return true;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
1
|
+
/**
|
|
2
|
+
* VectorManager - High-level Vector Operations Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified interface for vector operations combining
|
|
5
|
+
* embedding generation and HNSW indexing with smart caching.
|
|
6
|
+
* Uses hybrid HNSW implementation (browser: wasm, node: native).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { EmbeddingService, EmbeddingOptions, EmbeddingResult, BatchEmbeddingResult } from '../services/EmbeddingService';
|
|
10
|
+
import { createHnswService, isBrowser, isNode } from './createHnswService';
|
|
11
|
+
import type { IHnswService } from './IHnswService';
|
|
12
|
+
import {
|
|
13
|
+
VectorEmbedding,
|
|
14
|
+
EmbeddingConfig,
|
|
15
|
+
HNSWIndexConfig,
|
|
16
|
+
BatchConfig,
|
|
17
|
+
VectorSearchOptions,
|
|
18
|
+
VectorSearchResult,
|
|
19
|
+
VectorSearchMatch,
|
|
20
|
+
HNSWSearchResult
|
|
21
|
+
} from '../embedding/types';
|
|
22
|
+
|
|
23
|
+
export interface VectorManagerConfig {
|
|
24
|
+
embedding: EmbeddingConfig;
|
|
25
|
+
index?: Partial<HNSWIndexConfig>;
|
|
26
|
+
batch?: Partial<BatchConfig>;
|
|
27
|
+
enableAutoIndex?: boolean;
|
|
28
|
+
enableMemoryCache?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface VectorOperationResult {
|
|
32
|
+
success: boolean;
|
|
33
|
+
vectorId?: number;
|
|
34
|
+
embedding?: VectorEmbedding;
|
|
35
|
+
indexBlobId?: string;
|
|
36
|
+
processingTime: number;
|
|
37
|
+
error?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface VectorSearchStats {
|
|
41
|
+
searchTime: number;
|
|
42
|
+
embeddingTime: number;
|
|
43
|
+
indexSearchTime: number;
|
|
44
|
+
totalResults: number;
|
|
45
|
+
cacheHits: number;
|
|
46
|
+
indexSize: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Unified vector operations manager
|
|
51
|
+
*/
|
|
52
|
+
export class VectorManager {
|
|
53
|
+
private embeddingService: EmbeddingService;
|
|
54
|
+
private indexService: IHnswService | null = null;
|
|
55
|
+
private indexServicePromise: Promise<IHnswService> | null = null;
|
|
56
|
+
private vectorIdCounter = new Map<string, number>(); // userAddress -> nextVectorId
|
|
57
|
+
private memoryCache = new Map<string, VectorEmbedding>(); // text hash -> embedding
|
|
58
|
+
private config: VectorManagerConfig;
|
|
59
|
+
|
|
60
|
+
constructor(config: VectorManagerConfig) {
|
|
61
|
+
this.config = config;
|
|
62
|
+
|
|
63
|
+
// Initialize embedding service
|
|
64
|
+
this.embeddingService = new EmbeddingService(config.embedding);
|
|
65
|
+
|
|
66
|
+
// Initialize HNSW index service asynchronously using factory
|
|
67
|
+
this.indexServicePromise = this.initializeIndexService();
|
|
68
|
+
|
|
69
|
+
const envType = isBrowser() ? 'browser (hnswlib-wasm)' : isNode() ? 'Node.js (hnswlib-node)' : 'unknown';
|
|
70
|
+
console.log(`✅ VectorManager initializing with hybrid HNSW (${envType})`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Initialize HNSW service using factory
|
|
75
|
+
*/
|
|
76
|
+
private async initializeIndexService(): Promise<IHnswService> {
|
|
77
|
+
try {
|
|
78
|
+
const service = await createHnswService({
|
|
79
|
+
indexConfig: {
|
|
80
|
+
dimension: this.config.index?.dimension || 3072,
|
|
81
|
+
maxElements: this.config.index?.maxElements || 10000,
|
|
82
|
+
efConstruction: this.config.index?.efConstruction || 200,
|
|
83
|
+
m: this.config.index?.m || 16
|
|
84
|
+
},
|
|
85
|
+
batchConfig: this.config.batch
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
this.indexService = service;
|
|
89
|
+
console.log('✅ VectorManager HNSW service initialized successfully');
|
|
90
|
+
return service;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('❌ Failed to initialize HNSW service:', error);
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get HNSW service (waits for initialization if needed)
|
|
99
|
+
*/
|
|
100
|
+
private async getIndexService(): Promise<IHnswService> {
|
|
101
|
+
if (this.indexService) {
|
|
102
|
+
return this.indexService;
|
|
103
|
+
}
|
|
104
|
+
if (this.indexServicePromise) {
|
|
105
|
+
return this.indexServicePromise;
|
|
106
|
+
}
|
|
107
|
+
throw new Error('HNSW service not initialized');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Add text content to vector index (embed + index)
|
|
112
|
+
*/
|
|
113
|
+
async addTextToIndex(
|
|
114
|
+
userAddress: string,
|
|
115
|
+
text: string,
|
|
116
|
+
options: {
|
|
117
|
+
vectorId?: number;
|
|
118
|
+
metadata?: any;
|
|
119
|
+
embeddingType?: 'content' | 'metadata' | 'query';
|
|
120
|
+
enableCache?: boolean;
|
|
121
|
+
} = {}
|
|
122
|
+
): Promise<VectorOperationResult> {
|
|
123
|
+
const startTime = Date.now();
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Generate or get cached embedding
|
|
127
|
+
let embedding: VectorEmbedding;
|
|
128
|
+
const textHash = this.hashText(text);
|
|
129
|
+
|
|
130
|
+
if (options.enableCache !== false && this.config.enableMemoryCache && this.memoryCache.has(textHash)) {
|
|
131
|
+
embedding = this.memoryCache.get(textHash)!;
|
|
132
|
+
console.debug(`Using cached embedding for text hash: ${textHash.substring(0, 8)}`);
|
|
133
|
+
} else {
|
|
134
|
+
// Generate new embedding
|
|
135
|
+
const embeddingResult = await this.embeddingService.embedText({
|
|
136
|
+
text,
|
|
137
|
+
type: options.embeddingType || 'content'
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
embedding = {
|
|
141
|
+
vector: embeddingResult.vector,
|
|
142
|
+
dimension: embeddingResult.dimension,
|
|
143
|
+
model: embeddingResult.model,
|
|
144
|
+
metadata: {
|
|
145
|
+
contentType: 'text/plain',
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
source: 'vector-manager',
|
|
148
|
+
...options.metadata
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Cache if enabled
|
|
153
|
+
if (this.config.enableMemoryCache) {
|
|
154
|
+
this.memoryCache.set(textHash, embedding);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Get vector ID
|
|
159
|
+
const vectorId = options.vectorId || this.getNextVectorId(userAddress);
|
|
160
|
+
|
|
161
|
+
// Add to HNSW index
|
|
162
|
+
if (this.config.enableAutoIndex !== false) {
|
|
163
|
+
const indexService = await this.getIndexService();
|
|
164
|
+
await indexService.addVector(
|
|
165
|
+
userAddress,
|
|
166
|
+
vectorId,
|
|
167
|
+
embedding.vector,
|
|
168
|
+
{ text, ...options.metadata }
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
success: true,
|
|
174
|
+
vectorId,
|
|
175
|
+
embedding,
|
|
176
|
+
processingTime: Date.now() - startTime
|
|
177
|
+
};
|
|
178
|
+
} catch (error) {
|
|
179
|
+
return {
|
|
180
|
+
success: false,
|
|
181
|
+
processingTime: Date.now() - startTime,
|
|
182
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Search for similar texts using vector similarity
|
|
189
|
+
*/
|
|
190
|
+
async searchSimilarTexts(
|
|
191
|
+
userAddress: string,
|
|
192
|
+
queryText: string,
|
|
193
|
+
options: {
|
|
194
|
+
k?: number;
|
|
195
|
+
threshold?: number;
|
|
196
|
+
efSearch?: number;
|
|
197
|
+
category?: string;
|
|
198
|
+
metadata?: any;
|
|
199
|
+
includeEmbeddings?: boolean;
|
|
200
|
+
} = {}
|
|
201
|
+
): Promise<{
|
|
202
|
+
results: VectorSearchMatch[];
|
|
203
|
+
stats: VectorSearchStats;
|
|
204
|
+
}> {
|
|
205
|
+
const totalStartTime = Date.now();
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
// Generate query embedding
|
|
209
|
+
const embeddingStartTime = Date.now();
|
|
210
|
+
const queryEmbedding = await this.embeddingService.embedText({
|
|
211
|
+
text: queryText,
|
|
212
|
+
type: 'query'
|
|
213
|
+
});
|
|
214
|
+
const embeddingTime = Date.now() - embeddingStartTime;
|
|
215
|
+
|
|
216
|
+
// Search in HNSW index
|
|
217
|
+
const indexStartTime = Date.now();
|
|
218
|
+
const indexService = await this.getIndexService();
|
|
219
|
+
const searchResults = await indexService.search(
|
|
220
|
+
userAddress,
|
|
221
|
+
queryEmbedding.vector,
|
|
222
|
+
{
|
|
223
|
+
k: options.k || 10,
|
|
224
|
+
ef: options.efSearch || 50,
|
|
225
|
+
filter: options.metadata ? (meta) => this.matchesMetadata(meta, options.metadata!) : undefined
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
const indexSearchTime = Date.now() - indexStartTime;
|
|
229
|
+
|
|
230
|
+
// Convert HNSW results to VectorSearchMatch format
|
|
231
|
+
const results: VectorSearchMatch[] = [];
|
|
232
|
+
for (const result of searchResults) {
|
|
233
|
+
const vectorId = result.vectorId;
|
|
234
|
+
const distance = result.distance;
|
|
235
|
+
const similarity = result.score;
|
|
236
|
+
|
|
237
|
+
// Apply threshold filter
|
|
238
|
+
if (options.threshold && similarity < options.threshold) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const match: VectorSearchMatch = {
|
|
243
|
+
memoryId: `memory_${vectorId}`, // TODO: Map to actual memory ID
|
|
244
|
+
vectorId,
|
|
245
|
+
similarity,
|
|
246
|
+
distance,
|
|
247
|
+
metadata: {} // TODO: Get metadata from index
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
if (options.includeEmbeddings) {
|
|
251
|
+
match.embedding = {
|
|
252
|
+
vector: [], // TODO: Store and retrieve vectors
|
|
253
|
+
dimension: queryEmbedding.dimension,
|
|
254
|
+
model: queryEmbedding.model
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
results.push(match);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const stats: VectorSearchStats = {
|
|
262
|
+
searchTime: Date.now() - totalStartTime,
|
|
263
|
+
embeddingTime,
|
|
264
|
+
indexSearchTime,
|
|
265
|
+
totalResults: results.length,
|
|
266
|
+
cacheHits: 0, // TODO: Track cache hits
|
|
267
|
+
indexSize: 0 // TODO: Get from index service
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
return { results, stats };
|
|
271
|
+
} catch (error) {
|
|
272
|
+
throw new Error(`Vector search failed: ${error}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Batch add multiple texts to index
|
|
278
|
+
*/
|
|
279
|
+
async addTextsBatch(
|
|
280
|
+
userAddress: string,
|
|
281
|
+
texts: Array<{
|
|
282
|
+
text: string;
|
|
283
|
+
metadata?: any;
|
|
284
|
+
embeddingType?: 'content' | 'metadata' | 'query';
|
|
285
|
+
}>,
|
|
286
|
+
options: {
|
|
287
|
+
batchSize?: number;
|
|
288
|
+
enableCache?: boolean;
|
|
289
|
+
} = {}
|
|
290
|
+
): Promise<{
|
|
291
|
+
results: VectorOperationResult[];
|
|
292
|
+
stats: {
|
|
293
|
+
totalTime: number;
|
|
294
|
+
embeddingTime: number;
|
|
295
|
+
indexingTime: number;
|
|
296
|
+
successCount: number;
|
|
297
|
+
failureCount: number;
|
|
298
|
+
};
|
|
299
|
+
}> {
|
|
300
|
+
const startTime = Date.now();
|
|
301
|
+
const batchSize = options.batchSize || 10;
|
|
302
|
+
const results: VectorOperationResult[] = [];
|
|
303
|
+
|
|
304
|
+
// Extract texts for batch embedding
|
|
305
|
+
const textContents = texts.map(t => t.text);
|
|
306
|
+
|
|
307
|
+
// Generate embeddings in batch
|
|
308
|
+
const embeddingStartTime = Date.now();
|
|
309
|
+
const batchEmbeddings = await this.embeddingService.embedBatch(textContents);
|
|
310
|
+
const embeddingTime = Date.now() - embeddingStartTime;
|
|
311
|
+
|
|
312
|
+
// Add to index
|
|
313
|
+
const indexingStartTime = Date.now();
|
|
314
|
+
for (let i = 0; i < texts.length; i++) {
|
|
315
|
+
try {
|
|
316
|
+
const text = texts[i];
|
|
317
|
+
const vector = batchEmbeddings.vectors[i];
|
|
318
|
+
const vectorId = this.getNextVectorId(userAddress);
|
|
319
|
+
|
|
320
|
+
const embedding: VectorEmbedding = {
|
|
321
|
+
vector,
|
|
322
|
+
dimension: batchEmbeddings.dimension,
|
|
323
|
+
model: batchEmbeddings.model,
|
|
324
|
+
metadata: {
|
|
325
|
+
contentType: 'text/plain',
|
|
326
|
+
timestamp: Date.now(),
|
|
327
|
+
...text.metadata
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// Add to index
|
|
332
|
+
if (this.config.enableAutoIndex !== false) {
|
|
333
|
+
const indexService = await this.getIndexService();
|
|
334
|
+
await indexService.addVector(
|
|
335
|
+
userAddress,
|
|
336
|
+
vectorId,
|
|
337
|
+
vector,
|
|
338
|
+
text.metadata
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Cache embedding
|
|
343
|
+
if (this.config.enableMemoryCache && options.enableCache !== false) {
|
|
344
|
+
const textHash = this.hashText(text.text);
|
|
345
|
+
this.memoryCache.set(textHash, embedding);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
results.push({
|
|
349
|
+
success: true,
|
|
350
|
+
vectorId,
|
|
351
|
+
embedding,
|
|
352
|
+
processingTime: 0 // Individual timing not tracked in batch
|
|
353
|
+
});
|
|
354
|
+
} catch (error) {
|
|
355
|
+
results.push({
|
|
356
|
+
success: false,
|
|
357
|
+
processingTime: 0,
|
|
358
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const indexingTime = Date.now() - indexingStartTime;
|
|
364
|
+
const totalTime = Date.now() - startTime;
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
results,
|
|
368
|
+
stats: {
|
|
369
|
+
totalTime,
|
|
370
|
+
embeddingTime,
|
|
371
|
+
indexingTime,
|
|
372
|
+
successCount: results.filter(r => r.success).length,
|
|
373
|
+
failureCount: results.filter(r => !r.success).length
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Load user's vector index from storage
|
|
380
|
+
*/
|
|
381
|
+
async loadUserIndex(userAddress: string, indexBlobId?: string): Promise<void> {
|
|
382
|
+
const indexService = await this.getIndexService();
|
|
383
|
+
await indexService.loadIndex(userAddress);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Save user's vector index to storage
|
|
388
|
+
*/
|
|
389
|
+
async saveUserIndex(userAddress: string): Promise<void> {
|
|
390
|
+
const indexService = await this.getIndexService();
|
|
391
|
+
await indexService.saveIndex(userAddress);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Force flush pending vectors for a user
|
|
396
|
+
*/
|
|
397
|
+
async forceFlushUser(userAddress: string): Promise<void> {
|
|
398
|
+
const indexService = await this.getIndexService();
|
|
399
|
+
await indexService.flushBatch(userAddress);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get vector processing statistics
|
|
404
|
+
*/
|
|
405
|
+
async getStats() {
|
|
406
|
+
const embeddingStats = this.embeddingService.getStats();
|
|
407
|
+
|
|
408
|
+
let indexStats = null;
|
|
409
|
+
if (this.indexService) {
|
|
410
|
+
indexStats = this.indexService.getBatchStats();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
index: indexStats,
|
|
415
|
+
embedding: embeddingStats,
|
|
416
|
+
cache: {
|
|
417
|
+
memoryCache: {
|
|
418
|
+
size: this.memoryCache.size,
|
|
419
|
+
enabled: this.config.enableMemoryCache
|
|
420
|
+
},
|
|
421
|
+
vectorIdCounters: Object.fromEntries(this.vectorIdCounter)
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Clear cache and reset state for a user
|
|
428
|
+
*/
|
|
429
|
+
async clearUserData(userAddress: string): Promise<void> {
|
|
430
|
+
const indexService = await this.getIndexService();
|
|
431
|
+
await indexService.deleteIndex(userAddress);
|
|
432
|
+
this.vectorIdCounter.delete(userAddress);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Cleanup resources
|
|
437
|
+
*/
|
|
438
|
+
destroy(): void {
|
|
439
|
+
if (this.indexService) {
|
|
440
|
+
this.indexService.destroy();
|
|
441
|
+
}
|
|
442
|
+
this.indexService = null;
|
|
443
|
+
this.indexServicePromise = null;
|
|
444
|
+
this.memoryCache.clear();
|
|
445
|
+
this.vectorIdCounter.clear();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// ==================== PRIVATE METHODS ====================
|
|
449
|
+
|
|
450
|
+
private getNextVectorId(userAddress: string): number {
|
|
451
|
+
const current = this.vectorIdCounter.get(userAddress) || 0;
|
|
452
|
+
const next = current + 1;
|
|
453
|
+
this.vectorIdCounter.set(userAddress, next);
|
|
454
|
+
return next;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private hashText(text: string): string {
|
|
458
|
+
// Simple hash function for text caching
|
|
459
|
+
let hash = 0;
|
|
460
|
+
for (let i = 0; i < text.length; i++) {
|
|
461
|
+
const char = text.charCodeAt(i);
|
|
462
|
+
hash = ((hash << 5) - hash) + char;
|
|
463
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
464
|
+
}
|
|
465
|
+
return Math.abs(hash).toString(36);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private matchesMetadata(metadata: any, filter: any): boolean {
|
|
469
|
+
if (!metadata || !filter) return true;
|
|
470
|
+
|
|
471
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
472
|
+
if (metadata[key] !== value) return false;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
479
|
export default VectorManager;
|