lex-agentic-affect 0.1.0 → 0.1.2

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: d03176e4d632c5182d79f6c122b06ee6492b7a330ea28f26de0bdf2b38464d3c
4
- data.tar.gz: 036f318f959c28fd2e4ab3d33b439ac81742b52b406702a56667ad2a78c35f3b
3
+ metadata.gz: 64e47fe3d5e4b6c59bb58ed12d8acf1c1888e1668e4fe164a69461911050afff
4
+ data.tar.gz: 5d95cdf190ff874aaa8c46e184e079d73849b76891ec0138ef54fd40ac912b75
5
5
  SHA512:
6
- metadata.gz: 923827c5b0fae5871187437b4e0ffc7672ff52214ff0261c857c240128c4d1bd5a6dbbbe14b50e3caf22db645cd76e71c7ff490dbb348fd8ab5ed55dac6b4230
7
- data.tar.gz: e27fe89064ed41221e4879b841830058d759158eda0e7f396cf7acd22252c6c60d5b739ebc7956e3691713c6aaf8f08de0d556a15eadb5eddc1b3340f9f211df
6
+ metadata.gz: 8ec5b239a2ed5f20ebfa28c0c5e9c2e19032b2a474aa1fe3d4583e1c34092fcbee3673df7433460b5fdf67f1b562c7f253f261219ada523a0f349eb58941cc70
7
+ data.tar.gz: df01ac0b9ea74775059fde392e081f0b97a793a95d76b0011930d428b78f667482c3a77a97cf7c276a3c1dd6684e45419fb66b33c6ff4c435c70c1d6a43461f5
data/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [0.1.1] - 2026-03-18
4
+
5
+ ### Fixed
6
+ - Validate `channel` against `VITAL_CHANNELS` in `Interoception::BodyBudget#report_vital` — rejects unknown channel keys
7
+ - Validate `coping_type` against `COPING_TYPES` in `Appraisal::AppraisalEngine#add_coping_strategy` — rejects invalid coping types
4
8
 
5
9
  ## [0.1.0] - 2026-03-18
6
10
 
data/README.md CHANGED
@@ -1,13 +1,56 @@
1
1
  # lex-agentic-affect
2
2
 
3
- LEX agentic affect domain: emotions, valence, mood regulation
3
+ Domain consolidation gem for emotion, affect, and motivational processing. Bundles 17 source extensions into one loadable unit under `Legion::Extensions::Agentic::Affect`.
4
4
 
5
- ## Sub-modules
5
+ ## Overview
6
6
 
7
- *(populated as extensions are consolidated)*
7
+ **Gem**: `lex-agentic-affect`
8
+ **Version**: 0.1.1
9
+ **Namespace**: `Legion::Extensions::Agentic::Affect`
10
+
11
+ ## Sub-Modules
12
+
13
+ | Sub-Module | Source Gem | Purpose |
14
+ |---|---|---|
15
+ | `Affect::Emotion` | `lex-emotion` | Four-dimensional emotional valence/arousal, EMA momentum, gut instinct |
16
+ | `Affect::Mood` | `lex-mood` | Background mood baseline distinct from discrete emotions |
17
+ | `Affect::Appraisal` | `lex-appraisal` | Lazarus appraisal theory — primary/secondary appraisal of events |
18
+ | `Affect::CognitiveEmpathy` | `lex-cognitive-empathy` | Cognitive empathy processing |
19
+ | `Affect::Empathy` | `lex-empathy` | Affective and cognitive empathy |
20
+ | `Affect::Reappraisal` | `lex-cognitive-reappraisal` | Gross process model — six emotion regulation strategies |
21
+ | `Affect::Regulation` | `lex-emotional-regulation` | Regulation strategy selection and effectiveness tracking |
22
+ | `Affect::Defusion` | `lex-cognitive-defusion` | ACT-style cognitive defusion from difficult thoughts |
23
+ | `Affect::Contagion` | `lex-cognitive-contagion` | Emotional contagion spread across agent interactions |
24
+ | `Affect::SomaticMarker` | `lex-somatic-marker` | Damasio somatic marker hypothesis — gut-feeling tagging |
25
+ | `Affect::Interoception` | `lex-interoception` | Internal body state signals (fatigue, tension, arousal) |
26
+ | `Affect::Flow` | `lex-flow` | Csikszentmihalyi flow state |
27
+ | `Affect::Fatigue` | `lex-fatigue` | Mental fatigue accumulation and recovery modeling |
28
+ | `Affect::Motivation` | `lex-motivation` | Drive states — homeostatic and intrinsic motivation |
29
+ | `Affect::Reward` | `lex-reward` | Reward signal computation and prediction error |
30
+ | `Affect::Resilience` | `lex-resilience` | Recovery capacity and stress inoculation |
31
+ | `Affect::Resonance` | `lex-cognitive-resonance` | Affective resonance patterns |
32
+
33
+ ## Actors
34
+
35
+ - `Affect::Emotion::Actors::MomentumDecay` — runs every 60s, decays emotional momentum via `decay_momentum`
36
+ - `Affect::Interoception::Actors::Decay` — interval actor, decays interoceptive body state signals
37
+ - `Affect::Reappraisal::Actors::AutoRegulate` — runs every 300s, processes pending emotional events
38
+ - `Affect::SomaticMarker::Actors::Decay` — interval actor, decays somatic marker strength
8
39
 
9
40
  ## Installation
10
41
 
11
42
  ```ruby
12
43
  gem 'lex-agentic-affect'
13
44
  ```
45
+
46
+ ## Development
47
+
48
+ ```bash
49
+ bundle install
50
+ bundle exec rspec # 1523 examples, 0 failures
51
+ bundle exec rubocop # 0 offenses
52
+ ```
53
+
54
+ ## License
55
+
56
+ MIT
@@ -43,6 +43,7 @@ module Legion
43
43
  end
44
44
 
45
45
  def add_coping_strategy(name:, coping_type:, effectiveness:)
46
+ return false unless COPING_TYPES.include?(coping_type)
46
47
  return false if @coping_strategies.size >= MAX_COPING_STRATEGIES
47
48
 
48
49
  @coping_strategies[name] = {
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Affect
7
7
  module Appraisal
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -72,6 +72,18 @@ module Legion
72
72
  { arousal: arousal }
73
73
  end
74
74
 
75
+ def raise_urgency_for_knowledge_vulnerability(domains_at_risk:, severity: :warning, urgency_boost: 0.3, **)
76
+ boost = severity.to_sym == :critical ? [urgency_boost * 1.5, 1.0].min : urgency_boost.to_f
77
+ signal = { urgency_hint: boost, domain_weight: 0.6, impact_scope: 0.5,
78
+ outcome_severity: boost, novelty_score: 0.3 }
79
+ result = evaluate_valence(signal: signal, source_type: :mesh_priority)
80
+
81
+ Legion::Logging.info "[emotion] knowledge_vulnerability urgency raised: domains=#{Array(domains_at_risk).join(',')} " \
82
+ "severity=#{severity} boost=#{boost.round(2)} urgency=#{result[:valence][:urgency].round(2)}"
83
+
84
+ result.merge(event: :knowledge_vulnerability, domains_at_risk: Array(domains_at_risk), urgency_boost: boost)
85
+ end
86
+
75
87
  private
76
88
 
77
89
  def emotion_baseline
@@ -22,6 +22,8 @@ module Legion
22
22
 
23
23
  def report_vital(channel:, value:)
24
24
  channel = channel.to_sym
25
+ return nil unless VITAL_CHANNELS.include?(channel)
26
+
25
27
  normalized = value.clamp(0.0, 1.0)
26
28
  @baselines[channel] ||= DEFAULT_BASELINE
27
29
  @vitals[channel] = if @vitals.key?(channel)
@@ -12,6 +12,8 @@ module Legion
12
12
 
13
13
  def report_vital(channel:, value:, **)
14
14
  smoothed = body_budget.report_vital(channel: channel, value: value.to_f)
15
+ return { success: false, error: :invalid_channel, valid_channels: Helpers::Constants::VITAL_CHANNELS } unless smoothed
16
+
15
17
  deviation = body_budget.deviation_for(channel)
16
18
  Legion::Logging.debug "[interoception] vital: channel=#{channel} raw=#{value} " \
17
19
  "smoothed=#{smoothed.round(3)} deviation=#{deviation.round(3)}"
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Affect
7
7
  module Interoception
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Affect
7
- VERSION = '0.1.0'
7
+ VERSION = '0.1.2'
8
8
  end
9
9
  end
10
10
  end
@@ -73,6 +73,19 @@ RSpec.describe Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Appraisa
73
73
  # Strategy stored (engine is internal, test via evaluate_coping behavior)
74
74
  expect(data).to be_a(Hash)
75
75
  end
76
+
77
+ it 'rejects invalid coping_type' do
78
+ result = engine.add_coping_strategy(name: 'wishful', coping_type: :wishful_thinking, effectiveness: 0.5)
79
+ expect(result).to be(false)
80
+ end
81
+
82
+ it 'accepts all valid COPING_TYPES' do
83
+ constants = Legion::Extensions::Agentic::Affect::Appraisal::Helpers::Constants
84
+ constants::COPING_TYPES.each_with_index do |ct, i|
85
+ result = engine.add_coping_strategy(name: "strategy_#{i}", coping_type: ct, effectiveness: 0.5)
86
+ expect(result).to be(true)
87
+ end
88
+ end
76
89
  end
77
90
 
78
91
  describe '#evaluate_coping' do
@@ -64,4 +64,39 @@ RSpec.describe Legion::Extensions::Agentic::Affect::Emotion::Runners::Valence do
64
64
  expect(result[:arousal]).to be > 0.0
65
65
  end
66
66
  end
67
+
68
+ describe '#raise_urgency_for_knowledge_vulnerability' do
69
+ it 'returns a valence result with event tag' do
70
+ result = client.raise_urgency_for_knowledge_vulnerability(domains_at_risk: %w[pki vault])
71
+ expect(result[:event]).to eq(:knowledge_vulnerability)
72
+ expect(result[:domains_at_risk]).to eq(%w[pki vault])
73
+ end
74
+
75
+ it 'includes urgency_boost in the result' do
76
+ result = client.raise_urgency_for_knowledge_vulnerability(domains_at_risk: ['pki'])
77
+ expect(result[:urgency_boost]).to be > 0.0
78
+ end
79
+
80
+ it 'raises urgency higher for critical severity than warning' do
81
+ warning = client.raise_urgency_for_knowledge_vulnerability(
82
+ domains_at_risk: ['pki'], severity: :warning
83
+ )
84
+ critical = client.raise_urgency_for_knowledge_vulnerability(
85
+ domains_at_risk: ['pki'], severity: :critical
86
+ )
87
+ expect(critical[:urgency_boost]).to be > warning[:urgency_boost]
88
+ end
89
+
90
+ it 'returns a valence hash with all four dimensions' do
91
+ result = client.raise_urgency_for_knowledge_vulnerability(domains_at_risk: ['dns'])
92
+ expect(result[:valence].keys).to contain_exactly(:urgency, :importance, :novelty, :familiarity)
93
+ end
94
+
95
+ it 'accepts a custom urgency_boost' do
96
+ result = client.raise_urgency_for_knowledge_vulnerability(
97
+ domains_at_risk: ['ssh'], urgency_boost: 0.5
98
+ )
99
+ expect(result[:urgency_boost]).to be_within(0.01).of(0.5)
100
+ end
101
+ end
67
102
  end
@@ -26,6 +26,18 @@ RSpec.describe Legion::Extensions::Agentic::Affect::Interoception::Helpers::Body
26
26
  10.times { budget.report_vital(channel: :cpu_load, value: 0.9) }
27
27
  expect(budget.baselines[:cpu_load]).to be > 0.5
28
28
  end
29
+
30
+ it 'rejects invalid channels' do
31
+ expect(budget.report_vital(channel: :bogus_channel, value: 0.5)).to be_nil
32
+ expect(budget.channel_count).to eq(0)
33
+ end
34
+
35
+ it 'accepts all valid VITAL_CHANNELS' do
36
+ constants = Legion::Extensions::Agentic::Affect::Interoception::Helpers::Constants
37
+ constants::VITAL_CHANNELS.each do |ch|
38
+ expect(budget.report_vital(channel: ch, value: 0.5)).to be_a(Float)
39
+ end
40
+ end
29
41
  end
30
42
 
31
43
  describe '#deviation_for' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-agentic-affect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity