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,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Reappraisal
8
+ module Helpers
9
+ module LlmEnhancer
10
+ SYSTEM_PROMPT = <<~PROMPT
11
+ You are the emotion regulation processor for an autonomous AI agent built on LegionIO.
12
+ You practice cognitive reappraisal — re-interpreting emotional events to change their impact.
13
+ Generate genuine, psychologically-grounded re-framings. Be specific to the event content.
14
+ Do not dismiss or minimize. Reframe with depth and insight.
15
+ PROMPT
16
+
17
+ module_function
18
+
19
+ def available?
20
+ !!(defined?(Legion::LLM) && Legion::LLM.respond_to?(:started?) && Legion::LLM.started?)
21
+ rescue StandardError
22
+ false
23
+ end
24
+
25
+ def generate_reappraisal(event_content:, initial_appraisal:, strategy:, valence:, intensity:)
26
+ prompt = build_generate_reappraisal_prompt(
27
+ event_content: event_content,
28
+ initial_appraisal: initial_appraisal,
29
+ strategy: strategy,
30
+ valence: valence,
31
+ intensity: intensity
32
+ )
33
+ response = llm_ask(prompt)
34
+ parse_generate_reappraisal_response(response)
35
+ rescue StandardError => e
36
+ Legion::Logging.warn "[cognitive_reappraisal:llm] generate_reappraisal failed: #{e.message}"
37
+ nil
38
+ end
39
+
40
+ def llm_ask(prompt)
41
+ chat = Legion::LLM.chat
42
+ chat.with_instructions(SYSTEM_PROMPT)
43
+ chat.ask(prompt)
44
+ end
45
+ private_class_method :llm_ask
46
+
47
+ def build_generate_reappraisal_prompt(event_content:, initial_appraisal:, strategy:, valence:, intensity:)
48
+ <<~PROMPT
49
+ An emotional event needs cognitive reappraisal.
50
+
51
+ EVENT: #{event_content}
52
+ CURRENT APPRAISAL: #{initial_appraisal}
53
+ VALENCE: #{valence} (negative = aversive, positive = pleasant)
54
+ INTENSITY: #{intensity} (0-1, how activating)
55
+ STRATEGY: #{strategy}
56
+
57
+ Strategy guidelines:
58
+ - reinterpretation: re-frame the meaning of the event
59
+ - distancing: create psychological distance from the event
60
+ - benefit_finding: identify positive outcomes or growth opportunities
61
+ - normalizing: recognize this as a common experience
62
+ - perspective_taking: view from another agent's or future self's perspective
63
+ - temporal_distancing: project forward — how will this matter in a week/month?
64
+
65
+ Generate a specific, insightful reappraisal using the given strategy.
66
+
67
+ Format EXACTLY as:
68
+ REAPPRAISAL: <1-2 sentence reappraisal that applies the strategy to this specific event>
69
+ PROMPT
70
+ end
71
+ private_class_method :build_generate_reappraisal_prompt
72
+
73
+ def parse_generate_reappraisal_response(response)
74
+ return nil unless response&.content
75
+
76
+ match = response.content.match(/REAPPRAISAL:\s*(.+)/im)
77
+ return nil unless match
78
+
79
+ { new_appraisal: match.captures.first.strip }
80
+ end
81
+ private_class_method :parse_generate_reappraisal_response
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Reappraisal
8
+ module Helpers
9
+ class ReappraisalEngine
10
+ include Constants
11
+
12
+ attr_reader :events, :reappraisal_log
13
+
14
+ def initialize
15
+ @events = {}
16
+ @reappraisal_log = []
17
+ end
18
+
19
+ def register_event(content:, valence:, intensity:, appraisal:)
20
+ event = EmotionalEvent.new(
21
+ content: content,
22
+ valence: valence,
23
+ intensity: intensity,
24
+ appraisal: appraisal
25
+ )
26
+
27
+ @events.shift while @events.size >= Constants::MAX_EVENTS
28
+ @events[event.id] = event
29
+ event
30
+ end
31
+
32
+ def reappraise(event_id:, strategy:, new_appraisal:)
33
+ event = @events[event_id]
34
+ return { success: false, reason: :event_not_found } unless event
35
+ return { success: false, reason: :invalid_strategy } unless Constants.valid_strategy?(strategy)
36
+
37
+ old_valence = event.current_valence
38
+ old_intensity = event.current_intensity
39
+
40
+ change = event.reappraise!(strategy: strategy, new_appraisal: new_appraisal)
41
+
42
+ log_entry = {
43
+ event_id: event_id,
44
+ strategy: strategy,
45
+ valence_change: (event.current_valence - old_valence).round(10),
46
+ intensity_change: (old_intensity - event.current_intensity).round(10),
47
+ applied_at: Time.now.utc
48
+ }
49
+
50
+ @reappraisal_log.shift while @reappraisal_log.size >= Constants::MAX_REAPPRAISALS
51
+ @reappraisal_log << log_entry
52
+
53
+ {
54
+ success: true,
55
+ event_id: event_id,
56
+ strategy: strategy,
57
+ change: change.round(10),
58
+ current_valence: event.current_valence.round(10),
59
+ current_intensity: event.current_intensity.round(10)
60
+ }
61
+ end
62
+
63
+ def auto_reappraise(event_id:)
64
+ event = @events[event_id]
65
+ return { success: false, reason: :event_not_found } unless event
66
+
67
+ strategy = select_strategy(event)
68
+ new_appraisal = "auto-reappraised via #{strategy}"
69
+ reappraise(event_id: event_id, strategy: strategy, new_appraisal: new_appraisal)
70
+ end
71
+
72
+ def negative_events
73
+ @events.values.select(&:negative?)
74
+ end
75
+
76
+ def intense_events
77
+ @events.values.select(&:intense?)
78
+ end
79
+
80
+ def most_regulated(limit: 5)
81
+ @events.values
82
+ .sort_by { |e| -e.regulation_amount }
83
+ .first(limit)
84
+ end
85
+
86
+ def strategy_effectiveness
87
+ grouped = @reappraisal_log.group_by { |entry| entry[:strategy] }
88
+ grouped.transform_values do |entries|
89
+ changes = entries.map { |e| e[:valence_change] }
90
+ changes.sum.to_f / changes.size
91
+ end
92
+ end
93
+
94
+ def average_regulation
95
+ return 0.0 if @events.empty?
96
+
97
+ total = @events.values.sum(&:regulation_amount)
98
+ (total / @events.size).round(10)
99
+ end
100
+
101
+ def overall_regulation_ability
102
+ return 0.0 if @events.empty?
103
+
104
+ regulated_count = @events.values.count { |e| e.regulation_amount > 0.0 }
105
+ mean_reg = average_regulation
106
+ coverage = regulated_count.to_f / @events.size
107
+
108
+ ((mean_reg + coverage) / 2.0).round(10)
109
+ end
110
+
111
+ def reappraisal_report
112
+ {
113
+ total_events: @events.size,
114
+ total_reappraisals: @reappraisal_log.size,
115
+ negative_events: negative_events.size,
116
+ intense_events: intense_events.size,
117
+ average_regulation: average_regulation,
118
+ overall_regulation_ability: overall_regulation_ability,
119
+ strategy_effectiveness: strategy_effectiveness,
120
+ most_regulated: most_regulated(limit: 3).map(&:to_h)
121
+ }
122
+ end
123
+
124
+ def to_h
125
+ {
126
+ events: @events.transform_values(&:to_h),
127
+ reappraisal_log: @reappraisal_log,
128
+ average_regulation: average_regulation,
129
+ overall_regulation_ability: overall_regulation_ability,
130
+ strategy_effectiveness: strategy_effectiveness
131
+ }
132
+ end
133
+
134
+ private
135
+
136
+ def select_strategy(event)
137
+ if event.negative? && event.intense?
138
+ :distancing
139
+ elsif event.negative?
140
+ :reinterpretation
141
+ elsif event.intense?
142
+ :temporal_distancing
143
+ else
144
+ :benefit_finding
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Reappraisal
8
+ module Runners
9
+ module CognitiveReappraisal
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ def register_event(content:, valence:, intensity:, appraisal:, engine: nil, **)
14
+ eng = engine || reappraisal_engine
15
+ event = eng.register_event(content: content, valence: valence, intensity: intensity, appraisal: appraisal)
16
+
17
+ Legion::Logging.debug "[cognitive_reappraisal] registered event id=#{event.id[0..7]} " \
18
+ "valence=#{event.initial_valence.round(2)} intensity=#{event.initial_intensity.round(2)}"
19
+
20
+ {
21
+ success: true,
22
+ event_id: event.id,
23
+ valence: event.initial_valence.round(10),
24
+ intensity: event.initial_intensity.round(10),
25
+ negative: event.negative?,
26
+ intense: event.intense?
27
+ }
28
+ end
29
+
30
+ def reappraise_event(event_id:, strategy:, new_appraisal:, engine: nil, **)
31
+ unless Helpers::Constants.valid_strategy?(strategy)
32
+ return { success: false, reason: :invalid_strategy, valid_strategies: Helpers::Constants::STRATEGIES }
33
+ end
34
+
35
+ eng = engine || reappraisal_engine
36
+ appraisal = llm_appraisal_for(eng.events[event_id], strategy) || new_appraisal
37
+ result = eng.reappraise(event_id: event_id, strategy: strategy, new_appraisal: appraisal)
38
+
39
+ if result[:success]
40
+ Legion::Logging.info "[cognitive_reappraisal] reappraised event=#{event_id[0..7]} " \
41
+ "strategy=#{strategy} change=#{result[:change].round(2)}"
42
+ else
43
+ Legion::Logging.debug "[cognitive_reappraisal] reappraisal failed event=#{event_id[0..7]} reason=#{result[:reason]}"
44
+ end
45
+
46
+ result
47
+ end
48
+
49
+ def auto_reappraise_event(event_id:, engine: nil, **)
50
+ eng = engine || reappraisal_engine
51
+ event = eng.events[event_id]
52
+ return { success: false, reason: :event_not_found } unless event
53
+
54
+ strategy = select_strategy_for(event)
55
+ appraisal = llm_appraisal_for(event, strategy) || "auto-reappraised via #{strategy}"
56
+ result = eng.reappraise(event_id: event_id, strategy: strategy, new_appraisal: appraisal)
57
+
58
+ if result[:success]
59
+ Legion::Logging.info "[cognitive_reappraisal] auto-reappraised event=#{event_id[0..7]} " \
60
+ "strategy=#{strategy}"
61
+ else
62
+ Legion::Logging.debug "[cognitive_reappraisal] auto-reappraisal failed: #{result[:reason]}"
63
+ end
64
+
65
+ result
66
+ end
67
+
68
+ def negative_events(engine: nil, **)
69
+ eng = engine || reappraisal_engine
70
+ events = eng.negative_events
71
+ Legion::Logging.debug "[cognitive_reappraisal] negative events count=#{events.size}"
72
+ { events: events.map(&:to_h), count: events.size }
73
+ end
74
+
75
+ def intense_events(engine: nil, **)
76
+ eng = engine || reappraisal_engine
77
+ events = eng.intense_events
78
+ Legion::Logging.debug "[cognitive_reappraisal] intense events count=#{events.size}"
79
+ { events: events.map(&:to_h), count: events.size }
80
+ end
81
+
82
+ def most_regulated_events(limit: 5, engine: nil, **)
83
+ eng = engine || reappraisal_engine
84
+ events = eng.most_regulated(limit: limit)
85
+ Legion::Logging.debug "[cognitive_reappraisal] most regulated count=#{events.size}"
86
+ { events: events.map(&:to_h), count: events.size }
87
+ end
88
+
89
+ def reappraisal_status(engine: nil, **)
90
+ eng = engine || reappraisal_engine
91
+ Legion::Logging.debug "[cognitive_reappraisal] status: overall=#{eng.overall_regulation_ability.round(2)}"
92
+ {
93
+ overall_regulation_ability: eng.overall_regulation_ability,
94
+ average_regulation: eng.average_regulation,
95
+ total_events: eng.events.size,
96
+ total_reappraisals: eng.reappraisal_log.size,
97
+ strategy_effectiveness: eng.strategy_effectiveness
98
+ }
99
+ end
100
+
101
+ def reappraisal_report(engine: nil, **)
102
+ eng = engine || reappraisal_engine
103
+ Legion::Logging.debug '[cognitive_reappraisal] generating report'
104
+ { success: true, report: eng.reappraisal_report }
105
+ end
106
+
107
+ def regulate_pending_events(engine: nil, **)
108
+ eng = engine || reappraisal_engine
109
+ events = eng.events.values
110
+ checked = events.size
111
+ regulated = 0
112
+ event_ids = []
113
+
114
+ events.each do |event|
115
+ next unless event.negative? && event.reappraisal_count.zero?
116
+
117
+ result = eng.auto_reappraise(event_id: event.id)
118
+ next unless result[:success]
119
+
120
+ regulated += 1
121
+ event_ids << event.id
122
+ end
123
+
124
+ Legion::Logging.debug "[reappraisal] regulate pending: checked=#{checked} regulated=#{regulated}"
125
+ { checked: checked, regulated: regulated, event_ids: event_ids }
126
+ end
127
+
128
+ private
129
+
130
+ def reappraisal_engine
131
+ @reappraisal_engine ||= Helpers::ReappraisalEngine.new
132
+ end
133
+
134
+ def llm_appraisal_for(event, strategy)
135
+ return nil unless event && Helpers::LlmEnhancer.available?
136
+
137
+ result = Helpers::LlmEnhancer.generate_reappraisal(
138
+ event_content: event.content,
139
+ initial_appraisal: event.appraisal,
140
+ strategy: strategy,
141
+ valence: event.current_valence,
142
+ intensity: event.current_intensity
143
+ )
144
+ result&.fetch(:new_appraisal, nil)
145
+ end
146
+
147
+ def select_strategy_for(event)
148
+ if event.negative? && event.intense?
149
+ :distancing
150
+ elsif event.negative?
151
+ :reinterpretation
152
+ elsif event.intense?
153
+ :temporal_distancing
154
+ else
155
+ :benefit_finding
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Reappraisal
8
+ VERSION = '0.1.1'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/affect/reappraisal/version'
4
+ require 'legion/extensions/agentic/affect/reappraisal/helpers/constants'
5
+ require 'legion/extensions/agentic/affect/reappraisal/helpers/emotional_event'
6
+ require 'legion/extensions/agentic/affect/reappraisal/helpers/reappraisal_engine'
7
+ require 'legion/extensions/agentic/affect/reappraisal/helpers/llm_enhancer'
8
+ require 'legion/extensions/agentic/affect/reappraisal/runners/cognitive_reappraisal'
9
+ require 'legion/extensions/agentic/affect/reappraisal/client'
10
+
11
+ module Legion
12
+ module Extensions
13
+ module Agentic
14
+ module Affect
15
+ module Reappraisal
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/affect/regulation/helpers/constants'
4
+ require 'legion/extensions/agentic/affect/regulation/helpers/regulation_model'
5
+ require 'legion/extensions/agentic/affect/regulation/runners/emotional_regulation'
6
+
7
+ module Legion
8
+ module Extensions
9
+ module Agentic
10
+ module Affect
11
+ module Regulation
12
+ class Client
13
+ include Runners::EmotionalRegulation
14
+
15
+ attr_reader :regulation_model
16
+
17
+ def initialize(regulation_model: nil, **)
18
+ @regulation_model = regulation_model || Helpers::RegulationModel.new
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Regulation
8
+ module Helpers
9
+ module Constants
10
+ STRATEGIES = %i[
11
+ situation_selection
12
+ situation_modification
13
+ attentional_deployment
14
+ cognitive_reappraisal
15
+ response_suppression
16
+ ].freeze
17
+
18
+ # How much each strategy reduces unwanted emotion magnitude (0..1)
19
+ STRATEGY_EFFECTIVENESS = {
20
+ situation_selection: 0.8,
21
+ situation_modification: 0.6,
22
+ attentional_deployment: 0.5,
23
+ cognitive_reappraisal: 0.7,
24
+ response_suppression: 0.3
25
+ }.freeze
26
+
27
+ # Cognitive/energetic cost of applying each strategy (0..1)
28
+ STRATEGY_COST = {
29
+ situation_selection: 0.1,
30
+ situation_modification: 0.2,
31
+ attentional_deployment: 0.15,
32
+ cognitive_reappraisal: 0.25,
33
+ response_suppression: 0.35
34
+ }.freeze
35
+
36
+ # EMA alpha for skill updating
37
+ REGULATION_ALPHA = 0.12
38
+
39
+ # Initial per-strategy proficiency
40
+ DEFAULT_SKILL = 0.3
41
+
42
+ # Improvement per successful regulated use
43
+ SKILL_GAIN = 0.05
44
+
45
+ # Per-tick decay toward DEFAULT_SKILL
46
+ SKILL_DECAY = 0.01
47
+
48
+ # Maximum regulation events retained in history
49
+ MAX_REGULATION_HISTORY = 200
50
+
51
+ # Consecutive suppression uses before a penalty applies
52
+ SUPPRESSION_PENALTY_THRESHOLD = 5
53
+
54
+ # Bonus applied to recommendation score when reappraisal is chosen
55
+ REAPPRAISAL_BONUS = 0.1
56
+
57
+ # Human-readable proficiency labels keyed by magnitude ranges
58
+ REGULATION_LABELS = {
59
+ (0.8..) => :masterful,
60
+ (0.6...0.8) => :proficient,
61
+ (0.4...0.6) => :developing,
62
+ (0.2...0.4) => :novice,
63
+ (..0.2) => :reactive
64
+ }.freeze
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end