UNPKG

personal-data-wallet-sdk

Version:

TypeScript SDK for Personal Data Wallet - Decentralized memory system with AI embeddings, HNSW vector search, SEAL encryption and Walrus storage

832 lines (719 loc) 26 kB
/** * MemoryRetrievalService - Unified Memory Retrieval & Search * * Consolidates all memory retrieval operations into a single, powerful service * with advanced caching, decryption, analytics, and multi-dimensional search. * * Features: * - 🔍 Vector similarity search with HNSW indexing * - 📊 Semantic search with AI understanding * - 🕒 Time-based and metadata filtering * - 🔐 Automatic SEAL decryption pipeline * - 📈 Memory analytics and relationship discovery * - ⚡ Multi-tier caching for performance * - 🔄 Real-time memory streaming * - 📤 Export and backup capabilities */ import { EmbeddingService } from '../services/EmbeddingService'; import { VectorManager } from '../vector/VectorManager'; import { KnowledgeGraphManager } from '../graph/KnowledgeGraphManager'; import { StorageManager } from '../infrastructure/walrus/StorageManager'; import { BlockchainManager } from '../infrastructure/sui/BlockchainManager'; import { EncryptionService } from '../services/EncryptionService'; import { BatchManager } from '../batch/BatchManager'; import { MemoryDecryptionPipeline, DecryptionConfig } from './MemoryDecryptionPipeline'; // Enhanced types for unified retrieval export interface UnifiedMemoryQuery { // Core search parameters query?: string; userId: string; // Search types searchType?: 'vector' | 'semantic' | 'keyword' | 'hybrid' | 'graph' | 'temporal'; // Filtering options categories?: string[]; dateRange?: { start?: Date; end?: Date; }; importanceRange?: { min?: number; max?: number; }; tags?: string[]; contentTypes?: string[]; // Vector search parameters similarity?: { threshold?: number; k?: number; efSearch?: number; }; // Graph search parameters graphTraversal?: { maxDepth?: number; includeEntities?: string[]; excludeRelations?: string[]; }; // Result options includeContent?: boolean; includeMetadata?: boolean; includeEmbeddings?: boolean; includeAnalytics?: boolean; // Performance options useCache?: boolean; timeout?: number; batchSize?: number; } export interface UnifiedMemoryResult { id: string; content?: string; category: string; created: Date; updated?: Date; // Scoring and relevance similarity?: number; relevanceScore: number; searchRelevance: { vectorSimilarity?: number; semanticMatch?: number; keywordMatch?: number; graphRelevance?: number; temporalRelevance?: number; }; // Rich metadata metadata: { owner: string; size: number; importance: number; tags: string[]; contentType: string; isEncrypted: boolean; accessCount?: number; lastAccessed?: Date; }; // Storage information storage: { blobId: string; walrusHash?: string; blockchainId?: string; cacheStatus: 'cached' | 'retrieved' | 'not-cached'; }; // Relationships and context relationships?: { relatedMemories: string[]; knowledgeGraphNodes: string[]; semanticClusters: string[]; }; // Analytics analytics?: { viewCount: number; shareCount: number; editCount: number; sentimentScore?: number; topicDistribution?: Record<string, number>; }; } export interface RetrievalStats { totalResults: number; processingTime: number; cacheHitRate: number; searchBreakdown: { vectorSearchTime: number; semanticAnalysisTime: number; decryptionTime: number; graphTraversalTime: number; }; dataSourcesUsed: string[]; qualityMetrics: { averageRelevance: number; diversityScore: number; freshnessScore: number; }; } export interface RetrievalContext { query: UnifiedMemoryQuery; results: UnifiedMemoryResult[]; stats: RetrievalStats; suggestions: { relatedQueries: string[]; filterSuggestions: string[]; explorationPaths: string[]; }; timeline?: { events: Array<{ date: Date; type: 'created' | 'modified' | 'accessed' | 'shared'; memoryId: string; description: string; }>; }; } /** * Unified Memory Retrieval Service */ export class MemoryRetrievalService { private embeddingService: EmbeddingService; private vectorManager: VectorManager; private graphManager: KnowledgeGraphManager; private storageManager: StorageManager; private blockchainManager: BlockchainManager; private encryptionService: EncryptionService; private batchManager: BatchManager; private decryptionPipeline: MemoryDecryptionPipeline; // Multi-tier caching system private queryCache = new Map<string, { result: RetrievalContext; timestamp: number }>(); private contentCache = new Map<string, { content: string; metadata: any; timestamp: number }>(); private analyticsCache = new Map<string, { analytics: any; timestamp: number }>(); // Cache TTL settings private readonly QUERY_CACHE_TTL = 5 * 60 * 1000; // 5 minutes private readonly CONTENT_CACHE_TTL = 30 * 60 * 1000; // 30 minutes private readonly ANALYTICS_CACHE_TTL = 60 * 60 * 1000; // 1 hour constructor(config?: { embeddingService?: EmbeddingService; vectorManager?: VectorManager; graphManager?: KnowledgeGraphManager; storageManager?: StorageManager; blockchainManager?: BlockchainManager; encryptionService?: EncryptionService; batchManager?: BatchManager; decryptionConfig?: DecryptionConfig; }) { // Initialize services (can be injected or created with default configs) this.embeddingService = config?.embeddingService ?? new EmbeddingService(); this.storageManager = config?.storageManager ?? new StorageManager(); this.vectorManager = config?.vectorManager ?? new VectorManager( this.storageManager as any, // TODO: Fix type compatibility { embedding: { apiKey: '' }, index: { dimension: 768 }, batch: { maxBatchSize: 10 } } ); this.graphManager = config?.graphManager ?? new KnowledgeGraphManager(); this.blockchainManager = config?.blockchainManager ?? new BlockchainManager(); this.encryptionService = config?.encryptionService ?? new EncryptionService({} as any, {} as any); this.batchManager = config?.batchManager ?? new BatchManager(); // Initialize decryption pipeline this.decryptionPipeline = new MemoryDecryptionPipeline( this.encryptionService, this.storageManager, config?.decryptionConfig ); } // ==================== UNIFIED SEARCH ==================== /** * Main unified search method - handles all types of memory retrieval */ async searchMemories(query: UnifiedMemoryQuery): Promise<RetrievalContext> { const startTime = Date.now(); // Check cache first const cacheKey = this.generateCacheKey(query); if (query.useCache !== false) { const cached = this.getCachedQuery(cacheKey); if (cached) { return cached; } } try { // Execute search based on type let results: UnifiedMemoryResult[]; let searchStats: Partial<RetrievalStats['searchBreakdown']> = {}; switch (query.searchType || 'hybrid') { case 'vector': results = await this.performVectorSearch(query, searchStats); break; case 'semantic': results = await this.performSemanticSearch(query, searchStats); break; case 'keyword': results = await this.performKeywordSearch(query, searchStats); break; case 'graph': results = await this.performGraphSearch(query, searchStats); break; case 'temporal': results = await this.performTemporalSearch(query, searchStats); break; case 'hybrid': default: results = await this.performHybridSearch(query, searchStats); break; } // Apply filters and post-processing results = await this.applyFilters(results, query); results = await this.enrichResults(results, query); results = this.rankAndSortResults(results, query); // Auto-decrypt encrypted memories if decryption is available if (this.decryptionPipeline.isReady()) { try { results = await this.decryptionPipeline.decryptMemoryResults(results, query.userId); } catch (error) { console.warn('⚠️ Auto-decryption failed, returning encrypted results:', error); } } // Generate stats and suggestions const stats = this.generateStats(results, searchStats, startTime); const suggestions = await this.generateSuggestions(query, results); const timeline = await this.generateTimeline(results, query); const context: RetrievalContext = { query, results, stats, suggestions, timeline }; // Cache the results if (query.useCache !== false) { this.cacheQuery(cacheKey, context); } return context; } catch (error) { throw new Error(`Memory retrieval failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } // ==================== SPECIFIC SEARCH IMPLEMENTATIONS ==================== /** * Vector similarity search using HNSW index */ private async performVectorSearch( query: UnifiedMemoryQuery, stats: Partial<RetrievalStats['searchBreakdown']> ): Promise<UnifiedMemoryResult[]> { const vectorStart = Date.now(); if (!query.query) { throw new Error('Vector search requires a query string'); } // Generate query embedding const embedding = await this.embeddingService.embedText({ text: query.query, taskType: 'RETRIEVAL_QUERY' }); // Search vector index const vectorResults = await this.vectorManager.searchSimilarTexts( 'default-user', query.query, { k: query.similarity?.k || 10, efSearch: query.similarity?.efSearch || 100, threshold: query.similarity?.threshold || 0.7 } ); stats.vectorSearchTime = Date.now() - vectorStart; // Convert to unified format return await this.convertVectorResults(vectorResults.results, query); } /** * Semantic search with AI understanding */ private async performSemanticSearch( query: UnifiedMemoryQuery, stats: Partial<RetrievalStats['searchBreakdown']> ): Promise<UnifiedMemoryResult[]> { const semanticStart = Date.now(); // First, get vector results as base const vectorResults = await this.performVectorSearch(query, stats); // Apply semantic analysis for better understanding if (query.query) { // Analyze query semantics const semanticAnalysis = await this.analyzeQuerySemantics(query.query); // Re-rank results based on semantic understanding for (const result of vectorResults) { result.searchRelevance.semanticMatch = await this.calculateSemanticMatch( result, semanticAnalysis ); result.relevanceScore = this.combineRelevanceScores(result.searchRelevance); } } stats.semanticAnalysisTime = (stats.semanticAnalysisTime || 0) + (Date.now() - semanticStart); return vectorResults; } /** * Knowledge graph traversal search */ private async performGraphSearch( query: UnifiedMemoryQuery, stats: Partial<RetrievalStats['searchBreakdown']> ): Promise<UnifiedMemoryResult[]> { const graphStart = Date.now(); const results: UnifiedMemoryResult[] = []; if (query.query) { // Search graph for related entities and memories const graphResults = await this.graphManager.searchGraph( query.query, { maxResults: query.similarity?.k || 20 } ); // Find memories related to discovered entities for (const entity of graphResults.entities) { const relatedMemories = await this.graphManager.findMemoriesRelatedToEntity( entity.label || entity.id, query.userId ); const memoryIds = Array.isArray(relatedMemories) ? relatedMemories : (relatedMemories?.memories || []); for (const memoryId of memoryIds) { const memory = await this.retrieveMemoryById(memoryId, query); if (memory) { memory.searchRelevance.graphRelevance = entity.confidence || 0.8; results.push(memory); } } } } stats.graphTraversalTime = Date.now() - graphStart; return results; } /** * Temporal/time-based search */ private async performTemporalSearch( query: UnifiedMemoryQuery, stats: Partial<RetrievalStats['searchBreakdown']> ): Promise<UnifiedMemoryResult[]> { // Get all user memories const allMemories = await this.getAllUserMemories(query.userId); // Filter by date range let filteredMemories = allMemories; if (query.dateRange?.start) { filteredMemories = filteredMemories.filter( m => m.created >= query.dateRange!.start! ); } if (query.dateRange?.end) { filteredMemories = filteredMemories.filter( m => m.created <= query.dateRange!.end! ); } // Calculate temporal relevance filteredMemories.forEach(memory => { memory.searchRelevance.temporalRelevance = this.calculateTemporalRelevance( memory.created, query.dateRange ); }); return filteredMemories; } /** * Keyword-based search */ private async performKeywordSearch( query: UnifiedMemoryQuery, stats: Partial<RetrievalStats['searchBreakdown']> ): Promise<UnifiedMemoryResult[]> { if (!query.query) { return []; } const keywords = query.query.toLowerCase().split(/\s+/); const allMemories = await this.getAllUserMemories(query.userId); // Score memories based on keyword matches const results = allMemories.filter(memory => { const content = (memory.content || '').toLowerCase(); const matchCount = keywords.filter(keyword => content.includes(keyword) ).length; if (matchCount > 0) { memory.searchRelevance.keywordMatch = matchCount / keywords.length; return true; } return false; }); return results; } /** * Hybrid search combining multiple methods */ private async performHybridSearch( query: UnifiedMemoryQuery, stats: Partial<RetrievalStats['searchBreakdown']> ): Promise<UnifiedMemoryResult[]> { const allResults: UnifiedMemoryResult[] = []; const resultMap = new Map<string, UnifiedMemoryResult>(); // Perform multiple search types if (query.query) { // Vector search const vectorResults = await this.performVectorSearch(query, stats); vectorResults.forEach(result => { result.searchRelevance.vectorSimilarity = result.similarity || 0; resultMap.set(result.id, result); }); // Semantic enhancement const semanticResults = await this.performSemanticSearch(query, stats); semanticResults.forEach(result => { const existing = resultMap.get(result.id); if (existing) { existing.searchRelevance.semanticMatch = result.searchRelevance.semanticMatch; } else { resultMap.set(result.id, result); } }); // Graph search const graphResults = await this.performGraphSearch(query, stats); graphResults.forEach(result => { const existing = resultMap.get(result.id); if (existing) { existing.searchRelevance.graphRelevance = result.searchRelevance.graphRelevance; } else { resultMap.set(result.id, result); } }); } // Temporal search if date range specified if (query.dateRange) { const temporalResults = await this.performTemporalSearch(query, stats); temporalResults.forEach(result => { const existing = resultMap.get(result.id); if (existing) { existing.searchRelevance.temporalRelevance = result.searchRelevance.temporalRelevance; } else { resultMap.set(result.id, result); } }); } // Combine and calculate final relevance scores Array.from(resultMap.values()).forEach(result => { result.relevanceScore = this.combineRelevanceScores(result.searchRelevance); }); return Array.from(resultMap.values()); } // ==================== HELPER METHODS ==================== /** * Apply filters to search results */ private async applyFilters( results: UnifiedMemoryResult[], query: UnifiedMemoryQuery ): Promise<UnifiedMemoryResult[]> { let filtered = results; // Category filter if (query.categories && query.categories.length > 0) { filtered = filtered.filter(result => query.categories!.includes(result.category) ); } // Importance filter if (query.importanceRange) { filtered = filtered.filter(result => { const importance = result.metadata.importance; return (!query.importanceRange!.min || importance >= query.importanceRange!.min) && (!query.importanceRange!.max || importance <= query.importanceRange!.max); }); } // Tags filter if (query.tags && query.tags.length > 0) { filtered = filtered.filter(result => query.tags!.some(tag => result.metadata.tags.includes(tag)) ); } // Content type filter if (query.contentTypes && query.contentTypes.length > 0) { filtered = filtered.filter(result => query.contentTypes!.includes(result.metadata.contentType) ); } return filtered; } /** * Enrich results with additional data */ private async enrichResults( results: UnifiedMemoryResult[], query: UnifiedMemoryQuery ): Promise<UnifiedMemoryResult[]> { const enriched = await Promise.all(results.map(async (result) => { // Load content if requested if (query.includeContent && !result.content) { try { const content = await this.loadMemoryContent(result.storage.blobId, query.userId); result.content = content; } catch (error) { console.warn(`Failed to load content for memory ${result.id}:`, error); } } // Load analytics if requested if (query.includeAnalytics) { result.analytics = await this.loadMemoryAnalytics(result.id); } // Load relationships if requested if (query.includeMetadata) { result.relationships = await this.loadMemoryRelationships(result.id, query.userId); } return result; })); return enriched; } // ... [Continuing with remaining helper methods] /** * Rank and sort results by relevance */ private rankAndSortResults( results: UnifiedMemoryResult[], query: UnifiedMemoryQuery ): UnifiedMemoryResult[] { return results .sort((a, b) => b.relevanceScore - a.relevanceScore) .slice(0, query.similarity?.k || 50); } /** * Generate comprehensive search statistics */ private generateStats( results: UnifiedMemoryResult[], searchBreakdown: Partial<RetrievalStats['searchBreakdown']>, startTime: number ): RetrievalStats { const totalTime = Date.now() - startTime; return { totalResults: results.length, processingTime: totalTime, cacheHitRate: this.calculateCacheHitRate(), searchBreakdown: { vectorSearchTime: searchBreakdown.vectorSearchTime || 0, semanticAnalysisTime: searchBreakdown.semanticAnalysisTime || 0, decryptionTime: searchBreakdown.decryptionTime || 0, graphTraversalTime: searchBreakdown.graphTraversalTime || 0 }, dataSourcesUsed: this.getDataSourcesUsed(results), qualityMetrics: { averageRelevance: results.reduce((sum, r) => sum + r.relevanceScore, 0) / results.length || 0, diversityScore: this.calculateDiversityScore(results), freshnessScore: this.calculateFreshnessScore(results) } }; } // ==================== CACHE MANAGEMENT ==================== private generateCacheKey(query: UnifiedMemoryQuery): string { return `query:${JSON.stringify(query)}`; } private getCachedQuery(key: string): RetrievalContext | null { const cached = this.queryCache.get(key); if (cached && Date.now() - cached.timestamp < this.QUERY_CACHE_TTL) { return cached.result; } this.queryCache.delete(key); return null; } private cacheQuery(key: string, result: RetrievalContext): void { this.queryCache.set(key, { result, timestamp: Date.now() }); } // ==================== UTILITY METHODS ==================== private calculateCacheHitRate(): number { // Implementation for cache hit rate calculation return 0.85; // Placeholder } private getDataSourcesUsed(results: UnifiedMemoryResult[]): string[] { const sources = new Set<string>(); results.forEach(result => { if (result.storage.cacheStatus === 'cached') sources.add('cache'); if (result.storage.walrusHash) sources.add('walrus'); if (result.storage.blockchainId) sources.add('blockchain'); }); return Array.from(sources); } private calculateDiversityScore(results: UnifiedMemoryResult[]): number { const categories = new Set(results.map(r => r.category)); return categories.size / Math.max(results.length, 1); } private calculateFreshnessScore(results: UnifiedMemoryResult[]): number { const now = Date.now(); const avgAge = results.reduce((sum, r) => sum + (now - r.created.getTime()), 0) / results.length; const maxAge = 365 * 24 * 60 * 60 * 1000; // 1 year in ms return Math.max(0, 1 - (avgAge / maxAge)); } // Placeholder methods - to be implemented private async convertVectorResults(vectorResults: any[], query: UnifiedMemoryQuery): Promise<UnifiedMemoryResult[]> { // Convert vector search results to unified format return []; } private async analyzeQuerySemantics(query: string): Promise<any> { // Analyze query for semantic understanding return {}; } private async calculateSemanticMatch(result: UnifiedMemoryResult, semantics: any): Promise<number> { // Calculate semantic match score return 0.8; } private combineRelevanceScores(scores: UnifiedMemoryResult['searchRelevance']): number { // Combine different relevance scores into final score const weights = { vectorSimilarity: 0.4, semanticMatch: 0.3, keywordMatch: 0.1, graphRelevance: 0.15, temporalRelevance: 0.05 }; return (scores.vectorSimilarity || 0) * weights.vectorSimilarity + (scores.semanticMatch || 0) * weights.semanticMatch + (scores.keywordMatch || 0) * weights.keywordMatch + (scores.graphRelevance || 0) * weights.graphRelevance + (scores.temporalRelevance || 0) * weights.temporalRelevance; } private calculateTemporalRelevance(date: Date, range?: { start?: Date; end?: Date }): number { // Calculate temporal relevance score return 0.7; } private async getAllUserMemories(userId: string): Promise<UnifiedMemoryResult[]> { // Get all memories for user from blockchain return []; } private async retrieveMemoryById(memoryId: string, query: UnifiedMemoryQuery): Promise<UnifiedMemoryResult | null> { // Retrieve specific memory by ID return null; } private async loadMemoryContent(blobId: string, userId: string): Promise<string> { // Load and decrypt memory content return ""; } private async loadMemoryAnalytics(memoryId: string): Promise<any> { // Load memory analytics data return {}; } private async loadMemoryRelationships(memoryId: string, userId: string): Promise<any> { // Load memory relationships from knowledge graph return {}; } private async generateSuggestions(query: UnifiedMemoryQuery, results: UnifiedMemoryResult[]): Promise<any> { // Generate query suggestions and exploration paths return { relatedQueries: [], filterSuggestions: [], explorationPaths: [] }; } private async generateTimeline(results: UnifiedMemoryResult[], query: UnifiedMemoryQuery): Promise<any> { // Generate timeline of memory events return undefined; } // ==================== PUBLIC API ==================== /** * Get comprehensive memory retrieval statistics */ getRetrievalStats(): { cacheStats: { queries: number; content: number; analytics: number }; performanceMetrics: any; } { return { cacheStats: { queries: this.queryCache.size, content: this.contentCache.size, analytics: this.analyticsCache.size }, performanceMetrics: {} }; } /** * Clear all caches */ clearCache(): void { this.queryCache.clear(); this.contentCache.clear(); this.analyticsCache.clear(); } /** * Warm up caches for a user */ async warmupCache(userId: string): Promise<void> { // Pre-load frequently accessed data console.log(`Warming up cache for user ${userId}`); } }