@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,715 +1,715 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PDWVectorStore - AI SDK Integration
|
|
3
|
-
*
|
|
4
|
-
* A vector store implementation designed for Vercel AI SDK and other AI frameworks.
|
|
5
|
-
* Provides a familiar API (similar to Pinecone/Chroma) while leveraging PDW's full
|
|
6
|
-
* capabilities: Walrus decentralized storage, Sui blockchain, knowledge graphs,
|
|
7
|
-
* and optional SEAL encryption.
|
|
8
|
-
*
|
|
9
|
-
* @module ai-sdk/PDWVectorStore
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* import { embed } from 'ai';
|
|
14
|
-
* import { PDWVectorStore } from 'pdw-sdk/ai-sdk';
|
|
15
|
-
*
|
|
16
|
-
* const store = new PDWVectorStore(config);
|
|
17
|
-
* await store.initialize();
|
|
18
|
-
*
|
|
19
|
-
* // Add vector from AI SDK
|
|
20
|
-
* const { embedding } = await embed({ model, value: text });
|
|
21
|
-
* await store.add({ id, vector: embedding, text });
|
|
22
|
-
*
|
|
23
|
-
* // Search
|
|
24
|
-
* const results = await store.search(queryVector, { limit: 5 });
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
|
|
29
|
-
import { StorageService } from '../services/StorageService';
|
|
30
|
-
// Import environment detection from browser-safe file (no Node.js deps)
|
|
31
|
-
import { isBrowser, isNode } from '../vector/IHnswService';
|
|
32
|
-
import type { IHnswService } from '../vector/IHnswService';
|
|
33
|
-
import { GraphService } from '../graph/GraphService';
|
|
34
|
-
import { EmbeddingService } from '../services/EmbeddingService';
|
|
35
|
-
import type {
|
|
36
|
-
PDWVectorStoreConfig,
|
|
37
|
-
AddVectorParams,
|
|
38
|
-
AddVectorBatchParams,
|
|
39
|
-
SearchParams,
|
|
40
|
-
SearchResult,
|
|
41
|
-
AddVectorResult,
|
|
42
|
-
AddVectorBatchResult,
|
|
43
|
-
GetVectorParams,
|
|
44
|
-
GetVectorResult,
|
|
45
|
-
DeleteVectorParams,
|
|
46
|
-
DeleteVectorResult,
|
|
47
|
-
VectorStoreStats,
|
|
48
|
-
PDWErrorType,
|
|
49
|
-
PDWVectorStoreError as PDWVectorStoreErrorType,
|
|
50
|
-
} from './types';
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Custom error class for PDW Vector Store operations
|
|
54
|
-
*/
|
|
55
|
-
export class PDWVectorStoreError extends Error implements PDWVectorStoreErrorType {
|
|
56
|
-
constructor(
|
|
57
|
-
public type: PDWErrorType,
|
|
58
|
-
message: string,
|
|
59
|
-
public originalError?: Error
|
|
60
|
-
) {
|
|
61
|
-
super(message);
|
|
62
|
-
this.name = 'PDWVectorStoreError';
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* PDW Vector Store - Full-featured vector database with decentralized storage
|
|
68
|
-
*/
|
|
69
|
-
export class PDWVectorStore {
|
|
70
|
-
private config: PDWVectorStoreConfig;
|
|
71
|
-
private storageService: StorageService;
|
|
72
|
-
private vectorService: IHnswService | null = null;
|
|
73
|
-
private vectorServicePromise: Promise<IHnswService> | null = null;
|
|
74
|
-
private graphService?: GraphService;
|
|
75
|
-
private embeddingService?: EmbeddingService;
|
|
76
|
-
private suiClient: SuiClient;
|
|
77
|
-
private initialized: boolean = false;
|
|
78
|
-
private initPromise: Promise<void> | null = null;
|
|
79
|
-
|
|
80
|
-
// Cache for vector ID to blob ID mapping
|
|
81
|
-
private vectorIdMap: Map<string, { blobId: string; vectorId: number }> = new Map();
|
|
82
|
-
|
|
83
|
-
constructor(config: PDWVectorStoreConfig) {
|
|
84
|
-
this.config = config;
|
|
85
|
-
|
|
86
|
-
// Initialize Sui client
|
|
87
|
-
this.suiClient = config.sui.client || new SuiClient({
|
|
88
|
-
url: getFullnodeUrl(config.sui.network)
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Initialize StorageService
|
|
92
|
-
// Map devnet to testnet since StorageService only accepts testnet/mainnet
|
|
93
|
-
const networkForStorage = config.sui.network === 'devnet' ? 'testnet' : config.sui.network as 'testnet' | 'mainnet';
|
|
94
|
-
|
|
95
|
-
this.storageService = new StorageService({
|
|
96
|
-
packageId: config.sui.packageId,
|
|
97
|
-
walrusAggregatorUrl: config.walrus.aggregator,
|
|
98
|
-
walrusPublisherUrl: config.walrus.publisher,
|
|
99
|
-
suiClient: this.suiClient,
|
|
100
|
-
network: networkForStorage,
|
|
101
|
-
epochs: config.storage?.epochs || 3,
|
|
102
|
-
useUploadRelay: true,
|
|
103
|
-
sealService: config.sealService,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Initialize optional services
|
|
107
|
-
if (config.features?.extractKnowledgeGraph !== false && config.geminiApiKey) {
|
|
108
|
-
this.embeddingService = new EmbeddingService({
|
|
109
|
-
apiKey: config.geminiApiKey,
|
|
110
|
-
model: 'text-embedding-004',
|
|
111
|
-
dimensions: 3072,
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
this.storageService.initializeSearch(this.embeddingService);
|
|
115
|
-
|
|
116
|
-
// Initialize knowledge graph
|
|
117
|
-
this.initializeGraphService();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const envType = isBrowser() ? 'browser (hnswlib-wasm)' : isNode() ? 'Node.js (hnswlib-node)' : 'unknown';
|
|
121
|
-
console.log(`🚀 PDWVectorStore initializing with hybrid HNSW (${envType})`);
|
|
122
|
-
|
|
123
|
-
// Start initialization (includes HNSW service creation)
|
|
124
|
-
this.initPromise = this.initialize();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Get vector service (waits for initialization if needed)
|
|
129
|
-
*/
|
|
130
|
-
private async getVectorService(): Promise<IHnswService> {
|
|
131
|
-
if (this.vectorService) {
|
|
132
|
-
return this.vectorService;
|
|
133
|
-
}
|
|
134
|
-
if (this.vectorServicePromise) {
|
|
135
|
-
return this.vectorServicePromise;
|
|
136
|
-
}
|
|
137
|
-
throw new Error('Vector service not initialized');
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Initialize the vector store (HNSW service creation, index setup)
|
|
142
|
-
*/
|
|
143
|
-
private async initialize(): Promise<void> {
|
|
144
|
-
if (this.initialized) return;
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
console.log('🚀 Initializing PDW Vector Store...');
|
|
148
|
-
|
|
149
|
-
// Initialize HNSW service using factory (auto-detects environment)
|
|
150
|
-
// Dynamic import to avoid webpack bundling Node.js modules at build time
|
|
151
|
-
const distanceMetric = this.config.distanceMetric === 'euclidean' ? 'l2' : (this.config.distanceMetric || 'cosine');
|
|
152
|
-
|
|
153
|
-
const { createHnswService } = await import('../vector/createHnswService');
|
|
154
|
-
this.vectorServicePromise = createHnswService({
|
|
155
|
-
indexConfig: {
|
|
156
|
-
dimension: this.config.dimensions,
|
|
157
|
-
maxElements: this.config.index?.maxElements || 10000,
|
|
158
|
-
efConstruction: this.config.index?.efConstruction || 200,
|
|
159
|
-
m: this.config.index?.M || 16,
|
|
160
|
-
spaceType: distanceMetric as 'cosine' | 'l2' | 'ip',
|
|
161
|
-
},
|
|
162
|
-
batchConfig: {
|
|
163
|
-
maxBatchSize: this.config.features?.enableBatching !== false ? 50 : 1,
|
|
164
|
-
batchDelayMs: 5000,
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
this.vectorService = await this.vectorServicePromise;
|
|
169
|
-
|
|
170
|
-
// Try to create or get index for user
|
|
171
|
-
await this.vectorService.getOrCreateIndex(this.config.userAddress);
|
|
172
|
-
|
|
173
|
-
this.initialized = true;
|
|
174
|
-
console.log('✅ PDW Vector Store initialized');
|
|
175
|
-
} catch (error) {
|
|
176
|
-
console.error('❌ Failed to initialize PDW Vector Store:', error);
|
|
177
|
-
throw new PDWVectorStoreError(
|
|
178
|
-
'INDEX_ERROR' as any,
|
|
179
|
-
'Failed to initialize vector store',
|
|
180
|
-
error as Error
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Initialize knowledge graph service
|
|
187
|
-
*/
|
|
188
|
-
private async initializeGraphService(): Promise<void> {
|
|
189
|
-
if (!this.embeddingService) return;
|
|
190
|
-
|
|
191
|
-
try {
|
|
192
|
-
this.graphService = await this.storageService.initializeKnowledgeGraph({
|
|
193
|
-
embeddingService: this.embeddingService,
|
|
194
|
-
});
|
|
195
|
-
console.log('✅ Knowledge graph service initialized');
|
|
196
|
-
} catch (error) {
|
|
197
|
-
console.warn('⚠️ Knowledge graph initialization failed (non-fatal):', error);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Wait for initialization to complete
|
|
203
|
-
*/
|
|
204
|
-
private async ensureInitialized(): Promise<void> {
|
|
205
|
-
if (this.initPromise) {
|
|
206
|
-
await this.initPromise;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Add a vector with text and metadata to the store
|
|
212
|
-
*
|
|
213
|
-
* Performs full PDW pipeline:
|
|
214
|
-
* 1. Optional: Encrypt content with SEAL
|
|
215
|
-
* 2. Upload to Walrus decentralized storage
|
|
216
|
-
* 3. Register on Sui blockchain
|
|
217
|
-
* 4. Index vector in HNSW
|
|
218
|
-
* 5. Optional: Extract knowledge graph
|
|
219
|
-
*
|
|
220
|
-
* @param params - Vector parameters
|
|
221
|
-
* @returns Result with blob ID, transaction digest, and vector ID
|
|
222
|
-
*/
|
|
223
|
-
async add(params: AddVectorParams): Promise<AddVectorResult> {
|
|
224
|
-
await this.ensureInitialized();
|
|
225
|
-
|
|
226
|
-
const startTime = Date.now();
|
|
227
|
-
const {
|
|
228
|
-
id,
|
|
229
|
-
vector,
|
|
230
|
-
text,
|
|
231
|
-
metadata = {},
|
|
232
|
-
category = 'general',
|
|
233
|
-
importance = 5,
|
|
234
|
-
topic = '',
|
|
235
|
-
} = params;
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
// Validate vector dimensions
|
|
239
|
-
if (vector.length !== this.config.dimensions) {
|
|
240
|
-
throw new PDWVectorStoreError(
|
|
241
|
-
'VALIDATION_ERROR' as any,
|
|
242
|
-
`Vector dimension mismatch: expected ${this.config.dimensions}, got ${vector.length}`
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Prepare memory package
|
|
247
|
-
let encryptedContent: Uint8Array | undefined;
|
|
248
|
-
let isEncrypted = false;
|
|
249
|
-
|
|
250
|
-
if (this.config.features?.encryption && this.config.sealService) {
|
|
251
|
-
try {
|
|
252
|
-
const textBytes = new TextEncoder().encode(text);
|
|
253
|
-
const identity = `${this.config.sui.packageId}${this.config.userAddress.replace('0x', '')}`;
|
|
254
|
-
const result = await this.config.sealService.encryptData({
|
|
255
|
-
data: textBytes,
|
|
256
|
-
id: identity,
|
|
257
|
-
threshold: 2
|
|
258
|
-
});
|
|
259
|
-
encryptedContent = result.encryptedObject;
|
|
260
|
-
isEncrypted = true;
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.warn('⚠️ Encryption failed, storing unencrypted:', error);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Upload to Walrus with full metadata
|
|
267
|
-
const uploadResult = await this.storageService.uploadMemoryPackage(
|
|
268
|
-
{
|
|
269
|
-
content: text,
|
|
270
|
-
embedding: vector,
|
|
271
|
-
metadata: {
|
|
272
|
-
id,
|
|
273
|
-
category,
|
|
274
|
-
importance,
|
|
275
|
-
topic,
|
|
276
|
-
...metadata,
|
|
277
|
-
},
|
|
278
|
-
encryptedContent,
|
|
279
|
-
encryptionType: isEncrypted ? 'seal-real' : undefined,
|
|
280
|
-
identity: this.config.userAddress,
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
signer: this.config.signer,
|
|
284
|
-
epochs: this.config.storage?.epochs || 3,
|
|
285
|
-
deletable: this.config.storage?.deletable !== false,
|
|
286
|
-
metadata: {
|
|
287
|
-
'vector-id': id,
|
|
288
|
-
'category': category,
|
|
289
|
-
'importance': importance.toString(),
|
|
290
|
-
'topic': topic,
|
|
291
|
-
},
|
|
292
|
-
}
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
// Index vector
|
|
296
|
-
// Generate numeric vector ID from string ID (simple hash)
|
|
297
|
-
const vectorId = Math.abs(this.hashString(id));
|
|
298
|
-
|
|
299
|
-
// Add vector to index
|
|
300
|
-
const vectorService = await this.getVectorService();
|
|
301
|
-
await vectorService.addVector(
|
|
302
|
-
this.config.userAddress,
|
|
303
|
-
vectorId,
|
|
304
|
-
vector,
|
|
305
|
-
metadata
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
// Cache the mapping
|
|
309
|
-
this.vectorIdMap.set(id, {
|
|
310
|
-
blobId: uploadResult.blobId,
|
|
311
|
-
vectorId,
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
// Extract knowledge graph if enabled
|
|
315
|
-
let graphExtracted = false;
|
|
316
|
-
if (this.graphService && this.config.features?.extractKnowledgeGraph !== false) {
|
|
317
|
-
try {
|
|
318
|
-
const graphResult = await this.storageService.extractKnowledgeGraph(
|
|
319
|
-
text,
|
|
320
|
-
uploadResult.blobId,
|
|
321
|
-
{ confidenceThreshold: 0.6 }
|
|
322
|
-
);
|
|
323
|
-
|
|
324
|
-
if (graphResult.confidence > 0.5) {
|
|
325
|
-
this.storageService['knowledgeGraph'].addToUserGraph(
|
|
326
|
-
this.config.userAddress,
|
|
327
|
-
graphResult.entities,
|
|
328
|
-
graphResult.relationships,
|
|
329
|
-
uploadResult.blobId
|
|
330
|
-
);
|
|
331
|
-
graphExtracted = true;
|
|
332
|
-
}
|
|
333
|
-
} catch (error) {
|
|
334
|
-
console.warn('⚠️ Knowledge graph extraction failed (non-fatal):', error);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const uploadTimeMs = Date.now() - startTime;
|
|
339
|
-
|
|
340
|
-
return {
|
|
341
|
-
id,
|
|
342
|
-
blobId: uploadResult.blobId,
|
|
343
|
-
txDigest: uploadResult.metadata.contentHash, // Using content hash as tx digest
|
|
344
|
-
vectorId,
|
|
345
|
-
graphExtracted,
|
|
346
|
-
encrypted: isEncrypted,
|
|
347
|
-
uploadTimeMs,
|
|
348
|
-
};
|
|
349
|
-
} catch (error) {
|
|
350
|
-
throw new PDWVectorStoreError(
|
|
351
|
-
'STORAGE_ERROR' as any,
|
|
352
|
-
`Failed to add vector: ${error instanceof Error ? error.message : String(error)}`,
|
|
353
|
-
error as Error
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Add multiple vectors in batch
|
|
360
|
-
*
|
|
361
|
-
* @param params - Batch parameters with progress callback
|
|
362
|
-
* @returns Batch result with successful and failed items
|
|
363
|
-
*/
|
|
364
|
-
async addBatch(params: AddVectorBatchParams): Promise<AddVectorBatchResult> {
|
|
365
|
-
await this.ensureInitialized();
|
|
366
|
-
|
|
367
|
-
const startTime = Date.now();
|
|
368
|
-
const { vectors, onProgress } = params;
|
|
369
|
-
const successful: AddVectorResult[] = [];
|
|
370
|
-
const failed: Array<{ id: string; error: string }> = [];
|
|
371
|
-
|
|
372
|
-
for (let i = 0; i < vectors.length; i++) {
|
|
373
|
-
const vectorParams = vectors[i];
|
|
374
|
-
|
|
375
|
-
try {
|
|
376
|
-
if (onProgress) {
|
|
377
|
-
onProgress({
|
|
378
|
-
current: i + 1,
|
|
379
|
-
total: vectors.length,
|
|
380
|
-
stage: 'uploading',
|
|
381
|
-
message: `Processing vector ${i + 1}/${vectors.length}`,
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const result = await this.add(vectorParams);
|
|
386
|
-
successful.push(result);
|
|
387
|
-
} catch (error) {
|
|
388
|
-
failed.push({
|
|
389
|
-
id: vectorParams.id,
|
|
390
|
-
error: error instanceof Error ? error.message : String(error),
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const totalTimeMs = Date.now() - startTime;
|
|
396
|
-
|
|
397
|
-
return {
|
|
398
|
-
successful,
|
|
399
|
-
failed,
|
|
400
|
-
totalTimeMs,
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Search for similar vectors
|
|
406
|
-
*
|
|
407
|
-
* @param params - Search parameters
|
|
408
|
-
* @returns Array of search results sorted by similarity
|
|
409
|
-
*/
|
|
410
|
-
async search(params: SearchParams): Promise<SearchResult[]> {
|
|
411
|
-
await this.ensureInitialized();
|
|
412
|
-
|
|
413
|
-
const {
|
|
414
|
-
vector,
|
|
415
|
-
limit = 5,
|
|
416
|
-
filters,
|
|
417
|
-
minScore = 0,
|
|
418
|
-
includeGraph = false,
|
|
419
|
-
includeContent = true,
|
|
420
|
-
} = params;
|
|
421
|
-
|
|
422
|
-
try {
|
|
423
|
-
// Validate query vector
|
|
424
|
-
if (vector.length !== this.config.dimensions) {
|
|
425
|
-
throw new PDWVectorStoreError(
|
|
426
|
-
'VALIDATION_ERROR' as any,
|
|
427
|
-
`Query vector dimension mismatch: expected ${this.config.dimensions}, got ${vector.length}`
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Search HNSW index
|
|
432
|
-
const vectorService = await this.getVectorService();
|
|
433
|
-
const hnswResults = await vectorService.search(
|
|
434
|
-
this.config.userAddress,
|
|
435
|
-
vector,
|
|
436
|
-
{
|
|
437
|
-
k: limit * 2, // Get extra for filtering
|
|
438
|
-
ef: 50,
|
|
439
|
-
}
|
|
440
|
-
);
|
|
441
|
-
|
|
442
|
-
// Filter and format results
|
|
443
|
-
const results: SearchResult[] = [];
|
|
444
|
-
|
|
445
|
-
// Iterate over search results (IHnswSearchResultItem has vectorId, distance, score)
|
|
446
|
-
for (const result of hnswResults) {
|
|
447
|
-
const vectorId = result.vectorId;
|
|
448
|
-
const distance = result.distance;
|
|
449
|
-
const similarity = result.score;
|
|
450
|
-
|
|
451
|
-
// Find the cached vector info by numeric ID
|
|
452
|
-
const cachedEntry = Array.from(this.vectorIdMap.entries()).find(([_, v]) => v.vectorId === vectorId);
|
|
453
|
-
if (!cachedEntry) continue;
|
|
454
|
-
|
|
455
|
-
const [stringId, cached] = cachedEntry;
|
|
456
|
-
|
|
457
|
-
// Calculate similarity score (0-1 scale)
|
|
458
|
-
const score = similarity;
|
|
459
|
-
|
|
460
|
-
if (score < minScore) continue;
|
|
461
|
-
|
|
462
|
-
try {
|
|
463
|
-
// Retrieve content from Walrus
|
|
464
|
-
let text = '';
|
|
465
|
-
let metadata: Record<string, any> = {};
|
|
466
|
-
|
|
467
|
-
if (includeContent) {
|
|
468
|
-
const memoryPackage = await this.storageService.retrieveMemoryPackage(cached.blobId);
|
|
469
|
-
|
|
470
|
-
if (memoryPackage.storageApproach === 'json-package' && memoryPackage.memoryPackage) {
|
|
471
|
-
text = memoryPackage.memoryPackage.content;
|
|
472
|
-
metadata = memoryPackage.memoryPackage.metadata || {};
|
|
473
|
-
} else if (memoryPackage.isEncrypted && this.config.sealService) {
|
|
474
|
-
// Decrypt if encrypted
|
|
475
|
-
// TODO: Implement full decryption with session keys
|
|
476
|
-
console.warn('⚠️ SEAL decryption requires session keys - not yet implemented in PDWVectorStore');
|
|
477
|
-
text = '[Encrypted content - decryption requires session keys]';
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Apply metadata filters
|
|
482
|
-
if (filters) {
|
|
483
|
-
if (filters.category && !this.matchesFilter(metadata.category, filters.category)) {
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
if (filters.topic && !this.matchesFilter(metadata.topic, filters.topic)) {
|
|
487
|
-
continue;
|
|
488
|
-
}
|
|
489
|
-
if (filters.importance) {
|
|
490
|
-
const imp = metadata.importance || 5;
|
|
491
|
-
if (filters.importance.min && imp < filters.importance.min) continue;
|
|
492
|
-
if (filters.importance.max && imp > filters.importance.max) continue;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const result: SearchResult = {
|
|
497
|
-
id: stringId, // Use the string ID from the cache
|
|
498
|
-
text,
|
|
499
|
-
metadata,
|
|
500
|
-
score,
|
|
501
|
-
distance,
|
|
502
|
-
blobId: cached.blobId,
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
// Add graph data if requested
|
|
506
|
-
if (includeGraph && this.graphService) {
|
|
507
|
-
try {
|
|
508
|
-
const graphData = await this.storageService.searchKnowledgeGraph(
|
|
509
|
-
this.config.userAddress,
|
|
510
|
-
{ searchText: text, limit: 5 }
|
|
511
|
-
);
|
|
512
|
-
|
|
513
|
-
result.relatedEntities = graphData.entities.map(e => ({
|
|
514
|
-
id: e.id,
|
|
515
|
-
name: e.label, // Entity uses 'label' property
|
|
516
|
-
type: e.type,
|
|
517
|
-
confidence: e.confidence ?? 0, // Default to 0 if undefined
|
|
518
|
-
}));
|
|
519
|
-
|
|
520
|
-
result.relatedRelationships = graphData.relationships.map(r => ({
|
|
521
|
-
source: r.source,
|
|
522
|
-
target: r.target,
|
|
523
|
-
type: r.type ?? 'related', // Default type if undefined
|
|
524
|
-
confidence: r.confidence ?? 0, // Default to 0 if undefined
|
|
525
|
-
}));
|
|
526
|
-
} catch (error) {
|
|
527
|
-
console.warn('⚠️ Graph retrieval failed (non-fatal):', error);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
results.push(result);
|
|
532
|
-
|
|
533
|
-
if (results.length >= limit) break;
|
|
534
|
-
} catch (error) {
|
|
535
|
-
console.warn(`⚠️ Failed to retrieve result for vector ${vectorId}:`, error);
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
return results;
|
|
541
|
-
} catch (error) {
|
|
542
|
-
throw new PDWVectorStoreError(
|
|
543
|
-
'INDEX_ERROR' as any,
|
|
544
|
-
`Search failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
545
|
-
error as Error
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Get a vector by ID
|
|
552
|
-
*
|
|
553
|
-
* @param params - Get parameters
|
|
554
|
-
* @returns Vector data with metadata
|
|
555
|
-
*/
|
|
556
|
-
async get(params: GetVectorParams): Promise<GetVectorResult | null> {
|
|
557
|
-
await this.ensureInitialized();
|
|
558
|
-
|
|
559
|
-
const { id, includeContent = true, includeGraph = false } = params;
|
|
560
|
-
|
|
561
|
-
try {
|
|
562
|
-
const cached = this.vectorIdMap.get(id);
|
|
563
|
-
if (!cached) return null;
|
|
564
|
-
|
|
565
|
-
const memoryPackage = await this.storageService.retrieveMemoryPackage(cached.blobId);
|
|
566
|
-
|
|
567
|
-
let text = '';
|
|
568
|
-
let vector: number[] = [];
|
|
569
|
-
let metadata: Record<string, any> = {};
|
|
570
|
-
let encrypted = memoryPackage.isEncrypted;
|
|
571
|
-
let createdAt = memoryPackage.metadata.createdTimestamp;
|
|
572
|
-
|
|
573
|
-
if (memoryPackage.storageApproach === 'json-package' && memoryPackage.memoryPackage) {
|
|
574
|
-
text = memoryPackage.memoryPackage.content;
|
|
575
|
-
vector = memoryPackage.memoryPackage.embedding;
|
|
576
|
-
metadata = memoryPackage.memoryPackage.metadata || {};
|
|
577
|
-
createdAt = memoryPackage.memoryPackage.timestamp;
|
|
578
|
-
} else if (encrypted && this.config.sealService) {
|
|
579
|
-
// TODO: Implement full decryption with session keys
|
|
580
|
-
console.warn('⚠️ SEAL decryption requires session keys - not yet implemented in PDWVectorStore');
|
|
581
|
-
text = '[Encrypted content - decryption requires session keys]';
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
const result: GetVectorResult = {
|
|
585
|
-
id,
|
|
586
|
-
vector,
|
|
587
|
-
text,
|
|
588
|
-
metadata,
|
|
589
|
-
blobId: cached.blobId,
|
|
590
|
-
encrypted,
|
|
591
|
-
createdAt,
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
if (includeGraph && this.graphService) {
|
|
595
|
-
const graphData = await this.storageService.searchKnowledgeGraph(
|
|
596
|
-
this.config.userAddress,
|
|
597
|
-
{ searchText: text, limit: 10 }
|
|
598
|
-
);
|
|
599
|
-
|
|
600
|
-
result.graph = {
|
|
601
|
-
entities: graphData.entities.map(e => ({
|
|
602
|
-
id: e.id,
|
|
603
|
-
name: e.label, // Entity uses 'label' property
|
|
604
|
-
type: e.type,
|
|
605
|
-
confidence: e.confidence ?? 0,
|
|
606
|
-
})),
|
|
607
|
-
relationships: graphData.relationships.map(r => ({
|
|
608
|
-
source: r.source,
|
|
609
|
-
target: r.target,
|
|
610
|
-
type: r.type ?? 'related',
|
|
611
|
-
confidence: r.confidence ?? 0,
|
|
612
|
-
})),
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
return result;
|
|
617
|
-
} catch (error) {
|
|
618
|
-
throw new PDWVectorStoreError(
|
|
619
|
-
'STORAGE_ERROR' as any,
|
|
620
|
-
`Failed to get vector: ${error instanceof Error ? error.message : String(error)}`,
|
|
621
|
-
error as Error
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
* Delete vectors by IDs
|
|
628
|
-
*
|
|
629
|
-
* @param params - Delete parameters
|
|
630
|
-
* @returns Delete result
|
|
631
|
-
*/
|
|
632
|
-
async delete(params: DeleteVectorParams): Promise<DeleteVectorResult> {
|
|
633
|
-
await this.ensureInitialized();
|
|
634
|
-
|
|
635
|
-
const deleted: string[] = [];
|
|
636
|
-
const failed: Array<{ id: string; error: string }> = [];
|
|
637
|
-
|
|
638
|
-
for (const id of params.ids) {
|
|
639
|
-
try {
|
|
640
|
-
// Remove from cache
|
|
641
|
-
this.vectorIdMap.delete(id);
|
|
642
|
-
|
|
643
|
-
// Note: Walrus blobs are immutable, so we just remove from index
|
|
644
|
-
// In a production system, you'd mark as deleted in blockchain metadata
|
|
645
|
-
|
|
646
|
-
deleted.push(id);
|
|
647
|
-
} catch (error) {
|
|
648
|
-
failed.push({
|
|
649
|
-
id,
|
|
650
|
-
error: error instanceof Error ? error.message : String(error),
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
return { deleted, failed };
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
/**
|
|
659
|
-
* Get statistics about the vector store
|
|
660
|
-
*
|
|
661
|
-
* @returns Store statistics
|
|
662
|
-
*/
|
|
663
|
-
async stats(): Promise<VectorStoreStats> {
|
|
664
|
-
await this.ensureInitialized();
|
|
665
|
-
|
|
666
|
-
// Get vector count from our local mapping
|
|
667
|
-
const vectorCount = this.vectorIdMap.size;
|
|
668
|
-
|
|
669
|
-
const stats: VectorStoreStats = {
|
|
670
|
-
totalVectors: vectorCount,
|
|
671
|
-
storageBytes: 0, // Would need to track this
|
|
672
|
-
blockchainTxCount: vectorCount, // One tx per vector
|
|
673
|
-
index: {
|
|
674
|
-
dimensions: this.config.dimensions,
|
|
675
|
-
distanceMetric: this.config.distanceMetric || 'cosine',
|
|
676
|
-
indexSize: vectorCount,
|
|
677
|
-
},
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
if (this.graphService) {
|
|
681
|
-
const graphStats = await this.storageService.getGraphStatistics(this.config.userAddress);
|
|
682
|
-
stats.graph = {
|
|
683
|
-
totalEntities: graphStats.totalEntities,
|
|
684
|
-
totalRelationships: graphStats.totalRelationships,
|
|
685
|
-
entityTypes: graphStats.entityTypes,
|
|
686
|
-
relationshipTypes: graphStats.relationshipTypes,
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
return stats;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Helper: Hash string to numeric ID
|
|
695
|
-
*/
|
|
696
|
-
private hashString(str: string): number {
|
|
697
|
-
let hash = 0;
|
|
698
|
-
for (let i = 0; i < str.length; i++) {
|
|
699
|
-
const char = str.charCodeAt(i);
|
|
700
|
-
hash = ((hash << 5) - hash) + char;
|
|
701
|
-
hash = hash & hash; // Convert to 32bit integer
|
|
702
|
-
}
|
|
703
|
-
return hash;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* Helper: Check if a value matches a filter
|
|
708
|
-
*/
|
|
709
|
-
private matchesFilter(value: any, filter: string | string[]): boolean {
|
|
710
|
-
if (Array.isArray(filter)) {
|
|
711
|
-
return filter.includes(value);
|
|
712
|
-
}
|
|
713
|
-
return value === filter;
|
|
714
|
-
}
|
|
715
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* PDWVectorStore - AI SDK Integration
|
|
3
|
+
*
|
|
4
|
+
* A vector store implementation designed for Vercel AI SDK and other AI frameworks.
|
|
5
|
+
* Provides a familiar API (similar to Pinecone/Chroma) while leveraging PDW's full
|
|
6
|
+
* capabilities: Walrus decentralized storage, Sui blockchain, knowledge graphs,
|
|
7
|
+
* and optional SEAL encryption.
|
|
8
|
+
*
|
|
9
|
+
* @module ai-sdk/PDWVectorStore
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { embed } from 'ai';
|
|
14
|
+
* import { PDWVectorStore } from 'pdw-sdk/ai-sdk';
|
|
15
|
+
*
|
|
16
|
+
* const store = new PDWVectorStore(config);
|
|
17
|
+
* await store.initialize();
|
|
18
|
+
*
|
|
19
|
+
* // Add vector from AI SDK
|
|
20
|
+
* const { embedding } = await embed({ model, value: text });
|
|
21
|
+
* await store.add({ id, vector: embedding, text });
|
|
22
|
+
*
|
|
23
|
+
* // Search
|
|
24
|
+
* const results = await store.search(queryVector, { limit: 5 });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
|
|
29
|
+
import { StorageService } from '../services/StorageService';
|
|
30
|
+
// Import environment detection from browser-safe file (no Node.js deps)
|
|
31
|
+
import { isBrowser, isNode } from '../vector/IHnswService';
|
|
32
|
+
import type { IHnswService } from '../vector/IHnswService';
|
|
33
|
+
import { GraphService } from '../graph/GraphService';
|
|
34
|
+
import { EmbeddingService } from '../services/EmbeddingService';
|
|
35
|
+
import type {
|
|
36
|
+
PDWVectorStoreConfig,
|
|
37
|
+
AddVectorParams,
|
|
38
|
+
AddVectorBatchParams,
|
|
39
|
+
SearchParams,
|
|
40
|
+
SearchResult,
|
|
41
|
+
AddVectorResult,
|
|
42
|
+
AddVectorBatchResult,
|
|
43
|
+
GetVectorParams,
|
|
44
|
+
GetVectorResult,
|
|
45
|
+
DeleteVectorParams,
|
|
46
|
+
DeleteVectorResult,
|
|
47
|
+
VectorStoreStats,
|
|
48
|
+
PDWErrorType,
|
|
49
|
+
PDWVectorStoreError as PDWVectorStoreErrorType,
|
|
50
|
+
} from './types';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Custom error class for PDW Vector Store operations
|
|
54
|
+
*/
|
|
55
|
+
export class PDWVectorStoreError extends Error implements PDWVectorStoreErrorType {
|
|
56
|
+
constructor(
|
|
57
|
+
public type: PDWErrorType,
|
|
58
|
+
message: string,
|
|
59
|
+
public originalError?: Error
|
|
60
|
+
) {
|
|
61
|
+
super(message);
|
|
62
|
+
this.name = 'PDWVectorStoreError';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* PDW Vector Store - Full-featured vector database with decentralized storage
|
|
68
|
+
*/
|
|
69
|
+
export class PDWVectorStore {
|
|
70
|
+
private config: PDWVectorStoreConfig;
|
|
71
|
+
private storageService: StorageService;
|
|
72
|
+
private vectorService: IHnswService | null = null;
|
|
73
|
+
private vectorServicePromise: Promise<IHnswService> | null = null;
|
|
74
|
+
private graphService?: GraphService;
|
|
75
|
+
private embeddingService?: EmbeddingService;
|
|
76
|
+
private suiClient: SuiClient;
|
|
77
|
+
private initialized: boolean = false;
|
|
78
|
+
private initPromise: Promise<void> | null = null;
|
|
79
|
+
|
|
80
|
+
// Cache for vector ID to blob ID mapping
|
|
81
|
+
private vectorIdMap: Map<string, { blobId: string; vectorId: number }> = new Map();
|
|
82
|
+
|
|
83
|
+
constructor(config: PDWVectorStoreConfig) {
|
|
84
|
+
this.config = config;
|
|
85
|
+
|
|
86
|
+
// Initialize Sui client
|
|
87
|
+
this.suiClient = config.sui.client || new SuiClient({
|
|
88
|
+
url: getFullnodeUrl(config.sui.network)
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Initialize StorageService
|
|
92
|
+
// Map devnet to testnet since StorageService only accepts testnet/mainnet
|
|
93
|
+
const networkForStorage = config.sui.network === 'devnet' ? 'testnet' : config.sui.network as 'testnet' | 'mainnet';
|
|
94
|
+
|
|
95
|
+
this.storageService = new StorageService({
|
|
96
|
+
packageId: config.sui.packageId,
|
|
97
|
+
walrusAggregatorUrl: config.walrus.aggregator,
|
|
98
|
+
walrusPublisherUrl: config.walrus.publisher,
|
|
99
|
+
suiClient: this.suiClient,
|
|
100
|
+
network: networkForStorage,
|
|
101
|
+
epochs: config.storage?.epochs || 3,
|
|
102
|
+
useUploadRelay: true,
|
|
103
|
+
sealService: config.sealService,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Initialize optional services
|
|
107
|
+
if (config.features?.extractKnowledgeGraph !== false && config.geminiApiKey) {
|
|
108
|
+
this.embeddingService = new EmbeddingService({
|
|
109
|
+
apiKey: config.geminiApiKey,
|
|
110
|
+
model: 'text-embedding-004',
|
|
111
|
+
dimensions: 3072,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
this.storageService.initializeSearch(this.embeddingService);
|
|
115
|
+
|
|
116
|
+
// Initialize knowledge graph
|
|
117
|
+
this.initializeGraphService();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const envType = isBrowser() ? 'browser (hnswlib-wasm)' : isNode() ? 'Node.js (hnswlib-node)' : 'unknown';
|
|
121
|
+
console.log(`🚀 PDWVectorStore initializing with hybrid HNSW (${envType})`);
|
|
122
|
+
|
|
123
|
+
// Start initialization (includes HNSW service creation)
|
|
124
|
+
this.initPromise = this.initialize();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get vector service (waits for initialization if needed)
|
|
129
|
+
*/
|
|
130
|
+
private async getVectorService(): Promise<IHnswService> {
|
|
131
|
+
if (this.vectorService) {
|
|
132
|
+
return this.vectorService;
|
|
133
|
+
}
|
|
134
|
+
if (this.vectorServicePromise) {
|
|
135
|
+
return this.vectorServicePromise;
|
|
136
|
+
}
|
|
137
|
+
throw new Error('Vector service not initialized');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Initialize the vector store (HNSW service creation, index setup)
|
|
142
|
+
*/
|
|
143
|
+
private async initialize(): Promise<void> {
|
|
144
|
+
if (this.initialized) return;
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
console.log('🚀 Initializing PDW Vector Store...');
|
|
148
|
+
|
|
149
|
+
// Initialize HNSW service using factory (auto-detects environment)
|
|
150
|
+
// Dynamic import to avoid webpack bundling Node.js modules at build time
|
|
151
|
+
const distanceMetric = this.config.distanceMetric === 'euclidean' ? 'l2' : (this.config.distanceMetric || 'cosine');
|
|
152
|
+
|
|
153
|
+
const { createHnswService } = await import('../vector/createHnswService');
|
|
154
|
+
this.vectorServicePromise = createHnswService({
|
|
155
|
+
indexConfig: {
|
|
156
|
+
dimension: this.config.dimensions,
|
|
157
|
+
maxElements: this.config.index?.maxElements || 10000,
|
|
158
|
+
efConstruction: this.config.index?.efConstruction || 200,
|
|
159
|
+
m: this.config.index?.M || 16,
|
|
160
|
+
spaceType: distanceMetric as 'cosine' | 'l2' | 'ip',
|
|
161
|
+
},
|
|
162
|
+
batchConfig: {
|
|
163
|
+
maxBatchSize: this.config.features?.enableBatching !== false ? 50 : 1,
|
|
164
|
+
batchDelayMs: 5000,
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
this.vectorService = await this.vectorServicePromise;
|
|
169
|
+
|
|
170
|
+
// Try to create or get index for user
|
|
171
|
+
await this.vectorService.getOrCreateIndex(this.config.userAddress);
|
|
172
|
+
|
|
173
|
+
this.initialized = true;
|
|
174
|
+
console.log('✅ PDW Vector Store initialized');
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('❌ Failed to initialize PDW Vector Store:', error);
|
|
177
|
+
throw new PDWVectorStoreError(
|
|
178
|
+
'INDEX_ERROR' as any,
|
|
179
|
+
'Failed to initialize vector store',
|
|
180
|
+
error as Error
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Initialize knowledge graph service
|
|
187
|
+
*/
|
|
188
|
+
private async initializeGraphService(): Promise<void> {
|
|
189
|
+
if (!this.embeddingService) return;
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
this.graphService = await this.storageService.initializeKnowledgeGraph({
|
|
193
|
+
embeddingService: this.embeddingService,
|
|
194
|
+
});
|
|
195
|
+
console.log('✅ Knowledge graph service initialized');
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.warn('⚠️ Knowledge graph initialization failed (non-fatal):', error);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Wait for initialization to complete
|
|
203
|
+
*/
|
|
204
|
+
private async ensureInitialized(): Promise<void> {
|
|
205
|
+
if (this.initPromise) {
|
|
206
|
+
await this.initPromise;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Add a vector with text and metadata to the store
|
|
212
|
+
*
|
|
213
|
+
* Performs full PDW pipeline:
|
|
214
|
+
* 1. Optional: Encrypt content with SEAL
|
|
215
|
+
* 2. Upload to Walrus decentralized storage
|
|
216
|
+
* 3. Register on Sui blockchain
|
|
217
|
+
* 4. Index vector in HNSW
|
|
218
|
+
* 5. Optional: Extract knowledge graph
|
|
219
|
+
*
|
|
220
|
+
* @param params - Vector parameters
|
|
221
|
+
* @returns Result with blob ID, transaction digest, and vector ID
|
|
222
|
+
*/
|
|
223
|
+
async add(params: AddVectorParams): Promise<AddVectorResult> {
|
|
224
|
+
await this.ensureInitialized();
|
|
225
|
+
|
|
226
|
+
const startTime = Date.now();
|
|
227
|
+
const {
|
|
228
|
+
id,
|
|
229
|
+
vector,
|
|
230
|
+
text,
|
|
231
|
+
metadata = {},
|
|
232
|
+
category = 'general',
|
|
233
|
+
importance = 5,
|
|
234
|
+
topic = '',
|
|
235
|
+
} = params;
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
// Validate vector dimensions
|
|
239
|
+
if (vector.length !== this.config.dimensions) {
|
|
240
|
+
throw new PDWVectorStoreError(
|
|
241
|
+
'VALIDATION_ERROR' as any,
|
|
242
|
+
`Vector dimension mismatch: expected ${this.config.dimensions}, got ${vector.length}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Prepare memory package
|
|
247
|
+
let encryptedContent: Uint8Array | undefined;
|
|
248
|
+
let isEncrypted = false;
|
|
249
|
+
|
|
250
|
+
if (this.config.features?.encryption && this.config.sealService) {
|
|
251
|
+
try {
|
|
252
|
+
const textBytes = new TextEncoder().encode(text);
|
|
253
|
+
const identity = `${this.config.sui.packageId}${this.config.userAddress.replace('0x', '')}`;
|
|
254
|
+
const result = await this.config.sealService.encryptData({
|
|
255
|
+
data: textBytes,
|
|
256
|
+
id: identity,
|
|
257
|
+
threshold: 2
|
|
258
|
+
});
|
|
259
|
+
encryptedContent = result.encryptedObject;
|
|
260
|
+
isEncrypted = true;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.warn('⚠️ Encryption failed, storing unencrypted:', error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Upload to Walrus with full metadata
|
|
267
|
+
const uploadResult = await this.storageService.uploadMemoryPackage(
|
|
268
|
+
{
|
|
269
|
+
content: text,
|
|
270
|
+
embedding: vector,
|
|
271
|
+
metadata: {
|
|
272
|
+
id,
|
|
273
|
+
category,
|
|
274
|
+
importance,
|
|
275
|
+
topic,
|
|
276
|
+
...metadata,
|
|
277
|
+
},
|
|
278
|
+
encryptedContent,
|
|
279
|
+
encryptionType: isEncrypted ? 'seal-real' : undefined,
|
|
280
|
+
identity: this.config.userAddress,
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
signer: this.config.signer,
|
|
284
|
+
epochs: this.config.storage?.epochs || 3,
|
|
285
|
+
deletable: this.config.storage?.deletable !== false,
|
|
286
|
+
metadata: {
|
|
287
|
+
'vector-id': id,
|
|
288
|
+
'category': category,
|
|
289
|
+
'importance': importance.toString(),
|
|
290
|
+
'topic': topic,
|
|
291
|
+
},
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
// Index vector
|
|
296
|
+
// Generate numeric vector ID from string ID (simple hash)
|
|
297
|
+
const vectorId = Math.abs(this.hashString(id));
|
|
298
|
+
|
|
299
|
+
// Add vector to index
|
|
300
|
+
const vectorService = await this.getVectorService();
|
|
301
|
+
await vectorService.addVector(
|
|
302
|
+
this.config.userAddress,
|
|
303
|
+
vectorId,
|
|
304
|
+
vector,
|
|
305
|
+
metadata
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// Cache the mapping
|
|
309
|
+
this.vectorIdMap.set(id, {
|
|
310
|
+
blobId: uploadResult.blobId,
|
|
311
|
+
vectorId,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Extract knowledge graph if enabled
|
|
315
|
+
let graphExtracted = false;
|
|
316
|
+
if (this.graphService && this.config.features?.extractKnowledgeGraph !== false) {
|
|
317
|
+
try {
|
|
318
|
+
const graphResult = await this.storageService.extractKnowledgeGraph(
|
|
319
|
+
text,
|
|
320
|
+
uploadResult.blobId,
|
|
321
|
+
{ confidenceThreshold: 0.6 }
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
if (graphResult.confidence > 0.5) {
|
|
325
|
+
this.storageService['knowledgeGraph'].addToUserGraph(
|
|
326
|
+
this.config.userAddress,
|
|
327
|
+
graphResult.entities,
|
|
328
|
+
graphResult.relationships,
|
|
329
|
+
uploadResult.blobId
|
|
330
|
+
);
|
|
331
|
+
graphExtracted = true;
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.warn('⚠️ Knowledge graph extraction failed (non-fatal):', error);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const uploadTimeMs = Date.now() - startTime;
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
id,
|
|
342
|
+
blobId: uploadResult.blobId,
|
|
343
|
+
txDigest: uploadResult.metadata.contentHash, // Using content hash as tx digest
|
|
344
|
+
vectorId,
|
|
345
|
+
graphExtracted,
|
|
346
|
+
encrypted: isEncrypted,
|
|
347
|
+
uploadTimeMs,
|
|
348
|
+
};
|
|
349
|
+
} catch (error) {
|
|
350
|
+
throw new PDWVectorStoreError(
|
|
351
|
+
'STORAGE_ERROR' as any,
|
|
352
|
+
`Failed to add vector: ${error instanceof Error ? error.message : String(error)}`,
|
|
353
|
+
error as Error
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Add multiple vectors in batch
|
|
360
|
+
*
|
|
361
|
+
* @param params - Batch parameters with progress callback
|
|
362
|
+
* @returns Batch result with successful and failed items
|
|
363
|
+
*/
|
|
364
|
+
async addBatch(params: AddVectorBatchParams): Promise<AddVectorBatchResult> {
|
|
365
|
+
await this.ensureInitialized();
|
|
366
|
+
|
|
367
|
+
const startTime = Date.now();
|
|
368
|
+
const { vectors, onProgress } = params;
|
|
369
|
+
const successful: AddVectorResult[] = [];
|
|
370
|
+
const failed: Array<{ id: string; error: string }> = [];
|
|
371
|
+
|
|
372
|
+
for (let i = 0; i < vectors.length; i++) {
|
|
373
|
+
const vectorParams = vectors[i];
|
|
374
|
+
|
|
375
|
+
try {
|
|
376
|
+
if (onProgress) {
|
|
377
|
+
onProgress({
|
|
378
|
+
current: i + 1,
|
|
379
|
+
total: vectors.length,
|
|
380
|
+
stage: 'uploading',
|
|
381
|
+
message: `Processing vector ${i + 1}/${vectors.length}`,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const result = await this.add(vectorParams);
|
|
386
|
+
successful.push(result);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
failed.push({
|
|
389
|
+
id: vectorParams.id,
|
|
390
|
+
error: error instanceof Error ? error.message : String(error),
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const totalTimeMs = Date.now() - startTime;
|
|
396
|
+
|
|
397
|
+
return {
|
|
398
|
+
successful,
|
|
399
|
+
failed,
|
|
400
|
+
totalTimeMs,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Search for similar vectors
|
|
406
|
+
*
|
|
407
|
+
* @param params - Search parameters
|
|
408
|
+
* @returns Array of search results sorted by similarity
|
|
409
|
+
*/
|
|
410
|
+
async search(params: SearchParams): Promise<SearchResult[]> {
|
|
411
|
+
await this.ensureInitialized();
|
|
412
|
+
|
|
413
|
+
const {
|
|
414
|
+
vector,
|
|
415
|
+
limit = 5,
|
|
416
|
+
filters,
|
|
417
|
+
minScore = 0,
|
|
418
|
+
includeGraph = false,
|
|
419
|
+
includeContent = true,
|
|
420
|
+
} = params;
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
// Validate query vector
|
|
424
|
+
if (vector.length !== this.config.dimensions) {
|
|
425
|
+
throw new PDWVectorStoreError(
|
|
426
|
+
'VALIDATION_ERROR' as any,
|
|
427
|
+
`Query vector dimension mismatch: expected ${this.config.dimensions}, got ${vector.length}`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Search HNSW index
|
|
432
|
+
const vectorService = await this.getVectorService();
|
|
433
|
+
const hnswResults = await vectorService.search(
|
|
434
|
+
this.config.userAddress,
|
|
435
|
+
vector,
|
|
436
|
+
{
|
|
437
|
+
k: limit * 2, // Get extra for filtering
|
|
438
|
+
ef: 50,
|
|
439
|
+
}
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
// Filter and format results
|
|
443
|
+
const results: SearchResult[] = [];
|
|
444
|
+
|
|
445
|
+
// Iterate over search results (IHnswSearchResultItem has vectorId, distance, score)
|
|
446
|
+
for (const result of hnswResults) {
|
|
447
|
+
const vectorId = result.vectorId;
|
|
448
|
+
const distance = result.distance;
|
|
449
|
+
const similarity = result.score;
|
|
450
|
+
|
|
451
|
+
// Find the cached vector info by numeric ID
|
|
452
|
+
const cachedEntry = Array.from(this.vectorIdMap.entries()).find(([_, v]) => v.vectorId === vectorId);
|
|
453
|
+
if (!cachedEntry) continue;
|
|
454
|
+
|
|
455
|
+
const [stringId, cached] = cachedEntry;
|
|
456
|
+
|
|
457
|
+
// Calculate similarity score (0-1 scale)
|
|
458
|
+
const score = similarity;
|
|
459
|
+
|
|
460
|
+
if (score < minScore) continue;
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
// Retrieve content from Walrus
|
|
464
|
+
let text = '';
|
|
465
|
+
let metadata: Record<string, any> = {};
|
|
466
|
+
|
|
467
|
+
if (includeContent) {
|
|
468
|
+
const memoryPackage = await this.storageService.retrieveMemoryPackage(cached.blobId);
|
|
469
|
+
|
|
470
|
+
if (memoryPackage.storageApproach === 'json-package' && memoryPackage.memoryPackage) {
|
|
471
|
+
text = memoryPackage.memoryPackage.content;
|
|
472
|
+
metadata = memoryPackage.memoryPackage.metadata || {};
|
|
473
|
+
} else if (memoryPackage.isEncrypted && this.config.sealService) {
|
|
474
|
+
// Decrypt if encrypted
|
|
475
|
+
// TODO: Implement full decryption with session keys
|
|
476
|
+
console.warn('⚠️ SEAL decryption requires session keys - not yet implemented in PDWVectorStore');
|
|
477
|
+
text = '[Encrypted content - decryption requires session keys]';
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Apply metadata filters
|
|
482
|
+
if (filters) {
|
|
483
|
+
if (filters.category && !this.matchesFilter(metadata.category, filters.category)) {
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (filters.topic && !this.matchesFilter(metadata.topic, filters.topic)) {
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (filters.importance) {
|
|
490
|
+
const imp = metadata.importance || 5;
|
|
491
|
+
if (filters.importance.min && imp < filters.importance.min) continue;
|
|
492
|
+
if (filters.importance.max && imp > filters.importance.max) continue;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const result: SearchResult = {
|
|
497
|
+
id: stringId, // Use the string ID from the cache
|
|
498
|
+
text,
|
|
499
|
+
metadata,
|
|
500
|
+
score,
|
|
501
|
+
distance,
|
|
502
|
+
blobId: cached.blobId,
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// Add graph data if requested
|
|
506
|
+
if (includeGraph && this.graphService) {
|
|
507
|
+
try {
|
|
508
|
+
const graphData = await this.storageService.searchKnowledgeGraph(
|
|
509
|
+
this.config.userAddress,
|
|
510
|
+
{ searchText: text, limit: 5 }
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
result.relatedEntities = graphData.entities.map(e => ({
|
|
514
|
+
id: e.id,
|
|
515
|
+
name: e.label, // Entity uses 'label' property
|
|
516
|
+
type: e.type,
|
|
517
|
+
confidence: e.confidence ?? 0, // Default to 0 if undefined
|
|
518
|
+
}));
|
|
519
|
+
|
|
520
|
+
result.relatedRelationships = graphData.relationships.map(r => ({
|
|
521
|
+
source: r.source,
|
|
522
|
+
target: r.target,
|
|
523
|
+
type: r.type ?? 'related', // Default type if undefined
|
|
524
|
+
confidence: r.confidence ?? 0, // Default to 0 if undefined
|
|
525
|
+
}));
|
|
526
|
+
} catch (error) {
|
|
527
|
+
console.warn('⚠️ Graph retrieval failed (non-fatal):', error);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
results.push(result);
|
|
532
|
+
|
|
533
|
+
if (results.length >= limit) break;
|
|
534
|
+
} catch (error) {
|
|
535
|
+
console.warn(`⚠️ Failed to retrieve result for vector ${vectorId}:`, error);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return results;
|
|
541
|
+
} catch (error) {
|
|
542
|
+
throw new PDWVectorStoreError(
|
|
543
|
+
'INDEX_ERROR' as any,
|
|
544
|
+
`Search failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
545
|
+
error as Error
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Get a vector by ID
|
|
552
|
+
*
|
|
553
|
+
* @param params - Get parameters
|
|
554
|
+
* @returns Vector data with metadata
|
|
555
|
+
*/
|
|
556
|
+
async get(params: GetVectorParams): Promise<GetVectorResult | null> {
|
|
557
|
+
await this.ensureInitialized();
|
|
558
|
+
|
|
559
|
+
const { id, includeContent = true, includeGraph = false } = params;
|
|
560
|
+
|
|
561
|
+
try {
|
|
562
|
+
const cached = this.vectorIdMap.get(id);
|
|
563
|
+
if (!cached) return null;
|
|
564
|
+
|
|
565
|
+
const memoryPackage = await this.storageService.retrieveMemoryPackage(cached.blobId);
|
|
566
|
+
|
|
567
|
+
let text = '';
|
|
568
|
+
let vector: number[] = [];
|
|
569
|
+
let metadata: Record<string, any> = {};
|
|
570
|
+
let encrypted = memoryPackage.isEncrypted;
|
|
571
|
+
let createdAt = memoryPackage.metadata.createdTimestamp;
|
|
572
|
+
|
|
573
|
+
if (memoryPackage.storageApproach === 'json-package' && memoryPackage.memoryPackage) {
|
|
574
|
+
text = memoryPackage.memoryPackage.content;
|
|
575
|
+
vector = memoryPackage.memoryPackage.embedding;
|
|
576
|
+
metadata = memoryPackage.memoryPackage.metadata || {};
|
|
577
|
+
createdAt = memoryPackage.memoryPackage.timestamp;
|
|
578
|
+
} else if (encrypted && this.config.sealService) {
|
|
579
|
+
// TODO: Implement full decryption with session keys
|
|
580
|
+
console.warn('⚠️ SEAL decryption requires session keys - not yet implemented in PDWVectorStore');
|
|
581
|
+
text = '[Encrypted content - decryption requires session keys]';
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const result: GetVectorResult = {
|
|
585
|
+
id,
|
|
586
|
+
vector,
|
|
587
|
+
text,
|
|
588
|
+
metadata,
|
|
589
|
+
blobId: cached.blobId,
|
|
590
|
+
encrypted,
|
|
591
|
+
createdAt,
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
if (includeGraph && this.graphService) {
|
|
595
|
+
const graphData = await this.storageService.searchKnowledgeGraph(
|
|
596
|
+
this.config.userAddress,
|
|
597
|
+
{ searchText: text, limit: 10 }
|
|
598
|
+
);
|
|
599
|
+
|
|
600
|
+
result.graph = {
|
|
601
|
+
entities: graphData.entities.map(e => ({
|
|
602
|
+
id: e.id,
|
|
603
|
+
name: e.label, // Entity uses 'label' property
|
|
604
|
+
type: e.type,
|
|
605
|
+
confidence: e.confidence ?? 0,
|
|
606
|
+
})),
|
|
607
|
+
relationships: graphData.relationships.map(r => ({
|
|
608
|
+
source: r.source,
|
|
609
|
+
target: r.target,
|
|
610
|
+
type: r.type ?? 'related',
|
|
611
|
+
confidence: r.confidence ?? 0,
|
|
612
|
+
})),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return result;
|
|
617
|
+
} catch (error) {
|
|
618
|
+
throw new PDWVectorStoreError(
|
|
619
|
+
'STORAGE_ERROR' as any,
|
|
620
|
+
`Failed to get vector: ${error instanceof Error ? error.message : String(error)}`,
|
|
621
|
+
error as Error
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Delete vectors by IDs
|
|
628
|
+
*
|
|
629
|
+
* @param params - Delete parameters
|
|
630
|
+
* @returns Delete result
|
|
631
|
+
*/
|
|
632
|
+
async delete(params: DeleteVectorParams): Promise<DeleteVectorResult> {
|
|
633
|
+
await this.ensureInitialized();
|
|
634
|
+
|
|
635
|
+
const deleted: string[] = [];
|
|
636
|
+
const failed: Array<{ id: string; error: string }> = [];
|
|
637
|
+
|
|
638
|
+
for (const id of params.ids) {
|
|
639
|
+
try {
|
|
640
|
+
// Remove from cache
|
|
641
|
+
this.vectorIdMap.delete(id);
|
|
642
|
+
|
|
643
|
+
// Note: Walrus blobs are immutable, so we just remove from index
|
|
644
|
+
// In a production system, you'd mark as deleted in blockchain metadata
|
|
645
|
+
|
|
646
|
+
deleted.push(id);
|
|
647
|
+
} catch (error) {
|
|
648
|
+
failed.push({
|
|
649
|
+
id,
|
|
650
|
+
error: error instanceof Error ? error.message : String(error),
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return { deleted, failed };
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Get statistics about the vector store
|
|
660
|
+
*
|
|
661
|
+
* @returns Store statistics
|
|
662
|
+
*/
|
|
663
|
+
async stats(): Promise<VectorStoreStats> {
|
|
664
|
+
await this.ensureInitialized();
|
|
665
|
+
|
|
666
|
+
// Get vector count from our local mapping
|
|
667
|
+
const vectorCount = this.vectorIdMap.size;
|
|
668
|
+
|
|
669
|
+
const stats: VectorStoreStats = {
|
|
670
|
+
totalVectors: vectorCount,
|
|
671
|
+
storageBytes: 0, // Would need to track this
|
|
672
|
+
blockchainTxCount: vectorCount, // One tx per vector
|
|
673
|
+
index: {
|
|
674
|
+
dimensions: this.config.dimensions,
|
|
675
|
+
distanceMetric: this.config.distanceMetric || 'cosine',
|
|
676
|
+
indexSize: vectorCount,
|
|
677
|
+
},
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
if (this.graphService) {
|
|
681
|
+
const graphStats = await this.storageService.getGraphStatistics(this.config.userAddress);
|
|
682
|
+
stats.graph = {
|
|
683
|
+
totalEntities: graphStats.totalEntities,
|
|
684
|
+
totalRelationships: graphStats.totalRelationships,
|
|
685
|
+
entityTypes: graphStats.entityTypes,
|
|
686
|
+
relationshipTypes: graphStats.relationshipTypes,
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return stats;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Helper: Hash string to numeric ID
|
|
695
|
+
*/
|
|
696
|
+
private hashString(str: string): number {
|
|
697
|
+
let hash = 0;
|
|
698
|
+
for (let i = 0; i < str.length; i++) {
|
|
699
|
+
const char = str.charCodeAt(i);
|
|
700
|
+
hash = ((hash << 5) - hash) + char;
|
|
701
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
702
|
+
}
|
|
703
|
+
return hash;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Helper: Check if a value matches a filter
|
|
708
|
+
*/
|
|
709
|
+
private matchesFilter(value: any, filter: string | string[]): boolean {
|
|
710
|
+
if (Array.isArray(filter)) {
|
|
711
|
+
return filter.includes(value);
|
|
712
|
+
}
|
|
713
|
+
return value === filter;
|
|
714
|
+
}
|
|
715
|
+
}
|