lex-agentic-self 0.1.8 → 0.1.9
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/legion/extensions/agentic/self/personality/helpers/constants.rb +14 -0
- data/lib/legion/extensions/agentic/self/personality/helpers/personality_store.rb +38 -0
- data/lib/legion/extensions/agentic/self/personality/helpers/trait_model.rb +23 -0
- data/lib/legion/extensions/agentic/self/version.rb +1 -1
- data/spec/legion/extensions/agentic/self/personality/helpers/partner_signals_spec.rb +106 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 478de6acedf6c72ba3a5c715bc57f3124505486720b473b2db536d4abe48c58c
|
|
4
|
+
data.tar.gz: 8846a168b7d882d7e981a3d87eb87565e25b10ac24530221748382fdda1128cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 20df44e864e415b127e1f26a0d28bb0ed19c6589b53a40afbace9587c1166be962b6b8305e74c7ad4d4ea6b41eb9091f90328cbc3e23c3ab44ab9172cced706f
|
|
7
|
+
data.tar.gz: c768c0cc1794a6502e37d2c6524feaec104c8d47116e654f7d5dd19330768130212516cc074011b97b4e8e97f21c33931242e4cebf9ce0fba92064919bf7396d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.9] - 2026-03-31
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- add `PARTNER_SIGNAL_MAP` and `PARTNER_SIGNAL_THRESHOLD` constants to Personality::Helpers::Constants for partner-specific OCEAN nudges (weight 0.2 per signal)
|
|
7
|
+
- add `TraitModel#apply_partner_signals` to nudge extraversion, agreeableness, openness, and conscientiousness from partner engagement patterns; signals below threshold (0.3) are ignored
|
|
8
|
+
- wire partner signal extraction into `PersonalityStore#update` via `tick_results[:social]` reputation data (engagement frequency, direct address ratio, content diversity, consistency)
|
|
9
|
+
- add 16 specs covering PARTNER_SIGNAL_MAP entries, threshold gating, multi-signal application, and no observation_count side-effect
|
|
10
|
+
|
|
3
11
|
## [0.1.8] - 2026-03-30
|
|
4
12
|
|
|
5
13
|
### Fixed
|
|
@@ -70,6 +70,20 @@ module Legion
|
|
|
70
70
|
mood_stability: [:neuroticism, :negative, 0.3]
|
|
71
71
|
}.freeze
|
|
72
72
|
|
|
73
|
+
# Partner-specific signal map: partner interaction patterns that slowly nudge OCEAN traits.
|
|
74
|
+
# Lower weight (0.2) than general signals — personality should drift very slowly from
|
|
75
|
+
# partner engagement alone.
|
|
76
|
+
# Each entry: [trait, direction, weight]
|
|
77
|
+
PARTNER_SIGNAL_MAP = {
|
|
78
|
+
partner_engagement_frequency: [:extraversion, :positive, 0.2],
|
|
79
|
+
partner_direct_address_ratio: [:agreeableness, :positive, 0.2],
|
|
80
|
+
partner_content_diversity: [:openness, :positive, 0.2],
|
|
81
|
+
partner_consistency: [:conscientiousness, :positive, 0.2]
|
|
82
|
+
}.freeze
|
|
83
|
+
|
|
84
|
+
# Minimum signal value required to apply a partner nudge (0.0–1.0)
|
|
85
|
+
PARTNER_SIGNAL_THRESHOLD = 0.3
|
|
86
|
+
|
|
73
87
|
# Threshold for "high" trait descriptor
|
|
74
88
|
HIGH_THRESHOLD = 0.65
|
|
75
89
|
|
|
@@ -16,6 +16,8 @@ module Legion
|
|
|
16
16
|
def update(tick_results)
|
|
17
17
|
signals = extract_signals(tick_results)
|
|
18
18
|
@model.update(signals)
|
|
19
|
+
partner_signals = extract_partner_signals(tick_results)
|
|
20
|
+
@model.apply_partner_signals(partner_signals) unless partner_signals.empty?
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def full_description
|
|
@@ -41,6 +43,42 @@ module Legion
|
|
|
41
43
|
|
|
42
44
|
private
|
|
43
45
|
|
|
46
|
+
def extract_partner_signals(tick_results)
|
|
47
|
+
counts = partner_records(tick_results)
|
|
48
|
+
return {} if counts.empty?
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
partner_engagement_frequency: partner_engagement_frequency(counts),
|
|
52
|
+
partner_direct_address_ratio: avg_partner_field(counts, :direct_address_ratio),
|
|
53
|
+
partner_content_diversity: avg_partner_diversity(counts),
|
|
54
|
+
partner_consistency: avg_partner_field(counts, :consistency)
|
|
55
|
+
}.compact
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def partner_records(tick_results)
|
|
59
|
+
social = tick_results[:social] || tick_results[:social_cognition] || {}
|
|
60
|
+
return [] unless social.is_a?(Hash)
|
|
61
|
+
|
|
62
|
+
reputation = social[:reputation_updates] || social[:partners] || {}
|
|
63
|
+
return [] unless reputation.is_a?(Hash) && reputation.any?
|
|
64
|
+
|
|
65
|
+
reputation.values.grep(Hash)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def partner_engagement_frequency(counts)
|
|
69
|
+
(counts.count { |p| p[:message_count].to_i.positive? } / counts.size.to_f).clamp(0.0, 1.0)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def avg_partner_field(counts, key)
|
|
73
|
+
vals = counts.filter_map { |p| p[key] }.grep(Numeric)
|
|
74
|
+
vals.any? ? (vals.sum / vals.size.to_f).clamp(0.0, 1.0) : nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def avg_partner_diversity(counts)
|
|
78
|
+
vals = counts.filter_map { |p| p[:topic_diversity] || p[:content_diversity] }.grep(Numeric)
|
|
79
|
+
vals.any? ? (vals.sum / vals.size.to_f).clamp(0.0, 1.0) : nil
|
|
80
|
+
end
|
|
81
|
+
|
|
44
82
|
def extract_signals(tick_results)
|
|
45
83
|
signals = {}
|
|
46
84
|
|
|
@@ -30,6 +30,14 @@ module Legion
|
|
|
30
30
|
@traits[name.to_sym]
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def apply_partner_signals(signals)
|
|
34
|
+
observations = extract_partner_observations(signals)
|
|
35
|
+
return if observations.empty?
|
|
36
|
+
|
|
37
|
+
apply_observations(observations)
|
|
38
|
+
record_snapshot
|
|
39
|
+
end
|
|
40
|
+
|
|
33
41
|
def formed?
|
|
34
42
|
@observation_count >= Constants::FORMATION_THRESHOLD
|
|
35
43
|
end
|
|
@@ -105,6 +113,21 @@ module Legion
|
|
|
105
113
|
|
|
106
114
|
private
|
|
107
115
|
|
|
116
|
+
def extract_partner_observations(signals)
|
|
117
|
+
observations = Hash.new { |h, k| h[k] = [] }
|
|
118
|
+
|
|
119
|
+
Constants::PARTNER_SIGNAL_MAP.each do |signal_key, (trait, direction, weight)|
|
|
120
|
+
value = signals[signal_key]
|
|
121
|
+
next unless value.is_a?(Numeric)
|
|
122
|
+
next if value <= Constants::PARTNER_SIGNAL_THRESHOLD
|
|
123
|
+
|
|
124
|
+
effective = direction == :positive ? value : 1.0 - value
|
|
125
|
+
observations[trait] << { value: effective, weight: weight }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
observations
|
|
129
|
+
end
|
|
130
|
+
|
|
108
131
|
def extract_observations(signals)
|
|
109
132
|
observations = Hash.new { |h, k| h[k] = [] }
|
|
110
133
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Self::Personality::Helpers::TraitModel do
|
|
4
|
+
subject(:model) { described_class.new }
|
|
5
|
+
|
|
6
|
+
let(:constants) { Legion::Extensions::Agentic::Self::Personality::Helpers::Constants }
|
|
7
|
+
|
|
8
|
+
describe 'PARTNER_SIGNAL_MAP constant' do
|
|
9
|
+
it 'defines partner_engagement_frequency nudging extraversion positively' do
|
|
10
|
+
entry = constants::PARTNER_SIGNAL_MAP[:partner_engagement_frequency]
|
|
11
|
+
expect(entry).to eq([:extraversion, :positive, 0.2])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'defines partner_direct_address_ratio nudging agreeableness positively' do
|
|
15
|
+
entry = constants::PARTNER_SIGNAL_MAP[:partner_direct_address_ratio]
|
|
16
|
+
expect(entry).to eq([:agreeableness, :positive, 0.2])
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'defines partner_content_diversity nudging openness positively' do
|
|
20
|
+
entry = constants::PARTNER_SIGNAL_MAP[:partner_content_diversity]
|
|
21
|
+
expect(entry).to eq([:openness, :positive, 0.2])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'defines partner_consistency nudging conscientiousness positively' do
|
|
25
|
+
entry = constants::PARTNER_SIGNAL_MAP[:partner_consistency]
|
|
26
|
+
expect(entry).to eq([:conscientiousness, :positive, 0.2])
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'has all entries with weights of 0.2' do
|
|
30
|
+
constants::PARTNER_SIGNAL_MAP.each_value do |_trait, _direction, weight|
|
|
31
|
+
expect(weight).to eq(0.2)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'references only valid OCEAN traits' do
|
|
36
|
+
constants::PARTNER_SIGNAL_MAP.each_value do |trait, _direction, _weight|
|
|
37
|
+
expect(constants::TRAITS).to include(trait)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#apply_partner_signals' do
|
|
43
|
+
it 'nudges extraversion upward when partner_engagement_frequency is high' do
|
|
44
|
+
baseline = model.trait(:extraversion)
|
|
45
|
+
model.apply_partner_signals(partner_engagement_frequency: 0.9)
|
|
46
|
+
expect(model.trait(:extraversion)).to be > baseline
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'nudges agreeableness upward when partner_direct_address_ratio is high' do
|
|
50
|
+
baseline = model.trait(:agreeableness)
|
|
51
|
+
model.apply_partner_signals(partner_direct_address_ratio: 0.8)
|
|
52
|
+
expect(model.trait(:agreeableness)).to be > baseline
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'nudges openness upward when partner_content_diversity is high' do
|
|
56
|
+
baseline = model.trait(:openness)
|
|
57
|
+
model.apply_partner_signals(partner_content_diversity: 0.8)
|
|
58
|
+
expect(model.trait(:openness)).to be > baseline
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'nudges conscientiousness upward when partner_consistency is high' do
|
|
62
|
+
baseline = model.trait(:conscientiousness)
|
|
63
|
+
model.apply_partner_signals(partner_consistency: 0.8)
|
|
64
|
+
expect(model.trait(:conscientiousness)).to be > baseline
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'ignores signals below the minimum threshold' do
|
|
68
|
+
baseline = model.trait(:extraversion)
|
|
69
|
+
model.apply_partner_signals(partner_engagement_frequency: 0.1)
|
|
70
|
+
expect(model.trait(:extraversion)).to eq(baseline)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'ignores signals exactly at the threshold boundary' do
|
|
74
|
+
baseline = model.trait(:extraversion)
|
|
75
|
+
model.apply_partner_signals(partner_engagement_frequency: 0.3)
|
|
76
|
+
expect(model.trait(:extraversion)).to eq(baseline)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'applies multiple signals in a single call' do
|
|
80
|
+
extraversion_before = model.trait(:extraversion)
|
|
81
|
+
agreeableness_before = model.trait(:agreeableness)
|
|
82
|
+
|
|
83
|
+
model.apply_partner_signals(
|
|
84
|
+
partner_engagement_frequency: 0.9,
|
|
85
|
+
partner_direct_address_ratio: 0.8
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
expect(model.trait(:extraversion)).to be > extraversion_before
|
|
89
|
+
expect(model.trait(:agreeableness)).to be > agreeableness_before
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'ignores unrecognized signal keys' do
|
|
93
|
+
expect { model.apply_partner_signals(unknown_signal: 0.9) }.not_to raise_error
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'does not change observation_count' do
|
|
97
|
+
model.apply_partner_signals(partner_engagement_frequency: 0.9)
|
|
98
|
+
expect(model.observation_count).to eq(0)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'records a history snapshot after applying signals' do
|
|
102
|
+
model.apply_partner_signals(partner_engagement_frequency: 0.9)
|
|
103
|
+
expect(model.history.size).to eq(1)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-agentic-self
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -406,6 +406,7 @@ files:
|
|
|
406
406
|
- spec/legion/extensions/agentic/self/narrative_self/runners/narrative_self_spec.rb
|
|
407
407
|
- spec/legion/extensions/agentic/self/personality/client_spec.rb
|
|
408
408
|
- spec/legion/extensions/agentic/self/personality/helpers/constants_spec.rb
|
|
409
|
+
- spec/legion/extensions/agentic/self/personality/helpers/partner_signals_spec.rb
|
|
409
410
|
- spec/legion/extensions/agentic/self/personality/helpers/personality_store_spec.rb
|
|
410
411
|
- spec/legion/extensions/agentic/self/personality/helpers/trait_model_spec.rb
|
|
411
412
|
- spec/legion/extensions/agentic/self/personality/runners/personality_spec.rb
|