lex-memory 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 887236dfa6fe8f5f792dc57af29a84b1404bac3938fd3482644e15cbdfde394d
4
- data.tar.gz: 751161d389e5b4c2a4ecb690b31c0a2223a2e4a7d205623c40585131dedbd75b
3
+ metadata.gz: 82f15c25a2be58044cf03787524080a9215578ab854733cf500bc97d68cd3424
4
+ data.tar.gz: f93a129b74c70e1ae602b14c53967f658171b8ff9b783c14f28ba0c1f9d015e8
5
5
  SHA512:
6
- metadata.gz: 25fdd67e7aa1b5ed17fbe66253c9a4b925cfd0d82dcc2ccafe63a08f06f7a7126c8b33b99163d415043b43c3456be6a6ff43d1912de27580d255e2e033e176f0
7
- data.tar.gz: eda7ac4517f976d8b6f2672c872487e649970df67c1cb89a8249205f8c4294717f965871f6f43e7ab3deb9feefd68df15d1bb2af2f9a57002f2b956036a26f4b
6
+ metadata.gz: c639e1b1ad0b3a19c454f37704a7b97fcf5e933c079be7d91dfb54215c6bbd334a2f79ae44c381a1560d92a3e7e76bbf8ed3b5b575ccd7c8307c7cec42fd06a6
7
+ data.tar.gz: a97d6a06e69470aadca4f7fadc92a7f4118818a13203a780506051e83e9f3990023dee1996cfc9863339e709882b24e755e9aaaf4d886e82290e691b950e319d
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [0.2.0] - 2026-03-17
4
+
5
+ ### Added
6
+ - `PersistentStore`: Sequel-backed durable memory storage per agent (write, read, touch, count, total_bytes, eviction)
7
+ - `Quota`: per-agent trace count and byte size limits with LRU/confidence eviction strategies
8
+ - `BatchDecay`: periodic DB-backed confidence reduction with configurable rate and min threshold
4
9
 
5
10
  ## [0.1.2] - 2026-03-16
6
11
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lex-memory (0.1.2)
4
+ lex-memory (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -76,6 +76,7 @@ GEM
76
76
  sqlite3 (2.9.2)
77
77
  mini_portile2 (~> 2.8.0)
78
78
  sqlite3 (2.9.2-arm64-darwin)
79
+ sqlite3 (2.9.2-x86_64-linux-gnu)
79
80
  unicode-display_width (3.2.0)
80
81
  unicode-emoji (~> 4.1)
81
82
  unicode-emoji (4.2.0)
@@ -83,6 +84,7 @@ GEM
83
84
  PLATFORMS
84
85
  arm64-darwin-25
85
86
  ruby
87
+ x86_64-linux
86
88
 
87
89
  DEPENDENCIES
88
90
  lex-memory!
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Memory
6
+ module BatchDecay
7
+ DEFAULTS = {
8
+ rate: 0.999,
9
+ min_confidence: 0.01,
10
+ interval_hours: 1
11
+ }.freeze
12
+
13
+ class << self
14
+ def apply!(agent_id: nil, rate: DEFAULTS[:rate], min_confidence: DEFAULTS[:min_confidence])
15
+ return { updated: 0, evicted: 0 } unless db_ready?
16
+
17
+ conn = Legion::Data.connection
18
+ ds = conn[PersistentStore::TABLE]
19
+ ds = ds.where(agent_id: agent_id) if agent_id
20
+
21
+ updated = ds.where { confidence > min_confidence }
22
+ .update(confidence: Sequel[:confidence] * rate)
23
+
24
+ evicted = ds.where { confidence <= min_confidence }.delete
25
+
26
+ { updated: updated, evicted: evicted }
27
+ end
28
+
29
+ private
30
+
31
+ def db_ready?
32
+ defined?(Legion::Data) && Legion::Data.connection&.table_exists?(PersistentStore::TABLE)
33
+ rescue StandardError
34
+ false
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Memory
6
+ class PersistentStore
7
+ TABLE = :memory_traces
8
+
9
+ def initialize(agent_id:)
10
+ @agent_id = agent_id
11
+ end
12
+
13
+ def write(trace_type:, content:, associations: {}, confidence: 1.0)
14
+ return nil unless db_ready?
15
+
16
+ Legion::Data.connection[TABLE].insert(
17
+ agent_id: @agent_id,
18
+ trace_type: trace_type.to_s,
19
+ content: content.is_a?(String) ? content : Legion::JSON.dump(content),
20
+ associations: Legion::JSON.dump(associations),
21
+ confidence: confidence,
22
+ created_at: Time.now,
23
+ accessed_at: Time.now
24
+ )
25
+ end
26
+
27
+ def read(trace_type: nil, limit: 50, min_confidence: 0.0)
28
+ return [] unless db_ready?
29
+
30
+ ds = Legion::Data.connection[TABLE].where(agent_id: @agent_id)
31
+ ds = ds.where(trace_type: trace_type.to_s) if trace_type
32
+ ds = ds.where { confidence >= min_confidence }
33
+ ds.order(Sequel.desc(:accessed_at)).limit(limit).all
34
+ end
35
+
36
+ def touch(id)
37
+ return unless db_ready?
38
+
39
+ Legion::Data.connection[TABLE]
40
+ .where(id: id, agent_id: @agent_id)
41
+ .update(accessed_at: Time.now)
42
+ end
43
+
44
+ def count
45
+ return 0 unless db_ready?
46
+
47
+ Legion::Data.connection[TABLE].where(agent_id: @agent_id).count
48
+ end
49
+
50
+ def total_bytes
51
+ return 0 unless db_ready?
52
+
53
+ Legion::Data.connection[TABLE]
54
+ .where(agent_id: @agent_id)
55
+ .sum(Sequel.function(:length, :content)) || 0
56
+ end
57
+
58
+ def delete_lowest_confidence(count: 1)
59
+ return 0 unless db_ready?
60
+
61
+ ids = Legion::Data.connection[TABLE]
62
+ .where(agent_id: @agent_id)
63
+ .order(:confidence)
64
+ .limit(count)
65
+ .select(:id)
66
+ Legion::Data.connection[TABLE].where(id: ids).delete
67
+ end
68
+
69
+ def delete_least_recently_used(count: 1)
70
+ return 0 unless db_ready?
71
+
72
+ ids = Legion::Data.connection[TABLE]
73
+ .where(agent_id: @agent_id)
74
+ .order(:accessed_at)
75
+ .limit(count)
76
+ .select(:id)
77
+ Legion::Data.connection[TABLE].where(id: ids).delete
78
+ end
79
+
80
+ private
81
+
82
+ def db_ready?
83
+ defined?(Legion::Data) && Legion::Data.connection&.table_exists?(TABLE)
84
+ rescue StandardError
85
+ false
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Memory
6
+ class Quota
7
+ DEFAULTS = {
8
+ max_traces: 10_000,
9
+ max_bytes: 52_428_800, # 50MB
10
+ eviction: :lru
11
+ }.freeze
12
+
13
+ attr_reader :max_traces, :max_bytes, :eviction
14
+
15
+ def initialize(**opts)
16
+ config = DEFAULTS.merge(opts)
17
+ @max_traces = config[:max_traces]
18
+ @max_bytes = config[:max_bytes]
19
+ @eviction = config[:eviction].to_sym
20
+ end
21
+
22
+ def enforce!(store)
23
+ evict_count = store.count - max_traces
24
+ evict!(store, evict_count) if evict_count.positive?
25
+
26
+ overage = store.total_bytes - max_bytes
27
+ evict!(store, estimate_eviction_count(overage)) if overage.positive?
28
+ end
29
+
30
+ def within_limits?(store)
31
+ store.count <= max_traces && store.total_bytes <= max_bytes
32
+ end
33
+
34
+ private
35
+
36
+ def evict!(store, count)
37
+ return if count <= 0
38
+
39
+ case eviction
40
+ when :lru then store.delete_least_recently_used(count: count)
41
+ when :lowest_confidence then store.delete_lowest_confidence(count: count)
42
+ end
43
+ end
44
+
45
+ def estimate_eviction_count(overage_bytes)
46
+ [(overage_bytes / 1024.0 * 10).ceil, 1].max
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Memory
6
- VERSION = '0.1.2'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-memory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -30,6 +30,7 @@ files:
30
30
  - lib/legion/extensions/memory.rb
31
31
  - lib/legion/extensions/memory/actors/decay.rb
32
32
  - lib/legion/extensions/memory/actors/tier_migration.rb
33
+ - lib/legion/extensions/memory/batch_decay.rb
33
34
  - lib/legion/extensions/memory/client.rb
34
35
  - lib/legion/extensions/memory/helpers/cache_store.rb
35
36
  - lib/legion/extensions/memory/helpers/decay.rb
@@ -38,6 +39,8 @@ files:
38
39
  - lib/legion/extensions/memory/helpers/trace.rb
39
40
  - lib/legion/extensions/memory/local_migrations/20260316000001_create_memory_traces.rb
40
41
  - lib/legion/extensions/memory/local_migrations/20260316000002_create_memory_associations.rb
42
+ - lib/legion/extensions/memory/persistent_store.rb
43
+ - lib/legion/extensions/memory/quota.rb
41
44
  - lib/legion/extensions/memory/runners/consolidation.rb
42
45
  - lib/legion/extensions/memory/runners/traces.rb
43
46
  - lib/legion/extensions/memory/version.rb