Class: Legion::Extensions::Agentic::Memory::Trace::Helpers::CacheStore
- Inherits:
-
Object
- Object
- Legion::Extensions::Agentic::Memory::Trace::Helpers::CacheStore
- 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.
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 22 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.
20 21 22 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 20 def associations @associations end |
#traces ⇒ Object (readonly)
Returns the value of attribute traces.
20 21 22 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 20 def traces @traces end |
Instance Method Details
#all_traces(min_strength: 0.0) ⇒ Object
97 98 99 100 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 97 def all_traces(min_strength: 0.0) snapshot = @mutex.synchronize { @traces.values } snapshot.select { |t| t[:strength] >= min_strength } end |
#count ⇒ Object
102 103 104 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 102 def count @traces.size end |
#delete(trace_id) ⇒ Object
46 47 48 49 50 51 52 53 54 55 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 46 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
108 109 110 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 108 def firmware_traces retrieve_by_type(:firmware) end |
#flush ⇒ Object
Write dirty traces to cache as individual keys
143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 143 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
42 43 44 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 42 def get(trace_id) @traces[trace_id] end |
#record_coactivation(trace_id_a, trace_id_b) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 82 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
156 157 158 159 160 161 162 163 164 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 156 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
71 72 73 74 75 76 77 78 79 80 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 71 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
64 65 66 67 68 69 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 64 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
57 58 59 60 61 62 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 57 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
34 35 36 37 38 39 40 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 34 def store(trace) @mutex.synchronize do @traces[trace[:trace_id]] = trace @dirty_ids << trace[:trace_id] end trace[:trace_id] end |
#synchronize ⇒ Object
106 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 106 def synchronize(&) = @mutex.synchronize(&) |
#walk_associations(start_id:, max_hops: 12, min_strength: 0.1) ⇒ Object
112 113 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 |
# File 'lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb', line 112 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 |