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,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants do
6
+ describe 'DRIVE_TYPES' do
7
+ it 'defines 6 drive types' do
8
+ expect(described_class::DRIVE_TYPES.size).to eq(6)
9
+ end
10
+
11
+ it 'includes autonomy' do
12
+ expect(described_class::DRIVE_TYPES).to include(:autonomy)
13
+ end
14
+
15
+ it 'includes competence' do
16
+ expect(described_class::DRIVE_TYPES).to include(:competence)
17
+ end
18
+
19
+ it 'includes relatedness' do
20
+ expect(described_class::DRIVE_TYPES).to include(:relatedness)
21
+ end
22
+
23
+ it 'includes novelty' do
24
+ expect(described_class::DRIVE_TYPES).to include(:novelty)
25
+ end
26
+
27
+ it 'includes obligation' do
28
+ expect(described_class::DRIVE_TYPES).to include(:obligation)
29
+ end
30
+
31
+ it 'includes survival' do
32
+ expect(described_class::DRIVE_TYPES).to include(:survival)
33
+ end
34
+
35
+ it 'is frozen' do
36
+ expect(described_class::DRIVE_TYPES).to be_frozen
37
+ end
38
+ end
39
+
40
+ describe 'MOTIVATION_MODES' do
41
+ it 'defines 4 modes' do
42
+ expect(described_class::MOTIVATION_MODES).to eq(%i[approach avoidance maintenance dormant])
43
+ end
44
+
45
+ it 'is frozen' do
46
+ expect(described_class::MOTIVATION_MODES).to be_frozen
47
+ end
48
+ end
49
+
50
+ describe 'INTRINSIC_DRIVES' do
51
+ it 'contains autonomy, competence, relatedness, novelty' do
52
+ expect(described_class::INTRINSIC_DRIVES).to contain_exactly(:autonomy, :competence, :relatedness, :novelty)
53
+ end
54
+
55
+ it 'is a subset of DRIVE_TYPES' do
56
+ described_class::INTRINSIC_DRIVES.each do |d|
57
+ expect(described_class::DRIVE_TYPES).to include(d)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe 'EXTRINSIC_DRIVES' do
63
+ it 'contains obligation and survival' do
64
+ expect(described_class::EXTRINSIC_DRIVES).to contain_exactly(:obligation, :survival)
65
+ end
66
+
67
+ it 'is a subset of DRIVE_TYPES' do
68
+ described_class::EXTRINSIC_DRIVES.each do |d|
69
+ expect(described_class::DRIVE_TYPES).to include(d)
70
+ end
71
+ end
72
+ end
73
+
74
+ describe 'intrinsic + extrinsic = all drives' do
75
+ it 'covers all drive types without overlap' do
76
+ all = described_class::INTRINSIC_DRIVES + described_class::EXTRINSIC_DRIVES
77
+ expect(all.sort).to eq(described_class::DRIVE_TYPES.sort)
78
+ end
79
+ end
80
+
81
+ describe 'thresholds' do
82
+ it 'APPROACH_THRESHOLD is above AVOIDANCE_THRESHOLD' do
83
+ expect(described_class::APPROACH_THRESHOLD).to be > described_class::AVOIDANCE_THRESHOLD
84
+ end
85
+
86
+ it 'AVOIDANCE_THRESHOLD is above BURNOUT_THRESHOLD' do
87
+ expect(described_class::AVOIDANCE_THRESHOLD).to be > described_class::BURNOUT_THRESHOLD
88
+ end
89
+
90
+ it 'AMOTIVATION_THRESHOLD is defined' do
91
+ expect(described_class::AMOTIVATION_THRESHOLD).to be_a(Float)
92
+ end
93
+
94
+ it 'DRIVE_DECAY_RATE is small and positive' do
95
+ expect(described_class::DRIVE_DECAY_RATE).to be > 0.0
96
+ expect(described_class::DRIVE_DECAY_RATE).to be < 0.1
97
+ end
98
+
99
+ it 'DRIVE_ALPHA is a valid EMA alpha' do
100
+ expect(described_class::DRIVE_ALPHA).to be > 0.0
101
+ expect(described_class::DRIVE_ALPHA).to be < 1.0
102
+ end
103
+ end
104
+
105
+ describe 'MAX_GOALS' do
106
+ it 'is a positive integer' do
107
+ expect(described_class::MAX_GOALS).to be_a(Integer)
108
+ expect(described_class::MAX_GOALS).to be > 0
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Affect::Motivation::Helpers::DriveState do
6
+ subject(:state) { described_class.new }
7
+
8
+ describe '#initialize' do
9
+ it 'starts all drives at 0.5' do
10
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |type|
11
+ expect(state.drives[type][:level]).to eq(0.5)
12
+ end
13
+ end
14
+
15
+ it 'starts all drives unsatisfied' do
16
+ state.drives.each_value do |d|
17
+ expect(d[:satisfied]).to be false
18
+ end
19
+ end
20
+
21
+ it 'starts with nil last_signal for all drives' do
22
+ state.drives.each_value do |d|
23
+ expect(d[:last_signal]).to be_nil
24
+ end
25
+ end
26
+
27
+ it 'initializes all defined drive types' do
28
+ expect(state.drives.keys).to match_array(Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES)
29
+ end
30
+ end
31
+
32
+ describe '#update_drive' do
33
+ it 'updates level via EMA' do
34
+ initial = state.drive_level(:autonomy)
35
+ state.update_drive(:autonomy, 1.0)
36
+ expect(state.drive_level(:autonomy)).to be > initial
37
+ end
38
+
39
+ it 'clamps signal to 0.0..1.0' do
40
+ state.update_drive(:competence, 5.0)
41
+ expect(state.drive_level(:competence)).to be <= 1.0
42
+ end
43
+
44
+ it 'clamps negative signal to 0.0' do
45
+ state.update_drive(:competence, -1.0)
46
+ expect(state.drive_level(:competence)).to be >= 0.0
47
+ end
48
+
49
+ it 'marks drive satisfied when level crosses 0.6' do
50
+ 10.times { state.update_drive(:autonomy, 1.0) }
51
+ expect(state.satisfied?(:autonomy)).to be true
52
+ end
53
+
54
+ it 'sets last_signal timestamp' do
55
+ state.update_drive(:relatedness, 0.8)
56
+ expect(state.drives[:relatedness][:last_signal]).to be_a(Time)
57
+ end
58
+
59
+ it 'ignores unknown drive types' do
60
+ expect { state.update_drive(:unknown_drive, 0.5) }.not_to raise_error
61
+ end
62
+ end
63
+
64
+ describe '#drive_level' do
65
+ it 'returns level for known drive' do
66
+ expect(state.drive_level(:autonomy)).to eq(0.5)
67
+ end
68
+
69
+ it 'returns 0.0 for unknown drive' do
70
+ expect(state.drive_level(:nonexistent)).to eq(0.0)
71
+ end
72
+ end
73
+
74
+ describe '#satisfied?' do
75
+ it 'returns false initially' do
76
+ expect(state.satisfied?(:competence)).to be false
77
+ end
78
+
79
+ it 'returns false for unknown drive' do
80
+ expect(state.satisfied?(:nonexistent)).to be false
81
+ end
82
+
83
+ it 'returns true after sufficiently high signals' do
84
+ 10.times { state.update_drive(:competence, 1.0) }
85
+ expect(state.satisfied?(:competence)).to be true
86
+ end
87
+ end
88
+
89
+ describe '#intrinsic_average' do
90
+ it 'returns a float' do
91
+ expect(state.intrinsic_average).to be_a(Float)
92
+ end
93
+
94
+ it 'reflects only intrinsic drives' do
95
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::INTRINSIC_DRIVES.each do |d|
96
+ 10.times { state.update_drive(d, 1.0) }
97
+ end
98
+ expect(state.intrinsic_average).to be > state.extrinsic_average
99
+ end
100
+ end
101
+
102
+ describe '#extrinsic_average' do
103
+ it 'returns a float' do
104
+ expect(state.extrinsic_average).to be_a(Float)
105
+ end
106
+
107
+ it 'reflects only extrinsic drives' do
108
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::EXTRINSIC_DRIVES.each do |d|
109
+ 10.times { state.update_drive(d, 1.0) }
110
+ end
111
+ expect(state.extrinsic_average).to be > state.intrinsic_average
112
+ end
113
+ end
114
+
115
+ describe '#overall_level' do
116
+ it 'starts at 0.5' do
117
+ expect(state.overall_level).to eq(0.5)
118
+ end
119
+
120
+ it 'increases when drives are signalled high' do
121
+ initial = state.overall_level
122
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
123
+ state.update_drive(d, 1.0)
124
+ end
125
+ expect(state.overall_level).to be > initial
126
+ end
127
+ end
128
+
129
+ describe '#current_mode' do
130
+ it 'returns :maintenance at initial 0.5' do
131
+ expect(state.current_mode).to eq(:maintenance)
132
+ end
133
+
134
+ it 'returns :approach when overall level is high' do
135
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
136
+ 10.times { state.update_drive(d, 1.0) }
137
+ end
138
+ expect(state.current_mode).to eq(:approach)
139
+ end
140
+
141
+ it 'returns :dormant when overall level is very low' do
142
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
143
+ 20.times { state.update_drive(d, 0.0) }
144
+ end
145
+ expect(state.current_mode).to eq(:dormant)
146
+ end
147
+
148
+ it 'returns one of the defined modes' do
149
+ modes = Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::MOTIVATION_MODES
150
+ expect(modes).to include(state.current_mode)
151
+ end
152
+ end
153
+
154
+ describe '#decay_all' do
155
+ it 'decreases all drive levels' do
156
+ initial_levels = state.drives.transform_values { |d| d[:level] }
157
+ state.decay_all
158
+ state.drives.each do |type, d|
159
+ expect(d[:level]).to be <= initial_levels[type]
160
+ end
161
+ end
162
+
163
+ it 'does not drop drives below 0.0' do
164
+ 20.times { state.decay_all }
165
+ state.drives.each_value do |d|
166
+ expect(d[:level]).to be >= 0.0
167
+ end
168
+ end
169
+ end
170
+
171
+ describe '#amotivated?' do
172
+ it 'returns false at initial levels' do
173
+ expect(state.amotivated?).to be false
174
+ end
175
+
176
+ it 'returns true when all drives are very low' do
177
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
178
+ 20.times { state.update_drive(d, 0.0) }
179
+ end
180
+ expect(state.amotivated?).to be true
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Affect::Motivation::Helpers::MotivationStore do
6
+ subject(:store) { described_class.new }
7
+
8
+ describe '#initialize' do
9
+ it 'creates a default drive_state' do
10
+ expect(store.drive_state).to be_a(Legion::Extensions::Agentic::Affect::Motivation::Helpers::DriveState)
11
+ end
12
+
13
+ it 'starts with no goal motivations' do
14
+ expect(store.goal_motivations).to be_empty
15
+ end
16
+
17
+ it 'accepts an injected drive_state' do
18
+ ds = Legion::Extensions::Agentic::Affect::Motivation::Helpers::DriveState.new
19
+ s = described_class.new(drive_state: ds)
20
+ expect(s.drive_state).to be(ds)
21
+ end
22
+ end
23
+
24
+ describe '#commit_goal' do
25
+ it 'commits a goal with valid drives' do
26
+ result = store.commit_goal('goal_1', %i[autonomy competence])
27
+ expect(result).to be true
28
+ end
29
+
30
+ it 'stores the goal with drives and energy' do
31
+ store.commit_goal('goal_1', %i[autonomy])
32
+ entry = store.goal_motivations['goal_1']
33
+ expect(entry).to include(:drives, :energy, :committed)
34
+ end
35
+
36
+ it 'returns false for empty valid drives' do
37
+ result = store.commit_goal('bad_goal', [:nonexistent_drive])
38
+ expect(result).to be false
39
+ end
40
+
41
+ it 'filters invalid drives from list' do
42
+ result = store.commit_goal('mixed', %i[autonomy fake_drive])
43
+ expect(result).to be true
44
+ expect(store.goal_motivations['mixed'][:drives]).to eq([:autonomy])
45
+ end
46
+
47
+ it 'overwrites existing goal on recommit' do
48
+ store.commit_goal('goal_a', [:autonomy])
49
+ store.commit_goal('goal_a', [:competence])
50
+ expect(store.goal_motivations['goal_a'][:drives]).to eq([:competence])
51
+ end
52
+ end
53
+
54
+ describe '#release_goal' do
55
+ it 'removes the goal from tracking' do
56
+ store.commit_goal('goal_to_remove', [:autonomy])
57
+ store.release_goal('goal_to_remove')
58
+ expect(store.goal_motivations).not_to have_key('goal_to_remove')
59
+ end
60
+
61
+ it 'returns true even for unknown goal ids' do
62
+ expect(store.release_goal('nonexistent')).to be true
63
+ end
64
+ end
65
+
66
+ describe '#goal_energy' do
67
+ it 'returns 0.0 for unknown goal' do
68
+ expect(store.goal_energy('unknown')).to eq(0.0)
69
+ end
70
+
71
+ it 'returns a Float between 0 and 1 for a committed goal' do
72
+ store.commit_goal('energized', %i[autonomy competence])
73
+ energy = store.goal_energy('energized')
74
+ expect(energy).to be_a(Float)
75
+ expect(energy).to be_between(0.0, 1.0)
76
+ end
77
+ end
78
+
79
+ describe '#most_motivated_goal' do
80
+ it 'returns nil result when no goals committed' do
81
+ result = store.most_motivated_goal
82
+ expect(result).to be_nil
83
+ end
84
+
85
+ it 'returns the goal with highest energy' do
86
+ store.commit_goal('low_goal', [:obligation])
87
+ store.commit_goal('high_goal', %i[autonomy competence relatedness novelty])
88
+ # Signal high drives for high_goal
89
+ %i[autonomy competence relatedness novelty].each do |d|
90
+ 5.times { store.drive_state.update_drive(d, 1.0) }
91
+ end
92
+ result = store.most_motivated_goal
93
+ expect(result[:goal_id]).to eq('high_goal')
94
+ end
95
+
96
+ it 'includes goal_id, energy, and drives in result' do
97
+ store.commit_goal('g1', [:autonomy])
98
+ result = store.most_motivated_goal
99
+ expect(result).to include(:goal_id, :energy, :drives)
100
+ end
101
+ end
102
+
103
+ describe '#burnout_check' do
104
+ it 'returns burnout false initially' do
105
+ result = store.burnout_check
106
+ expect(result[:burnout]).to be false
107
+ end
108
+
109
+ it 'returns overall_level in result' do
110
+ result = store.burnout_check
111
+ expect(result[:overall_level]).to be_a(Float)
112
+ end
113
+
114
+ it 'returns low_motivation_ticks in result' do
115
+ result = store.burnout_check
116
+ expect(result).to have_key(:low_motivation_ticks)
117
+ end
118
+
119
+ it 'increments low_motivation_ticks when level is very low' do
120
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
121
+ 20.times { store.drive_state.update_drive(d, 0.0) }
122
+ end
123
+ store.burnout_check
124
+ result = store.burnout_check
125
+ expect(result[:low_motivation_ticks]).to be >= 1
126
+ end
127
+
128
+ it 'detects burnout after 10 consecutive low ticks' do
129
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
130
+ 20.times { store.drive_state.update_drive(d, 0.0) }
131
+ end
132
+ 11.times { store.burnout_check }
133
+ result = store.burnout_check
134
+ expect(result[:burnout]).to be true
135
+ end
136
+
137
+ it 'resets counter when level recovers' do
138
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
139
+ 20.times { store.drive_state.update_drive(d, 0.0) }
140
+ end
141
+ 5.times { store.burnout_check }
142
+
143
+ Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::DRIVE_TYPES.each do |d|
144
+ 10.times { store.drive_state.update_drive(d, 1.0) }
145
+ end
146
+ result = store.burnout_check
147
+ expect(result[:low_motivation_ticks]).to eq(0)
148
+ end
149
+ end
150
+
151
+ describe '#stats' do
152
+ it 'returns overall_level' do
153
+ expect(store.stats).to have_key(:overall_level)
154
+ end
155
+
156
+ it 'returns current_mode' do
157
+ expect(store.stats).to have_key(:current_mode)
158
+ end
159
+
160
+ it 'returns intrinsic_average' do
161
+ expect(store.stats).to have_key(:intrinsic_average)
162
+ end
163
+
164
+ it 'returns extrinsic_average' do
165
+ expect(store.stats).to have_key(:extrinsic_average)
166
+ end
167
+
168
+ it 'returns amotivated flag' do
169
+ expect(store.stats).to have_key(:amotivated)
170
+ end
171
+
172
+ it 'returns goal_count' do
173
+ store.commit_goal('g1', [:autonomy])
174
+ expect(store.stats[:goal_count]).to eq(1)
175
+ end
176
+ end
177
+
178
+ describe 'goal cap (MAX_GOALS)' do
179
+ it 'does not exceed MAX_GOALS entries' do
180
+ max = Legion::Extensions::Agentic::Affect::Motivation::Helpers::Constants::MAX_GOALS
181
+ (max + 5).times { |i| store.commit_goal("goal_#{i}", [:autonomy]) }
182
+ expect(store.goal_motivations.size).to be <= max
183
+ end
184
+ end
185
+ end