lex-mesh 0.4.7 → 0.4.8
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1de324c2997f1d71286302c373a002c92bde5a389cfc9baf9bdce04d373f4fc5
|
|
4
|
+
data.tar.gz: 365de50aed497f545fb7deb881c9c3b87156acf6f8e2a5d443393004868ae278
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 506f44f20bec8e35b4b5fc3eb389796e4664511fa0feea50dd962ead40b10cb977a4c0ebc518d4ab20d5cdeaed2b1c2374e3a4ef5a9011121b4cb614b6540ce3
|
|
7
|
+
data.tar.gz: 188f168003f79c0ed067cc75f98888fa2ecb0dee5244ad79d76eeeb5f5f538ddbd414614be318137806ce69b2d87894b1ec0e479f46ab7d2238700f0286a7989
|
|
@@ -90,7 +90,7 @@ module Legion
|
|
|
90
90
|
confidence = SOURCE_CONFIDENCE.fetch(source.to_s, 0.5)
|
|
91
91
|
memory_runner.store_trace(
|
|
92
92
|
type: :semantic,
|
|
93
|
-
content_payload: { domain: domain, value: value, source: source }
|
|
93
|
+
content_payload: pref_json_dump({ domain: domain, value: value, source: source }),
|
|
94
94
|
domain_tags: ['preference', "preference:#{domain}", "owner:#{owner_id}"],
|
|
95
95
|
origin: :direct_experience,
|
|
96
96
|
confidence: confidence
|
|
@@ -251,14 +251,31 @@ module Legion
|
|
|
251
251
|
payload = trace[:content_payload]
|
|
252
252
|
return nil unless payload.is_a?(String)
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
parsed = parse_preference_payload_json(payload)
|
|
255
|
+
parsed ||= parse_preference_payload_legacy(payload)
|
|
256
|
+
return nil unless parsed
|
|
257
|
+
|
|
258
|
+
{ domain: parsed[:domain], value: parsed[:value], source: parsed[:source], confidence: trace[:confidence] }
|
|
259
|
+
rescue StandardError => _e
|
|
260
|
+
nil
|
|
261
|
+
end
|
|
256
262
|
|
|
257
|
-
|
|
263
|
+
def parse_preference_payload_json(payload)
|
|
264
|
+
data = pref_json_load(payload)
|
|
265
|
+
return nil unless data.is_a?(Hash) && data[:domain] && data[:value] && data[:source]
|
|
266
|
+
|
|
267
|
+
data
|
|
258
268
|
rescue StandardError => _e
|
|
259
269
|
nil
|
|
260
270
|
end
|
|
261
271
|
|
|
272
|
+
def parse_preference_payload_legacy(payload)
|
|
273
|
+
match = payload.match(/domain.*?(\w+).*?value.*?(\w+).*?source.*?(\w+)/)
|
|
274
|
+
return nil unless match
|
|
275
|
+
|
|
276
|
+
{ domain: match[1], value: match[2], source: match[3] }
|
|
277
|
+
end
|
|
278
|
+
|
|
262
279
|
def compute_compatibility(profile)
|
|
263
280
|
return nil unless profile.is_a?(Hash) && profile[:personality]
|
|
264
281
|
return nil unless personality_available?
|
|
@@ -353,7 +370,15 @@ module Legion
|
|
|
353
370
|
unique_channels = signals.map { |s| s[:channel] }.uniq
|
|
354
371
|
return nil unless unique_channels.size >= 3
|
|
355
372
|
|
|
356
|
-
{ domain: 'format', value: '
|
|
373
|
+
{ domain: 'format', value: 'structured', source: 'observation', confidence: 0.55 }
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def pref_json_dump(data)
|
|
377
|
+
Legion::JSON.dump(data) # rubocop:disable Legion/HelperMigration/DirectJson
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def pref_json_load(payload)
|
|
381
|
+
Legion::JSON.load(payload) # rubocop:disable Legion/HelperMigration/DirectJson
|
|
357
382
|
end
|
|
358
383
|
end
|
|
359
384
|
end
|
|
@@ -104,6 +104,24 @@ RSpec.describe Legion::Extensions::Mesh::Helpers::PreferenceProfile do
|
|
|
104
104
|
expect(result[:stored]).to be false
|
|
105
105
|
expect(result[:reason]).to eq(:memory_not_available)
|
|
106
106
|
end
|
|
107
|
+
|
|
108
|
+
it 'serializes payload as JSON string' do
|
|
109
|
+
captured_payload = nil
|
|
110
|
+
runner_double = double('memory_runner')
|
|
111
|
+
allow(profile_mod).to receive(:memory_available?).and_return(true)
|
|
112
|
+
allow(profile_mod).to receive(:memory_runner).and_return(runner_double)
|
|
113
|
+
allow(runner_double).to receive(:store_trace) do |**args|
|
|
114
|
+
captured_payload = args[:content_payload]
|
|
115
|
+
{ stored: true }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
profile_mod.store_preference(owner_id: 'u1', domain: 'verbosity', value: 'concise', source: 'explicit')
|
|
119
|
+
|
|
120
|
+
parsed = Legion::JSON.load(captured_payload)
|
|
121
|
+
expect(parsed[:domain]).to eq('verbosity')
|
|
122
|
+
expect(parsed[:value]).to eq('concise')
|
|
123
|
+
expect(parsed[:source]).to eq('explicit')
|
|
124
|
+
end
|
|
107
125
|
end
|
|
108
126
|
|
|
109
127
|
describe '.clear_preferences' do
|
|
@@ -136,6 +154,38 @@ RSpec.describe Legion::Extensions::Mesh::Helpers::PreferenceProfile do
|
|
|
136
154
|
end
|
|
137
155
|
end
|
|
138
156
|
|
|
157
|
+
describe '.parse_preference_trace' do
|
|
158
|
+
it 'parses JSON-encoded payload and returns symbol-keyed hash' do
|
|
159
|
+
payload = Legion::JSON.dump({ domain: 'verbosity', value: 'concise', source: 'explicit' })
|
|
160
|
+
trace = { content_payload: payload, confidence: 0.9 }
|
|
161
|
+
result = profile_mod.parse_preference_trace(trace)
|
|
162
|
+
expect(result[:domain]).to eq('verbosity')
|
|
163
|
+
expect(result[:value]).to eq('concise')
|
|
164
|
+
expect(result[:source]).to eq('explicit')
|
|
165
|
+
expect(result[:confidence]).to eq(0.9)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'falls back to legacy regex for old .to_s hash format' do
|
|
169
|
+
legacy_payload = '{:domain=>"verbosity", :value=>"concise", :source=>"explicit"}'
|
|
170
|
+
trace = { content_payload: legacy_payload, confidence: 0.7 }
|
|
171
|
+
result = profile_mod.parse_preference_trace(trace)
|
|
172
|
+
expect(result[:domain]).to eq('verbosity')
|
|
173
|
+
expect(result[:value]).to eq('concise')
|
|
174
|
+
expect(result[:source]).to eq('explicit')
|
|
175
|
+
expect(result[:confidence]).to eq(0.7)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'returns nil for a non-string payload' do
|
|
179
|
+
trace = { content_payload: nil, confidence: 0.5 }
|
|
180
|
+
expect(profile_mod.parse_preference_trace(trace)).to be_nil
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'returns nil for a payload that cannot be parsed by either method' do
|
|
184
|
+
trace = { content_payload: 'garbage data without structure', confidence: 0.5 }
|
|
185
|
+
expect(profile_mod.parse_preference_trace(trace)).to be_nil
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
139
189
|
describe '.erase_partner!' do
|
|
140
190
|
before do
|
|
141
191
|
described_class.clear_observations
|
|
@@ -321,7 +371,7 @@ RSpec.describe Legion::Extensions::Mesh::Helpers::PreferenceProfile do
|
|
|
321
371
|
expect(tone[:source]).to eq('observation')
|
|
322
372
|
end
|
|
323
373
|
|
|
324
|
-
it 'derives :
|
|
374
|
+
it 'derives :structured format for mixed channel usage after threshold' do
|
|
325
375
|
channels = %i[cli api chat rest]
|
|
326
376
|
20.times.with_index do |i, _|
|
|
327
377
|
ch = channels[i % channels.length]
|
|
@@ -333,10 +383,27 @@ RSpec.describe Legion::Extensions::Mesh::Helpers::PreferenceProfile do
|
|
|
333
383
|
inferred = described_class.inferred_preferences('user-mix')
|
|
334
384
|
format = inferred.find { |p| p[:domain] == 'format' }
|
|
335
385
|
expect(format).not_to be_nil
|
|
336
|
-
expect(format[:value]).to eq('
|
|
386
|
+
expect(format[:value]).to eq('structured')
|
|
337
387
|
expect(format[:source]).to eq('observation')
|
|
338
388
|
end
|
|
339
389
|
|
|
390
|
+
it 'derive_format never returns a value outside VALID_VALUES[:format]' do
|
|
391
|
+
channels = %i[cli api chat rest grpc websocket]
|
|
392
|
+
20.times.with_index do |i, _|
|
|
393
|
+
ch = channels[i % channels.length]
|
|
394
|
+
described_class.update_from_observation(
|
|
395
|
+
owner_id: 'user-valid',
|
|
396
|
+
signals: { content_type: :text, channel: ch, direct_address: false }
|
|
397
|
+
)
|
|
398
|
+
end
|
|
399
|
+
inferred = described_class.inferred_preferences('user-valid')
|
|
400
|
+
format_pref = inferred.find { |p| p[:domain] == 'format' }
|
|
401
|
+
if format_pref
|
|
402
|
+
valid_format_values = described_class::VALID_VALUES['format'].map(&:to_s)
|
|
403
|
+
expect(valid_format_values).to include(format_pref[:value])
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
340
407
|
it 'keeps separate observation counts per owner_id' do
|
|
341
408
|
3.times { described_class.update_from_observation(owner_id: 'user-a', signals: cli_signal) }
|
|
342
409
|
7.times { described_class.update_from_observation(owner_id: 'user-b', signals: cli_signal) }
|
data/spec/spec_helper.rb
CHANGED
|
@@ -35,8 +35,8 @@ module Legion
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
Legion::Settings
|
|
39
|
-
Legion::Settings
|
|
38
|
+
Legion::Settings[:client] ||= {}
|
|
39
|
+
Legion::Settings[:client][:name] = 'test-agent'
|
|
40
40
|
|
|
41
41
|
require 'legion/extensions/mesh'
|
|
42
42
|
|