lex-mesh 0.4.6 → 0.4.7

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: 5e748e565682b21ecca099dff05a5192840b124d01697a572dcb34e4fd8ddf4b
4
- data.tar.gz: 01ba8a7a0c658ef92be7bd39faa85e3d616e9b65ff8a05f8eb476816877a5e03
3
+ metadata.gz: cd84b8f23017907b298f8f567e7bfeeda0a0fdcc4a8105dcb8b0228e57042e4b
4
+ data.tar.gz: f207ee8b98551427165a196528377b6b57270ef1afeda079941a13918c4c907f
5
5
  SHA512:
6
- metadata.gz: 5c13da093e85c3524da32a7415600c8e6f46376fa3b9c1f86fc64115ec9b44f375a304e799edf2bb0fcd19647fa9fadbb5bc669332cfc65d8094a2ed51cf8da2
7
- data.tar.gz: f12094b18f644e91eca7fe9ac0cdd8d987ce41d910830d89bb149f9843368c76511f53a7e8aba0110d15918a0d7410053bf552bb0480101ab1227097bbe86011
6
+ metadata.gz: 8d374bd0d78453bc8a0b1f3cfcde49a781fd1d43baf948ad56bbe0319b537329a19e0f397e76efc9341822d9d5fa57d8f528a710c7669f46e9d3eb407bede0ee
7
+ data.tar.gz: 4eeea99fe27e30c68febc9b5456ffaf2f1ed0637476362985ce5e6ec58526e9e9d967436b965135296d2997fea7b1547ea556742e81f078360cf3fa9daa651e4
@@ -6,7 +6,7 @@ module Legion
6
6
  module Extensions
7
7
  module Mesh
8
8
  module Actor
9
- class Gossip < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/EveryActorRequiresTime
9
+ class Gossip < Legion::Extensions::Actors::Every
10
10
  def runner_class
11
11
  Legion::Extensions::Mesh::Runners::Mesh
12
12
  end
@@ -6,7 +6,7 @@ module Legion
6
6
  module Extensions
7
7
  module Mesh
8
8
  module Actor
9
- class Heartbeat < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/EveryActorRequiresTime
9
+ class Heartbeat < Legion::Extensions::Actors::Every
10
10
  def runner_class
11
11
  Legion::Extensions::Mesh::Runners::Mesh
12
12
  end
@@ -6,7 +6,7 @@ module Legion
6
6
  module Extensions
7
7
  module Mesh
8
8
  module Actor
9
- class PendingExpiry < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/EveryActorRequiresTime
9
+ class PendingExpiry < Legion::Extensions::Actors::Every
10
10
  def runner_class
11
11
  Legion::Extensions::Mesh::Runners::Preferences
12
12
  end
@@ -6,7 +6,7 @@ module Legion
6
6
  module Extensions
7
7
  module Mesh
8
8
  module Actor
9
- class SilenceWatchdog < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/EveryActorRequiresTime
9
+ class SilenceWatchdog < Legion::Extensions::Actors::Every
10
10
  def runner_class
11
11
  Legion::Extensions::Mesh::Runners::Mesh
12
12
  end
@@ -103,7 +103,34 @@ module Legion
103
103
  def clear_preferences(owner_id:, source: nil)
104
104
  return { cleared: false, reason: :memory_not_available } unless memory_available?
105
105
 
106
- { cleared: true, owner_id: owner_id, source: source }
106
+ runner = memory_runner
107
+ result = runner.retrieve_by_domain(domain_tag: "owner:#{owner_id}")
108
+ traces = result[:traces] || []
109
+ traces.each { |t| runner.delete_trace(trace_id: t[:trace_id]) }
110
+ { cleared: true, owner_id: owner_id, source: source, count: traces.size }
111
+ rescue StandardError => e
112
+ { cleared: false, reason: :error, message: e.message }
113
+ end
114
+
115
+ def erase_partner!(identity:)
116
+ key = identity.to_s
117
+ @observation_counts&.delete(key) # rubocop:disable ThreadSafety/ClassInstanceVariable
118
+ @observation_signals&.delete(key) # rubocop:disable ThreadSafety/ClassInstanceVariable
119
+ @inferred_preferences&.delete(key) # rubocop:disable ThreadSafety/ClassInstanceVariable
120
+ clear_mesh_cache(agent_id: key)
121
+
122
+ traces_deleted = 0
123
+ if memory_available?
124
+ runner = memory_runner
125
+ result = runner.retrieve_by_domain(domain_tag: "owner:#{key}")
126
+ traces = result[:traces] || []
127
+ traces.each { |t| runner.delete_trace(trace_id: t[:trace_id]) }
128
+ traces_deleted = traces.size
129
+ end
130
+
131
+ { erased: true, identity: key, traces_deleted: traces_deleted }
132
+ rescue StandardError => e
133
+ { erased: false, identity: key, reason: :error, message: e.message }
107
134
  end
108
135
 
109
136
  def preference_instructions(profile:)
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Mesh
6
- VERSION = '0.4.6'
6
+ VERSION = '0.4.7'
7
7
  end
8
8
  end
9
9
  end
@@ -12,12 +12,16 @@ unless defined?(Legion::Extensions::Agentic::Memory::Trace::Runners::Traces)
12
12
  module Runners
13
13
  module Traces
14
14
  def retrieve_by_domain(**)
15
- []
15
+ { count: 0, traces: [] }
16
16
  end
17
17
 
18
18
  def store_trace(**)
19
19
  { stored: true }
20
20
  end
21
+
22
+ def delete_trace(trace_id:, **)
23
+ { deleted: true, trace_id: trace_id }
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -107,6 +111,90 @@ RSpec.describe Legion::Extensions::Mesh::Helpers::PreferenceProfile do
107
111
  result = profile_mod.clear_preferences(owner_id: 'user1', source: 'explicit')
108
112
  expect(result[:cleared]).to be true
109
113
  end
114
+
115
+ it 'actually deletes traces via memory runner when memory is available' do
116
+ trace = { trace_id: 'abc-123', domain_tags: ['preference', 'owner:user1'], confidence: 0.9 }
117
+ runner_double = double('memory_runner')
118
+ allow(profile_mod).to receive(:memory_available?).and_return(true)
119
+ allow(profile_mod).to receive(:memory_runner).and_return(runner_double)
120
+ allow(runner_double).to receive(:retrieve_by_domain).and_return({ traces: [trace] })
121
+ allow(runner_double).to receive(:delete_trace).and_return({ deleted: true })
122
+
123
+ result = profile_mod.clear_preferences(owner_id: 'user1')
124
+
125
+ expect(runner_double).to have_received(:retrieve_by_domain).with(hash_including(domain_tag: 'owner:user1'))
126
+ expect(runner_double).to have_received(:delete_trace).with(hash_including(trace_id: 'abc-123'))
127
+ expect(result[:cleared]).to be true
128
+ expect(result[:count]).to eq(1)
129
+ end
130
+
131
+ it 'returns not_available when memory is unavailable' do
132
+ allow(profile_mod).to receive(:memory_available?).and_return(false)
133
+ result = profile_mod.clear_preferences(owner_id: 'user1')
134
+ expect(result[:cleared]).to be false
135
+ expect(result[:reason]).to eq(:memory_not_available)
136
+ end
137
+ end
138
+
139
+ describe '.erase_partner!' do
140
+ before do
141
+ described_class.clear_observations
142
+ described_class.clear_mesh_cache
143
+ end
144
+
145
+ it 'removes observation counts for the identity' do
146
+ 5.times { described_class.update_from_observation(owner_id: 'partner-x', signals: { channel: :cli, direct_address: false }) }
147
+ described_class.erase_partner!(identity: 'partner-x')
148
+ expect(described_class.observation_counts['partner-x']).to be_nil
149
+ end
150
+
151
+ it 'removes inferred preferences for the identity' do
152
+ 20.times { described_class.update_from_observation(owner_id: 'partner-x', signals: { channel: :cli, direct_address: false }) }
153
+ described_class.erase_partner!(identity: 'partner-x')
154
+ expect(described_class.inferred_preferences('partner-x')).to be_empty
155
+ end
156
+
157
+ it 'removes mesh cache entries for the identity' do
158
+ described_class.store_mesh_profile(
159
+ agent_id: 'partner-x',
160
+ profile: { verbosity: :concise },
161
+ source_agent_id: 'partner-x'
162
+ )
163
+ described_class.erase_partner!(identity: 'partner-x')
164
+ expect(described_class.cached_mesh_profile(agent_id: 'partner-x')).to be_nil
165
+ end
166
+
167
+ it 'deletes memory traces tagged with the identity' do
168
+ trace = { trace_id: 'xyz-789', domain_tags: ['preference', 'owner:partner-x'], confidence: 0.8 }
169
+ runner_double = double('memory_runner')
170
+ allow(described_class).to receive(:memory_available?).and_return(true)
171
+ allow(described_class).to receive(:memory_runner).and_return(runner_double)
172
+ allow(runner_double).to receive(:retrieve_by_domain).and_return({ traces: [trace] })
173
+ allow(runner_double).to receive(:delete_trace).and_return({ deleted: true })
174
+
175
+ described_class.erase_partner!(identity: 'partner-x')
176
+
177
+ expect(runner_double).to have_received(:delete_trace).with(hash_including(trace_id: 'xyz-789'))
178
+ end
179
+
180
+ it 'leaves data for other identities untouched' do
181
+ 3.times { described_class.update_from_observation(owner_id: 'partner-y', signals: { channel: :cli, direct_address: false }) }
182
+ described_class.store_mesh_profile(
183
+ agent_id: 'partner-y',
184
+ profile: { verbosity: :detailed },
185
+ source_agent_id: 'partner-y'
186
+ )
187
+ described_class.erase_partner!(identity: 'partner-x')
188
+ expect(described_class.observation_counts['partner-y']).to eq(3)
189
+ expect(described_class.cached_mesh_profile(agent_id: 'partner-y')).not_to be_nil
190
+ end
191
+
192
+ it 'returns a result hash with erased identity and counts' do
193
+ result = described_class.erase_partner!(identity: 'partner-x')
194
+ expect(result).to be_a(Hash)
195
+ expect(result[:erased]).to be true
196
+ expect(result[:identity]).to eq('partner-x')
197
+ end
110
198
  end
111
199
 
112
200
  describe '.store_mesh_profile' do
@@ -31,7 +31,7 @@ RSpec.describe Legion::Extensions::Mesh::Runners::Preferences do
31
31
  end)
32
32
  stub_const('Legion::Extensions::Mesh::Transport::Messages::PreferenceQuery',
33
33
  Class.new do
34
- def initialize(**_opts); end
34
+ def initialize(**opts); end
35
35
 
36
36
  def publish; end
37
37
  end)
data/spec/spec_helper.rb CHANGED
@@ -36,7 +36,7 @@ module Legion
36
36
  end
37
37
 
38
38
  Legion::Settings.loader.settings[:client] ||= {}
39
- Legion::Settings.loader.settings[:client][:name] = 'test-agent'
39
+ Legion::Settings.loader.settings[:client][:name] = 'test-agent' # rubocop:disable Legion/Llm/SettingsAccessPath
40
40
 
41
41
  require 'legion/extensions/mesh'
42
42
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-mesh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.6
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity