lex-agentic-affect 0.1.0

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.
Files changed (218) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE +21 -0
  5. data/README.md +13 -0
  6. data/lex-agentic-affect.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/affect/appraisal/client.rb +20 -0
  8. data/lib/legion/extensions/agentic/affect/appraisal/helpers/appraisal.rb +112 -0
  9. data/lib/legion/extensions/agentic/affect/appraisal/helpers/appraisal_engine.rb +129 -0
  10. data/lib/legion/extensions/agentic/affect/appraisal/helpers/constants.rb +43 -0
  11. data/lib/legion/extensions/agentic/affect/appraisal/runners/appraisal.rb +105 -0
  12. data/lib/legion/extensions/agentic/affect/appraisal/version.rb +13 -0
  13. data/lib/legion/extensions/agentic/affect/appraisal.rb +19 -0
  14. data/lib/legion/extensions/agentic/affect/cognitive_empathy/client.rb +19 -0
  15. data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/constants.rb +37 -0
  16. data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/empathy_engine.rb +151 -0
  17. data/lib/legion/extensions/agentic/affect/cognitive_empathy/helpers/perspective.rb +92 -0
  18. data/lib/legion/extensions/agentic/affect/cognitive_empathy/runners/cognitive_empathy.rb +93 -0
  19. data/lib/legion/extensions/agentic/affect/cognitive_empathy/version.rb +13 -0
  20. data/lib/legion/extensions/agentic/affect/cognitive_empathy.rb +20 -0
  21. data/lib/legion/extensions/agentic/affect/contagion/client.rb +28 -0
  22. data/lib/legion/extensions/agentic/affect/contagion/helpers/constants.rb +34 -0
  23. data/lib/legion/extensions/agentic/affect/contagion/helpers/contagion_engine.rb +184 -0
  24. data/lib/legion/extensions/agentic/affect/contagion/helpers/meme.rb +97 -0
  25. data/lib/legion/extensions/agentic/affect/contagion/runners/cognitive_contagion.rb +125 -0
  26. data/lib/legion/extensions/agentic/affect/contagion/version.rb +13 -0
  27. data/lib/legion/extensions/agentic/affect/contagion.rb +19 -0
  28. data/lib/legion/extensions/agentic/affect/defusion/client.rb +28 -0
  29. data/lib/legion/extensions/agentic/affect/defusion/helpers/constants.rb +64 -0
  30. data/lib/legion/extensions/agentic/affect/defusion/helpers/defusion_engine.rb +167 -0
  31. data/lib/legion/extensions/agentic/affect/defusion/helpers/thought.rb +92 -0
  32. data/lib/legion/extensions/agentic/affect/defusion/runners/cognitive_defusion.rb +127 -0
  33. data/lib/legion/extensions/agentic/affect/defusion/version.rb +13 -0
  34. data/lib/legion/extensions/agentic/affect/defusion.rb +19 -0
  35. data/lib/legion/extensions/agentic/affect/emotion/actors/momentum_decay.rb +45 -0
  36. data/lib/legion/extensions/agentic/affect/emotion/client.rb +36 -0
  37. data/lib/legion/extensions/agentic/affect/emotion/helpers/baseline.rb +52 -0
  38. data/lib/legion/extensions/agentic/affect/emotion/helpers/momentum.rb +52 -0
  39. data/lib/legion/extensions/agentic/affect/emotion/helpers/valence.rb +92 -0
  40. data/lib/legion/extensions/agentic/affect/emotion/runners/gut.rb +102 -0
  41. data/lib/legion/extensions/agentic/affect/emotion/runners/valence.rb +120 -0
  42. data/lib/legion/extensions/agentic/affect/emotion/version.rb +13 -0
  43. data/lib/legion/extensions/agentic/affect/emotion.rb +20 -0
  44. data/lib/legion/extensions/agentic/affect/empathy/client.rb +21 -0
  45. data/lib/legion/extensions/agentic/affect/empathy/helpers/constants.rb +54 -0
  46. data/lib/legion/extensions/agentic/affect/empathy/helpers/mental_model.rb +185 -0
  47. data/lib/legion/extensions/agentic/affect/empathy/helpers/model_store.rb +88 -0
  48. data/lib/legion/extensions/agentic/affect/empathy/runners/empathy.rb +173 -0
  49. data/lib/legion/extensions/agentic/affect/empathy/version.rb +13 -0
  50. data/lib/legion/extensions/agentic/affect/empathy.rb +20 -0
  51. data/lib/legion/extensions/agentic/affect/fatigue/client.rb +26 -0
  52. data/lib/legion/extensions/agentic/affect/fatigue/helpers/constants.rb +54 -0
  53. data/lib/legion/extensions/agentic/affect/fatigue/helpers/energy_model.rb +181 -0
  54. data/lib/legion/extensions/agentic/affect/fatigue/helpers/fatigue_store.rb +146 -0
  55. data/lib/legion/extensions/agentic/affect/fatigue/runners/fatigue.rb +89 -0
  56. data/lib/legion/extensions/agentic/affect/fatigue/version.rb +13 -0
  57. data/lib/legion/extensions/agentic/affect/fatigue.rb +19 -0
  58. data/lib/legion/extensions/agentic/affect/flow/client.rb +25 -0
  59. data/lib/legion/extensions/agentic/affect/flow/helpers/constants.rb +84 -0
  60. data/lib/legion/extensions/agentic/affect/flow/helpers/flow_detector.rb +166 -0
  61. data/lib/legion/extensions/agentic/affect/flow/runners/flow.rb +129 -0
  62. data/lib/legion/extensions/agentic/affect/flow/version.rb +13 -0
  63. data/lib/legion/extensions/agentic/affect/flow.rb +18 -0
  64. data/lib/legion/extensions/agentic/affect/interoception/actors/decay.rb +45 -0
  65. data/lib/legion/extensions/agentic/affect/interoception/client.rb +28 -0
  66. data/lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb +152 -0
  67. data/lib/legion/extensions/agentic/affect/interoception/helpers/constants.rb +68 -0
  68. data/lib/legion/extensions/agentic/affect/interoception/helpers/somatic_marker.rb +75 -0
  69. data/lib/legion/extensions/agentic/affect/interoception/runners/interoception.rb +101 -0
  70. data/lib/legion/extensions/agentic/affect/interoception/version.rb +13 -0
  71. data/lib/legion/extensions/agentic/affect/interoception.rb +20 -0
  72. data/lib/legion/extensions/agentic/affect/mood/client.rb +21 -0
  73. data/lib/legion/extensions/agentic/affect/mood/helpers/constants.rb +78 -0
  74. data/lib/legion/extensions/agentic/affect/mood/helpers/mood_state.rb +154 -0
  75. data/lib/legion/extensions/agentic/affect/mood/runners/mood.rb +122 -0
  76. data/lib/legion/extensions/agentic/affect/mood/version.rb +13 -0
  77. data/lib/legion/extensions/agentic/affect/mood.rb +18 -0
  78. data/lib/legion/extensions/agentic/affect/motivation/client.rb +26 -0
  79. data/lib/legion/extensions/agentic/affect/motivation/helpers/constants.rb +48 -0
  80. data/lib/legion/extensions/agentic/affect/motivation/helpers/drive_state.rb +98 -0
  81. data/lib/legion/extensions/agentic/affect/motivation/helpers/motivation_store.rb +106 -0
  82. data/lib/legion/extensions/agentic/affect/motivation/runners/motivation.rb +165 -0
  83. data/lib/legion/extensions/agentic/affect/motivation/version.rb +13 -0
  84. data/lib/legion/extensions/agentic/affect/motivation.rb +19 -0
  85. data/lib/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate.rb +45 -0
  86. data/lib/legion/extensions/agentic/affect/reappraisal/client.rb +28 -0
  87. data/lib/legion/extensions/agentic/affect/reappraisal/helpers/constants.rb +82 -0
  88. data/lib/legion/extensions/agentic/affect/reappraisal/helpers/emotional_event.rb +98 -0
  89. data/lib/legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer.rb +88 -0
  90. data/lib/legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine.rb +153 -0
  91. data/lib/legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal.rb +164 -0
  92. data/lib/legion/extensions/agentic/affect/reappraisal/version.rb +13 -0
  93. data/lib/legion/extensions/agentic/affect/reappraisal.rb +20 -0
  94. data/lib/legion/extensions/agentic/affect/regulation/client.rb +25 -0
  95. data/lib/legion/extensions/agentic/affect/regulation/helpers/constants.rb +71 -0
  96. data/lib/legion/extensions/agentic/affect/regulation/helpers/regulation_model.rb +175 -0
  97. data/lib/legion/extensions/agentic/affect/regulation/runners/emotional_regulation.rb +127 -0
  98. data/lib/legion/extensions/agentic/affect/regulation/version.rb +13 -0
  99. data/lib/legion/extensions/agentic/affect/regulation.rb +18 -0
  100. data/lib/legion/extensions/agentic/affect/resilience/client.rb +27 -0
  101. data/lib/legion/extensions/agentic/affect/resilience/helpers/adversity_tracker.rb +130 -0
  102. data/lib/legion/extensions/agentic/affect/resilience/helpers/constants.rb +79 -0
  103. data/lib/legion/extensions/agentic/affect/resilience/helpers/resilience_model.rb +165 -0
  104. data/lib/legion/extensions/agentic/affect/resilience/runners/resilience.rb +150 -0
  105. data/lib/legion/extensions/agentic/affect/resilience/version.rb +13 -0
  106. data/lib/legion/extensions/agentic/affect/resilience.rb +19 -0
  107. data/lib/legion/extensions/agentic/affect/resonance/client.rb +24 -0
  108. data/lib/legion/extensions/agentic/affect/resonance/helpers/category.rb +75 -0
  109. data/lib/legion/extensions/agentic/affect/resonance/helpers/constants.rb +47 -0
  110. data/lib/legion/extensions/agentic/affect/resonance/helpers/resonance_engine.rb +115 -0
  111. data/lib/legion/extensions/agentic/affect/resonance/runners/cognitive_resonance.rb +94 -0
  112. data/lib/legion/extensions/agentic/affect/resonance/version.rb +13 -0
  113. data/lib/legion/extensions/agentic/affect/resonance.rb +19 -0
  114. data/lib/legion/extensions/agentic/affect/reward/client.rb +26 -0
  115. data/lib/legion/extensions/agentic/affect/reward/helpers/constants.rb +67 -0
  116. data/lib/legion/extensions/agentic/affect/reward/helpers/reward_signal.rb +178 -0
  117. data/lib/legion/extensions/agentic/affect/reward/helpers/reward_store.rb +142 -0
  118. data/lib/legion/extensions/agentic/affect/reward/runners/reward.rb +92 -0
  119. data/lib/legion/extensions/agentic/affect/reward/version.rb +13 -0
  120. data/lib/legion/extensions/agentic/affect/reward.rb +19 -0
  121. data/lib/legion/extensions/agentic/affect/somatic_marker/actors/decay.rb +45 -0
  122. data/lib/legion/extensions/agentic/affect/somatic_marker/client.rb +29 -0
  123. data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/body_state.rb +69 -0
  124. data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/constants.rb +43 -0
  125. data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb +160 -0
  126. data/lib/legion/extensions/agentic/affect/somatic_marker/helpers/somatic_marker.rb +74 -0
  127. data/lib/legion/extensions/agentic/affect/somatic_marker/runners/somatic_marker.rb +132 -0
  128. data/lib/legion/extensions/agentic/affect/somatic_marker/version.rb +13 -0
  129. data/lib/legion/extensions/agentic/affect/somatic_marker.rb +20 -0
  130. data/lib/legion/extensions/agentic/affect/version.rb +11 -0
  131. data/lib/legion/extensions/agentic/affect.rb +34 -0
  132. data/spec/legion/extensions/agentic/affect/appraisal/client_spec.rb +52 -0
  133. data/spec/legion/extensions/agentic/affect/appraisal/helpers/appraisal_engine_spec.rb +161 -0
  134. data/spec/legion/extensions/agentic/affect/appraisal/helpers/appraisal_spec.rb +175 -0
  135. data/spec/legion/extensions/agentic/affect/appraisal/helpers/constants_spec.rb +49 -0
  136. data/spec/legion/extensions/agentic/affect/appraisal/runners/appraisal_spec.rb +116 -0
  137. data/spec/legion/extensions/agentic/affect/cognitive_empathy/client_spec.rb +62 -0
  138. data/spec/legion/extensions/agentic/affect/cognitive_empathy/helpers/empathy_engine_spec.rb +316 -0
  139. data/spec/legion/extensions/agentic/affect/cognitive_empathy/helpers/perspective_spec.rb +132 -0
  140. data/spec/legion/extensions/agentic/affect/cognitive_empathy/runners/cognitive_empathy_spec.rb +200 -0
  141. data/spec/legion/extensions/agentic/affect/contagion/client_spec.rb +63 -0
  142. data/spec/legion/extensions/agentic/affect/contagion/helpers/constants_spec.rb +86 -0
  143. data/spec/legion/extensions/agentic/affect/contagion/helpers/contagion_engine_spec.rb +241 -0
  144. data/spec/legion/extensions/agentic/affect/contagion/helpers/meme_spec.rb +160 -0
  145. data/spec/legion/extensions/agentic/affect/contagion/runners/cognitive_contagion_spec.rb +211 -0
  146. data/spec/legion/extensions/agentic/affect/defusion/client_spec.rb +80 -0
  147. data/spec/legion/extensions/agentic/affect/defusion/helpers/constants_spec.rb +84 -0
  148. data/spec/legion/extensions/agentic/affect/defusion/helpers/defusion_engine_spec.rb +250 -0
  149. data/spec/legion/extensions/agentic/affect/defusion/helpers/thought_spec.rb +178 -0
  150. data/spec/legion/extensions/agentic/affect/defusion/runners/cognitive_defusion_spec.rb +185 -0
  151. data/spec/legion/extensions/agentic/affect/emotion/actors/momentum_decay_spec.rb +46 -0
  152. data/spec/legion/extensions/agentic/affect/emotion/client_spec.rb +46 -0
  153. data/spec/legion/extensions/agentic/affect/emotion/helpers/baseline_spec.rb +48 -0
  154. data/spec/legion/extensions/agentic/affect/emotion/helpers/momentum_spec.rb +45 -0
  155. data/spec/legion/extensions/agentic/affect/emotion/helpers/valence_spec.rb +91 -0
  156. data/spec/legion/extensions/agentic/affect/emotion/runners/gut_spec.rb +73 -0
  157. data/spec/legion/extensions/agentic/affect/emotion/runners/valence_spec.rb +67 -0
  158. data/spec/legion/extensions/agentic/affect/empathy/client_spec.rb +20 -0
  159. data/spec/legion/extensions/agentic/affect/empathy/helpers/constants_spec.rb +23 -0
  160. data/spec/legion/extensions/agentic/affect/empathy/helpers/mental_model_spec.rb +150 -0
  161. data/spec/legion/extensions/agentic/affect/empathy/helpers/model_store_spec.rb +94 -0
  162. data/spec/legion/extensions/agentic/affect/empathy/runners/empathy_spec.rb +127 -0
  163. data/spec/legion/extensions/agentic/affect/fatigue/client_spec.rb +66 -0
  164. data/spec/legion/extensions/agentic/affect/fatigue/helpers/constants_spec.rb +130 -0
  165. data/spec/legion/extensions/agentic/affect/fatigue/helpers/energy_model_spec.rb +281 -0
  166. data/spec/legion/extensions/agentic/affect/fatigue/helpers/fatigue_store_spec.rb +157 -0
  167. data/spec/legion/extensions/agentic/affect/fatigue/runners/fatigue_spec.rb +127 -0
  168. data/spec/legion/extensions/agentic/affect/flow/client_spec.rb +58 -0
  169. data/spec/legion/extensions/agentic/affect/flow/helpers/constants_spec.rb +112 -0
  170. data/spec/legion/extensions/agentic/affect/flow/helpers/flow_detector_spec.rb +268 -0
  171. data/spec/legion/extensions/agentic/affect/flow/runners/flow_spec.rb +222 -0
  172. data/spec/legion/extensions/agentic/affect/interoception/client_spec.rb +52 -0
  173. data/spec/legion/extensions/agentic/affect/interoception/helpers/body_budget_spec.rb +178 -0
  174. data/spec/legion/extensions/agentic/affect/interoception/helpers/somatic_marker_spec.rb +120 -0
  175. data/spec/legion/extensions/agentic/affect/interoception/runners/interoception_spec.rb +108 -0
  176. data/spec/legion/extensions/agentic/affect/mood/client_spec.rb +20 -0
  177. data/spec/legion/extensions/agentic/affect/mood/helpers/constants_spec.rb +29 -0
  178. data/spec/legion/extensions/agentic/affect/mood/helpers/mood_state_spec.rb +94 -0
  179. data/spec/legion/extensions/agentic/affect/mood/runners/mood_spec.rb +71 -0
  180. data/spec/legion/extensions/agentic/affect/motivation/client_spec.rb +35 -0
  181. data/spec/legion/extensions/agentic/affect/motivation/helpers/constants_spec.rb +111 -0
  182. data/spec/legion/extensions/agentic/affect/motivation/helpers/drive_state_spec.rb +183 -0
  183. data/spec/legion/extensions/agentic/affect/motivation/helpers/motivation_store_spec.rb +185 -0
  184. data/spec/legion/extensions/agentic/affect/motivation/runners/motivation_spec.rb +248 -0
  185. data/spec/legion/extensions/agentic/affect/reappraisal/actors/auto_regulate_spec.rb +46 -0
  186. data/spec/legion/extensions/agentic/affect/reappraisal/client_spec.rb +64 -0
  187. data/spec/legion/extensions/agentic/affect/reappraisal/helpers/constants_spec.rb +102 -0
  188. data/spec/legion/extensions/agentic/affect/reappraisal/helpers/emotional_event_spec.rb +177 -0
  189. data/spec/legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer_spec.rb +161 -0
  190. data/spec/legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine_spec.rb +211 -0
  191. data/spec/legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal_spec.rb +312 -0
  192. data/spec/legion/extensions/agentic/affect/regulation/client_spec.rb +61 -0
  193. data/spec/legion/extensions/agentic/affect/regulation/helpers/constants_spec.rb +108 -0
  194. data/spec/legion/extensions/agentic/affect/regulation/helpers/regulation_model_spec.rb +200 -0
  195. data/spec/legion/extensions/agentic/affect/regulation/runners/emotional_regulation_spec.rb +190 -0
  196. data/spec/legion/extensions/agentic/affect/resilience/client_spec.rb +36 -0
  197. data/spec/legion/extensions/agentic/affect/resilience/helpers/adversity_tracker_spec.rb +164 -0
  198. data/spec/legion/extensions/agentic/affect/resilience/helpers/constants_spec.rb +78 -0
  199. data/spec/legion/extensions/agentic/affect/resilience/helpers/resilience_model_spec.rb +133 -0
  200. data/spec/legion/extensions/agentic/affect/resilience/runners/resilience_spec.rb +150 -0
  201. data/spec/legion/extensions/agentic/affect/resonance/client_spec.rb +66 -0
  202. data/spec/legion/extensions/agentic/affect/resonance/cognitive_resonance_spec.rb +27 -0
  203. data/spec/legion/extensions/agentic/affect/resonance/helpers/category_spec.rb +146 -0
  204. data/spec/legion/extensions/agentic/affect/resonance/helpers/constants_spec.rb +104 -0
  205. data/spec/legion/extensions/agentic/affect/resonance/helpers/resonance_engine_spec.rb +189 -0
  206. data/spec/legion/extensions/agentic/affect/resonance/runners/cognitive_resonance_spec.rb +197 -0
  207. data/spec/legion/extensions/agentic/affect/reward/client_spec.rb +42 -0
  208. data/spec/legion/extensions/agentic/affect/reward/helpers/constants_spec.rb +91 -0
  209. data/spec/legion/extensions/agentic/affect/reward/helpers/reward_signal_spec.rb +296 -0
  210. data/spec/legion/extensions/agentic/affect/reward/helpers/reward_store_spec.rb +167 -0
  211. data/spec/legion/extensions/agentic/affect/reward/runners/reward_spec.rb +149 -0
  212. data/spec/legion/extensions/agentic/affect/somatic_marker/client_spec.rb +83 -0
  213. data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/body_state_spec.rb +155 -0
  214. data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store_spec.rb +233 -0
  215. data/spec/legion/extensions/agentic/affect/somatic_marker/helpers/somatic_marker_spec.rb +172 -0
  216. data/spec/legion/extensions/agentic/affect/somatic_marker/runners/somatic_marker_spec.rb +181 -0
  217. data/spec/spec_helper.rb +46 -0
  218. metadata +302 -0
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/affect/regulation/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Affect::Regulation::Client do
6
+ subject(:client) { described_class.new }
7
+
8
+ describe '#initialize' do
9
+ it 'creates a regulation_model' do
10
+ expect(client.regulation_model).to be_a(Legion::Extensions::Agentic::Affect::Regulation::Helpers::RegulationModel)
11
+ end
12
+
13
+ it 'accepts an injected regulation_model' do
14
+ custom_model = Legion::Extensions::Agentic::Affect::Regulation::Helpers::RegulationModel.new
15
+ c = described_class.new(regulation_model: custom_model)
16
+ expect(c.regulation_model).to be(custom_model)
17
+ end
18
+ end
19
+
20
+ it 'responds to all runner methods' do
21
+ expect(client).to respond_to(:regulate_emotion)
22
+ expect(client).to respond_to(:recommend_strategy)
23
+ expect(client).to respond_to(:update_emotional_regulation)
24
+ expect(client).to respond_to(:regulation_profile)
25
+ expect(client).to respond_to(:regulation_history)
26
+ expect(client).to respond_to(:emotional_regulation_stats)
27
+ end
28
+
29
+ it 'persists regulation model state across calls' do
30
+ client.regulate_emotion(emotion_magnitude: 0.7, emotion_valence: :negative, strategy: :cognitive_reappraisal)
31
+ stats = client.emotional_regulation_stats
32
+ expect(stats[:total_events]).to eq(1)
33
+ end
34
+
35
+ it 'runs a full regulation cycle' do
36
+ # First, get a recommendation
37
+ rec = client.recommend_strategy(emotion_magnitude: 0.8, emotion_valence: :negative)
38
+ expect(rec[:recommended]).to be_a(Symbol)
39
+
40
+ # Apply that strategy
41
+ reg = client.regulate_emotion(emotion_magnitude: 0.8, emotion_valence: :negative,
42
+ strategy: rec[:recommended])
43
+ expect(reg[:regulated_magnitude]).to be < 0.8
44
+
45
+ # Tick decay
46
+ tick = client.update_emotional_regulation
47
+ expect(tick[:success]).to be(true)
48
+
49
+ # Check profile
50
+ profile = client.regulation_profile
51
+ expect(profile[:skills]).not_to be_empty
52
+
53
+ # Check history
54
+ history = client.regulation_history
55
+ expect(history[:count]).to eq(1)
56
+
57
+ # Check stats
58
+ stats = client.emotional_regulation_stats
59
+ expect(stats[:total_events]).to eq(1)
60
+ end
61
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Affect::Regulation::Helpers::Constants do
4
+ let(:mod) { described_class }
5
+
6
+ describe 'STRATEGIES' do
7
+ it 'defines all five strategies' do
8
+ expect(mod::STRATEGIES).to eq(%i[
9
+ situation_selection
10
+ situation_modification
11
+ attentional_deployment
12
+ cognitive_reappraisal
13
+ response_suppression
14
+ ])
15
+ end
16
+
17
+ it 'is frozen' do
18
+ expect(mod::STRATEGIES).to be_frozen
19
+ end
20
+ end
21
+
22
+ describe 'STRATEGY_EFFECTIVENESS' do
23
+ it 'covers all strategies' do
24
+ expect(mod::STRATEGY_EFFECTIVENESS.keys).to match_array(mod::STRATEGIES)
25
+ end
26
+
27
+ it 'has values in [0, 1]' do
28
+ mod::STRATEGY_EFFECTIVENESS.each_value do |v|
29
+ expect(v).to be_between(0.0, 1.0)
30
+ end
31
+ end
32
+
33
+ it 'ranks situation_selection as most effective' do
34
+ expect(mod::STRATEGY_EFFECTIVENESS[:situation_selection]).to eq(0.8)
35
+ end
36
+
37
+ it 'ranks response_suppression as least effective' do
38
+ expect(mod::STRATEGY_EFFECTIVENESS[:response_suppression]).to eq(0.3)
39
+ end
40
+ end
41
+
42
+ describe 'STRATEGY_COST' do
43
+ it 'covers all strategies' do
44
+ expect(mod::STRATEGY_COST.keys).to match_array(mod::STRATEGIES)
45
+ end
46
+
47
+ it 'has values in [0, 1]' do
48
+ mod::STRATEGY_COST.each_value do |v|
49
+ expect(v).to be_between(0.0, 1.0)
50
+ end
51
+ end
52
+
53
+ it 'ranks situation_selection as lowest cost' do
54
+ expect(mod::STRATEGY_COST[:situation_selection]).to eq(0.1)
55
+ end
56
+
57
+ it 'ranks response_suppression as highest cost' do
58
+ expect(mod::STRATEGY_COST[:response_suppression]).to eq(0.35)
59
+ end
60
+ end
61
+
62
+ describe 'REGULATION_LABELS' do
63
+ it 'covers all ranges without gaps for values 0..1' do
64
+ [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0].each do |value|
65
+ matched = mod::REGULATION_LABELS.any? { |range, _| range.cover?(value) }
66
+ expect(matched).to be(true), "No range covers #{value}"
67
+ end
68
+ end
69
+
70
+ it 'maps 1.0 to :masterful' do
71
+ label = mod::REGULATION_LABELS.find { |range, _| range.cover?(1.0) }&.last
72
+ expect(label).to eq(:masterful)
73
+ end
74
+
75
+ it 'maps 0.0 to :reactive' do
76
+ label = mod::REGULATION_LABELS.find { |range, _| range.cover?(0.0) }&.last
77
+ expect(label).to eq(:reactive)
78
+ end
79
+
80
+ it 'maps 0.5 to :developing' do
81
+ label = mod::REGULATION_LABELS.find { |range, _| range.cover?(0.5) }&.last
82
+ expect(label).to eq(:developing)
83
+ end
84
+ end
85
+
86
+ describe 'numeric constants' do
87
+ it 'has REGULATION_ALPHA as a small positive float' do
88
+ expect(mod::REGULATION_ALPHA).to be > 0.0
89
+ expect(mod::REGULATION_ALPHA).to be < 1.0
90
+ end
91
+
92
+ it 'has DEFAULT_SKILL in [0, 1]' do
93
+ expect(mod::DEFAULT_SKILL).to be_between(0.0, 1.0)
94
+ end
95
+
96
+ it 'has SKILL_GAIN > SKILL_DECAY' do
97
+ expect(mod::SKILL_GAIN).to be > mod::SKILL_DECAY
98
+ end
99
+
100
+ it 'has MAX_REGULATION_HISTORY as positive integer' do
101
+ expect(mod::MAX_REGULATION_HISTORY).to be > 0
102
+ end
103
+
104
+ it 'has SUPPRESSION_PENALTY_THRESHOLD as positive integer' do
105
+ expect(mod::SUPPRESSION_PENALTY_THRESHOLD).to be > 0
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Affect::Regulation::Helpers::RegulationModel do
4
+ subject(:model) { described_class.new }
5
+
6
+ let(:c) { Legion::Extensions::Agentic::Affect::Regulation::Helpers::Constants }
7
+
8
+ describe '#initialize' do
9
+ it 'starts all skills at DEFAULT_SKILL' do
10
+ c::STRATEGIES.each do |strategy|
11
+ expect(model.skill[strategy]).to eq(c::DEFAULT_SKILL)
12
+ end
13
+ end
14
+
15
+ it 'starts with zero consecutive suppressions' do
16
+ expect(model.consecutive_suppressions).to eq(0)
17
+ end
18
+
19
+ it 'starts with empty history' do
20
+ expect(model.regulation_history).to be_empty
21
+ end
22
+ end
23
+
24
+ describe '#regulate' do
25
+ context 'with a valid strategy' do
26
+ it 'returns success: true' do
27
+ result = model.regulate(emotion_magnitude: 0.8, emotion_valence: :negative, strategy: :cognitive_reappraisal)
28
+ expect(result[:success]).to be(true)
29
+ end
30
+
31
+ it 'reduces emotion magnitude' do
32
+ result = model.regulate(emotion_magnitude: 0.8, emotion_valence: :negative, strategy: :cognitive_reappraisal)
33
+ expect(result[:regulated_magnitude]).to be < 0.8
34
+ end
35
+
36
+ it 'returns the strategy used' do
37
+ result = model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :attentional_deployment)
38
+ expect(result[:strategy]).to eq(:attentional_deployment)
39
+ end
40
+
41
+ it 'returns a cost value' do
42
+ result = model.regulate(emotion_magnitude: 0.6, emotion_valence: :neutral, strategy: :situation_modification)
43
+ expect(result[:cost]).to be > 0.0
44
+ end
45
+
46
+ it 'records an event in history' do
47
+ expect { model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :cognitive_reappraisal) }
48
+ .to change { model.regulation_history.size }.by(1)
49
+ end
50
+
51
+ it 'does not reduce regulated_magnitude below 0' do
52
+ result = model.regulate(emotion_magnitude: 0.0, emotion_valence: :neutral, strategy: :situation_selection)
53
+ expect(result[:regulated_magnitude]).to be >= 0.0
54
+ end
55
+ end
56
+
57
+ context 'with an unknown strategy' do
58
+ it 'returns success: false' do
59
+ result = model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :teleportation)
60
+ expect(result[:success]).to be(false)
61
+ end
62
+
63
+ it 'does not change the magnitude' do
64
+ result = model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :teleportation)
65
+ expect(result[:regulated_magnitude]).to eq(0.5)
66
+ end
67
+
68
+ it 'includes reason: :unknown_strategy' do
69
+ result = model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :teleportation)
70
+ expect(result[:reason]).to eq(:unknown_strategy)
71
+ end
72
+ end
73
+
74
+ context 'suppression tracking' do
75
+ it 'increments consecutive_suppressions on suppression use' do
76
+ model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :response_suppression)
77
+ expect(model.consecutive_suppressions).to eq(1)
78
+ end
79
+
80
+ it 'resets consecutive_suppressions when a different strategy is used' do
81
+ model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :response_suppression)
82
+ model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :cognitive_reappraisal)
83
+ expect(model.consecutive_suppressions).to eq(0)
84
+ end
85
+ end
86
+
87
+ context 'skill learning' do
88
+ it 'improves skill on successful regulation' do
89
+ initial = model.skill[:cognitive_reappraisal]
90
+ model.regulate(emotion_magnitude: 0.8, emotion_valence: :negative, strategy: :cognitive_reappraisal)
91
+ expect(model.skill[:cognitive_reappraisal]).to be > initial
92
+ end
93
+ end
94
+
95
+ context 'history capping' do
96
+ it 'caps history at MAX_REGULATION_HISTORY' do
97
+ (c::MAX_REGULATION_HISTORY + 10).times do
98
+ model.regulate(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :attentional_deployment)
99
+ end
100
+ expect(model.regulation_history.size).to eq(c::MAX_REGULATION_HISTORY)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#recommend_strategy' do
106
+ it 'returns a recommended strategy' do
107
+ result = model.recommend_strategy(emotion_magnitude: 0.7, emotion_valence: :negative)
108
+ expect(c::STRATEGIES).to include(result[:recommended])
109
+ end
110
+
111
+ it 'returns scores for all strategies' do
112
+ result = model.recommend_strategy(emotion_magnitude: 0.5, emotion_valence: :neutral)
113
+ expect(result[:scores].keys).to match_array(c::STRATEGIES)
114
+ end
115
+
116
+ it 'returns the context' do
117
+ result = model.recommend_strategy(emotion_magnitude: 0.5, emotion_valence: :neutral, context: :sustained)
118
+ expect(result[:context]).to eq(:sustained)
119
+ end
120
+
121
+ it 'penalises situation_selection at high magnitude' do
122
+ result = model.recommend_strategy(emotion_magnitude: 0.9, emotion_valence: :negative, context: :general)
123
+ # situation_selection should score lower than cognitive_reappraisal at high magnitude
124
+ expect(result[:scores][:situation_selection]).to be < result[:scores][:cognitive_reappraisal]
125
+ end
126
+
127
+ it 'penalises suppression in sustained context' do
128
+ general_result = model.recommend_strategy(emotion_magnitude: 0.5, emotion_valence: :neutral, context: :general)
129
+ sustained_result = model.recommend_strategy(emotion_magnitude: 0.5, emotion_valence: :neutral, context: :sustained)
130
+ expect(sustained_result[:scores][:response_suppression]).to be < general_result[:scores][:response_suppression]
131
+ end
132
+ end
133
+
134
+ describe '#decay' do
135
+ it 'moves skills above DEFAULT_SKILL toward DEFAULT_SKILL' do
136
+ model.instance_variable_get(:@skill)[:cognitive_reappraisal] = 0.8
137
+ model.decay
138
+ expect(model.skill[:cognitive_reappraisal]).to be < 0.8
139
+ end
140
+
141
+ it 'does not decay skills below 0' do
142
+ c::STRATEGIES.each do |s|
143
+ model.instance_variable_get(:@skill)[s] = 0.0
144
+ end
145
+ model.decay
146
+ c::STRATEGIES.each do |s|
147
+ expect(model.skill[s]).to be >= 0.0
148
+ end
149
+ end
150
+ end
151
+
152
+ describe '#skill_for' do
153
+ it 'returns the skill value for a known strategy' do
154
+ expect(model.skill_for(:cognitive_reappraisal)).to eq(c::DEFAULT_SKILL)
155
+ end
156
+
157
+ it 'returns DEFAULT_SKILL for an unknown strategy' do
158
+ expect(model.skill_for(:nonexistent)).to eq(c::DEFAULT_SKILL)
159
+ end
160
+ end
161
+
162
+ describe '#overall_regulation_ability' do
163
+ it 'returns a float in [0, 1]' do
164
+ ability = model.overall_regulation_ability
165
+ expect(ability).to be_between(0.0, 1.0)
166
+ end
167
+
168
+ it 'starts at DEFAULT_SKILL when all skills are equal' do
169
+ expect(model.overall_regulation_ability).to be_within(0.001).of(c::DEFAULT_SKILL)
170
+ end
171
+ end
172
+
173
+ describe '#regulation_label' do
174
+ it 'returns a symbol from REGULATION_LABELS' do
175
+ expect(c::REGULATION_LABELS.values).to include(model.regulation_label)
176
+ end
177
+
178
+ it 'returns :novice when ability is around DEFAULT_SKILL (0.3)' do
179
+ expect(model.regulation_label).to eq(:novice)
180
+ end
181
+
182
+ it 'returns :masterful when all skills are near 1.0' do
183
+ c::STRATEGIES.each do |s|
184
+ model.instance_variable_get(:@skill)[s] = 0.95
185
+ end
186
+ expect(model.regulation_label).to eq(:masterful)
187
+ end
188
+ end
189
+
190
+ describe '#to_h' do
191
+ it 'includes all expected keys' do
192
+ hash = model.to_h
193
+ expect(hash.keys).to include(:skill, :consecutive_suppressions, :overall_ability, :regulation_label, :history_size)
194
+ end
195
+
196
+ it 'returns a duplicate of skill (not same object)' do
197
+ expect(model.to_h[:skill]).not_to be(model.skill)
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/affect/regulation/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Affect::Regulation::Runners::EmotionalRegulation do
6
+ let(:client) { Legion::Extensions::Agentic::Affect::Regulation::Client.new }
7
+
8
+ describe '#regulate_emotion' do
9
+ it 'returns success: true' do
10
+ result = client.regulate_emotion(emotion_magnitude: 0.7, emotion_valence: :negative)
11
+ expect(result[:success]).to be(true)
12
+ end
13
+
14
+ it 'returns a regulated_magnitude' do
15
+ result = client.regulate_emotion(emotion_magnitude: 0.7, emotion_valence: :negative)
16
+ expect(result[:regulated_magnitude]).to be_a(Float)
17
+ end
18
+
19
+ it 'reduces magnitude when a valid strategy is provided' do
20
+ result = client.regulate_emotion(emotion_magnitude: 0.8, emotion_valence: :negative,
21
+ strategy: :cognitive_reappraisal)
22
+ expect(result[:regulated_magnitude]).to be < 0.8
23
+ end
24
+
25
+ it 'auto-selects a strategy when none given' do
26
+ result = client.regulate_emotion(emotion_magnitude: 0.6, emotion_valence: :neutral)
27
+ expect(result[:strategy]).not_to be_nil
28
+ end
29
+
30
+ it 'accepts and uses an explicit strategy' do
31
+ result = client.regulate_emotion(emotion_magnitude: 0.5, emotion_valence: :neutral,
32
+ strategy: :attentional_deployment)
33
+ expect(result[:strategy]).to eq(:attentional_deployment)
34
+ end
35
+
36
+ it 'returns a cost value' do
37
+ result = client.regulate_emotion(emotion_magnitude: 0.5, emotion_valence: :neutral,
38
+ strategy: :situation_modification)
39
+ expect(result[:cost]).to be > 0.0
40
+ end
41
+
42
+ it 'returns success: false for unknown strategy' do
43
+ result = client.regulate_emotion(emotion_magnitude: 0.5, emotion_valence: :neutral,
44
+ strategy: :nonexistent)
45
+ expect(result[:success]).to be(false)
46
+ end
47
+ end
48
+
49
+ describe '#recommend_strategy' do
50
+ it 'returns success: true' do
51
+ result = client.recommend_strategy(emotion_magnitude: 0.7, emotion_valence: :negative)
52
+ expect(result[:success]).to be(true)
53
+ end
54
+
55
+ it 'returns a recommended strategy symbol' do
56
+ result = client.recommend_strategy(emotion_magnitude: 0.7, emotion_valence: :negative)
57
+ expect(Legion::Extensions::Agentic::Affect::Regulation::Helpers::Constants::STRATEGIES).to include(result[:recommended])
58
+ end
59
+
60
+ it 'returns scores for all strategies' do
61
+ result = client.recommend_strategy(emotion_magnitude: 0.5, emotion_valence: :neutral)
62
+ expect(result[:scores].keys).to match_array(Legion::Extensions::Agentic::Affect::Regulation::Helpers::Constants::STRATEGIES)
63
+ end
64
+
65
+ it 'accepts a context parameter' do
66
+ result = client.recommend_strategy(emotion_magnitude: 0.5, emotion_valence: :neutral, context: :sustained)
67
+ expect(result[:context]).to eq(:sustained)
68
+ end
69
+ end
70
+
71
+ describe '#update_emotional_regulation' do
72
+ it 'returns success: true' do
73
+ result = client.update_emotional_regulation
74
+ expect(result[:success]).to be(true)
75
+ end
76
+
77
+ it 'returns overall_ability' do
78
+ result = client.update_emotional_regulation
79
+ expect(result[:overall_ability]).to be_a(Float)
80
+ end
81
+
82
+ it 'returns a regulation_label symbol' do
83
+ result = client.update_emotional_regulation
84
+ expect(result[:regulation_label]).to be_a(Symbol)
85
+ end
86
+ end
87
+
88
+ describe '#regulation_profile' do
89
+ it 'returns success: true' do
90
+ result = client.regulation_profile
91
+ expect(result[:success]).to be(true)
92
+ end
93
+
94
+ it 'returns skills for all strategies' do
95
+ result = client.regulation_profile
96
+ expect(result[:skills].keys).to match_array(Legion::Extensions::Agentic::Affect::Regulation::Helpers::Constants::STRATEGIES)
97
+ end
98
+
99
+ it 'returns overall ability' do
100
+ result = client.regulation_profile
101
+ expect(result[:overall]).to be_a(Float)
102
+ end
103
+
104
+ it 'returns a label' do
105
+ result = client.regulation_profile
106
+ expect(result[:label]).to be_a(Symbol)
107
+ end
108
+
109
+ it 'returns suppressions count' do
110
+ result = client.regulation_profile
111
+ expect(result[:suppressions]).to be_a(Integer)
112
+ end
113
+ end
114
+
115
+ describe '#regulation_history' do
116
+ it 'returns success: true' do
117
+ result = client.regulation_history
118
+ expect(result[:success]).to be(true)
119
+ end
120
+
121
+ it 'starts with empty events' do
122
+ result = client.regulation_history
123
+ expect(result[:events]).to be_empty
124
+ end
125
+
126
+ it 'returns events after regulation' do
127
+ client.regulate_emotion(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :cognitive_reappraisal)
128
+ result = client.regulation_history
129
+ expect(result[:count]).to eq(1)
130
+ end
131
+
132
+ it 'respects the count parameter' do
133
+ 5.times do
134
+ client.regulate_emotion(emotion_magnitude: 0.5, emotion_valence: :neutral, strategy: :attentional_deployment)
135
+ end
136
+ result = client.regulation_history(count: 3)
137
+ expect(result[:events].size).to be <= 3
138
+ end
139
+ end
140
+
141
+ describe '#emotional_regulation_stats' do
142
+ it 'returns success: true' do
143
+ result = client.emotional_regulation_stats
144
+ expect(result[:success]).to be(true)
145
+ end
146
+
147
+ context 'with no history' do
148
+ it 'returns zero total_events' do
149
+ expect(client.emotional_regulation_stats[:total_events]).to eq(0)
150
+ end
151
+
152
+ it 'returns 0.0 success_rate' do
153
+ expect(client.emotional_regulation_stats[:success_rate]).to eq(0.0)
154
+ end
155
+ end
156
+
157
+ context 'with some history' do
158
+ before do
159
+ 3.times do
160
+ client.regulate_emotion(emotion_magnitude: 0.6, emotion_valence: :negative,
161
+ strategy: :cognitive_reappraisal)
162
+ end
163
+ end
164
+
165
+ it 'returns correct total_events' do
166
+ expect(client.emotional_regulation_stats[:total_events]).to eq(3)
167
+ end
168
+
169
+ it 'returns a success_rate in [0, 1]' do
170
+ rate = client.emotional_regulation_stats[:success_rate]
171
+ expect(rate).to be_between(0.0, 1.0)
172
+ end
173
+
174
+ it 'returns average_cost' do
175
+ expect(client.emotional_regulation_stats[:average_cost]).to be > 0.0
176
+ end
177
+
178
+ it 'returns a strategy_breakdown hash' do
179
+ breakdown = client.emotional_regulation_stats[:strategy_breakdown]
180
+ expect(breakdown).to be_a(Hash)
181
+ expect(breakdown.keys).to match_array(Legion::Extensions::Agentic::Affect::Regulation::Helpers::Constants::STRATEGIES)
182
+ end
183
+
184
+ it 'correctly counts strategy usage in breakdown' do
185
+ breakdown = client.emotional_regulation_stats[:strategy_breakdown]
186
+ expect(breakdown[:cognitive_reappraisal][:count]).to eq(3)
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Affect::Resilience::Client do
6
+ describe '#initialize' do
7
+ it 'creates default adversity tracker and model' do
8
+ client = described_class.new
9
+ expect(client.adversity_tracker).to be_a(Legion::Extensions::Agentic::Affect::Resilience::Helpers::AdversityTracker)
10
+ expect(client.resilience_model).to be_a(Legion::Extensions::Agentic::Affect::Resilience::Helpers::ResilienceModel)
11
+ end
12
+
13
+ it 'accepts injected dependencies' do
14
+ tracker = Legion::Extensions::Agentic::Affect::Resilience::Helpers::AdversityTracker.new
15
+ model = Legion::Extensions::Agentic::Affect::Resilience::Helpers::ResilienceModel.new
16
+ client = described_class.new(adversity_tracker: tracker, resilience_model: model)
17
+ expect(client.adversity_tracker).to be(tracker)
18
+ expect(client.resilience_model).to be(model)
19
+ end
20
+
21
+ it 'ignores unknown kwargs' do
22
+ expect { described_class.new(unknown: true) }.not_to raise_error
23
+ end
24
+ end
25
+
26
+ describe 'runner integration' do
27
+ let(:client) { described_class.new }
28
+
29
+ it { expect(client).to respond_to(:update_resilience) }
30
+ it { expect(client).to respond_to(:register_adversity) }
31
+ it { expect(client).to respond_to(:resilience_status) }
32
+ it { expect(client).to respond_to(:adversity_report) }
33
+ it { expect(client).to respond_to(:dimension_detail) }
34
+ it { expect(client).to respond_to(:resilience_stats) }
35
+ end
36
+ end