lex-agentic-memory 0.1.33 → 0.1.35

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: 01630a8c5fd981fb85c69337d299f71dc215b79b9ce3dca7a9b0aef57545fde3
4
- data.tar.gz: 6eb6bd8f8e924aacb9a805561f9f39c0ac18b5d1f559faa7f58a1af3a6d3ad8a
3
+ metadata.gz: bb940d62021d4a86ed5de171d6b275c9287a9ca727efadd3c60c3a87ca0f921e
4
+ data.tar.gz: b02842d4a5939e436d7ae4f72cca295839061f5fa4cdbf9b47736f37e462e76e
5
5
  SHA512:
6
- metadata.gz: 69c12558b2cb6d7a883a9f0bd345ad0934273847b1a44f2dcaed02682a347d9a88dfddbbf6b2ab48d91a418c83f137eb585723dc3aecf19c0a2fb2e1454e7bd3
7
- data.tar.gz: 8200e4e37b770d4afa344153cd6dc95b9bd047dd55d34079b1bfc6c87c7f261e0049ee2c6f77e4f2b04bf7455745f88eb06160ad006eb81dda7ee0d2053093f9
6
+ metadata.gz: e28e286f59952562c8c00ad37cb06f84914f2b93af864cb95a1d9904c218dc72d28bb09a4df049c418f5a66df752a199171c0e553e684c234ae888ab73be24a8
7
+ data.tar.gz: 12febef87343cde5c4ca8f372c62a6f7d5b053a47ad5362710ee54224be60ceb899f7f0f32eeb65cc9474ebe5b47535731e2f6a3e83a89f3d315c6780774ea77
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.34] - 2026-05-08
4
+ ### Fixed
5
+ - Deferred GAIA heartbeat maintenance no longer initializes the shared trace store just to return a deferred summary, avoiding idle local trace table scans.
6
+ - `Store#parse_db_content` now returns bracket-prefixed raw trace/log text without JSON parse attempts or malformed JSON debug noise while still parsing real JSON objects and arrays.
7
+
8
+ ## [0.1.35] - 2026-05-15
9
+ ### Fixed
10
+ - Normalize trace affect fields before persisting through in-memory, cache, local SQLite, and Postgres stores so string-backed values do not crash or silently collapse to `0.0`.
11
+ - Preserve numeric `emotional_valence` across local trace persistence and normalize legacy structured payloads when they are reloaded.
12
+
3
13
  ## [0.1.33] - 2026-05-07
4
14
  ### Fixed
5
15
  - `PostgresStore#parse_json_or_raw` no longer attempts JSON parse on plain-text content — checks for `{`/`[` prefix before parsing, eliminating ERROR log spam during bulk reads with mixed content types
@@ -164,9 +164,9 @@ module Legion
164
164
  site.survey.merge(
165
165
  depth_progress: depth_progress(site),
166
166
  artifact_types: site.artifacts_found
167
- .each_with_object(Hash.new(0)) do |a, h|
168
- h[a.artifact_type] += 1
169
- end
167
+ .each_with_object(Hash.new(0)) do |a, h|
168
+ h[a.artifact_type] += 1
169
+ end
170
170
  )
171
171
  end
172
172
 
@@ -18,12 +18,14 @@ module Legion
18
18
  attr_reader :store
19
19
 
20
20
  def initialize(store: nil, **)
21
- @default_store = store || Legion::Extensions::Agentic::Memory::Trace.shared_store
21
+ @default_store = store if store
22
22
  end
23
23
 
24
24
  private
25
25
 
26
- attr_reader :default_store
26
+ def default_store
27
+ @default_store ||= Legion::Extensions::Agentic::Memory::Trace.shared_store
28
+ end
27
29
  end
28
30
  end
29
31
  end
@@ -38,11 +38,12 @@ module Legion
38
38
  end
39
39
 
40
40
  def store(trace)
41
+ normalized_trace = Helpers::Trace.normalize_trace_affect(trace)
41
42
  @mutex.synchronize do
42
- @traces[trace[:trace_id]] = trace
43
- @dirty_ids << trace[:trace_id]
43
+ @traces[normalized_trace[:trace_id]] = normalized_trace
44
+ @dirty_ids << normalized_trace[:trace_id]
44
45
  end
45
- trace[:trace_id]
46
+ normalized_trace[:trace_id]
46
47
  end
47
48
 
48
49
  def get(trace_id)
@@ -27,15 +27,16 @@ module Legion
27
27
  def store(trace)
28
28
  return nil unless db_ready?
29
29
 
30
- row = serialize_trace(trace)
30
+ normalized_trace = Helpers::Trace.normalize_trace_affect(trace)
31
+ row = serialize_trace(normalized_trace)
31
32
  ds = db[TRACES_TABLE]
32
33
  if db.adapter_scheme == :mysql2
33
34
  ds.insert_conflict(update: row.except(:trace_id)).insert(row)
34
35
  else
35
36
  ds.insert_conflict(target: :trace_id, update: row.except(:trace_id)).insert(row)
36
37
  end
37
- HotTier.cache_trace(trace, tenant_id: @tenant_id, agent_id: @agent_id) if HotTier.available?
38
- trace[:trace_id]
38
+ HotTier.cache_trace(normalized_trace, tenant_id: @tenant_id, agent_id: @agent_id) if HotTier.available?
39
+ normalized_trace[:trace_id]
39
40
  rescue StandardError => e
40
41
  log_warn("store failed: #{e.message}")
41
42
  nil
@@ -299,7 +300,7 @@ module Legion
299
300
  tags = trace[:domain_tags]
300
301
  assocs = trace[:associated_traces]
301
302
  conf = trace[:confidence]
302
- ev = trace[:emotional_valence]
303
+ ev = Helpers::Trace.normalize_emotional_valence(trace[:emotional_valence])
303
304
 
