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,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Affect
9
+ module Contagion
10
+ module Helpers
11
+ class Meme
12
+ attr_reader :id, :label, :contagion_type, :virulence,
13
+ :carriers, :recovered, :immune,
14
+ :total_transmissions, :created_at
15
+
16
+ def initialize(label:, contagion_type: :cognitive, virulence: Constants::DEFAULT_VIRULENCE)
17
+ @id = SecureRandom.uuid
18
+ @label = label
19
+ @contagion_type = validate_contagion_type(contagion_type)
20
+ @virulence = virulence.clamp(0.0, 1.0).round(10)
21
+ @carriers = Set.new
22
+ @recovered = Set.new
23
+ @immune = Set.new
24
+ @total_transmissions = 0
25
+ @created_at = Time.now.utc
26
+ end
27
+
28
+ def virulence_label
29
+ Constants::VIRULENCE_LABELS.find { |range, _| range.cover?(@virulence) }&.last || :contained
30
+ end
31
+
32
+ def carrier_count
33
+ @carriers.size
34
+ end
35
+
36
+ def transmission_rate
37
+ return 0.0 if @carriers.empty?
38
+
39
+ (@total_transmissions.to_f / @carriers.size).round(10)
40
+ end
41
+
42
+ def infect!(agent_id:)
43
+ return :already_carrier if @carriers.include?(agent_id)
44
+ return :immune if @immune.include?(agent_id)
45
+
46
+ @carriers.add(agent_id)
47
+ @recovered.delete(agent_id)
48
+ @total_transmissions += 1
49
+ :infected
50
+ end
51
+
52
+ def recover!(agent_id:)
53
+ return :not_a_carrier unless @carriers.include?(agent_id)
54
+
55
+ @carriers.delete(agent_id)
56
+ @recovered.add(agent_id)
57
+ :recovered
58
+ end
59
+
60
+ def immunize!(agent_id:)
61
+ @carriers.delete(agent_id)
62
+ @immune.add(agent_id)
63
+ :immunized
64
+ end
65
+
66
+ def carrying?(agent_id:)
67
+ @carriers.include?(agent_id)
68
+ end
69
+
70
+ def to_h
71
+ {
72
+ id: @id,
73
+ label: @label,
74
+ contagion_type: @contagion_type,
75
+ virulence: @virulence,
76
+ virulence_label: virulence_label,
77
+ carrier_count: carrier_count,
78
+ recovered_count: @recovered.size,
79
+ immune_count: @immune.size,
80
+ total_transmissions: @total_transmissions,
81
+ transmission_rate: transmission_rate,
82
+ created_at: @created_at
83
+ }
84
+ end
85
+
86
+ private
87
+
88
+ def validate_contagion_type(type)
89
+ Constants::CONTAGION_TYPES.include?(type) ? type : :cognitive
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Contagion
8
+ module Runners
9
+ module CognitiveContagion
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ def create_meme(label:, contagion_type: :cognitive, virulence: nil, **)
14
+ v = virulence || Helpers::Constants::DEFAULT_VIRULENCE
15
+ result = engine.create_meme(label: label, contagion_type: contagion_type, virulence: v)
16
+
17
+ if result.is_a?(Hash) && result[:error]
18
+ Legion::Logging.warn "[cognitive_contagion] create_meme failed: #{result[:error]}"
19
+ return result
20
+ end
21
+
22
+ Legion::Logging.info "[cognitive_contagion] meme created: id=#{result.id} label=#{label} " \
23
+ "virulence=#{result.virulence} type=#{contagion_type}"
24
+ result.to_h
25
+ end
26
+
27
+ def register_agent(agent_id:, resistance: nil, **)
28
+ r = resistance || Helpers::Constants::DEFAULT_RESISTANCE
29
+ result = engine.register_agent(agent_id: agent_id, resistance: r)
30
+
31
+ if result.is_a?(Hash) && result[:error]
32
+ Legion::Logging.warn "[cognitive_contagion] register_agent failed: #{result[:error]}"
33
+ return result
34
+ end
35
+
36
+ Legion::Logging.debug "[cognitive_contagion] agent registered: id=#{agent_id} resistance=#{r}"
37
+ result
38
+ end
39
+
40
+ def attempt_transmission(meme_id:, source_agent_id:, target_agent_id:, **)
41
+ result = engine.attempt_transmission(
42
+ meme_id: meme_id,
43
+ source_agent_id: source_agent_id,
44
+ target_agent_id: target_agent_id
45
+ )
46
+ Legion::Logging.debug "[cognitive_contagion] transmission: meme=#{meme_id} " \
47
+ "#{source_agent_id}->#{target_agent_id} transmitted=#{result[:transmitted]}"
48
+ result
49
+ end
50
+
51
+ def recover_agent(meme_id:, agent_id:, **)
52
+ result = engine.recover_agent(meme_id: meme_id, agent_id: agent_id)
53
+ Legion::Logging.debug "[cognitive_contagion] recover: meme=#{meme_id} agent=#{agent_id} " \
54
+ "result=#{result[:result]}"
55
+ result
56
+ end
57
+
58
+ def infect_agent(meme_id:, agent_id:, **)
59
+ meme = engine.memes[meme_id]
60
+ return { infected: false, reason: :meme_not_found } unless meme
61
+
62
+ result = meme.infect!(agent_id: agent_id)
63
+ Legion::Logging.debug "[cognitive_contagion] infect_agent: meme=#{meme_id} agent=#{agent_id} result=#{result}"
64
+ { infected: result == :infected, agent_id: agent_id, meme_id: meme_id, result: result }
65
+ end
66
+
67
+ def immunize_agent(meme_id:, agent_id:, **)
68
+ result = engine.immunize_agent(meme_id: meme_id, agent_id: agent_id)
69
+ Legion::Logging.debug "[cognitive_contagion] immunize: meme=#{meme_id} agent=#{agent_id}"
70
+ result
71
+ end
72
+
73
+ def spread_step(meme_id:, **)
74
+ result = engine.spread_step(meme_id: meme_id)
75
+ Legion::Logging.info "[cognitive_contagion] spread_step: meme=#{meme_id} " \
76
+ "transmissions=#{result[:transmissions]} recoveries=#{result[:recoveries]}"
77
+ result
78
+ end
79
+
80
+ def epidemic_report(meme_id:, **)
81
+ result = engine.epidemic_report(meme_id: meme_id)
82
+ Legion::Logging.debug "[cognitive_contagion] epidemic_report: meme=#{meme_id} " \
83
+ "infected=#{result[:infected]} virulence_label=#{result[:virulence_label]}"
84
+ result
85
+ end
86
+
87
+ def most_viral(limit: 5, **)
88
+ results = engine.most_viral(limit: limit)
89
+ Legion::Logging.debug "[cognitive_contagion] most_viral: limit=#{limit} count=#{results.size}"
90
+ { memes: results, count: results.size }
91
+ end
92
+
93
+ def agent_status(agent_id:, meme_id:, **)
94
+ result = engine.agent_status(agent_id: agent_id, meme_id: meme_id)
95
+ Legion::Logging.debug "[cognitive_contagion] agent_status: agent=#{agent_id} " \
96
+ "meme=#{meme_id} status=#{result[:status]}"
97
+ result
98
+ end
99
+
100
+ def susceptible_agents(meme_id:, **)
101
+ agents = engine.susceptible_agents(meme_id: meme_id)
102
+ Legion::Logging.debug "[cognitive_contagion] susceptible_agents: meme=#{meme_id} count=#{agents.size}"
103
+ { agents: agents, count: agents.size, meme_id: meme_id }
104
+ end
105
+
106
+ def contagion_status(**)
107
+ Legion::Logging.debug '[cognitive_contagion] contagion_status requested'
108
+ summary = engine.to_h.slice(:meme_count, :agent_count)
109
+ summary.merge(contagion_types: Helpers::Constants::CONTAGION_TYPES,
110
+ max_agents: Helpers::Constants::MAX_AGENTS,
111
+ max_memes: Helpers::Constants::MAX_MEMES)
112
+ end
113
+
114
+ private
115
+
116
+ def engine
117
+ @engine ||= Helpers::ContagionEngine.new
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ 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 Contagion
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/affect/contagion/version'
4
+ require 'legion/extensions/agentic/affect/contagion/helpers/constants'
5
+ require 'legion/extensions/agentic/affect/contagion/helpers/meme'
6
+ require 'legion/extensions/agentic/affect/contagion/helpers/contagion_engine'
7
+ require 'legion/extensions/agentic/affect/contagion/runners/cognitive_contagion'
8
+ require 'legion/extensions/agentic/affect/contagion/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module Agentic
13
+ module Affect
14
+ module Contagion
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/affect/defusion/helpers/constants'
4
+ require 'legion/extensions/agentic/affect/defusion/helpers/thought'
5
+ require 'legion/extensions/agentic/affect/defusion/helpers/defusion_engine'
6
+ require 'legion/extensions/agentic/affect/defusion/runners/cognitive_defusion'
7
+
8
+ module Legion
9
+ module Extensions
10
+ module Agentic
11
+ module Affect
12
+ module Defusion
13
+ class Client
14
+ include Runners::CognitiveDefusion
15
+
16
+ def initialize(engine: nil)
17
+ @defusion_engine = engine || Helpers::DefusionEngine.new
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :defusion_engine
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Defusion
8
+ module Helpers
9
+ module Constants
10
+ MAX_THOUGHTS = 300
11
+ DEFAULT_FUSION = 0.7
12
+ FUSION_DELTA_FUSE = 0.05
13
+ FUSION_DELTA_VISIT = 0.02
14
+
15
+ DEFUSION_TECHNIQUES = %i[labeling distancing contextualization acceptance reframing metaphor].freeze
16
+
17
+ TECHNIQUE_POTENCY = {
18
+ labeling: 0.08,
19
+ distancing: 0.12,
20
+ contextualization: 0.10,
21
+ acceptance: 0.15,
22
+ reframing: 0.10,
23
+ metaphor: 0.06
24
+ }.freeze
25
+
26
+ FUSION_LABELS = {
27
+ (0.8..) => :enmeshed,
28
+ (0.6...0.8) => :fused,
29
+ (0.4...0.6) => :partially_fused,
30
+ (0.2...0.4) => :defused,
31
+ (..0.2) => :fully_defused
32
+ }.freeze
33
+
34
+ BELIEF_LABELS = {
35
+ (0.8..) => :entrenched,
36
+ (0.6...0.8) => :strong,
37
+ (0.4...0.6) => :moderate,
38
+ (0.2...0.4) => :weak,
39
+ (..0.2) => :negligible
40
+ }.freeze
41
+
42
+ FUSION_THRESHOLD = 0.7
43
+ DEFUSED_THRESHOLD = 0.3
44
+ RUMINATION_COUNT = 3
45
+
46
+ THOUGHT_TYPES = %i[belief assumption evaluation prediction judgment self_concept rule].freeze
47
+
48
+ # Technique recommendations by thought type
49
+ RECOMMENDED_TECHNIQUES = {
50
+ belief: :acceptance,
51
+ assumption: :contextualization,
52
+ evaluation: :distancing,
53
+ prediction: :reframing,
54
+ judgment: :labeling,
55
+ self_concept: :distancing,
56
+ rule: :contextualization
57
+ }.freeze
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Affect
7
+ module Defusion
8
+ module Helpers
9
+ class DefusionEngine
10
+ include Constants
11
+
12
+ attr_reader :thoughts, :defusion_history
13
+
14
+ def initialize
15
+ @thoughts = {}
16
+ @defusion_history = []
17
+ end
18
+
19
+ def register_thought(content:, thought_type:, belief_strength: 0.5)
20
+ return { error: :invalid_thought_type, valid: THOUGHT_TYPES } unless THOUGHT_TYPES.include?(thought_type)
21
+
22
+ if @thoughts.size >= MAX_THOUGHTS
23
+ oldest = @thoughts.values.min_by(&:created_at)
24
+ @thoughts.delete(oldest.id) if oldest
25
+ end
26
+
27
+ thought = Thought.new(content: content, thought_type: thought_type, belief_strength: belief_strength)
28
+ @thoughts[thought.id] = thought
29
+ { thought_id: thought.id, thought: thought.to_h }
30
+ end
31
+
32
+ def apply_defusion(thought_id:, technique:)
33
+ thought = @thoughts[thought_id]
34
+ return { error: :thought_not_found } unless thought
35
+ return { error: :invalid_technique, valid: DEFUSION_TECHNIQUES } unless DEFUSION_TECHNIQUES.include?(technique)
36
+
37
+ before_fusion = thought.fusion_level
38
+ result = thought.defuse!(technique: technique)
39
+
40
+ @defusion_history << {
41
+ thought_id: thought_id,
42
+ technique: technique,
43
+ before_fusion: before_fusion,
44
+ after_fusion: thought.fusion_level,
45
+ at: Time.now.utc
46
+ }
47
+
48
+ {
49
+ success: true,
50
+ thought_id: thought_id,
51
+ technique: technique,
52
+ before: result[:before],
53
+ after: result[:after],
54
+ reduction: result[:reduction],
55
+ fusion_label: thought.fusion_label,
56
+ defused: thought.defused?
57
+ }
58
+ end
59
+
60
+ def apply_all_techniques(thought_id:)
61
+ thought = @thoughts[thought_id]
62
+ return { error: :thought_not_found } unless thought
63
+
64
+ results = DEFUSION_TECHNIQUES.map do |technique|
65
+ apply_defusion(thought_id: thought_id, technique: technique)
66
+ end
67
+
68
+ {
69
+ thought_id: thought_id,
70
+ techniques: results,
71
+ final_fusion: thought.fusion_level,
72
+ fusion_label: thought.fusion_label,
73
+ defused: thought.defused?,
74
+ total_applied: results.size
75
+ }
76
+ end
77
+
78
+ def visit_thought(thought_id:)
79
+ thought = @thoughts[thought_id]
80
+ return { error: :thought_not_found } unless thought
81
+
82
+ result = thought.visit!
83
+ {
84
+ thought_id: thought_id,
85
+ visit_count: result[:visit_count],
86
+ fusion: thought.fusion_level,
87
+ ruminating: thought.ruminating?
88
+ }
89
+ end
90
+
91
+ def enmeshed_thoughts
92
+ @thoughts.values.select(&:enmeshed?)
93
+ end
94
+
95
+ def defused_thoughts
96
+ @thoughts.values.select(&:defused?)
97
+ end
98
+
99
+ def ruminating_thoughts
100
+ @thoughts.values.select(&:ruminating?)
101
+ end
102
+
103
+ def most_fused(limit: 5)
104
+ @thoughts.values
105
+ .sort_by { |t| -t.fusion_level }
106
+ .first(limit)
107
+ end
108
+
109
+ def recommend_technique(thought_id:)
110
+ thought = @thoughts[thought_id]
111
+ return { error: :thought_not_found } unless thought
112
+
113
+ technique = RECOMMENDED_TECHNIQUES.fetch(thought.thought_type, :acceptance)
114
+ potency = TECHNIQUE_POTENCY[technique]
115
+
116
+ {
117
+ thought_id: thought_id,
118
+ thought_type: thought.thought_type,
119
+ technique: technique,
120
+ potency: potency,
121
+ current_fusion: thought.fusion_level,
122
+ projected_fusion: (thought.fusion_level - potency).clamp(0.0, 1.0).round(10)
123
+ }
124
+ end
125
+
126
+ def average_fusion
127
+ return 0.0 if @thoughts.empty?
128
+
129
+ total = @thoughts.values.sum(&:fusion_level)
130
+ (total / @thoughts.size).round(10)
131
+ end
132
+
133
+ def defusion_effectiveness
134
+ return 0.0 if @defusion_history.empty?
135
+
136
+ total_reduction = @defusion_history.sum { |h| h[:before_fusion] - h[:after_fusion] }
137
+ (total_reduction / @defusion_history.size).round(10)
138
+ end
139
+
140
+ def defusion_report
141
+ all = @thoughts.values
142
+ {
143
+ total_thoughts: all.size,
144
+ enmeshed_count: all.count(&:enmeshed?),
145
+ defused_count: all.count(&:defused?),
146
+ ruminating_count: all.count(&:ruminating?),
147
+ average_fusion: average_fusion,
148
+ defusion_attempts: @defusion_history.size,
149
+ defusion_effectiveness: defusion_effectiveness,
150
+ most_fused: most_fused(limit: 3).map(&:to_h)
151
+ }
152
+ end
153
+
154
+ def to_h
155
+ {
156
+ thoughts: @thoughts.transform_values(&:to_h),
157
+ defusion_history: @defusion_history,
158
+ report: defusion_report
159
+ }
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Affect
9
+ module Defusion
10
+ module Helpers
11
+ class Thought
12
+ include Constants
13
+
14
+ attr_reader :id, :content, :thought_type, :belief_strength,
15
+ :fusion_level, :defusion_count, :visit_count, :created_at
16
+
17
+ def initialize(content:, thought_type:, belief_strength:)
18
+ @id = SecureRandom.uuid
19
+ @content = content
20
+ @thought_type = thought_type
21
+ @belief_strength = belief_strength.clamp(0.0, 1.0)
22
+ @fusion_level = DEFAULT_FUSION
23
+ @defusion_count = 0
24
+ @visit_count = 0
25
+ @created_at = Time.now.utc
26
+ end
27
+
28
+ def defuse!(technique:)
29
+ potency = TECHNIQUE_POTENCY.fetch(technique, 0.0)
30
+ before = @fusion_level
31
+ @fusion_level = (@fusion_level - potency).clamp(0.0, 1.0).round(10)
32
+ @defusion_count += 1
33
+ { before: before, after: @fusion_level, technique: technique, reduction: (before - @fusion_level).round(10) }
34
+ end
35
+
36
+ def fuse!
37
+ before = @fusion_level
38
+ @fusion_level = (@fusion_level + FUSION_DELTA_FUSE).clamp(0.0, 1.0).round(10)
39
+ { before: before, after: @fusion_level }
40
+ end
41
+
42
+ def visit!
43
+ @visit_count += 1
44
+ before = @fusion_level
45
+ @fusion_level = (@fusion_level + FUSION_DELTA_VISIT).clamp(0.0, 1.0).round(10)
46
+ { visit_count: @visit_count, fusion_before: before, fusion_after: @fusion_level }
47
+ end
48
+
49
+ def enmeshed?
50
+ @fusion_level >= FUSION_THRESHOLD
51
+ end
52
+
53
+ def defused?
54
+ @fusion_level <= DEFUSED_THRESHOLD
55
+ end
56
+
57
+ def ruminating?
58
+ @visit_count >= RUMINATION_COUNT
59
+ end
60
+
61
+ def fusion_label
62
+ FUSION_LABELS.find { |range, _| range.cover?(@fusion_level) }&.last || :unknown
63
+ end
64
+
65
+ def belief_label
66
+ BELIEF_LABELS.find { |range, _| range.cover?(@belief_strength) }&.last || :unknown
67
+ end
68
+
69
+ def to_h
70
+ {
71
+ id: @id,
72
+ content: @content,
73
+ thought_type: @thought_type,
74
+ belief_strength: @belief_strength,
75
+ fusion_level: @fusion_level,
76
+ defusion_count: @defusion_count,
77
+ visit_count: @visit_count,
78
+ fusion_label: fusion_label,
79
+ belief_label: belief_label,
80
+ enmeshed: enmeshed?,
81
+ defused: defused?,
82
+ ruminating: ruminating?,
83
+ created_at: @created_at
84
+ }
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end