Module: Legion::Extensions::Agentic::Memory::Trace::Helpers::HotTier

Defined in:
lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb

Constant Summary collapse

HOT_TTL =

24 hours

86_400

Class Method Summary collapse

Class Method Details

.available?Boolean

Returns true when the RedisHash module is loaded and Redis is reachable.

Returns:

  • (Boolean)


56
57
58
59
60
61
62
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 56

def available?
  defined?(Legion::Cache::RedisHash) &&
    Legion::Cache::RedisHash.redis_available?
rescue StandardError => e
  log.error "[trace_persistence] hot_tier available?: #{e.message}"
  false
end

.cache_scope_id(trace, tenant_id: nil, agent_id: nil) ⇒ Object



76
77
78
79
80
81
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 76

def cache_scope_id(trace, tenant_id: nil, agent_id: nil)
  return scope_id(tenant_id: tenant_id, agent_id: agent_id) if agent_id
  return tenant_id if tenant_id

  trace[:partition_id]
end

.cache_trace(trace, tenant_id: nil, agent_id: nil) ⇒ Object

Cache a trace in the Redis hot tier.



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 19

def cache_trace(trace, tenant_id: nil, agent_id: nil)
  return unless available?

  scope = cache_scope_id(trace, tenant_id: tenant_id, agent_id: agent_id)
  key = trace_key(scope, trace[:trace_id])
  data = serialize_trace(trace)
  Legion::Cache::RedisHash.hset(key, data)
  Legion::Cache::RedisHash.expire(key, HOT_TTL)

  index_key = "legion:tier:hot:#{scope}"
  Legion::Cache::RedisHash.zadd(index_key, Time.now.to_f, trace[:trace_id])
end

.deserialize_trace(data) ⇒ Object

Deserialize a Redis string-hash back to a typed trace hash.



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 99

def deserialize_trace(data)
  {
    trace_id:        data['trace_id'],
    trace_type:      data['trace_type']&.to_sym,
    content_payload: data['content_payload'],
    strength:        data['strength']&.to_f,
    peak_strength:   data['peak_strength']&.to_f,
    confidence:      data['confidence']&.to_f,
    storage_tier:    :hot,
    partition_id:    data['partition_id'],
    last_reinforced: data['last_reinforced']
  }
end

.evict_trace(trace_id, tenant_id: nil, agent_id: nil) ⇒ Object

Evict a trace from the hot tier and remove it from the sorted-set index.



44
45
46
47
48
49
50
51
52
53
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 44

def evict_trace(trace_id, tenant_id: nil, agent_id: nil)
  return unless available?

  scope = scope_id(tenant_id: tenant_id, agent_id: agent_id)
  key = trace_key(scope, trace_id)
  Legion::Cache.delete(key)

  index_key = "legion:tier:hot:#{scope}"
  Legion::Cache::RedisHash.zrem(index_key, trace_id)
end

.fetch_trace(trace_id, tenant_id: nil, agent_id: nil) ⇒ Object

Fetch a trace from the hot tier. Returns a deserialized trace hash or nil on miss.



33
34
35
36
37
38
39
40
41
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 33

def fetch_trace(trace_id, tenant_id: nil, agent_id: nil)
  return nil unless available?

  key = trace_key(scope_id(tenant_id: tenant_id, agent_id: agent_id), trace_id)
  data = Legion::Cache::RedisHash.hgetall(key)
  return nil if data.nil? || data.empty?

  deserialize_trace(data)
end

.logObject



12
13
14
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 12

def self.log
  Legion::Logging
end

.scope_id(tenant_id: nil, agent_id: nil) ⇒ Object



69
70
71
72
73
74
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 69

def scope_id(tenant_id: nil, agent_id: nil)
  return tenant_id if tenant_id && agent_id.nil?
  return agent_id if agent_id && tenant_id.nil?

  [tenant_id, agent_id].compact.join(':')
end

.serialize_trace(trace) ⇒ Object

Serialize a trace hash to a string-only flat hash suitable for Redis HSET.



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 84

def serialize_trace(trace)
  {
    'trace_id'        => trace[:trace_id].to_s,
    'trace_type'      => trace[:trace_type].to_s,
    'content_payload' => trace[:content_payload].to_s,
    'strength'        => trace[:strength].to_s,
    'peak_strength'   => trace[:peak_strength].to_s,
    'confidence'      => trace[:confidence].to_s,
    'storage_tier'    => 'hot',
    'partition_id'    => trace[:partition_id].to_s,
    'last_reinforced' => (trace[:last_reinforced] || Time.now).to_s
  }
end

.trace_key(scope_id, trace_id) ⇒ Object

Build the namespaced Redis key for a trace.



65
66
67
# File 'lib/legion/extensions/agentic/memory/trace/helpers/hot_tier.rb', line 65

def trace_key(scope_id, trace_id)
  "legion:trace:#{scope_id}:#{trace_id}"
end