/** * Memory Element - Persistent context storage for continuity and learning * * Provides multiple storage backends, retention policies, and search capabilities * for maintaining context across sessions and interactions. * * SECURITY MEASURES IMPLEMENTED: * 1. Input sanitization for all memory content * 2. Memory size limits to prevent unbounded growth * 3. Path validation for file-based storage * 4. Retention policy enforcement * 5. Privacy level access control * 6. Audit logging for all operations */ import { BaseElement } from '../BaseElement.js'; import { IElement, ElementValidationResult } from '../../types/elements/index.js'; import { IElementMetadata } from '../../types/elements/IElement.js'; import { MetadataService } from '../../services/MetadataService.js'; import { PrivacyLevel, StorageBackend, TrustLevel } from './constants.js'; import { MemoryType } from './types.js'; export interface MemoryMetadata extends IElementMetadata { storageBackend?: StorageBackend; retentionDays?: number; privacyLevel?: PrivacyLevel; searchable?: boolean; maxEntries?: number; encryptionEnabled?: boolean; indexThreshold?: number; enableContentIndex?: boolean; maxTermsPerEntry?: number; minTermLength?: number; triggers?: string[]; autoLoad?: boolean; priority?: number; memoryType?: MemoryType; } export interface MemoryEntry { id: string; timestamp: Date; content: string; tags?: string[]; metadata?: Record; expiresAt?: Date; privacyLevel?: PrivacyLevel; trustLevel?: TrustLevel; sanitizedPatterns?: unknown[]; sanitizedContent?: string; source?: string; } export interface MemorySearchOptions { query?: string; tags?: string[]; startDate?: Date; endDate?: Date; limit?: number; privacyLevel?: PrivacyLevel; } /** * Memory Element Implementation * * TODO: Memory Sharding Strategy (Issue #981) * --------------------------------------------- * Current: Single Map for all memories * Problem: Large memory sets (>10K entries) cause performance degradation * * Planned Sharding Architecture: * 1. Shard memories across multiple files based on hash(memoryId) % shardCount * 2. Each shard file <256KB for optimal YAML parsing * 3. Memory references stored separately from content (like git objects) * 4. Large binary content (PDFs, images) stored as external references * * Benefits: * - Parallel loading of memory shards * - Reduced memory footprint (load only needed shards) * - Better corruption resistance (one shard failure doesn't affect others) * - Efficient incremental updates * * TODO: Content Integrity Verification (Issue #982) * -------------------------------------------------- * Add SHA-256 hashes to detect: * - Accidental corruption from disk errors * - Intentional tampering with memory files * - Version conflicts during concurrent access * * Implementation: * - Store hash in memory metadata * - Verify on load, warn on mismatch * - Option to auto-restore from backup on corruption * * TODO: Memory Capacity Management (Issue #983) * --------------------------------------------- * Current: Synchronous retention enforcement on each add * Better: Background cleanup with smart triggers: * - Cleanup when 90% capacity reached * - Batch deletions for efficiency * - LRU eviction with access tracking * - Preserve "pinned" memories regardless of age */ export declare class Memory extends BaseElement implements IElement { private static readonly createdMemoryNames; private static memoryManagerResolver?; /** * Static resolver for RetentionPolicyService (Issue #51) * Used to check if retention enforcement should happen on load */ private static retentionPolicyResolver?; static configureMemoryManagerResolver(resolver: () => { list(): Promise; save(memory: Memory, filePath?: string): Promise; } | undefined): void; /** * Configure the RetentionPolicyService resolver (Issue #51) * Called during DI container setup */ static configureRetentionPolicyResolver(resolver: () => { shouldEnforceOnLoad(): boolean; isEnabled(): boolean; } | undefined): void; /** * Reset all static resolvers (for test cleanup) * Call this in afterEach hooks to prevent test isolation issues * where a stale resolver references disposed services */ static resetResolvers(): void; /** * Get the RetentionPolicyService instance * Returns undefined if not configured (allows graceful fallback) */ private static getRetentionPolicyService; private static getMemoryManager; private entries; private storageBackend; private retentionDays; private privacyLevel; private searchable; private maxEntries; private searchIndex; private sanitizationCache; private filePath?; private static readonly MAX_SANITIZATION_CACHE_SIZE; private static readonly MAX_SANITIZATION_CACHE_MEMORY_MB; constructor(metadata: Partial | undefined, metadataService: MetadataService); /** * Helper method to get the current number of entries * Compatible with LRUCache */ private get entriesSize(); /** * Add a new memory entry * SECURITY: Sanitizes input and enforces size limits * FIX #1315: Removed blocking validation - all entries created as UNTRUSTED * Background validation will update trust levels asynchronously (Issue #1314) * * FIX: Refactored to reduce cognitive complexity (SonarCloud S3776) * FIX (PR #1313 review): Sanitize source parameter for log injection prevention */ addEntry(content: string, tags?: string[], metadata?: Record, source?: string): Promise; /** * Enforce capacity limit synchronously * FIX (PR #1313): Made synchronous to prevent race conditions * This is called AFTER adding an entry to ensure we never exceed maxEntries */ private enforceCapacitySync; /** * Search memory entries * SECURITY: Respects privacy levels and sanitizes search queries * * IMPLEMENTED: Basic indexed search for O(log n) performance (Issue #984) * - Tag index: Map> for instant tag lookups ✓ * - Content index: Inverted index for term search ✓ * - Date index: Binary tree for efficient range queries ✓ * - Privacy index: Pre-sorted entries by privacy level ✓ * * TODO: Advanced indexing features (Future enhancements): * - Composite indices: Combined indices for common query patterns * - Index-of-indexes pattern: * - Master index file (meta.yaml) with pointers to shard indices * - Each shard maintains its own local index * - Periodic index compaction and optimization * - Persistent index storage to disk * - Incremental index updates for large datasets * * Performance improvement achieved: * - Previous: ~100ms for 10,000 entries (linear scan) * - Current: <5ms for same dataset (indexed search) */ search(options?: MemorySearchOptions): Promise; /** * Get a specific memory entry by ID */ getEntry(id: string): Promise; /** * Delete a memory entry * SECURITY: Validates permissions and logs deletion */ deleteEntry(id: string): Promise; /** * Get formatted content of all memory entries * Returns entries as a readable string for display * FIX #1269: Sandboxes untrusted content to prevent prompt injection */ get content(): string; private formatEntryForDisplay; private prepareEntryForDisplay; private revalidateTrustedEntry; private getSafeSanitizedContent; private getTrustIndicator; /** * Sandbox untrusted content with clear delimiters * FIX #1269: Prevents AI from interpreting user content as instructions */ private sandboxUntrustedContent; /** * Enforce retention policy by removing expired entries * SECURITY: Ensures memory doesn't grow unbounded */ enforceRetentionPolicy(): Promise; /** * Clear all memory entries * SECURITY: Requires confirmation and logs the action */ clearAll(confirm?: boolean): Promise; /** * Helper function to ensure a value is a valid Date object * FIX #1069: Validates and converts timestamps to Date objects */ private ensureDateObject; /** * Get memory statistics */ getStats(): { totalEntries: number; totalSize: number; oldestEntry?: Date; newestEntry?: Date; tagFrequency: Map; }; /** * Validate the memory element */ validate(): ElementValidationResult; /** * Serialize memory to string */ serialize(): string; /** * Process and validate a single memory entry during deserialization * FIX #1315: Reads trust level from metadata instead of re-validating * Returns true if entry was loaded, false if quarantined */ private processDeserializedEntry; /** * Deserialize memory from string * SECURITY: Validates all loaded data * FIX #1269: Added ContentValidator to prevent loading infected memories */ deserialize(data: string): void; private calculateExpiryDate; private sanitizeTags; private sanitizeMetadata; private canAccessPrivacyLevel; private isValidEntry; /** * Optimized sanitization with checksum caching * Avoids re-sanitizing content that hasn't changed * @param content Content to sanitize * @param maxLength Maximum allowed length * @returns Sanitized content */ private sanitizeWithCache; /** * Build search index with retry logic * Attempts to build the index up to 3 times with exponential backoff * This ensures search functionality even if there are transient failures */ private buildSearchIndexWithRetry; /** * Get all entries with a specific trust level * FIX #1320: Public API for accessing entries by trust level * Used by BackgroundValidator to find untrusted entries * * @param trustLevel - The trust level to filter by * @returns Array of memory entries matching the trust level */ getEntriesByTrustLevel(trustLevel: TrustLevel): MemoryEntry[]; /** * Get all entries in this memory * FIX #1320: Public API for accessing all entries * Replaces the need for `(memory as any).entries` hacks * * @returns Array of all memory entries */ getAllEntries(): MemoryEntry[]; /** * Get the entries map directly * Used by RetentionPolicyService for retention enforcement (Issue #51) * * @returns Map of entry ID to memory entry */ getEntries(): Map; /** * Remove a specific entry by ID * FIX #51: Public API for retention policy to remove expired entries * Replaces the need for `(memory as any).entries.delete()` hacks * * @param entryId - The ID of the entry to remove * @returns true if entry was removed, false if not found */ removeEntry(entryId: string): boolean; /** * Get an iterator over all entries * FIX #1320: Memory-efficient way to iterate entries * * @returns Iterator over memory entries */ getEntriesIterator(): IterableIterator; /** * Set the file path for this memory * FIX #1320: Used by MemoryManager after loading * FIX (SonarCloud): Added input validation with proper error types * @param path - The file path where this memory is stored * @throws {TypeError} If path is not a string * @throws {Error} If path is empty */ setFilePath(path: string): void; /** * Get the file path for this memory * FIX #1320: Returns the path where this memory is stored * @returns The file path, or undefined if not yet persisted */ getFilePath(): string | undefined; /** * Save this memory to disk * FIX #1320: Instance method for persisting memory changes * Used by BackgroundValidator to save updated trust levels * * @returns Promise that resolves when save is complete * @throws {Error} If memory has not been loaded from file and no path is set */ save(): Promise; /** * Find all memories that have entries with a specific trust level * FIX #1320: Static query API for finding memories by trust level * Used by BackgroundValidator to discover untrusted memories * * @param trustLevel - The trust level to filter by * @param options - Optional query options * @param options.limit - Maximum number of memories to return * @returns Promise resolving to array of memories with matching entries */ static findByTrustLevel(trustLevel: TrustLevel, options?: { limit?: number; }): Promise; /** * General query API for finding memories * FIX #1320: Flexible query API for multiple criteria * FIX (SonarCloud): Refactored to reduce cognitive complexity from 20 to 8 * * @param filter - Query filter criteria * @param filter.trustLevel - Filter by trust level * @param filter.tags - Filter by tags * @param filter.maxAge - Filter by age in days * @returns Promise resolving to array of matching memories */ static find(filter: { trustLevel?: TrustLevel; tags?: string[]; maxAge?: number; }): Promise; /** * Check if a memory matches the given filter criteria * FIX (SonarCloud): Extracted to reduce cognitive complexity * @private */ private static matchesFilter; } //# sourceMappingURL=Memory.d.ts.map