304
305
  {
305
306
  trace_id: trace[:trace_id],
@@ -314,8 +315,8 @@ module Legion
314
315
  strength: trace[:strength],
315
316
  peak_strength: trace[:peak_strength],
316
317
  base_decay_rate: trace[:base_decay_rate],
317
- emotional_valence: ev.is_a?(Numeric) ? ev.to_f : 0.0,
318
- emotional_intensity: trace[:emotional_intensity],
318
+ emotional_valence: ev,
319
+ emotional_intensity: Helpers::Trace.normalize_emotional_intensity(trace[:emotional_intensity]),
319
320
  origin: sanitize_pg_string(trace[:origin].to_s),
320
321
  source_agent_id: sanitize_pg_string(trace[:source_agent_id]),
321
322
  storage_tier: sanitize_pg_string(trace[:storage_tier].to_s),
@@ -29,7 +29,7 @@ module Legion
29
29
  end
30
30
 
31
31
  def store(trace)
32
- persisted_trace = trace.dup
32
+ persisted_trace = Helpers::Trace.normalize_trace_affect(trace)
33
33
  persisted_trace[:partition_id] ||= @partition_id
34
34
  @mutex.synchronize do
35
35
  @traces_dirty = true if @traces[persisted_trace[:trace_id]] != persisted_trace
@@ -120,7 +120,7 @@ module Legion
120
120
  snapshot = Array(traces).each_with_object({}) do |trace, memo|
121
121
  next unless trace.is_a?(Hash) && trace[:trace_id]
122
122
 
123
- restored = trace.dup
123
+ restored = Helpers::Trace.normalize_trace_affect(trace)
124
124
  restored[:partition_id] ||= @partition_id
125
125
  memo[restored[:trace_id]] = restored
126
126
  end
@@ -294,7 +294,7 @@ module Legion
294
294
  strength: trace[:strength],
295
295
  peak_strength: trace[:peak_strength],
296
296
  base_decay_rate: trace[:base_decay_rate],
297
- emotional_valence: trace[:emotional_valence].is_a?(Hash) ? ::JSON.generate(trace[:emotional_valence]) : nil,
297
+ emotional_valence: Helpers::Trace.normalize_emotional_valence(trace[:emotional_valence]).to_s,
298
298
  emotional_intensity: trace[:emotional_intensity],
299
299
  domain_tags: trace[:domain_tags].is_a?(Array) ? ::JSON.generate(trace[:domain_tags]) : nil,
300
300
  origin: trace[:origin].to_s,
@@ -325,7 +325,7 @@ module Legion
325
325
  strength: row[:strength],
326
326
  peak_strength: row[:peak_strength],
327
327
  base_decay_rate: row[:base_decay_rate],
328
- emotional_valence: parse_db_json(row[:emotional_valence], 'emotional_valence', symbolize: true) { 0.0 },
328
+ emotional_valence: deserialize_emotional_valence(row[:emotional_valence]),
329
329
  emotional_intensity: row[:emotional_intensity],
330
330
  domain_tags: parse_db_json(row[:domain_tags], 'domain_tags') { [] },
331
331
  origin: row[:origin]&.to_sym,
@@ -348,15 +348,28 @@ module Legion
348
348
  return raw unless raw.is_a?(String)
349
349
 
350
350
  stripped = raw.strip
351
- return raw unless stripped.start_with?('{', '[')
351
+ return raw unless parseable_content_json?(stripped)
352
352
 
353
353
  parsed = Legion::JSON.load(stripped)
354
354
  parsed.is_a?(Hash) || parsed.is_a?(Array) ? parsed : raw
355
- rescue StandardError => e
356
- log.debug "[trace_persistence] malformed JSON in content column, returning raw: #{e.message}"
355
+ rescue StandardError => _e
357
356
  raw
358
357
  end
359
358
 
359
+ def parseable_content_json?(value)
360
+ return true if value.start_with?('{')
361
+ return false unless value.start_with?('[')
362
+
363
+ first_array_value = value[1..]&.lstrip&.[](0)
364
+ %w[{ [ " ]].include?(first_array_value)
365
+ end
366
+
367
+ def deserialize_emotional_valence(raw)
368
+ return 0.0 if raw.nil? || raw.to_s.strip.empty?
369
+
370
+ Helpers::Trace.normalize_emotional_valence(raw)
371
+ end
372
+
360
373
  def parse_db_json(raw, field, symbolize: false, &default)
361
374
  return default&.call if raw.nil? || raw.to_s.strip.empty?
362
375
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
3
4
  require 'securerandom'
4
5
 
5
6
  module Legion
@@ -48,6 +49,7 @@ module Legion
48
49
  ASSOCIATION_BONUS = 0.15 # bonus for Hebbian-associated traces
49
50
  MAX_ASSOCIATIONS = 20 # max Hebbian links per trace
50
51
  COACTIVATION_THRESHOLD = 3 # co-activations before Hebbian link forms
52
+ VALENCE_SCALAR_KEYS = %i[valence emotional_valence sentiment polarity score].freeze
51
53
 
52
54
  module_function
53
55
 
@@ -59,6 +61,10 @@ module Legion
59
61
  raise ArgumentError, "invalid origin: #{origin}" unless ORIGINS.include?(origin)
60
62
 
61
63
  now = Time.now.utc
64
+ emotional_context = normalize_trace_affect(
65
+ emotional_valence: emotional_valence,
66
+ emotional_intensity: emotional_intensity
67
+ )
62
68
 
63
69
  {
64
70
  trace_id: SecureRandom.uuid,
@@ -68,8 +74,8 @@ module Legion
68
74
  strength: STARTING_STRENGTHS[type],
69
75
  peak_strength: STARTING_STRENGTHS[type],
70
76
  base_decay_rate: BASE_DECAY_RATES[type],
71
- emotional_valence: emotional_valence.clamp(-1.0, 1.0),
72
- emotional_intensity: emotional_intensity.clamp(0.0, 1.0),
77
+ emotional_valence: emotional_context[:emotional_valence],
78
+ emotional_intensity: emotional_context[:emotional_intensity],
73
79
  domain_tags: Array(domain_tags),
74
80
  origin: origin,
75
81
  source_agent_id: source_agent_id,
@@ -98,11 +104,89 @@ module Legion
98
104
  true
99
105
  end
100
106
 
107
+ def normalize_trace_affect(trace)
108
+ normalized = trace.dup
109
+ normalized[:emotional_valence] = normalize_emotional_valence(normalized[:emotional_valence])
110
+ normalized[:emotional_intensity] = normalize_emotional_intensity(normalized[:emotional_intensity])
111
+ normalized
112
+ end
113
+
114
+ def normalize_emotional_valence(value)
115
+ normalize_scalar(value, min: -1.0, max: 1.0, hash_keys: VALENCE_SCALAR_KEYS)
116
+ end
117
+
118
+ def normalize_emotional_intensity(value)
119
+ normalize_scalar(value, min: 0.0, max: 1.0)
120
+ end
121
+
101
122
  def default_partition_id
102
123
  Legion::Settings.dig(:agent, :id) || 'default'
103
124
  rescue StandardError => _e
104
125
  'default'
105
126
  end
127
+
128
+ def normalize_scalar(value, min:, max:, hash_keys: [])
129
+ case value
130
+ when Numeric
131
+ value.to_f.clamp(min, max)
132
+ when String
133
+ normalize_string_scalar(value, min: min, max: max, hash_keys: hash_keys)
134
+ when Hash
135
+ normalize_hash_scalar(value, min: min, max: max, hash_keys: hash_keys)
136
+ else
137
+ 0.0
138
+ end
139
+ end
140
+
141
+ def normalize_string_scalar(value, min:, max:, hash_keys:)
142
+ stripped = value.strip
143
+ return 0.0 if stripped.empty?
144
+
145
+ Float(stripped).clamp(min, max)
146
+ rescue ArgumentError, TypeError => e
147
+ Legion::Logging.debug("[memory][trace] normalize_string_scalar fallback: #{e.message}")
148
+ parsed = parse_structured_scalar(stripped)
149
+ return normalize_scalar(parsed, min: min, max: max, hash_keys: hash_keys) if parsed
150
+
151
+ 0.0
152
+ end
153
+
154
+ def normalize_hash_scalar(value, min:, max:, hash_keys:)
155
+ symbolized = symbolize_keys(value)
156
+ scalar_value = hash_keys.lazy.map { |key| symbolized[key] }.find { |candidate| scalar_candidate?(candidate) }
157
+ return normalize_scalar(scalar_value, min: min, max: max, hash_keys: hash_keys) if scalar_candidate?(scalar_value)
158
+
159
+ numeric_values = symbolized.values.select { |candidate| scalar_candidate?(candidate) }
160
+ return normalize_scalar(numeric_values.first, min: min, max: max, hash_keys: hash_keys) if numeric_values.one?
161
+
162
+ 0.0
163
+ end
164
+
165
+ def parse_structured_scalar(value)
166
+ return unless value.start_with?('{', '[')
167
+
168
+ ::JSON.parse(value)
169
+ rescue ::JSON::ParserError => e
170
+ Legion::Logging.debug("[memory][trace] parse_structured_scalar ignored: #{e.message}")
171
+ nil
172
+ end
173
+
174
+ def scalar_candidate?(value)
175
+ value.is_a?(Numeric) || value.is_a?(String)
176
+ end
177
+
178
+ def symbolize_keys(value)
179
+ case value
180
+ when Hash
181
+ value.each_with_object({}) do |(key, nested), memo|
182
+ memo[key.to_sym] = symbolize_keys(nested)
183
+ end
184
+ when Array
185
+ value.map { |nested| symbolize_keys(nested) }
186
+ else
187
+ value
188
+ end
189
+ end
106
190
  end
107
191
  end
108
192
  end
@@ -31,12 +31,12 @@ module Legion
31
31
  end
32
32
 
33
33
  def decay_cycle(store: nil, tick_count: 1, maintenance: true, **)
34
- store ||= default_store
35
34
  unless maintenance
36
- deferred = deferred_decay_summary(store)
35
+ deferred = deferred_decay_summary(store || cached_default_store)
37
36
  return { **deferred }
38
37
  end
39
38
 
39
+ store ||= default_store
40
40
  decayed = 0
41
41
  pruned = 0
42
42
  total = trace_count(store)
@@ -139,7 +139,7 @@ module Legion
139
139
 
140
140
  def deferred_decay_summary(store)
141
141
  summary = Legion::Extensions::Agentic::Memory::Trace.last_maintenance_summary || {}
142
- current_count = trace_count(store)
142
+ current_count = store ? trace_count(store) : 0
143
143
 
144
144
  {
145
145
  decayed: summary[:decayed] || 0,
@@ -173,6 +173,10 @@ module Legion
173
173
  @default_store ||= Legion::Extensions::Agentic::Memory::Trace.shared_store
174
174
  end
175
175
 
176
+ def cached_default_store
177
+ @default_store if instance_variable_defined?(:@default_store)
178
+ end
179
+
176
180
  include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
177
181
  end
178
182
  end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Memory
7
- VERSION = '0.1.33'
7
+ VERSION = '0.1.35'
8
8
  end
9
9
  end
10
10
  end
@@ -24,6 +24,14 @@ RSpec.describe Legion::Extensions::Agentic::Memory::Trace::Client do
24
24
  expect(client).to respond_to(:erase_by_agent)
25
25
  end
26
26
 
27
+ it 'does not initialize the shared trace store until a store-backed operation needs it' do
28
+ allow(Legion::Extensions::Agentic::Memory::Trace).to receive(:shared_store)
29
+
30
+ described_class.new
31
+
32
+ expect(Legion::Extensions::Agentic::Memory::Trace).not_to have_received(:shared_store)
33
+ end
34
+
27
35
  it 'uses provided store' do
28
36
  store = Legion::Extensions::Agentic::Memory::Trace::Helpers::Store.new
29
37
  client = described_class.new(store: store)
@@ -238,6 +238,20 @@ RSpec.describe Legion::Extensions::Agentic::Memory::Trace::Helpers::PostgresStor
238
238
  end
239
239
  end
240
240
 
241
+ describe 'emotional valence normalization' do
242
+ it 'normalizes string-backed affect fields before persisting' do
243
+ trace = trace_helper.new_trace(type: :episodic, content_payload: { event: 'partner ping' })
244
+ trace[:emotional_valence] = '0.7'
245
+ trace[:emotional_intensity] = '0.9'
246
+
247
+ store.store(trace)
248
+
249
+ row = db[:memory_traces].where(trace_id: trace[:trace_id]).first
250
+ expect(row[:emotional_valence]).to be_within(0.001).of(0.7)
251
+ expect(row[:emotional_intensity]).to be_within(0.001).of(0.9)
252
+ end
253
+ end
254
+
241
255
  # --- retrieve_by_type ---
242
256
 
243
257
  describe '#retrieve_by_type' do
@@ -128,6 +128,30 @@ RSpec.describe Legion::Extensions::Agentic::Memory::Trace::Helpers::Store do
128
128
  end
129
129
  end
130
130
 
131
+ describe '#parse_db_content' do
132
+ let(:parser) { described_class.allocate }
133
+
134
+ it 'returns bracket-prefixed raw log text without logging malformed JSON noise' do
135
+ expect(parser).not_to receive(:log)
136
+
137
+ result = parser.send(:parse_db_content, '[tool][file_read] opened file')
138
+
139
+ expect(result).to eq('[tool][file_read] opened file')
140
+ end
141
+
142
+ it 'still parses JSON object content' do
143
+ result = parser.send(:parse_db_content, '{"event":"meeting"}')
144
+
145
+ expect(result).to eq({ event: 'meeting' })
146
+ end
147
+
148
+ it 'still parses JSON array content when it looks like serialized payload data' do
149
+ result = parser.send(:parse_db_content, '[{"event":"meeting"}]')
150
+
151
+ expect(result).to eq([{ event: 'meeting' }])
152
+ end
153
+ end
154
+
131
155
  describe '#count' do
132
156
  it 'returns number of stored traces' do
133
157
  expect(store.count).to eq(0)
@@ -36,6 +36,30 @@ RSpec.describe Legion::Extensions::Agentic::Memory::Trace::Helpers::Trace do
36
36
  expect(trace[:emotional_intensity]).to eq(0.0)
37
37
  end
38
38
 
39
+ it 'normalizes string and structured emotional values safely' do
40
+ trace = described_class.new_trace(
41
+ type: :episodic,
42
+ content_payload: { event: 'partner ping' },
43
+ emotional_valence: '{:urgency=>0.6, :importance=>0.8}',
44
+ emotional_intensity: '0.75'
45
+ )
46
+
47
+ expect(trace[:emotional_valence]).to eq(0.0)
48
+ expect(trace[:emotional_intensity]).to eq(0.75)
49
+ end
50
+
51
+ it 'extracts scalar valence from hash payloads when an explicit valence key exists' do
52
+ trace = described_class.new_trace(
53
+ type: :semantic,
54
+ content_payload: { fact: 'test' },
55
+ emotional_valence: { valence: 0.4 },
56
+ emotional_intensity: '2.0'
57
+ )
58
+
59
+ expect(trace[:emotional_valence]).to eq(0.4)
60
+ expect(trace[:emotional_intensity]).to eq(1.0)
61
+ end
62
+
39
63
  it 'rejects invalid trace types' do
40
64
  expect do
41
65
  described_class.new_trace(type: :bogus, content_payload: {})
@@ -249,12 +249,12 @@ RSpec.describe 'lex-memory local SQLite persistence' do
249
249
  expect(fresh.get(episodic_trace[:trace_id])).not_to be_nil
250
250
  end
251
251
 
252
- it 'honors symbolize parsing for JSON hash fields' do
252
+ it 'restores numeric emotional_valence values from local persistence' do
253
253
  trace = trace_helper.new_trace(
254
254
  type: :semantic,
255
255
  content_payload: { fact: 'symbolized' },
256
256
  domain_tags: ['json'],
257
- emotional_valence: { joy: 0.8 }
257
+ emotional_valence: 0.8
258
258
  )
259
259
  store.store(trace)
260
260
  store.save_to_local
@@ -262,8 +262,25 @@ RSpec.describe 'lex-memory local SQLite persistence' do
262
262
  fresh = Legion::Extensions::Agentic::Memory::Trace::Helpers::Store.new
263
263
  restored = fresh.get(trace[:trace_id])
264
264
 
265
- expect(restored[:emotional_valence]).to include(joy: 0.8)
266
- expect(restored[:emotional_valence]).not_to have_key('joy')
265
+ expect(restored[:emotional_valence]).to be_within(0.001).of(0.8)
266
+ end
267
+
268
+ it 'normalizes legacy JSON emotional_valence payloads on load' do
269
+ trace = trace_helper.new_trace(
270
+ type: :semantic,
271
+ content_payload: { fact: 'legacy' },
272
+ domain_tags: ['json']
273
+ )
274
+ store.store(trace)
275
+ store.save_to_local
276
+
277
+ db = Legion::Data::Local.connection
278
+ db[:memory_traces].where(trace_id: trace[:trace_id]).update(emotional_valence: '{"valence":0.8}')
279
+
280
+ fresh = Legion::Extensions::Agentic::Memory::Trace::Helpers::Store.new
281
+ restored = fresh.get(trace[:trace_id])
282
+
283
+ expect(restored[:emotional_valence]).to be_within(0.001).of(0.8)
267
284
  end
268
285
 
269
286
  it 'restores associations from the database into a fresh store' do
@@ -53,6 +53,23 @@ RSpec.describe Legion::Extensions::Agentic::Memory::Trace::Runners::Consolidatio
53
53
  end
54
54
 
55
55
  describe '#decay_cycle' do
56
+ it 'does not initialize the shared store when Gaia defers heartbeat maintenance' do
57
+ runner = Object.new.extend(described_class)
58
+ allow(Legion::Extensions::Agentic::Memory::Trace).to receive(:shared_store)
59
+
60
+ result = runner.decay_cycle(maintenance: false)
61
+
62
+ expect(Legion::Extensions::Agentic::Memory::Trace).not_to have_received(:shared_store)
63
+ expect(result).to include(
64
+ decayed: 0,
65
+ pruned: 0,
66
+ total: 0,
67
+ remaining: 0,
68
+ deferred: true,
69
+ reason: :background_decay_actor
70
+ )
71
+ end
72
+
56
73
  it 'defers Gaia heartbeat decay work to the background actor when maintenance is false' do
57
74
  client.store_trace(type: :semantic, content_payload: {})
58
75
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-agentic-memory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.33
4
+ version: 0.1.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity