Class: DSPy::Memory::MemoryCompactor
- Inherits:
-
Object
- Object
- DSPy::Memory::MemoryCompactor
- Extended by:
- T::Sig
- Defined in:
- lib/dspy/memory/memory_compactor.rb
Overview
Simple memory compaction system with inline triggers Handles deduplication, relevance pruning, and conflict resolution
Constant Summary collapse
- DEFAULT_MAX_MEMORIES =
Compaction thresholds
1000
- DEFAULT_MAX_AGE_DAYS =
90
- DEFAULT_SIMILARITY_THRESHOLD =
0.95
- DEFAULT_LOW_ACCESS_THRESHOLD =
0.1
Instance Attribute Summary collapse
-
#low_access_threshold ⇒ Object
readonly
Returns the value of attribute low_access_threshold.
-
#max_age_days ⇒ Object
readonly
Returns the value of attribute max_age_days.
-
#max_memories ⇒ Object
readonly
Returns the value of attribute max_memories.
-
#similarity_threshold ⇒ Object
readonly
Returns the value of attribute similarity_threshold.
Instance Method Summary collapse
- #age_compaction_needed?(store, user_id) ⇒ Boolean
- #compact_if_needed!(store, embedding_engine, user_id: nil) ⇒ Object
- #duplication_compaction_needed?(store, embedding_engine, user_id) ⇒ Boolean
-
#initialize(max_memories: DEFAULT_MAX_MEMORIES, max_age_days: DEFAULT_MAX_AGE_DAYS, similarity_threshold: DEFAULT_SIMILARITY_THRESHOLD, low_access_threshold: DEFAULT_LOW_ACCESS_THRESHOLD) ⇒ MemoryCompactor
constructor
A new instance of MemoryCompactor.
- #relevance_compaction_needed?(store, user_id) ⇒ Boolean
- #size_compaction_needed?(store, user_id) ⇒ Boolean
Constructor Details
#initialize(max_memories: DEFAULT_MAX_MEMORIES, max_age_days: DEFAULT_MAX_AGE_DAYS, similarity_threshold: DEFAULT_SIMILARITY_THRESHOLD, low_access_threshold: DEFAULT_LOW_ACCESS_THRESHOLD) ⇒ MemoryCompactor
Returns a new instance of MemoryCompactor.
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/dspy/memory/memory_compactor.rb', line 38 def initialize( max_memories: DEFAULT_MAX_MEMORIES, max_age_days: DEFAULT_MAX_AGE_DAYS, similarity_threshold: DEFAULT_SIMILARITY_THRESHOLD, low_access_threshold: DEFAULT_LOW_ACCESS_THRESHOLD ) @max_memories = max_memories @max_age_days = max_age_days @similarity_threshold = similarity_threshold @low_access_threshold = low_access_threshold end |
Instance Attribute Details
#low_access_threshold ⇒ Object (readonly)
Returns the value of attribute low_access_threshold.
28 29 30 |
# File 'lib/dspy/memory/memory_compactor.rb', line 28 def low_access_threshold @low_access_threshold end |
#max_age_days ⇒ Object (readonly)
Returns the value of attribute max_age_days.
22 23 24 |
# File 'lib/dspy/memory/memory_compactor.rb', line 22 def max_age_days @max_age_days end |
#max_memories ⇒ Object (readonly)
Returns the value of attribute max_memories.
19 20 21 |
# File 'lib/dspy/memory/memory_compactor.rb', line 19 def max_memories @max_memories end |
#similarity_threshold ⇒ Object (readonly)
Returns the value of attribute similarity_threshold.
25 26 27 |
# File 'lib/dspy/memory/memory_compactor.rb', line 25 def similarity_threshold @similarity_threshold end |
Instance Method Details
#age_compaction_needed?(store, user_id) ⇒ Boolean
86 87 88 89 90 91 92 |
# File 'lib/dspy/memory/memory_compactor.rb', line 86 def age_compaction_needed?(store, user_id) memories = store.list(user_id: user_id) return false if memories.empty? # Check if any memory exceeds the age limit memories.any? { |memory| memory.age_in_days > @max_age_days } end |
#compact_if_needed!(store, embedding_engine, user_id: nil) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/dspy/memory/memory_compactor.rb', line 52 def compact_if_needed!(store, , user_id: nil) DSPy::Context.with_span(operation: 'memory.compaction_check', 'memory.user_id' => user_id) do results = {} # Check triggers in order of impact if size_compaction_needed?(store, user_id) results[:size_compaction] = perform_size_compaction!(store, user_id) end if age_compaction_needed?(store, user_id) results[:age_compaction] = perform_age_compaction!(store, user_id) end if duplication_compaction_needed?(store, , user_id) results[:deduplication] = perform_deduplication!(store, , user_id) end if relevance_compaction_needed?(store, user_id) results[:relevance_pruning] = perform_relevance_pruning!(store, user_id) end results[:total_compacted] = results.values.sum { |r| r.is_a?(Hash) ? r[:removed_count] || 0 : 0 } results end end |
#duplication_compaction_needed?(store, embedding_engine, user_id) ⇒ Boolean
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/dspy/memory/memory_compactor.rb', line 96 def duplication_compaction_needed?(store, , user_id) # Sample recent memories to check for duplicates recent_memories = store.list(user_id: user_id, limit: 50) return false if recent_memories.length < 10 # Quick duplicate check on a sample sample_size = [recent_memories.length / 4, 10].max sample = recent_memories.sample(sample_size) duplicate_count = 0 sample.each_with_index do |memory1, i| sample[(i+1)..-1].each do |memory2| next unless memory1. && memory2. similarity = .cosine_similarity(memory1., memory2.) duplicate_count += 1 if similarity > @similarity_threshold end end # Need deduplication if > 20% of sample has duplicates (duplicate_count.to_f / sample_size) > 0.2 end |
#relevance_compaction_needed?(store, user_id) ⇒ Boolean
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/dspy/memory/memory_compactor.rb', line 121 def relevance_compaction_needed?(store, user_id) memories = store.list(user_id: user_id, limit: 100) return false if memories.length < 50 # Check if many memories have low access counts total_access = memories.sum(&:access_count) return false if total_access == 0 # Calculate relative access for each memory low_access_count = memories.count do |memory| relative_access = memory.access_count.to_f / total_access relative_access < @low_access_threshold end # Need pruning if > 30% of memories have low relative access low_access_ratio = low_access_count.to_f / memories.length low_access_ratio > 0.3 end |
#size_compaction_needed?(store, user_id) ⇒ Boolean
80 81 82 |
# File 'lib/dspy/memory/memory_compactor.rb', line 80 def size_compaction_needed?(store, user_id) store.count(user_id: user_id) > @max_memories end |