@cmdoss/memwal-sdk 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +547 -547
- package/BENCHMARKS.md +238 -238
- package/README.md +181 -181
- 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/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/PersonalDataWallet.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +23 -0
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +15 -2
- package/dist/client/SimplePDWClient.js.map +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/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/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +49 -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 +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/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/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/storage/QuiltBatchManager.d.ts +10 -3
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +49 -27
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +109 -35
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +26 -7
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/package.json +1 -1
- package/src/access/index.ts +8 -8
- package/src/aggregation/index.ts +8 -8
- package/src/ai-sdk/PDWVectorStore.ts +4 -1
- package/src/browser.ts +15 -10
- package/src/client/ClientMemoryManager.ts +6 -1
- package/src/client/SimplePDWClient.ts +40 -2
- package/src/client/namespaces/IndexNamespace.ts +89 -11
- package/src/client/namespaces/SearchNamespace.ts +27 -14
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +55 -1
- package/src/client/namespaces/consolidated/StorageNamespace.ts +57 -0
- package/src/client/signers/DappKitSigner.ts +207 -207
- package/src/generated/pdw/capability.ts +319 -319
- package/src/generated/pdw/deps/sui/object.ts +12 -12
- package/src/generated/pdw/deps/sui/vec_map.ts +32 -32
- package/src/generated/pdw/memory.ts +1087 -1087
- package/src/generated/pdw/wallet.ts +123 -123
- package/src/generated/utils/index.ts +159 -159
- package/src/graph/GraphService.ts +1 -1
- package/src/permissions/ConsentRepository.browser.ts +249 -0
- package/src/permissions/index.ts +9 -9
- package/src/services/GeminiAIService.ts +283 -27
- package/src/services/MemoryIndexService.ts +85 -3
- package/src/services/storage/QuiltBatchManager.ts +55 -29
- package/src/utils/rebuildIndexNode.ts +126 -43
- package/src/vector/NodeHnswService.ts +29 -7
- package/src/wallet/index.ts +17 -17
|
@@ -568,18 +568,34 @@ export class MemoryIndexService {
|
|
|
568
568
|
}
|
|
569
569
|
|
|
570
570
|
/**
|
|
571
|
-
* Load index from storage
|
|
571
|
+
* Load index from storage (local or Walrus)
|
|
572
|
+
*
|
|
573
|
+
* @param userAddress - User's wallet address
|
|
574
|
+
* @param indexBlobId - Optional Walrus blob ID to load from cloud
|
|
572
575
|
*/
|
|
573
576
|
async loadIndex(userAddress: string, indexBlobId?: string): Promise<void> {
|
|
574
577
|
const hnswService = await this.getHnswService();
|
|
578
|
+
|
|
579
|
+
// If blobId provided, try to load from Walrus first
|
|
580
|
+
if (indexBlobId && 'loadFromWalrus' in hnswService) {
|
|
581
|
+
console.log(`📥 Attempting to load index from Walrus: ${indexBlobId}`);
|
|
582
|
+
const walrusLoaded = await (hnswService as any).loadFromWalrus(userAddress, indexBlobId);
|
|
583
|
+
if (walrusLoaded) {
|
|
584
|
+
console.log(`✅ Memory index loaded from Walrus for user ${userAddress}`);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
console.log(`⚠️ Walrus load failed, falling back to local storage`);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Fallback to local storage
|
|
575
591
|
const loaded = await hnswService.loadIndex(userAddress);
|
|
576
592
|
if (loaded) {
|
|
577
|
-
console.log(`✅ Memory index loaded for user ${userAddress}`);
|
|
593
|
+
console.log(`✅ Memory index loaded from local storage for user ${userAddress}`);
|
|
578
594
|
}
|
|
579
595
|
}
|
|
580
596
|
|
|
581
597
|
/**
|
|
582
|
-
* Save index to storage
|
|
598
|
+
* Save index to local storage
|
|
583
599
|
*/
|
|
584
600
|
async saveIndex(userAddress: string): Promise<void> {
|
|
585
601
|
const hnswService = await this.getHnswService();
|
|
@@ -587,6 +603,72 @@ export class MemoryIndexService {
|
|
|
587
603
|
console.log(`✅ Memory index saved for user ${userAddress}`);
|
|
588
604
|
}
|
|
589
605
|
|
|
606
|
+
/**
|
|
607
|
+
* Sync index to Walrus cloud storage
|
|
608
|
+
*
|
|
609
|
+
* @param userAddress - User's wallet address
|
|
610
|
+
* @returns Walrus blob ID if successful, null if Walrus is disabled
|
|
611
|
+
*/
|
|
612
|
+
async syncToWalrus(userAddress: string): Promise<string | null> {
|
|
613
|
+
const hnswService = await this.getHnswService();
|
|
614
|
+
|
|
615
|
+
if (!('syncToWalrus' in hnswService)) {
|
|
616
|
+
console.warn('⚠️ HNSW service does not support Walrus sync');
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const blobId = await (hnswService as any).syncToWalrus(userAddress);
|
|
621
|
+
if (blobId) {
|
|
622
|
+
console.log(`☁️ Memory index synced to Walrus: ${blobId}`);
|
|
623
|
+
}
|
|
624
|
+
return blobId;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Load index directly from Walrus cloud storage
|
|
629
|
+
*
|
|
630
|
+
* @param userAddress - User's wallet address
|
|
631
|
+
* @param blobId - Walrus blob ID
|
|
632
|
+
* @returns true if successfully loaded
|
|
633
|
+
*/
|
|
634
|
+
async loadFromWalrus(userAddress: string, blobId: string): Promise<boolean> {
|
|
635
|
+
const hnswService = await this.getHnswService();
|
|
636
|
+
|
|
637
|
+
if (!('loadFromWalrus' in hnswService)) {
|
|
638
|
+
console.warn('⚠️ HNSW service does not support Walrus load');
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const loaded = await (hnswService as any).loadFromWalrus(userAddress, blobId);
|
|
643
|
+
if (loaded) {
|
|
644
|
+
console.log(`☁️ Memory index loaded from Walrus: ${blobId}`);
|
|
645
|
+
}
|
|
646
|
+
return loaded;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Get the Walrus blob ID for a user's index (if backed up)
|
|
651
|
+
*
|
|
652
|
+
* @param userAddress - User's wallet address
|
|
653
|
+
* @returns Blob ID or null if not backed up
|
|
654
|
+
*/
|
|
655
|
+
getWalrusBlobId(userAddress: string): string | null {
|
|
656
|
+
if (this.hnswService && 'getWalrusBlobId' in this.hnswService) {
|
|
657
|
+
return (this.hnswService as any).getWalrusBlobId(userAddress);
|
|
658
|
+
}
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Check if Walrus backup is enabled
|
|
664
|
+
*/
|
|
665
|
+
isWalrusEnabled(): boolean {
|
|
666
|
+
if (this.hnswService && 'isWalrusEnabled' in this.hnswService) {
|
|
667
|
+
return (this.hnswService as any).isWalrusEnabled();
|
|
668
|
+
}
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
|
|
590
672
|
/**
|
|
591
673
|
* Clear user's index
|
|
592
674
|
*/
|
|
@@ -245,18 +245,26 @@ export class QuiltBatchManager {
|
|
|
245
245
|
console.log(` Gas saved: ${gasSaved} vs individual uploads`);
|
|
246
246
|
|
|
247
247
|
// Build file results using original WalrusFile objects for metadata
|
|
248
|
-
//
|
|
248
|
+
// Use shared quiltId as blobId - SDK can only read via getBlob(quiltId).files()
|
|
249
|
+
// Match files by identifier when reading
|
|
250
|
+
const quiltId = uploadedFilesInfo[0]?.blobId || '';
|
|
251
|
+
|
|
249
252
|
const fileResults: QuiltFileResult[] = await Promise.all(
|
|
250
253
|
files.map(async (originalFile, i) => {
|
|
251
254
|
const identifier = await originalFile.getIdentifier() || `file-${i}`;
|
|
252
255
|
const tags = await originalFile.getTags() || {};
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
const fileInfo = uploadedFilesInfo[i];
|
|
257
|
+
|
|
258
|
+
// quiltPatchId is stored for reference but not used for retrieval
|
|
259
|
+
const quiltPatchId = fileInfo?.id || '';
|
|
260
|
+
|
|
261
|
+
console.log(` File ${i}: identifier=${identifier}, quiltId=${quiltId.substring(0, 20)}...`);
|
|
255
262
|
|
|
256
263
|
return {
|
|
257
264
|
identifier,
|
|
258
|
-
blobId
|
|
259
|
-
|
|
265
|
+
// Use shared quiltId as blobId - read via getBlob(quiltId).files()
|
|
266
|
+
blobId: quiltId,
|
|
267
|
+
quiltPatchId,
|
|
260
268
|
tags: Object.fromEntries(
|
|
261
269
|
Object.entries(tags).map(([k, v]) => [k, String(v)])
|
|
262
270
|
),
|
|
@@ -265,9 +273,6 @@ export class QuiltBatchManager {
|
|
|
265
273
|
})
|
|
266
274
|
);
|
|
267
275
|
|
|
268
|
-
// Get quiltId from first uploaded file
|
|
269
|
-
const quiltId = uploadedFilesInfo[0]?.blobId || '';
|
|
270
|
-
|
|
271
276
|
return {
|
|
272
277
|
quiltId,
|
|
273
278
|
blobObjectId: undefined, // Not available from flow
|
|
@@ -373,18 +378,26 @@ export class QuiltBatchManager {
|
|
|
373
378
|
console.log(` Upload time: ${uploadTimeMs.toFixed(1)}ms`);
|
|
374
379
|
|
|
375
380
|
// Build file results using original WalrusFile objects for metadata
|
|
376
|
-
//
|
|
381
|
+
// Use shared quiltId as blobId - SDK can only read via getBlob(quiltId).files()
|
|
382
|
+
// Match files by identifier when reading
|
|
383
|
+
const quiltId = uploadedFilesInfo[0]?.blobId || '';
|
|
384
|
+
|
|
377
385
|
const fileResults: QuiltFileResult[] = await Promise.all(
|
|
378
386
|
walrusFiles.map(async (originalFile, i) => {
|
|
379
387
|
const identifier = await originalFile.getIdentifier() || files[i]?.identifier || `file-${i}`;
|
|
380
388
|
const tags = await originalFile.getTags() || {};
|
|
381
|
-
|
|
382
|
-
|
|
389
|
+
const fileInfo = uploadedFilesInfo[i];
|
|
390
|
+
|
|
391
|
+
// quiltPatchId is stored for reference but not used for retrieval
|
|
392
|
+
const quiltPatchId = fileInfo?.id || '';
|
|
393
|
+
|
|
394
|
+
console.log(` File ${i}: identifier=${identifier}, quiltId=${quiltId.substring(0, 20)}...`);
|
|
383
395
|
|
|
384
396
|
return {
|
|
385
397
|
identifier,
|
|
386
|
-
blobId
|
|
387
|
-
|
|
398
|
+
// Use shared quiltId as blobId - read via getBlob(quiltId).files()
|
|
399
|
+
blobId: quiltId,
|
|
400
|
+
quiltPatchId,
|
|
388
401
|
tags: Object.fromEntries(
|
|
389
402
|
Object.entries(tags).map(([k, v]) => [k, String(v)])
|
|
390
403
|
),
|
|
@@ -393,9 +406,6 @@ export class QuiltBatchManager {
|
|
|
393
406
|
})
|
|
394
407
|
);
|
|
395
408
|
|
|
396
|
-
// Get quiltId from first uploaded file
|
|
397
|
-
const quiltId = uploadedFilesInfo[0]?.blobId || '';
|
|
398
|
-
|
|
399
409
|
return {
|
|
400
410
|
quiltId,
|
|
401
411
|
blobObjectId: undefined, // Not available from flow
|
|
@@ -418,14 +428,19 @@ export class QuiltBatchManager {
|
|
|
418
428
|
/**
|
|
419
429
|
* Retrieve all files from a Quilt
|
|
420
430
|
*
|
|
421
|
-
*
|
|
431
|
+
* Uses getBlob().files() pattern which correctly parses Quilt structure
|
|
432
|
+
* and returns individual files with their identifiers and tags.
|
|
433
|
+
*
|
|
434
|
+
* @param quiltId - The Quilt blob ID (shared blobId)
|
|
422
435
|
* @returns Array of WalrusFile objects
|
|
423
436
|
*/
|
|
424
437
|
async getQuiltFiles(quiltId: string): Promise<Array<WalrusFile>> {
|
|
425
438
|
try {
|
|
426
439
|
console.log(`📂 Retrieving files from Quilt ${quiltId}...`);
|
|
427
440
|
|
|
428
|
-
|
|
441
|
+
// Use getBlob().files() to correctly parse Quilt and get individual files
|
|
442
|
+
const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
|
|
443
|
+
const files = await blob.files();
|
|
429
444
|
|
|
430
445
|
console.log(`✅ Retrieved ${files.length} files from Quilt`);
|
|
431
446
|
|
|
@@ -440,7 +455,9 @@ export class QuiltBatchManager {
|
|
|
440
455
|
/**
|
|
441
456
|
* Retrieve a specific file by identifier from a Quilt
|
|
442
457
|
*
|
|
443
|
-
*
|
|
458
|
+
* Uses getBlob().files() to get all files then matches by identifier.
|
|
459
|
+
*
|
|
460
|
+
* @param quiltId - The Quilt blob ID (shared blobId)
|
|
444
461
|
* @param identifier - The file identifier within the quilt
|
|
445
462
|
* @returns QuiltRetrieveResult with content and metadata
|
|
446
463
|
*/
|
|
@@ -453,21 +470,26 @@ export class QuiltBatchManager {
|
|
|
453
470
|
try {
|
|
454
471
|
console.log(`📄 Retrieving file "${identifier}" from Quilt ${quiltId}...`);
|
|
455
472
|
|
|
456
|
-
// Get all files from quilt
|
|
457
|
-
const
|
|
473
|
+
// Get all files from quilt using getBlob().files()
|
|
474
|
+
const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
|
|
475
|
+
const files = await blob.files();
|
|
458
476
|
|
|
459
477
|
// Find file by identifier
|
|
460
|
-
|
|
478
|
+
let matchingFile: WalrusFile | undefined;
|
|
479
|
+
for (const f of files) {
|
|
461
480
|
const fileIdentifier = await f.getIdentifier();
|
|
462
|
-
|
|
463
|
-
|
|
481
|
+
if (fileIdentifier === identifier) {
|
|
482
|
+
matchingFile = f;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
464
486
|
|
|
465
|
-
if (!
|
|
487
|
+
if (!matchingFile) {
|
|
466
488
|
throw new Error(`File "${identifier}" not found in Quilt`);
|
|
467
489
|
}
|
|
468
490
|
|
|
469
|
-
const content = await
|
|
470
|
-
const tags = await
|
|
491
|
+
const content = await matchingFile.bytes();
|
|
492
|
+
const tags = await matchingFile.getTags();
|
|
471
493
|
const retrievalTimeMs = performance.now() - startTime;
|
|
472
494
|
|
|
473
495
|
console.log(`✅ Retrieved file "${identifier}" (${content.length} bytes)`);
|
|
@@ -488,14 +510,18 @@ export class QuiltBatchManager {
|
|
|
488
510
|
/**
|
|
489
511
|
* List all patches in a Quilt with their metadata
|
|
490
512
|
*
|
|
491
|
-
*
|
|
513
|
+
* Uses getBlob().files() to correctly parse Quilt structure.
|
|
514
|
+
*
|
|
515
|
+
* @param quiltId - The Quilt blob ID (shared blobId)
|
|
492
516
|
* @returns Array of QuiltListResult with identifiers and tags
|
|
493
517
|
*/
|
|
494
518
|
async listQuiltPatches(quiltId: string): Promise<QuiltListResult[]> {
|
|
495
519
|
try {
|
|
496
520
|
console.log(`📋 Listing patches in Quilt ${quiltId}...`);
|
|
497
521
|
|
|
498
|
-
|
|
522
|
+
// Use getBlob().files() to correctly parse Quilt
|
|
523
|
+
const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
|
|
524
|
+
const files = await blob.files();
|
|
499
525
|
|
|
500
526
|
const results: QuiltListResult[] = await Promise.all(
|
|
501
527
|
files.map(async (file) => {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import type { SuiClient } from '@mysten/sui/client';
|
|
30
|
-
import { WalrusClient } from '@mysten/walrus';
|
|
30
|
+
import { WalrusClient, WalrusFile } from '@mysten/walrus';
|
|
31
31
|
|
|
32
32
|
export interface RebuildIndexNodeOptions {
|
|
33
33
|
/** User's blockchain address */
|
|
@@ -212,60 +212,143 @@ export async function rebuildIndexNode(options: RebuildIndexNodeOptions): Promis
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
// Process
|
|
215
|
+
// Process memories grouped by blobId (for Quilt support)
|
|
216
|
+
// In a Quilt, multiple memories share the same blobId
|
|
217
|
+
const memoriesByBlobId = new Map<string, typeof memories>();
|
|
218
|
+
for (const memory of memories) {
|
|
219
|
+
const list = memoriesByBlobId.get(memory.blobId) || [];
|
|
220
|
+
list.push(memory);
|
|
221
|
+
memoriesByBlobId.set(memory.blobId, list);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log(`[rebuildIndexNode] Unique blobIds: ${memoriesByBlobId.size} (${memoriesByBlobId.size < totalMemories ? 'Quilt detected' : 'individual blobs'})`);
|
|
225
|
+
|
|
216
226
|
let indexedCount = 0;
|
|
217
227
|
let failedCount = 0;
|
|
228
|
+
let processedCount = 0;
|
|
218
229
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const progress = `Memory ${i + 1}/${totalMemories}`;
|
|
230
|
+
// Cache for Quilt files to avoid re-fetching
|
|
231
|
+
const quiltFileCache = new Map<string, WalrusFile[]>();
|
|
222
232
|
|
|
223
|
-
|
|
224
|
-
|
|
233
|
+
for (const [blobId, memoriesInBlob] of memoriesByBlobId) {
|
|
234
|
+
console.log(`[rebuildIndexNode] Processing blobId ${blobId.substring(0, 20)}... (${memoriesInBlob.length} memories)`);
|
|
225
235
|
|
|
226
236
|
try {
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
// Use getBlob().files() to correctly parse Quilt structure
|
|
238
|
+
// For regular blob: returns [singleFile]
|
|
239
|
+
// For Quilt: returns [file1, file2, ...] - all files in the quilt
|
|
240
|
+
let files: WalrusFile[];
|
|
241
|
+
|
|
242
|
+
if (quiltFileCache.has(blobId)) {
|
|
243
|
+
files = quiltFileCache.get(blobId)!;
|
|
244
|
+
console.log(`[rebuildIndexNode] ♻️ Using cached files (${files.length} files)`);
|
|
245
|
+
} else {
|
|
246
|
+
const blob = await walrusClient.walrus.getBlob({ blobId });
|
|
247
|
+
files = await blob.files();
|
|
248
|
+
quiltFileCache.set(blobId, files);
|
|
249
|
+
console.log(`[rebuildIndexNode] 📥 Fetched ${files.length} file(s) from Walrus`);
|
|
239
250
|
}
|
|
240
251
|
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
{
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
// For each memory in this blobId
|
|
253
|
+
for (let i = 0; i < memoriesInBlob.length; i++) {
|
|
254
|
+
const memory = memoriesInBlob[i];
|
|
255
|
+
processedCount++;
|
|
256
|
+
const progress = `Memory ${processedCount}/${totalMemories}`;
|
|
257
|
+
|
|
258
|
+
console.log(`[rebuildIndexNode] Processing ${progress}: vectorId=${memory.vectorId}`);
|
|
259
|
+
onProgress?.(processedCount, totalMemories, `Processing ${progress}...`);
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
// Determine which file to use
|
|
263
|
+
// For Quilt: match by index
|
|
264
|
+
// For single blob: use the only file
|
|
265
|
+
const fileIndex = files.length === 1 ? 0 : Math.min(i, files.length - 1);
|
|
266
|
+
const file = files[fileIndex];
|
|
267
|
+
|
|
268
|
+
if (!file) {
|
|
269
|
+
throw new Error(`No file found at index ${fileIndex}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Get file content
|
|
273
|
+
const rawBytes = await file.bytes();
|
|
274
|
+
const rawText = new TextDecoder().decode(rawBytes);
|
|
275
|
+
const trimmedText = rawText.trim();
|
|
276
|
+
|
|
277
|
+
// Get file identifier and tags if available (for Quilts)
|
|
278
|
+
const identifier = await file.getIdentifier();
|
|
279
|
+
const tags = await file.getTags();
|
|
280
|
+
|
|
281
|
+
if (identifier) {
|
|
282
|
+
console.log(`[rebuildIndexNode] 📎 File identifier: ${identifier}`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let content: string;
|
|
286
|
+
let embedding: number[];
|
|
287
|
+
let metadata: { category?: string; importance?: number; topic?: string } = {};
|
|
288
|
+
let timestamp = Date.now();
|
|
289
|
+
|
|
290
|
+
if (trimmedText.startsWith('{') && trimmedText.endsWith('}')) {
|
|
291
|
+
// JSON package format (correct format)
|
|
292
|
+
try {
|
|
293
|
+
const memoryData: MemoryContent = JSON.parse(trimmedText);
|
|
294
|
+
content = memoryData.content;
|
|
295
|
+
embedding = memoryData.embedding;
|
|
296
|
+
metadata = memoryData.metadata || {};
|
|
297
|
+
timestamp = memoryData.timestamp || Date.now();
|
|
298
|
+
|
|
299
|
+
if (!embedding || embedding.length !== 3072) {
|
|
300
|
+
throw new Error(`Invalid embedding in JSON: length=${embedding?.length || 0}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
console.log(`[rebuildIndexNode] 📦 Format: JSON package`);
|
|
304
|
+
} catch (jsonError) {
|
|
305
|
+
throw new Error(`Invalid JSON structure: ${(jsonError as Error).message}`);
|
|
306
|
+
}
|
|
307
|
+
} else if (trimmedText.length > 0 && !trimmedText.includes('\x00') && trimmedText.length < 10000) {
|
|
308
|
+
// Plain text format - cannot index without embedding
|
|
309
|
+
throw new Error('Plain text format detected but no embedding available - skip');
|
|
310
|
+
} else {
|
|
311
|
+
throw new Error('Binary, encrypted, or empty content - cannot index');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Add to HNSW index
|
|
315
|
+
await hnswService.addVector(
|
|
316
|
+
userAddress,
|
|
317
|
+
memory.vectorId,
|
|
318
|
+
embedding,
|
|
319
|
+
{
|
|
320
|
+
blobId: memory.blobId,
|
|
321
|
+
memoryObjectId: memory.id,
|
|
322
|
+
category: metadata.category || memory.category || tags?.['category'],
|
|
323
|
+
importance: metadata.importance || memory.importance || parseInt(tags?.['importance'] || '5'),
|
|
324
|
+
topic: metadata.topic || tags?.['topic'] || '',
|
|
325
|
+
timestamp,
|
|
326
|
+
content,
|
|
327
|
+
isEncrypted: false
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
indexedCount++;
|
|
332
|
+
console.log(`[rebuildIndexNode] ✓ Indexed: "${content.substring(0, 30)}..."`);
|
|
333
|
+
|
|
334
|
+
} catch (error: any) {
|
|
335
|
+
failedCount++;
|
|
336
|
+
const errorMsg = error.message || String(error);
|
|
337
|
+
errors.push({ blobId: memory.blobId, error: errorMsg });
|
|
338
|
+
console.error(`[rebuildIndexNode] ✗ Failed: ${errorMsg}`);
|
|
258
339
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
indexedCount++;
|
|
262
|
-
console.log(`[rebuildIndexNode] ✓ Indexed: ${memory.blobId.substring(0, 20)}...`);
|
|
340
|
+
}
|
|
263
341
|
|
|
264
342
|
} catch (error: any) {
|
|
265
|
-
|
|
343
|
+
// Failed to fetch files for this blobId
|
|
266
344
|
const errorMsg = error.message || String(error);
|
|
267
|
-
|
|
268
|
-
|
|
345
|
+
console.error(`[rebuildIndexNode] ✗ Failed to fetch blobId: ${errorMsg}`);
|
|
346
|
+
|
|
347
|
+
for (const memory of memoriesInBlob) {
|
|
348
|
+
processedCount++;
|
|
349
|
+
failedCount++;
|
|
350
|
+
errors.push({ blobId: memory.blobId, error: `Failed to fetch blob: ${errorMsg}` });
|
|
351
|
+
}
|
|
269
352
|
}
|
|
270
353
|
}
|
|
271
354
|
|
|
@@ -248,6 +248,7 @@ export class NodeHnswService implements IHnswService {
|
|
|
248
248
|
vector: number[],
|
|
249
249
|
metadata?: Record<string, any>
|
|
250
250
|
): Promise<void> {
|
|
251
|
+
console.log(`[NodeHnswService] addVector: userAddress=${userAddress.slice(0, 10)}..., vectorId=${vectorId}, dims=${vector.length}`);
|
|
251
252
|
await this.getOrCreateIndex(userAddress);
|
|
252
253
|
|
|
253
254
|
const entry = this.indexCache.get(userAddress);
|
|
@@ -262,9 +263,11 @@ export class NodeHnswService implements IHnswService {
|
|
|
262
263
|
}
|
|
263
264
|
entry.isDirty = true;
|
|
264
265
|
this.batchStats.pendingJobs++;
|
|
266
|
+
console.log(`[NodeHnswService] addVector: Added to pending batch. Pending: ${entry.pendingVectors.size}, isDirty: ${entry.isDirty}`);
|
|
265
267
|
|
|
266
268
|
// Flush if batch is large enough
|
|
267
269
|
if (entry.pendingVectors.size >= 50) {
|
|
270
|
+
console.log(`[NodeHnswService] addVector: Batch size >= 50, auto-flushing...`);
|
|
268
271
|
await this.flushBatch(userAddress);
|
|
269
272
|
}
|
|
270
273
|
}
|
|
@@ -338,8 +341,12 @@ export class NodeHnswService implements IHnswService {
|
|
|
338
341
|
|
|
339
342
|
async flushBatch(userAddress: string): Promise<void> {
|
|
340
343
|
const entry = this.indexCache.get(userAddress);
|
|
341
|
-
if (!entry || entry.pendingVectors.size === 0)
|
|
344
|
+
if (!entry || entry.pendingVectors.size === 0) {
|
|
345
|
+
console.log(`[NodeHnswService] flushBatch: No pending vectors for ${userAddress.slice(0, 10)}..., skipping`);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
342
348
|
|
|
349
|
+
console.log(`[NodeHnswService] flushBatch: Flushing ${entry.pendingVectors.size} vectors for ${userAddress.slice(0, 10)}...`);
|
|
343
350
|
const startTime = Date.now();
|
|
344
351
|
let processed = 0;
|
|
345
352
|
|
|
@@ -348,6 +355,7 @@ export class NodeHnswService implements IHnswService {
|
|
|
348
355
|
entry.index.addPoint(vector, vectorId);
|
|
349
356
|
processed++;
|
|
350
357
|
}
|
|
358
|
+
console.log(`[NodeHnswService] flushBatch: Added ${processed} points to index`);
|
|
351
359
|
|
|
352
360
|
entry.pendingVectors.clear();
|
|
353
361
|
entry.isDirty = true;
|
|
@@ -361,21 +369,28 @@ export class NodeHnswService implements IHnswService {
|
|
|
361
369
|
(this.batchStats.averageProcessingTime + processingTime) / 2;
|
|
362
370
|
|
|
363
371
|
// Auto-save
|
|
372
|
+
console.log(`[NodeHnswService] flushBatch: Calling saveIndex()...`);
|
|
364
373
|
await this.saveIndex(userAddress);
|
|
374
|
+
console.log(`[NodeHnswService] flushBatch: Complete in ${processingTime}ms`);
|
|
365
375
|
} catch (error) {
|
|
366
376
|
this.batchStats.failedJobs++;
|
|
367
|
-
console.error('[NodeHnswService]
|
|
377
|
+
console.error('[NodeHnswService] flushBatch error:', error);
|
|
368
378
|
throw error;
|
|
369
379
|
}
|
|
370
380
|
}
|
|
371
381
|
|
|
372
382
|
async saveIndex(userAddress: string): Promise<void> {
|
|
373
383
|
const entry = this.indexCache.get(userAddress);
|
|
374
|
-
if (!entry)
|
|
384
|
+
if (!entry) {
|
|
385
|
+
console.log(`[NodeHnswService] saveIndex: No cache entry for ${userAddress}, skipping`);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
375
388
|
|
|
376
389
|
try {
|
|
377
390
|
const indexPath = this.getIndexPath(userAddress);
|
|
391
|
+
console.log(`[NodeHnswService] saveIndex: Writing to ${indexPath}`);
|
|
378
392
|
entry.index.writeIndex(indexPath);
|
|
393
|
+
console.log(`[NodeHnswService] saveIndex: writeIndex() complete`);
|
|
379
394
|
|
|
380
395
|
// Save metadata separately
|
|
381
396
|
const fs = await import('fs/promises');
|
|
@@ -385,19 +400,26 @@ export class NodeHnswService implements IHnswService {
|
|
|
385
400
|
metadataObj[k] = v;
|
|
386
401
|
}
|
|
387
402
|
|
|
388
|
-
// Preserve existing
|
|
389
|
-
|
|
403
|
+
// Preserve existing metadata and merge with in-memory metadata
|
|
404
|
+
// This prevents data loss when cache is cleared between requests
|
|
405
|
+
let existingMeta: Record<string, any> = {};
|
|
390
406
|
try {
|
|
391
407
|
const existingContent = await fs.readFile(metadataPath, 'utf-8');
|
|
392
|
-
|
|
408
|
+
existingMeta = JSON.parse(existingContent);
|
|
393
409
|
} catch {
|
|
394
410
|
// No existing metadata file
|
|
395
411
|
}
|
|
396
412
|
|
|
413
|
+
// Merge: existing metadata + in-memory metadata (in-memory takes priority for same keys)
|
|
414
|
+
const mergedMetadata = {
|
|
415
|
+
...(existingMeta.metadata || {}),
|
|
416
|
+
...metadataObj
|
|
417
|
+
};
|
|
418
|
+
|
|
397
419
|
await fs.writeFile(metadataPath, JSON.stringify({
|
|
398
420
|
version: entry.version,
|
|
399
421
|
dimensions: entry.dimensions,
|
|
400
|
-
metadata:
|
|
422
|
+
metadata: mergedMetadata,
|
|
401
423
|
walrusBlobId: existingMeta.walrusBlobId,
|
|
402
424
|
walrusSyncTime: existingMeta.walrusSyncTime
|
|
403
425
|
}));
|
package/src/wallet/index.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wallet Module
|
|
3
|
-
*
|
|
4
|
-
* @deprecated This module is deprecated. Use CapabilityService and ContextNamespace instead.
|
|
5
|
-
* - MainWalletService → CapabilityService (from services/CapabilityService)
|
|
6
|
-
* - ContextWalletService → ContextNamespace (from client/namespaces/ContextNamespace)
|
|
7
|
-
*
|
|
8
|
-
* These services will be removed in the next major version.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** @deprecated Use CapabilityService instead */
|
|
12
|
-
export { MainWalletService } from './MainWalletService';
|
|
13
|
-
export type { MainWalletServiceConfig } from './MainWalletService';
|
|
14
|
-
|
|
15
|
-
/** @deprecated Use ContextNamespace instead */
|
|
16
|
-
export { ContextWalletService } from './ContextWalletService';
|
|
17
|
-
export type { ContextWalletServiceConfig } from './ContextWalletService';
|
|
1
|
+
/**
|
|
2
|
+
* Wallet Module
|
|
3
|
+
*
|
|
4
|
+
* @deprecated This module is deprecated. Use CapabilityService and ContextNamespace instead.
|
|
5
|
+
* - MainWalletService → CapabilityService (from services/CapabilityService)
|
|
6
|
+
* - ContextWalletService → ContextNamespace (from client/namespaces/ContextNamespace)
|
|
7
|
+
*
|
|
8
|
+
* These services will be removed in the next major version.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** @deprecated Use CapabilityService instead */
|
|
12
|
+
export { MainWalletService } from './MainWalletService';
|
|
13
|
+
export type { MainWalletServiceConfig } from './MainWalletService';
|
|
14
|
+
|
|
15
|
+
/** @deprecated Use ContextNamespace instead */
|
|
16
|
+
export { ContextWalletService } from './ContextWalletService';
|
|
17
|
+
export type { ContextWalletServiceConfig } from './ContextWalletService';
|