Class: Legion::Extensions::Agentic::Memory::Trace::Helpers::CacheStore
- Inherits:
-
Object
- Object
- Legion::Extensions::Agentic::Memory::Trace::Helpers::CacheStore
- Includes:
- Logging::Helper
- Defined in:
- lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb
Overview
Cache-backed store using Legion::Cache (Memcached/Redis). Each trace is stored as an individual cache key for scalability. An index key tracks all known trace IDs. Keeps a local in-memory copy for fast reads; syncs to cache on flush.
Constant Summary collapse
- TRACE_PREFIX =
'legion:memory:trace:'- INDEX_KEY =
'legion:memory:trace_index'- ASSOC_KEY =
'legion:memory:associations'- TTL =
24 hours
86_400- FLUSH_BATCH =
traces per flush batch
500
Instance Attribute Summary collapse
-
#associations ⇒ Object
readonly
Returns the value of attribute associations.
-
#traces ⇒ Object
readonly
Returns the value of attribute traces.
Instance Method Summary collapse
- #all_traces(min_strength: 0.0) ⇒ Object
- #count ⇒ Object
- #delete(trace_id) ⇒ Object
- #firmware_traces ⇒ Object
-
#flush ⇒ Object
Write dirty traces to cache as individual keys.
- #get(trace_id) ⇒ Object
-
#initialize ⇒ CacheStore
constructor
A new instance of CacheStore.
- #record_coactivation(trace_id_a, trace_id_b) ⇒ Object
-
#reload ⇒ Object
Pull latest state from cache.
- #retrieve_associated(trace_id, min_strength: 0.0, limit: 20) ⇒ Object
- #retrieve_by_domain(domain_tag, min_strength: 0.0, limit: 100) ⇒ Object
- #retrieve_by_type(type, min_strength: 0.0, limit: 100) ⇒ Object
- #store(trace) ⇒ Object
- #synchronize ⇒ Object
- #walk_associations(start_id:, max_hops: 12, min_strength: 0.1) ⇒ Object
Constructor Details
#initialize ⇒ CacheStore
Returns a new instance of CacheStore.
24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 24 def initialize log.info('[memory] CacheStore initialized (memcached-backed, per-key)') @mutex = Mutex.new @traces = {} @associations = {} @dirty_ids = Set.new @deleted_ids = Set.new @assoc_dirty = false load_index log.info("[memory] CacheStore loaded #{@traces.size} traces from cache") end |
Instance Attribute Details
#associations ⇒ Object (readonly)
Returns the value of attribute associations.
22 23 24 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 22 def associations @associations end |
#traces ⇒ Object (readonly)
Returns the value of attribute traces.
22 23 24 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 22 def traces @traces end |
Instance Method Details
#all_traces(min_strength: 0.0) ⇒ Object
99 100 101 102 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 99 def all_traces(min_strength: 0.0) snapshot = @mutex.synchronize { @traces.values } snapshot.select { |t| t[:strength] >= min_strength } end |
#count ⇒ Object
104 105 106 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 104 def count @traces.size end |
#delete(trace_id) ⇒ Object
48 49 50 51 52 53 54 55 56 57 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 48 def delete(trace_id) @mutex.synchronize do @traces.delete(trace_id) @associations.delete(trace_id) @associations.each_value { |links| links.delete(trace_id) } @dirty_ids.delete(trace_id) @deleted_ids << trace_id @assoc_dirty = true end end |
#firmware_traces ⇒ Object
110 111 112 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 110 def firmware_traces retrieve_by_type(:firmware) end |
#flush ⇒ Object
Write dirty traces to cache as individual keys
145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 145 def flush @mutex.synchronize do flush_deleted flush_traces flush_associations flush_index log.debug("[memory] CacheStore flushed #{@dirty_ids.size} dirty traces (#{@traces.size} total)") @dirty_ids.clear @deleted_ids.clear end end |
#get(trace_id) ⇒ Object
44 45 46 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 44 def get(trace_id) @traces[trace_id] end |
#record_coactivation(trace_id_a, trace_id_b) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 84 def record_coactivation(trace_id_a, trace_id_b) return if trace_id_a == trace_id_b @mutex.synchronize do @associations[trace_id_a] ||= {} @associations[trace_id_b] ||= {} @associations[trace_id_a][trace_id_b] = (@associations[trace_id_a][trace_id_b] || 0) + 1 @associations[trace_id_b][trace_id_a] = (@associations[trace_id_b][trace_id_a] || 0) + 1 threshold = Helpers::Trace::COACTIVATION_THRESHOLD link_traces(trace_id_a, trace_id_b) if @associations[trace_id_a][trace_id_b] >= threshold @assoc_dirty = true end end |
#reload ⇒ Object
Pull latest state from cache
158 159 160 161 162 163 164 165 166 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 158 def reload @traces.clear @associations = {} @dirty_ids.clear @deleted_ids.clear @assoc_dirty = false load_index log.debug("[memory] CacheStore reloaded #{@traces.size} traces from cache") end |
#retrieve_associated(trace_id, min_strength: 0.0, limit: 20) ⇒ Object
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 73 def retrieve_associated(trace_id, min_strength: 0.0, limit: 20) trace = @traces[trace_id] return [] unless trace trace[:associated_traces] .filter_map { |id| @traces[id] } .select { |t| t[:strength] >= min_strength } .sort_by { |t| -t[:strength] } .first(limit) end |
#retrieve_by_domain(domain_tag, min_strength: 0.0, limit: 100) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 66 def retrieve_by_domain(domain_tag, min_strength: 0.0, limit: 100) snapshot = @mutex.synchronize { @traces.values } snapshot.select { |t| t[:domain_tags].include?(domain_tag) && t[:strength] >= min_strength } .sort_by { |t| -t[:strength] } .first(limit) end |
#retrieve_by_type(type, min_strength: 0.0, limit: 100) ⇒ Object
59 60 61 62 63 64 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 59 def retrieve_by_type(type, min_strength: 0.0, limit: 100) snapshot = @mutex.synchronize { @traces.values } snapshot.select { |t| t[:trace_type] == type && t[:strength] >= min_strength } .sort_by { |t| -t[:strength] } .first(limit) end |
#store(trace) ⇒ Object
36 37 38 39 40 41 42 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 36 def store(trace) @mutex.synchronize do @traces[trace[:trace_id]] = trace @dirty_ids << trace[:trace_id] end trace[:trace_id] end |
#synchronize ⇒ Object
108 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 108 def synchronize(&) = @mutex.synchronize(&) |
#walk_associations(start_id:, max_hops: 12, min_strength: 0.1) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 114 def walk_associations(start_id:, max_hops: 12, min_strength: 0.1) snapshot = @mutex.synchronize { @traces.dup } return [] unless snapshot.key?(start_id) results = [] visited = Set.new([start_id]) queue = [[start_id, 0, [start_id]]] until queue.empty? current_id, depth, path = queue.shift current = snapshot[current_id] next unless current current[:associated_traces].each do |neighbor_id| next if visited.include?(neighbor_id) neighbor = snapshot[neighbor_id] next unless neighbor next unless neighbor[:strength] >= min_strength visited << neighbor_id neighbor_path = path + [neighbor_id] results << { trace_id: neighbor_id, depth: depth + 1, path: neighbor_path } queue << [neighbor_id, depth + 1, neighbor_path] if depth + 1 < max_hops end end results end |