@cmdoss/memwal-sdk 0.6.1 → 0.7.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/dist/ai-sdk/PDWVectorStore.d.ts.map +1 -1
- package/dist/ai-sdk/PDWVectorStore.js +4 -1
- package/dist/ai-sdk/PDWVectorStore.js.map +1 -1
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/browser.d.ts +5 -6
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +7 -6
- package/dist/browser.js.map +1 -1
- package/dist/client/ClientMemoryManager.d.ts +1 -0
- package/dist/client/ClientMemoryManager.d.ts.map +1 -1
- package/dist/client/ClientMemoryManager.js +5 -1
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +24 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +31 -9
- 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/IndexNamespace.d.ts +38 -9
- package/dist/client/namespaces/IndexNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/IndexNamespace.js +77 -10
- package/dist/client/namespaces/IndexNamespace.js.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +27 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +104 -0
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/SearchNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/SearchNamespace.js +25 -14
- package/dist/client/namespaces/SearchNamespace.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.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +69 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +46 -0
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +34 -0
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/graph/GraphService.js +2 -2
- 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/permissions/ConsentRepository.browser.d.ts +56 -0
- package/dist/permissions/ConsentRepository.browser.d.ts.map +1 -0
- package/dist/permissions/ConsentRepository.browser.js +198 -0
- package/dist/permissions/ConsentRepository.browser.js.map +1 -0
- 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/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/GeminiAIService.d.ts.map +1 -1
- package/dist/services/GeminiAIService.js +283 -27
- package/dist/services/GeminiAIService.js.map +1 -1
- 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/MemoryIndexService.d.ts +31 -2
- package/dist/services/MemoryIndexService.d.ts.map +1 -1
- package/dist/services/MemoryIndexService.js +75 -3
- package/dist/services/MemoryIndexService.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 +10 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +13 -0
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +111 -4
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +450 -38
- 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 +387 -45
- 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 +108 -10
- 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/ai-sdk/PDWVectorStore.ts +4 -1
- package/src/ai-sdk/tools.ts +2 -2
- package/src/browser.ts +15 -10
- package/src/client/ClientMemoryManager.ts +6 -1
- package/src/client/SimplePDWClient.ts +63 -10
- package/src/client/namespaces/EmbeddingsNamespace.ts +1 -1
- package/src/client/namespaces/IndexNamespace.ts +89 -11
- package/src/client/namespaces/MemoryNamespace.ts +137 -0
- package/src/client/namespaces/SearchNamespace.ts +27 -14
- package/src/client/namespaces/consolidated/AINamespace.ts +2 -2
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +73 -1
- package/src/client/namespaces/consolidated/StorageNamespace.ts +57 -0
- package/src/core/types/index.ts +1 -1
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +2 -2
- package/src/index.ts +25 -1
- package/src/permissions/ConsentRepository.browser.ts +249 -0
- package/src/retrieval/MemoryRetrievalService.ts +78 -4
- package/src/services/EmbeddingService.ts +66 -1
- package/src/services/GeminiAIService.ts +283 -27
- package/src/services/IndexManager.ts +18 -45
- package/src/services/MemoryIndexService.ts +85 -3
- package/src/services/QueryService.ts +1 -1
- package/src/services/StorageService.ts +15 -0
- package/src/services/storage/QuiltBatchManager.ts +538 -42
- package/src/services/storage/index.ts +6 -1
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndexNode.ts +482 -52
- package/src/vector/HnswWasmService.ts +95 -43
- package/src/vector/IHnswService.ts +10 -1
- package/src/vector/NodeHnswService.ts +130 -10
- package/src/vector/createHnswService.ts +1 -1
- package/src/vector/index.ts +1 -1
|
@@ -31,7 +31,7 @@ import type { Keypair } from '@mysten/sui/cryptography';
|
|
|
31
31
|
import type { UnifiedSigner, WalletAdapter } from './signers';
|
|
32
32
|
import { KeypairSigner, WalletAdapterSigner } from './signers';
|
|
33
33
|
import { StorageService } from '../services/StorageService';
|
|
34
|
-
import { EmbeddingService } from '../services/EmbeddingService';
|
|
34
|
+
import { EmbeddingService, getSharedEmbeddingService } from '../services/EmbeddingService';
|
|
35
35
|
import { MemoryService } from '../services/MemoryService';
|
|
36
36
|
import { QueryService } from '../services/QueryService';
|
|
37
37
|
import { ClassifierService } from '../services/ClassifierService';
|
|
@@ -130,7 +130,7 @@ export interface SimplePDWConfig {
|
|
|
130
130
|
modelName?: string;
|
|
131
131
|
/**
|
|
132
132
|
* Embedding dimensions
|
|
133
|
-
* @default
|
|
133
|
+
* @default 3072 (for google/openrouter), 1536 (for openai)
|
|
134
134
|
*/
|
|
135
135
|
dimensions?: number;
|
|
136
136
|
};
|
|
@@ -190,6 +190,23 @@ export interface SimplePDWConfig {
|
|
|
190
190
|
/** Progress callback for index operations */
|
|
191
191
|
onProgress?: IndexProgressCallback;
|
|
192
192
|
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Optional: Index backup to Walrus cloud storage
|
|
196
|
+
* Enables syncing local HNSW index to Walrus for cross-device restoration
|
|
197
|
+
*/
|
|
198
|
+
indexBackup?: {
|
|
199
|
+
/** Enable Walrus backup for local index */
|
|
200
|
+
enabled: boolean;
|
|
201
|
+
/** Walrus aggregator URL for downloading */
|
|
202
|
+
aggregatorUrl?: string;
|
|
203
|
+
/** Walrus publisher URL for uploading */
|
|
204
|
+
publisherUrl?: string;
|
|
205
|
+
/** Auto-sync index to Walrus on every save (default: false) */
|
|
206
|
+
autoSync?: boolean;
|
|
207
|
+
/** Storage duration in epochs (default: 3) */
|
|
208
|
+
epochs?: number;
|
|
209
|
+
};
|
|
193
210
|
}
|
|
194
211
|
|
|
195
212
|
/**
|
|
@@ -239,6 +256,13 @@ interface ResolvedConfig {
|
|
|
239
256
|
enableAutoSave?: boolean;
|
|
240
257
|
onProgress?: IndexProgressCallback;
|
|
241
258
|
};
|
|
259
|
+
indexBackup?: {
|
|
260
|
+
enabled: boolean;
|
|
261
|
+
aggregatorUrl?: string;
|
|
262
|
+
publisherUrl?: string;
|
|
263
|
+
autoSync?: boolean;
|
|
264
|
+
epochs?: number;
|
|
265
|
+
};
|
|
242
266
|
}
|
|
243
267
|
|
|
244
268
|
/**
|
|
@@ -360,7 +384,8 @@ export class SimplePDWClient {
|
|
|
360
384
|
enableLocalIndexing: config.features?.enableLocalIndexing ?? true,
|
|
361
385
|
enableKnowledgeGraph: config.features?.enableKnowledgeGraph ?? true
|
|
362
386
|
},
|
|
363
|
-
indexManager: config.indexManager
|
|
387
|
+
indexManager: config.indexManager,
|
|
388
|
+
indexBackup: config.indexBackup
|
|
364
389
|
};
|
|
365
390
|
}
|
|
366
391
|
|
|
@@ -433,17 +458,19 @@ export class SimplePDWClient {
|
|
|
433
458
|
useUploadRelay: true
|
|
434
459
|
});
|
|
435
460
|
|
|
436
|
-
// 2. Embedding Service (if API key provided)
|
|
461
|
+
// 2. Embedding Service (if API key provided) - uses singleton pattern
|
|
437
462
|
let embedding: EmbeddingService | undefined;
|
|
438
463
|
if (embeddingConfig.apiKey) {
|
|
439
|
-
|
|
464
|
+
// Use singleton to share EmbeddingService across all clients
|
|
465
|
+
// Reduces memory usage and connection overhead for multi-user scenarios
|
|
466
|
+
embedding = getSharedEmbeddingService({
|
|
440
467
|
provider: embeddingConfig.provider,
|
|
441
468
|
apiKey: embeddingConfig.apiKey,
|
|
442
469
|
modelName: embeddingConfig.modelName,
|
|
443
470
|
dimensions: embeddingConfig.dimensions
|
|
444
471
|
});
|
|
445
472
|
|
|
446
|
-
console.log(`✅ Embedding Service
|
|
473
|
+
console.log(`✅ Embedding Service (singleton): ${embeddingConfig.provider}/${embeddingConfig.modelName} (${embeddingConfig.dimensions}d)`);
|
|
447
474
|
|
|
448
475
|
// Connect to storage for search
|
|
449
476
|
storage.initializeSearch(embedding);
|
|
@@ -473,6 +500,15 @@ export class SimplePDWClient {
|
|
|
473
500
|
// Note: This starts async initialization - services will wait for it when needed
|
|
474
501
|
let sharedHnswService: IHnswService | undefined;
|
|
475
502
|
if (config.features.enableLocalIndexing) {
|
|
503
|
+
// Prepare Walrus backup config if enabled
|
|
504
|
+
const walrusBackupConfig = config.indexBackup?.enabled ? {
|
|
505
|
+
enabled: true,
|
|
506
|
+
aggregatorUrl: config.indexBackup.aggregatorUrl || config.walrus.aggregator,
|
|
507
|
+
publisherUrl: config.indexBackup.publisherUrl || config.walrus.publisher,
|
|
508
|
+
autoSync: config.indexBackup.autoSync ?? false,
|
|
509
|
+
epochs: config.indexBackup.epochs ?? 3
|
|
510
|
+
} : undefined;
|
|
511
|
+
|
|
476
512
|
// Dynamic import to avoid bundling Node.js dependencies (hnswlib-node) in browser builds
|
|
477
513
|
// When enableLocalIndexing is false, this code never runs and webpack won't bundle it
|
|
478
514
|
this.sharedHnswServicePromise = import('../vector/createHnswService').then(
|
|
@@ -486,10 +522,14 @@ export class SimplePDWClient {
|
|
|
486
522
|
batchConfig: {
|
|
487
523
|
maxBatchSize: 100,
|
|
488
524
|
batchDelayMs: 5000
|
|
489
|
-
}
|
|
525
|
+
},
|
|
526
|
+
walrusBackup: walrusBackupConfig
|
|
490
527
|
})
|
|
491
528
|
);
|
|
492
529
|
console.log('✅ Shared HNSW service initialization started (singleton for all vector services)');
|
|
530
|
+
if (walrusBackupConfig?.enabled) {
|
|
531
|
+
console.log(' ☁️ Walrus backup enabled for local index');
|
|
532
|
+
}
|
|
493
533
|
}
|
|
494
534
|
|
|
495
535
|
// 9a. Vector Service (if local indexing enabled)
|
|
@@ -722,11 +762,24 @@ export class SimplePDWClient {
|
|
|
722
762
|
}
|
|
723
763
|
|
|
724
764
|
// Initialize knowledge graph if enabled
|
|
725
|
-
|
|
726
|
-
|
|
765
|
+
// Use apiKey (OpenRouter) as primary, fallback to geminiApiKey for backward compatibility
|
|
766
|
+
const graphApiKey = this.config.ai.apiKey || this.config.ai.geminiApiKey;
|
|
767
|
+
if (this.config.features.enableKnowledgeGraph && this.services.embedding && graphApiKey) {
|
|
768
|
+
const graphService = await this.services.storage.initializeKnowledgeGraph({
|
|
727
769
|
embeddingService: this.services.embedding,
|
|
728
|
-
geminiApiKey:
|
|
770
|
+
geminiApiKey: graphApiKey
|
|
729
771
|
});
|
|
772
|
+
|
|
773
|
+
// Update QueryService with the initialized GraphService
|
|
774
|
+
if (graphService && this.services.query && this.services.memoryIndex && this.services.embedding) {
|
|
775
|
+
this.services.query.initialize(
|
|
776
|
+
this.services.memoryIndex,
|
|
777
|
+
this.services.embedding,
|
|
778
|
+
this.services.storage,
|
|
779
|
+
graphService
|
|
780
|
+
);
|
|
781
|
+
console.log('✅ QueryService updated with Knowledge Graph');
|
|
782
|
+
}
|
|
730
783
|
}
|
|
731
784
|
|
|
732
785
|
this.initialized = true;
|
|
@@ -24,7 +24,7 @@ export class EmbeddingsNamespace {
|
|
|
24
24
|
*
|
|
25
25
|
* @param text - Text to embed
|
|
26
26
|
* @param options - Embedding options
|
|
27
|
-
* @returns Embedding vector (
|
|
27
|
+
* @returns Embedding vector (3072 dimensions for Gemini)
|
|
28
28
|
*/
|
|
29
29
|
async generate(text: string, options?: { type?: 'query' | 'document' }): Promise<number[]> {
|
|
30
30
|
if (!this.services.embedding) {
|
|
@@ -189,13 +189,11 @@ export class IndexNamespace {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
|
-
* Save index to
|
|
192
|
+
* Save index to local storage
|
|
193
193
|
*
|
|
194
|
-
* Persists the HNSW index binary to
|
|
195
|
-
* Uses HnswWasmService.saveIndex() which properly serializes the index.
|
|
194
|
+
* Persists the HNSW index binary to local filesystem.
|
|
196
195
|
*
|
|
197
196
|
* @param spaceId - Index space identifier (userAddress)
|
|
198
|
-
* @returns Blob ID of saved index on Walrus, or null if no index exists
|
|
199
197
|
*/
|
|
200
198
|
async save(spaceId: string): Promise<void> {
|
|
201
199
|
const { type, service } = this.getService();
|
|
@@ -211,26 +209,106 @@ export class IndexNamespace {
|
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
/**
|
|
214
|
-
* Load index from Walrus
|
|
212
|
+
* Load index from storage (local or Walrus)
|
|
215
213
|
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
214
|
+
* If blobId is provided, attempts to load from Walrus first.
|
|
215
|
+
* Falls back to local storage if Walrus load fails.
|
|
218
216
|
*
|
|
219
217
|
* @param spaceId - Index space identifier (userAddress)
|
|
220
|
-
* @param blobId -
|
|
218
|
+
* @param blobId - Optional Walrus blob ID to load from cloud
|
|
221
219
|
*/
|
|
222
|
-
async load(spaceId: string, blobId
|
|
220
|
+
async load(spaceId: string, blobId?: string): Promise<void> {
|
|
223
221
|
const { type, service } = this.getService();
|
|
224
222
|
|
|
225
223
|
if (type === 'memoryIndex') {
|
|
226
|
-
// MemoryIndexService.loadIndex(userAddress, indexBlobId?)
|
|
227
224
|
await service.loadIndex(spaceId, blobId);
|
|
228
|
-
|
|
225
|
+
if (blobId) {
|
|
226
|
+
console.log(`Index loaded from Walrus: ${blobId}`);
|
|
227
|
+
} else {
|
|
228
|
+
console.log(`Index loaded from local storage: ${spaceId}`);
|
|
229
|
+
}
|
|
229
230
|
} else {
|
|
230
231
|
await service.loadIndex(spaceId, blobId);
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Sync index to Walrus cloud storage
|
|
237
|
+
*
|
|
238
|
+
* Uploads the HNSW index binary + metadata to Walrus for durability.
|
|
239
|
+
* This enables cross-device index restoration.
|
|
240
|
+
*
|
|
241
|
+
* @param spaceId - Index space identifier (userAddress)
|
|
242
|
+
* @returns Walrus blob ID if successful, null if Walrus is disabled
|
|
243
|
+
*/
|
|
244
|
+
async syncToWalrus(spaceId: string): Promise<string | null> {
|
|
245
|
+
const { type, service } = this.getService();
|
|
246
|
+
|
|
247
|
+
if (type === 'memoryIndex' && 'syncToWalrus' in service) {
|
|
248
|
+
const blobId = await service.syncToWalrus(spaceId);
|
|
249
|
+
if (blobId) {
|
|
250
|
+
console.log(`Index synced to Walrus: ${blobId}`);
|
|
251
|
+
}
|
|
252
|
+
return blobId;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
console.warn('Walrus sync not available for this service type');
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Load index from Walrus cloud storage
|
|
261
|
+
*
|
|
262
|
+
* Downloads and restores a previously synced index from Walrus.
|
|
263
|
+
*
|
|
264
|
+
* @param spaceId - Index space identifier (userAddress)
|
|
265
|
+
* @param blobId - Walrus blob ID of the saved index
|
|
266
|
+
* @returns true if successfully loaded
|
|
267
|
+
*/
|
|
268
|
+
async loadFromWalrus(spaceId: string, blobId: string): Promise<boolean> {
|
|
269
|
+
const { type, service } = this.getService();
|
|
270
|
+
|
|
271
|
+
if (type === 'memoryIndex' && 'loadFromWalrus' in service) {
|
|
272
|
+
const loaded = await service.loadFromWalrus(spaceId, blobId);
|
|
273
|
+
if (loaded) {
|
|
274
|
+
console.log(`Index loaded from Walrus: ${blobId}`);
|
|
275
|
+
}
|
|
276
|
+
return loaded;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
console.warn('Walrus load not available for this service type');
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get the Walrus blob ID for a user's index (if backed up)
|
|
285
|
+
*
|
|
286
|
+
* @param spaceId - Index space identifier (userAddress)
|
|
287
|
+
* @returns Blob ID or null if not backed up
|
|
288
|
+
*/
|
|
289
|
+
getWalrusBlobId(spaceId: string): string | null {
|
|
290
|
+
const { type, service } = this.getService();
|
|
291
|
+
|
|
292
|
+
if (type === 'memoryIndex' && 'getWalrusBlobId' in service) {
|
|
293
|
+
return service.getWalrusBlobId(spaceId);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Check if Walrus backup is enabled
|
|
301
|
+
*/
|
|
302
|
+
isWalrusEnabled(): boolean {
|
|
303
|
+
const { type, service } = this.getService();
|
|
304
|
+
|
|
305
|
+
if (type === 'memoryIndex' && 'isWalrusEnabled' in service) {
|
|
306
|
+
return service.isWalrusEnabled();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
|
|
234
312
|
/**
|
|
235
313
|
* Clear index and remove all vectors
|
|
236
314
|
*
|
|
@@ -1132,4 +1132,141 @@ export class MemoryNamespace {
|
|
|
1132
1132
|
throw new Error(`Failed to export memories: ${error instanceof Error ? error.message : String(error)}`);
|
|
1133
1133
|
}
|
|
1134
1134
|
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Index memories from a Quilt into the local HNSW index
|
|
1138
|
+
*
|
|
1139
|
+
* This allows Quilt batch-uploaded memories to be searchable via vector search.
|
|
1140
|
+
* The method fetches memory packages from the Quilt and indexes each one.
|
|
1141
|
+
*
|
|
1142
|
+
* @param quiltId - The Quilt blob ID containing memory packages
|
|
1143
|
+
* @param options - Indexing options
|
|
1144
|
+
* @returns Result with number of memories indexed
|
|
1145
|
+
*
|
|
1146
|
+
* @example
|
|
1147
|
+
* ```typescript
|
|
1148
|
+
* // After uploading a batch via Quilt
|
|
1149
|
+
* const result = await pdw.memory.indexFromQuilt('GTNhNTdWecbUVg3cZuC_VKlRSzJE3iQfBkojWUuwoh0');
|
|
1150
|
+
* console.log(`Indexed ${result.indexed} memories from Quilt`);
|
|
1151
|
+
* ```
|
|
1152
|
+
*/
|
|
1153
|
+
async indexFromQuilt(
|
|
1154
|
+
quiltId: string,
|
|
1155
|
+
options?: { forceReindex?: boolean }
|
|
1156
|
+
): Promise<{
|
|
1157
|
+
success: boolean;
|
|
1158
|
+
total: number;
|
|
1159
|
+
indexed: number;
|
|
1160
|
+
skipped: number;
|
|
1161
|
+
failed: number;
|
|
1162
|
+
errors: string[];
|
|
1163
|
+
}> {
|
|
1164
|
+
const errors: string[] = [];
|
|
1165
|
+
let indexed = 0;
|
|
1166
|
+
let skipped = 0;
|
|
1167
|
+
let failed = 0;
|
|
1168
|
+
|
|
1169
|
+
try {
|
|
1170
|
+
console.log(`📦 Indexing memories from Quilt ${quiltId}...`);
|
|
1171
|
+
|
|
1172
|
+
// Check if index service is available
|
|
1173
|
+
if (!this.services.memoryIndex) {
|
|
1174
|
+
throw new Error('Memory index service not available');
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// Check if quilt manager is available
|
|
1178
|
+
if (!this.services.storage?.quiltBatchManager) {
|
|
1179
|
+
throw new Error('Quilt batch manager not available');
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Fetch all memory packages from the Quilt
|
|
1183
|
+
const packages = await this.services.storage.quiltBatchManager.getAllMemoryPackages(quiltId);
|
|
1184
|
+
console.log(` Found ${packages.length} memory packages in Quilt`);
|
|
1185
|
+
|
|
1186
|
+
// Index each memory
|
|
1187
|
+
for (const pkg of packages) {
|
|
1188
|
+
try {
|
|
1189
|
+
const { identifier, memoryPackage, tags } = pkg;
|
|
1190
|
+
|
|
1191
|
+
// Skip if no embedding
|
|
1192
|
+
if (!memoryPackage.embedding || memoryPackage.embedding.length === 0) {
|
|
1193
|
+
console.warn(` ⚠️ Skipping ${identifier}: no embedding`);
|
|
1194
|
+
skipped++;
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// Create a unique memory ID from identifier or use memoryId from metadata
|
|
1199
|
+
const memoryId = memoryPackage.metadata?.memoryId as string ||
|
|
1200
|
+
identifier.replace('.json', '').replace('memory-', '');
|
|
1201
|
+
|
|
1202
|
+
// Build metadata for indexing (satisfy MemoryMetadata interface)
|
|
1203
|
+
const metadata = {
|
|
1204
|
+
category: memoryPackage.metadata?.category || 'general',
|
|
1205
|
+
importance: memoryPackage.metadata?.importance || 3,
|
|
1206
|
+
topic: memoryPackage.metadata?.topic || '',
|
|
1207
|
+
contentType: 'text',
|
|
1208
|
+
contentSize: memoryPackage.content?.length || 0,
|
|
1209
|
+
contentHash: '', // Not available from Quilt package
|
|
1210
|
+
embeddingDimension: memoryPackage.embedding?.length || 0,
|
|
1211
|
+
createdTimestamp: memoryPackage.timestamp,
|
|
1212
|
+
customMetadata: {
|
|
1213
|
+
quiltId,
|
|
1214
|
+
identifier,
|
|
1215
|
+
...Object.fromEntries(
|
|
1216
|
+
Object.entries(memoryPackage.metadata || {}).map(([k, v]) => [k, String(v)])
|
|
1217
|
+
)
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
// Content is empty if encrypted, use placeholder
|
|
1222
|
+
const content = memoryPackage.content || '[encrypted]';
|
|
1223
|
+
const isEncrypted = memoryPackage.encrypted === true;
|
|
1224
|
+
|
|
1225
|
+
// Index the memory
|
|
1226
|
+
await this.services.memoryIndex.indexMemory(
|
|
1227
|
+
this.services.config.userAddress,
|
|
1228
|
+
memoryId,
|
|
1229
|
+
quiltId, // Use quiltId as blobId for retrieval reference
|
|
1230
|
+
content,
|
|
1231
|
+
metadata,
|
|
1232
|
+
memoryPackage.embedding,
|
|
1233
|
+
{ isEncrypted }
|
|
1234
|
+
);
|
|
1235
|
+
|
|
1236
|
+
indexed++;
|
|
1237
|
+
console.log(` ✅ Indexed ${identifier} (${indexed}/${packages.length})`);
|
|
1238
|
+
|
|
1239
|
+
} catch (pkgError) {
|
|
1240
|
+
const errMsg = pkgError instanceof Error ? pkgError.message : String(pkgError);
|
|
1241
|
+
errors.push(`${pkg.identifier}: ${errMsg}`);
|
|
1242
|
+
failed++;
|
|
1243
|
+
console.error(` ❌ Failed to index ${pkg.identifier}:`, errMsg);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
console.log(`\n📊 Quilt indexing complete:`);
|
|
1248
|
+
console.log(` Total: ${packages.length}, Indexed: ${indexed}, Skipped: ${skipped}, Failed: ${failed}`);
|
|
1249
|
+
|
|
1250
|
+
return {
|
|
1251
|
+
success: failed === 0,
|
|
1252
|
+
total: packages.length,
|
|
1253
|
+
indexed,
|
|
1254
|
+
skipped,
|
|
1255
|
+
failed,
|
|
1256
|
+
errors
|
|
1257
|
+
};
|
|
1258
|
+
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
1261
|
+
console.error(`❌ Failed to index from Quilt: ${errMsg}`);
|
|
1262
|
+
return {
|
|
1263
|
+
success: false,
|
|
1264
|
+
total: 0,
|
|
1265
|
+
indexed,
|
|
1266
|
+
skipped,
|
|
1267
|
+
failed,
|
|
1268
|
+
errors: [errMsg, ...errors]
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1135
1272
|
}
|
|
@@ -154,18 +154,26 @@ export class SearchNamespace {
|
|
|
154
154
|
|
|
155
155
|
// Convert to SearchResult format
|
|
156
156
|
// Option A+: Content may be available from local index when encryption is OFF
|
|
157
|
-
const searchResults: SearchResult[] = results.map((r: any) =>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
157
|
+
const searchResults: SearchResult[] = results.map((r: any) => {
|
|
158
|
+
// blobId must be a valid Walrus blob ID, not a vectorId
|
|
159
|
+
// Only use metadata.blobId if it's a non-empty string that looks like a Walrus blobId
|
|
160
|
+
const rawBlobId = r.metadata?.blobId;
|
|
161
|
+
const isValidBlobId = rawBlobId && typeof rawBlobId === 'string' && rawBlobId.length > 10 && !/^\d+$/.test(rawBlobId);
|
|
162
|
+
const blobId = isValidBlobId ? rawBlobId : (r.metadata?.memoryObjectId || '');
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
id: r.memoryId || r.vectorId.toString(),
|
|
166
|
+
content: r.metadata?.content || r.content || '', // ✅ Get content from index metadata if available
|
|
167
|
+
score: r.similarity,
|
|
168
|
+
similarity: r.similarity,
|
|
169
|
+
category: r.metadata?.category,
|
|
170
|
+
importance: r.metadata?.importance || 5,
|
|
171
|
+
topic: r.metadata?.topic,
|
|
172
|
+
blobId,
|
|
173
|
+
metadata: r.metadata || {},
|
|
174
|
+
timestamp: r.metadata?.timestamp || Date.now()
|
|
175
|
+
};
|
|
176
|
+
});
|
|
169
177
|
|
|
170
178
|
// Optionally fetch content from Walrus
|
|
171
179
|
if (fetchContent) {
|
|
@@ -329,7 +337,12 @@ export class SearchNamespace {
|
|
|
329
337
|
const localResults = this.services.vector.getVectorsByCategory(spaceId, category);
|
|
330
338
|
|
|
331
339
|
for (const { vectorId, metadata } of localResults) {
|
|
332
|
-
|
|
340
|
+
// blobId must be a valid Walrus blob ID, not a vectorId
|
|
341
|
+
const rawBlobId = metadata?.blobId;
|
|
342
|
+
const isValidBlobId = rawBlobId && typeof rawBlobId === 'string' && rawBlobId.length > 10 && !/^\d+$/.test(rawBlobId);
|
|
343
|
+
const blobId = isValidBlobId ? rawBlobId : (metadata?.memoryObjectId || '');
|
|
344
|
+
const id = blobId || metadata?.memoryId || vectorId?.toString();
|
|
345
|
+
|
|
333
346
|
if (id && !seenIds.has(id)) {
|
|
334
347
|
seenIds.add(id);
|
|
335
348
|
results.push({
|
|
@@ -340,7 +353,7 @@ export class SearchNamespace {
|
|
|
340
353
|
category: metadata?.category,
|
|
341
354
|
importance: metadata?.importance || 5,
|
|
342
355
|
topic: metadata?.topic,
|
|
343
|
-
blobId
|
|
356
|
+
blobId,
|
|
344
357
|
metadata: metadata || {},
|
|
345
358
|
timestamp: metadata?.timestamp || Date.now()
|
|
346
359
|
});
|
|
@@ -76,12 +76,12 @@ export class AINamespace {
|
|
|
76
76
|
*
|
|
77
77
|
* @param text - Text to embed
|
|
78
78
|
* @param options - Embedding options
|
|
79
|
-
* @returns Embedding vector (
|
|
79
|
+
* @returns Embedding vector (3072 dimensions for Gemini)
|
|
80
80
|
*
|
|
81
81
|
* @example
|
|
82
82
|
* ```typescript
|
|
83
83
|
* const vector = await pdw.ai.embed('My favorite color is blue');
|
|
84
|
-
* console.log(vector.length); //
|
|
84
|
+
* console.log(vector.length); // 3072
|
|
85
85
|
* ```
|
|
86
86
|
*/
|
|
87
87
|
async embed(text: string, options?: EmbedOptions): Promise<number[]> {
|
|
@@ -135,12 +135,84 @@ class TxSubNamespace {
|
|
|
135
135
|
* ```
|
|
136
136
|
*/
|
|
137
137
|
async execute(tx: Transaction): Promise<TransactionResult> {
|
|
138
|
+
const signer = this.services.config.signer;
|
|
139
|
+
|
|
140
|
+
// Check if signer supports signAndExecuteTransaction (browser wallets like DappKitSigner)
|
|
141
|
+
// Browser wallets cannot expose raw Signer for security reasons
|
|
142
|
+
if ('signAndExecuteTransaction' in signer && typeof signer.signAndExecuteTransaction === 'function') {
|
|
143
|
+
try {
|
|
144
|
+
// Use the signer's signAndExecuteTransaction directly
|
|
145
|
+
const result = await signer.signAndExecuteTransaction(tx);
|
|
146
|
+
|
|
147
|
+
// Get full transaction details to extract created objects
|
|
148
|
+
let createdObjects: Array<{ objectId: string; objectType: string }> | undefined;
|
|
149
|
+
let mutatedObjects: Array<{ objectId: string; objectType: string }> | undefined;
|
|
150
|
+
|
|
151
|
+
if (result.objectChanges && Array.isArray(result.objectChanges)) {
|
|
152
|
+
createdObjects = result.objectChanges
|
|
153
|
+
.filter((change: any) => change.type === 'created')
|
|
154
|
+
.map((change: any) => ({
|
|
155
|
+
objectId: change.objectId,
|
|
156
|
+
objectType: change.objectType || 'unknown',
|
|
157
|
+
}));
|
|
158
|
+
|
|
159
|
+
mutatedObjects = result.objectChanges
|
|
160
|
+
.filter((change: any) => change.type === 'mutated')
|
|
161
|
+
.map((change: any) => ({
|
|
162
|
+
objectId: change.objectId,
|
|
163
|
+
objectType: change.objectType || 'unknown',
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Determine status from effects
|
|
168
|
+
// dapp-kit may not return full effects structure unless custom execute is configured
|
|
169
|
+
// We check multiple indicators:
|
|
170
|
+
// 1. If effects.status.status explicitly says 'failure', it failed
|
|
171
|
+
// 2. If effects.status.status says 'success', it succeeded
|
|
172
|
+
// 3. If we have a digest but no effects status, assume success (tx was submitted and confirmed)
|
|
173
|
+
let status: 'success' | 'failure';
|
|
174
|
+
const effectsStatus = result.effects?.status?.status;
|
|
175
|
+
|
|
176
|
+
if (effectsStatus === 'failure') {
|
|
177
|
+
status = 'failure';
|
|
178
|
+
} else if (effectsStatus === 'success') {
|
|
179
|
+
status = 'success';
|
|
180
|
+
} else if (result.digest) {
|
|
181
|
+
// Has digest but no explicit status - DappKitSigner waits for confirmation
|
|
182
|
+
// If we reach here without error, the transaction was successful
|
|
183
|
+
status = 'success';
|
|
184
|
+
} else {
|
|
185
|
+
status = 'failure';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
digest: result.digest,
|
|
190
|
+
status,
|
|
191
|
+
effects: result.effects,
|
|
192
|
+
createdObjects,
|
|
193
|
+
mutatedObjects,
|
|
194
|
+
gasUsed: result.effects?.gasUsed?.computationCost
|
|
195
|
+
? Number(result.effects.gasUsed.computationCost)
|
|
196
|
+
: undefined,
|
|
197
|
+
error: status === 'failure' ? (result.effects?.status?.error || 'Transaction failed without digest') : undefined,
|
|
198
|
+
};
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error('Transaction execution failed:', error);
|
|
201
|
+
return {
|
|
202
|
+
digest: '',
|
|
203
|
+
status: 'failure',
|
|
204
|
+
error: error instanceof Error ? error.message : String(error),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Fallback: Use TransactionService with raw Signer (Node.js/backend)
|
|
138
210
|
if (!this.services.tx) {
|
|
139
211
|
throw new Error('Transaction service not configured.');
|
|
140
212
|
}
|
|
141
213
|
return await this.services.tx.executeTransaction(
|
|
142
214
|
tx,
|
|
143
|
-
|
|
215
|
+
signer.getSigner()
|
|
144
216
|
);
|
|
145
217
|
}
|
|
146
218
|
|
|
@@ -437,4 +437,61 @@ export class StorageNamespace {
|
|
|
437
437
|
};
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
|
+
|
|
441
|
+
// ==========================================================================
|
|
442
|
+
// Batch Operations (Quilt)
|
|
443
|
+
// ==========================================================================
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Upload multiple memories as a Quilt (batch upload)
|
|
447
|
+
*
|
|
448
|
+
* Uses Walrus Quilt for ~90% gas savings compared to individual uploads.
|
|
449
|
+
* Requires 2 user signatures:
|
|
450
|
+
* - Transaction 1: Register blob on-chain
|
|
451
|
+
* - Transaction 2: Certify upload on-chain
|
|
452
|
+
*
|
|
453
|
+
* @param memories - Array of memories to upload
|
|
454
|
+
* @param options - Upload options including signer
|
|
455
|
+
* @returns Quilt result with file mappings
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* ```typescript
|
|
459
|
+
* const result = await pdw.storage.uploadMemoryBatch(
|
|
460
|
+
* memories,
|
|
461
|
+
* {
|
|
462
|
+
* signer: pdw.getConfig().signer,
|
|
463
|
+
* epochs: 3,
|
|
464
|
+
* userAddress: pdw.getConfig().userAddress
|
|
465
|
+
* }
|
|
466
|
+
* );
|
|
467
|
+
* console.log(`Uploaded ${result.files.length} files`);
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
async uploadMemoryBatch(
|
|
471
|
+
memories: Array<{
|
|
472
|
+
content: string;
|
|
473
|
+
category: string;
|
|
474
|
+
importance: number;
|
|
475
|
+
topic: string;
|
|
476
|
+
embedding: number[];
|
|
477
|
+
encryptedContent: Uint8Array;
|
|
478
|
+
summary?: string;
|
|
479
|
+
id?: string;
|
|
480
|
+
}>,
|
|
481
|
+
options: {
|
|
482
|
+
signer: any; // UnifiedSigner
|
|
483
|
+
epochs?: number;
|
|
484
|
+
userAddress: string;
|
|
485
|
+
}
|
|
486
|
+
): Promise<{
|
|
487
|
+
quiltId: string;
|
|
488
|
+
files: Array<{ identifier: string; blobId: string }>;
|
|
489
|
+
uploadTimeMs: number;
|
|
490
|
+
}> {
|
|
491
|
+
if (!this.services.storage) {
|
|
492
|
+
throw new Error('Storage service not configured.');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return this.services.storage.uploadMemoryBatch(memories, options);
|
|
496
|
+
}
|
|
440
497
|
}
|
package/src/core/types/index.ts
CHANGED
|
@@ -232,7 +232,7 @@ export interface VectorEmbedding {
|
|
|
232
232
|
|
|
233
233
|
export interface EmbeddingOptions {
|
|
234
234
|
model?: string;
|
|
235
|
-
dimension?: number; // Default
|
|
235
|
+
dimension?: number; // Default 3072 for Gemini
|
|
236
236
|
normalize?: boolean;
|
|
237
237
|
batchSize?: number; // For batch processing
|
|
238
238
|
}
|