lex-agentic-social 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 (235) 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-social.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/social/apprenticeship/client.rb +28 -0
  8. data/lib/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship.rb +90 -0
  9. data/lib/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_engine.rb +109 -0
  10. data/lib/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_model.rb +93 -0
  11. data/lib/legion/extensions/agentic/social/apprenticeship/runners/cognitive_apprenticeship.rb +112 -0
  12. data/lib/legion/extensions/agentic/social/apprenticeship/version.rb +13 -0
  13. data/lib/legion/extensions/agentic/social/apprenticeship.rb +19 -0
  14. data/lib/legion/extensions/agentic/social/conflict/actors/stale_check.rb +45 -0
  15. data/lib/legion/extensions/agentic/social/conflict/client.rb +27 -0
  16. data/lib/legion/extensions/agentic/social/conflict/helpers/conflict_log.rb +70 -0
  17. data/lib/legion/extensions/agentic/social/conflict/helpers/llm_enhancer.rb +130 -0
  18. data/lib/legion/extensions/agentic/social/conflict/helpers/severity.rb +47 -0
  19. data/lib/legion/extensions/agentic/social/conflict/runners/conflict.rb +112 -0
  20. data/lib/legion/extensions/agentic/social/conflict/version.rb +13 -0
  21. data/lib/legion/extensions/agentic/social/conflict.rb +19 -0
  22. data/lib/legion/extensions/agentic/social/conscience/client.rb +26 -0
  23. data/lib/legion/extensions/agentic/social/conscience/helpers/constants.rb +53 -0
  24. data/lib/legion/extensions/agentic/social/conscience/helpers/moral_evaluator.rb +178 -0
  25. data/lib/legion/extensions/agentic/social/conscience/helpers/moral_store.rb +116 -0
  26. data/lib/legion/extensions/agentic/social/conscience/runners/conscience.rb +117 -0
  27. data/lib/legion/extensions/agentic/social/conscience/version.rb +13 -0
  28. data/lib/legion/extensions/agentic/social/conscience.rb +19 -0
  29. data/lib/legion/extensions/agentic/social/consent/actors/tier_evaluation.rb +45 -0
  30. data/lib/legion/extensions/agentic/social/consent/client.rb +27 -0
  31. data/lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb +199 -0
  32. data/lib/legion/extensions/agentic/social/consent/helpers/tiers.rb +54 -0
  33. data/lib/legion/extensions/agentic/social/consent/local_migrations/20260316000010_create_consent_domains.rb +16 -0
  34. data/lib/legion/extensions/agentic/social/consent/runners/consent.rb +228 -0
  35. data/lib/legion/extensions/agentic/social/consent/version.rb +13 -0
  36. data/lib/legion/extensions/agentic/social/consent.rb +25 -0
  37. data/lib/legion/extensions/agentic/social/entrainment/client.rb +19 -0
  38. data/lib/legion/extensions/agentic/social/entrainment/helpers/constants.rb +40 -0
  39. data/lib/legion/extensions/agentic/social/entrainment/helpers/entrainment_engine.rb +120 -0
  40. data/lib/legion/extensions/agentic/social/entrainment/helpers/pairing.rb +86 -0
  41. data/lib/legion/extensions/agentic/social/entrainment/runners/cognitive_entrainment.rb +89 -0
  42. data/lib/legion/extensions/agentic/social/entrainment/version.rb +13 -0
  43. data/lib/legion/extensions/agentic/social/entrainment.rb +19 -0
  44. data/lib/legion/extensions/agentic/social/governance/actors/shadow_ai_scan.rb +19 -0
  45. data/lib/legion/extensions/agentic/social/governance/actors/vote_timeout.rb +45 -0
  46. data/lib/legion/extensions/agentic/social/governance/client.rb +27 -0
  47. data/lib/legion/extensions/agentic/social/governance/helpers/layers.rb +40 -0
  48. data/lib/legion/extensions/agentic/social/governance/helpers/proposal.rb +94 -0
  49. data/lib/legion/extensions/agentic/social/governance/runners/governance.rb +87 -0
  50. data/lib/legion/extensions/agentic/social/governance/runners/shadow_ai.rb +93 -0
  51. data/lib/legion/extensions/agentic/social/governance/version.rb +13 -0
  52. data/lib/legion/extensions/agentic/social/governance.rb +20 -0
  53. data/lib/legion/extensions/agentic/social/joint_attention/actors/decay.rb +45 -0
  54. data/lib/legion/extensions/agentic/social/joint_attention/client.rb +28 -0
  55. data/lib/legion/extensions/agentic/social/joint_attention/helpers/attention_target.rb +124 -0
  56. data/lib/legion/extensions/agentic/social/joint_attention/helpers/constants.rb +34 -0
  57. data/lib/legion/extensions/agentic/social/joint_attention/helpers/joint_focus_manager.rb +157 -0
  58. data/lib/legion/extensions/agentic/social/joint_attention/runners/joint_attention.rb +88 -0
  59. data/lib/legion/extensions/agentic/social/joint_attention/version.rb +13 -0
  60. data/lib/legion/extensions/agentic/social/joint_attention.rb +20 -0
  61. data/lib/legion/extensions/agentic/social/mentalizing/actors/decay.rb +45 -0
  62. data/lib/legion/extensions/agentic/social/mentalizing/client.rb +28 -0
  63. data/lib/legion/extensions/agentic/social/mentalizing/helpers/belief_attribution.rb +58 -0
  64. data/lib/legion/extensions/agentic/social/mentalizing/helpers/constants.rb +33 -0
  65. data/lib/legion/extensions/agentic/social/mentalizing/helpers/mental_model.rb +137 -0
  66. data/lib/legion/extensions/agentic/social/mentalizing/runners/mentalizing.rb +93 -0
  67. data/lib/legion/extensions/agentic/social/mentalizing/version.rb +13 -0
  68. data/lib/legion/extensions/agentic/social/mentalizing.rb +20 -0
  69. data/lib/legion/extensions/agentic/social/mirror/client.rb +33 -0
  70. data/lib/legion/extensions/agentic/social/mirror/helpers/constants.rb +65 -0
  71. data/lib/legion/extensions/agentic/social/mirror/helpers/mirror_engine.rb +132 -0
  72. data/lib/legion/extensions/agentic/social/mirror/helpers/mirror_event.rb +46 -0
  73. data/lib/legion/extensions/agentic/social/mirror/helpers/simulation.rb +43 -0
  74. data/lib/legion/extensions/agentic/social/mirror/runners/observe.rb +52 -0
  75. data/lib/legion/extensions/agentic/social/mirror/runners/resonance.rb +79 -0
  76. data/lib/legion/extensions/agentic/social/mirror/runners/simulate.rb +63 -0
  77. data/lib/legion/extensions/agentic/social/mirror/version.rb +13 -0
  78. data/lib/legion/extensions/agentic/social/mirror.rb +22 -0
  79. data/lib/legion/extensions/agentic/social/mirror_system/actors/decay.rb +45 -0
  80. data/lib/legion/extensions/agentic/social/mirror_system/client.rb +28 -0
  81. data/lib/legion/extensions/agentic/social/mirror_system/helpers/constants.rb +62 -0
  82. data/lib/legion/extensions/agentic/social/mirror_system/helpers/mirror_system.rb +162 -0
  83. data/lib/legion/extensions/agentic/social/mirror_system/helpers/observed_behavior.rb +67 -0
  84. data/lib/legion/extensions/agentic/social/mirror_system/runners/mirror.rb +99 -0
  85. data/lib/legion/extensions/agentic/social/mirror_system/version.rb +13 -0
  86. data/lib/legion/extensions/agentic/social/mirror_system.rb +20 -0
  87. data/lib/legion/extensions/agentic/social/moral_reasoning/client.rb +19 -0
  88. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/constants.rb +49 -0
  89. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/dilemma.rb +68 -0
  90. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/llm_enhancer.rb +140 -0
  91. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb +239 -0
  92. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_foundation.rb +45 -0
  93. data/lib/legion/extensions/agentic/social/moral_reasoning/runners/moral_reasoning.rb +121 -0
  94. data/lib/legion/extensions/agentic/social/moral_reasoning/version.rb +13 -0
  95. data/lib/legion/extensions/agentic/social/moral_reasoning.rb +21 -0
  96. data/lib/legion/extensions/agentic/social/perspective_shifting/client.rb +29 -0
  97. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/constants.rb +67 -0
  98. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/perspective.rb +45 -0
  99. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/perspective_view.rb +57 -0
  100. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/shifting_engine.rb +166 -0
  101. data/lib/legion/extensions/agentic/social/perspective_shifting/runners/perspective_shifting.rb +167 -0
  102. data/lib/legion/extensions/agentic/social/perspective_shifting/version.rb +13 -0
  103. data/lib/legion/extensions/agentic/social/perspective_shifting.rb +20 -0
  104. data/lib/legion/extensions/agentic/social/social/client.rb +25 -0
  105. data/lib/legion/extensions/agentic/social/social/helpers/constants.rb +84 -0
  106. data/lib/legion/extensions/agentic/social/social/helpers/social_graph.rb +172 -0
  107. data/lib/legion/extensions/agentic/social/social/runners/social.rb +146 -0
  108. data/lib/legion/extensions/agentic/social/social/version.rb +13 -0
  109. data/lib/legion/extensions/agentic/social/social.rb +18 -0
  110. data/lib/legion/extensions/agentic/social/social_learning/client.rb +25 -0
  111. data/lib/legion/extensions/agentic/social/social_learning/helpers/constants.rb +42 -0
  112. data/lib/legion/extensions/agentic/social/social_learning/helpers/model_agent.rb +82 -0
  113. data/lib/legion/extensions/agentic/social/social_learning/helpers/observed_behavior.rb +61 -0
  114. data/lib/legion/extensions/agentic/social/social_learning/helpers/social_learning_engine.rb +134 -0
  115. data/lib/legion/extensions/agentic/social/social_learning/runners/social_learning.rb +105 -0
  116. data/lib/legion/extensions/agentic/social/social_learning/version.rb +13 -0
  117. data/lib/legion/extensions/agentic/social/social_learning.rb +20 -0
  118. data/lib/legion/extensions/agentic/social/symbiosis/client.rb +23 -0
  119. data/lib/legion/extensions/agentic/social/symbiosis/helpers/constants.rb +50 -0
  120. data/lib/legion/extensions/agentic/social/symbiosis/helpers/ecosystem.rb +113 -0
  121. data/lib/legion/extensions/agentic/social/symbiosis/helpers/symbiosis_engine.rb +104 -0
  122. data/lib/legion/extensions/agentic/social/symbiosis/helpers/symbiotic_bond.rb +112 -0
  123. data/lib/legion/extensions/agentic/social/symbiosis/runners/cognitive_symbiosis.rb +101 -0
  124. data/lib/legion/extensions/agentic/social/symbiosis/version.rb +13 -0
  125. data/lib/legion/extensions/agentic/social/symbiosis.rb +22 -0
  126. data/lib/legion/extensions/agentic/social/theory_of_mind/client.rb +26 -0
  127. data/lib/legion/extensions/agentic/social/theory_of_mind/helpers/agent_model.rb +173 -0
  128. data/lib/legion/extensions/agentic/social/theory_of_mind/helpers/constants.rb +70 -0
  129. data/lib/legion/extensions/agentic/social/theory_of_mind/helpers/mental_state_tracker.rb +169 -0
  130. data/lib/legion/extensions/agentic/social/theory_of_mind/runners/theory_of_mind.rb +159 -0
  131. data/lib/legion/extensions/agentic/social/theory_of_mind/version.rb +13 -0
  132. data/lib/legion/extensions/agentic/social/theory_of_mind.rb +19 -0
  133. data/lib/legion/extensions/agentic/social/trust/actors/decay.rb +45 -0
  134. data/lib/legion/extensions/agentic/social/trust/client.rb +27 -0
  135. data/lib/legion/extensions/agentic/social/trust/helpers/trust_map.rb +160 -0
  136. data/lib/legion/extensions/agentic/social/trust/helpers/trust_model.rb +52 -0
  137. data/lib/legion/extensions/agentic/social/trust/local_migrations/20260316000020_create_trust_entries.rb +23 -0
  138. data/lib/legion/extensions/agentic/social/trust/runners/trust.rb +80 -0
  139. data/lib/legion/extensions/agentic/social/trust/version.rb +13 -0
  140. data/lib/legion/extensions/agentic/social/trust.rb +25 -0
  141. data/lib/legion/extensions/agentic/social/version.rb +11 -0
  142. data/lib/legion/extensions/agentic/social.rb +34 -0
  143. data/spec/legion/extensions/agentic/social/apprenticeship/client_spec.rb +20 -0
  144. data/spec/legion/extensions/agentic/social/apprenticeship/cognitive_apprenticeship_spec.rb +11 -0
  145. data/spec/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_engine_spec.rb +146 -0
  146. data/spec/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_model_spec.rb +124 -0
  147. data/spec/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_spec.rb +136 -0
  148. data/spec/legion/extensions/agentic/social/apprenticeship/runners/cognitive_apprenticeship_spec.rb +154 -0
  149. data/spec/legion/extensions/agentic/social/conflict/actors/stale_check_spec.rb +45 -0
  150. data/spec/legion/extensions/agentic/social/conflict/client_spec.rb +15 -0
  151. data/spec/legion/extensions/agentic/social/conflict/helpers/conflict_log_spec.rb +232 -0
  152. data/spec/legion/extensions/agentic/social/conflict/helpers/llm_enhancer_spec.rb +189 -0
  153. data/spec/legion/extensions/agentic/social/conflict/helpers/severity_spec.rb +215 -0
  154. data/spec/legion/extensions/agentic/social/conflict/runners/conflict_spec.rb +151 -0
  155. data/spec/legion/extensions/agentic/social/conscience/client_spec.rb +58 -0
  156. data/spec/legion/extensions/agentic/social/conscience/helpers/constants_spec.rb +124 -0
  157. data/spec/legion/extensions/agentic/social/conscience/helpers/moral_evaluator_spec.rb +253 -0
  158. data/spec/legion/extensions/agentic/social/conscience/helpers/moral_store_spec.rb +230 -0
  159. data/spec/legion/extensions/agentic/social/conscience/runners/conscience_spec.rb +239 -0
  160. data/spec/legion/extensions/agentic/social/consent/actors/tier_evaluation_spec.rb +46 -0
  161. data/spec/legion/extensions/agentic/social/consent/client_spec.rb +33 -0
  162. data/spec/legion/extensions/agentic/social/consent/helpers/tiers_spec.rb +49 -0
  163. data/spec/legion/extensions/agentic/social/consent/local_persistence_spec.rb +234 -0
  164. data/spec/legion/extensions/agentic/social/consent/runners/consent_spec.rb +224 -0
  165. data/spec/legion/extensions/agentic/social/entrainment/client_spec.rb +21 -0
  166. data/spec/legion/extensions/agentic/social/entrainment/helpers/entrainment_engine_spec.rb +116 -0
  167. data/spec/legion/extensions/agentic/social/entrainment/helpers/pairing_spec.rb +103 -0
  168. data/spec/legion/extensions/agentic/social/entrainment/runners/cognitive_entrainment_spec.rb +87 -0
  169. data/spec/legion/extensions/agentic/social/governance/actors/vote_timeout_spec.rb +45 -0
  170. data/spec/legion/extensions/agentic/social/governance/client_spec.rb +14 -0
  171. data/spec/legion/extensions/agentic/social/governance/helpers/layers_spec.rb +190 -0
  172. data/spec/legion/extensions/agentic/social/governance/helpers/proposal_spec.rb +188 -0
  173. data/spec/legion/extensions/agentic/social/governance/runners/governance_spec.rb +101 -0
  174. data/spec/legion/extensions/agentic/social/governance/runners/shadow_ai_spec.rb +65 -0
  175. data/spec/legion/extensions/agentic/social/joint_attention/client_spec.rb +36 -0
  176. data/spec/legion/extensions/agentic/social/joint_attention/helpers/attention_target_spec.rb +258 -0
  177. data/spec/legion/extensions/agentic/social/joint_attention/helpers/joint_focus_manager_spec.rb +238 -0
  178. data/spec/legion/extensions/agentic/social/joint_attention/runners/joint_attention_spec.rb +228 -0
  179. data/spec/legion/extensions/agentic/social/mentalizing/client_spec.rb +19 -0
  180. data/spec/legion/extensions/agentic/social/mentalizing/helpers/belief_attribution_spec.rb +108 -0
  181. data/spec/legion/extensions/agentic/social/mentalizing/helpers/mental_model_spec.rb +179 -0
  182. data/spec/legion/extensions/agentic/social/mentalizing/runners/mentalizing_spec.rb +162 -0
  183. data/spec/legion/extensions/agentic/social/mirror/client_spec.rb +92 -0
  184. data/spec/legion/extensions/agentic/social/mirror/helpers/constants_spec.rb +123 -0
  185. data/spec/legion/extensions/agentic/social/mirror/helpers/mirror_engine_spec.rb +217 -0
  186. data/spec/legion/extensions/agentic/social/mirror/helpers/mirror_event_spec.rb +102 -0
  187. data/spec/legion/extensions/agentic/social/mirror/helpers/simulation_spec.rb +100 -0
  188. data/spec/legion/extensions/agentic/social/mirror/runners/observe_spec.rb +77 -0
  189. data/spec/legion/extensions/agentic/social/mirror/runners/resonance_spec.rb +123 -0
  190. data/spec/legion/extensions/agentic/social/mirror/runners/simulate_spec.rb +103 -0
  191. data/spec/legion/extensions/agentic/social/mirror_system/client_spec.rb +40 -0
  192. data/spec/legion/extensions/agentic/social/mirror_system/helpers/mirror_system_spec.rb +144 -0
  193. data/spec/legion/extensions/agentic/social/mirror_system/helpers/observed_behavior_spec.rb +98 -0
  194. data/spec/legion/extensions/agentic/social/mirror_system/runners/mirror_spec.rb +122 -0
  195. data/spec/legion/extensions/agentic/social/moral_reasoning/client_spec.rb +34 -0
  196. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/dilemma_spec.rb +108 -0
  197. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/llm_enhancer_spec.rb +232 -0
  198. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine_spec.rb +266 -0
  199. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/moral_foundation_spec.rb +70 -0
  200. data/spec/legion/extensions/agentic/social/moral_reasoning/runners/moral_reasoning_spec.rb +275 -0
  201. data/spec/legion/extensions/agentic/social/perspective_shifting/client_spec.rb +30 -0
  202. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/constants_spec.rb +99 -0
  203. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/perspective_spec.rb +77 -0
  204. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/perspective_view_spec.rb +105 -0
  205. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/shifting_engine_spec.rb +246 -0
  206. data/spec/legion/extensions/agentic/social/perspective_shifting/runners/perspective_shifting_spec.rb +277 -0
  207. data/spec/legion/extensions/agentic/social/social/client_spec.rb +72 -0
  208. data/spec/legion/extensions/agentic/social/social/helpers/constants_spec.rb +99 -0
  209. data/spec/legion/extensions/agentic/social/social/helpers/social_graph_spec.rb +322 -0
  210. data/spec/legion/extensions/agentic/social/social/runners/social_spec.rb +220 -0
  211. data/spec/legion/extensions/agentic/social/social_learning/client_spec.rb +25 -0
  212. data/spec/legion/extensions/agentic/social/social_learning/helpers/constants_spec.rb +44 -0
  213. data/spec/legion/extensions/agentic/social/social_learning/helpers/model_agent_spec.rb +120 -0
  214. data/spec/legion/extensions/agentic/social/social_learning/helpers/observed_behavior_spec.rb +81 -0
  215. data/spec/legion/extensions/agentic/social/social_learning/helpers/social_learning_engine_spec.rb +196 -0
  216. data/spec/legion/extensions/agentic/social/social_learning/runners/social_learning_spec.rb +150 -0
  217. data/spec/legion/extensions/agentic/social/symbiosis/client_spec.rb +45 -0
  218. data/spec/legion/extensions/agentic/social/symbiosis/helpers/constants_spec.rb +73 -0
  219. data/spec/legion/extensions/agentic/social/symbiosis/helpers/ecosystem_spec.rb +185 -0
  220. data/spec/legion/extensions/agentic/social/symbiosis/helpers/symbiosis_engine_spec.rb +182 -0
  221. data/spec/legion/extensions/agentic/social/symbiosis/helpers/symbiotic_bond_spec.rb +209 -0
  222. data/spec/legion/extensions/agentic/social/symbiosis/runners/cognitive_symbiosis_spec.rb +182 -0
  223. data/spec/legion/extensions/agentic/social/theory_of_mind/client_spec.rb +63 -0
  224. data/spec/legion/extensions/agentic/social/theory_of_mind/helpers/agent_model_spec.rb +244 -0
  225. data/spec/legion/extensions/agentic/social/theory_of_mind/helpers/constants_spec.rb +71 -0
  226. data/spec/legion/extensions/agentic/social/theory_of_mind/helpers/mental_state_tracker_spec.rb +228 -0
  227. data/spec/legion/extensions/agentic/social/theory_of_mind/runners/theory_of_mind_spec.rb +221 -0
  228. data/spec/legion/extensions/agentic/social/trust/actors/decay_spec.rb +62 -0
  229. data/spec/legion/extensions/agentic/social/trust/client_spec.rb +17 -0
  230. data/spec/legion/extensions/agentic/social/trust/helpers/trust_map_spec.rb +299 -0
  231. data/spec/legion/extensions/agentic/social/trust/helpers/trust_model_spec.rb +179 -0
  232. data/spec/legion/extensions/agentic/social/trust/local_persistence_spec.rb +359 -0
  233. data/spec/legion/extensions/agentic/social/trust/runners/trust_spec.rb +84 -0
  234. data/spec/spec_helper.rb +54 -0
  235. metadata +319 -0
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::JointAttention::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'instantiates without arguments' do
7
+ expect(client).to be_a(described_class)
8
+ end
9
+
10
+ it 'accepts an injected joint_focus_manager' do
11
+ mgr = Legion::Extensions::Agentic::Social::JointAttention::Helpers::JointFocusManager.new
12
+ c = described_class.new(joint_focus_manager: mgr)
13
+ expect(c).to be_a(described_class)
14
+ end
15
+
16
+ it 'includes runner methods' do
17
+ expect(client).to respond_to(:create_attention_target)
18
+ expect(client).to respond_to(:join_attention)
19
+ expect(client).to respond_to(:leave_attention)
20
+ expect(client).to respond_to(:direct_attention)
21
+ expect(client).to respond_to(:establish_mutual_awareness)
22
+ expect(client).to respond_to(:update_gaze)
23
+ expect(client).to respond_to(:shared_focus)
24
+ expect(client).to respond_to(:attention_targets_for)
25
+ expect(client).to respond_to(:update_joint_attention)
26
+ expect(client).to respond_to(:joint_attention_stats)
27
+ end
28
+
29
+ it 'two clients maintain independent state' do
30
+ c1 = described_class.new
31
+ c2 = described_class.new
32
+ c1.create_attention_target(name: 'only-in-c1', domain: :test, creator: 'agent-1')
33
+ expect(c1.joint_attention_stats[:stats][:target_count]).to eq(1)
34
+ expect(c2.joint_attention_stats[:stats][:target_count]).to eq(0)
35
+ end
36
+ end
@@ -0,0 +1,258 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::JointAttention::Helpers::AttentionTarget do
4
+ subject(:target) do
5
+ described_class.new(name: 'task-planning', domain: :collaboration, priority: 0.7, creator_agent_id: 'agent-1')
6
+ end
7
+
8
+ describe '#initialize' do
9
+ it 'assigns fields' do
10
+ expect(target.name).to eq('task-planning')
11
+ expect(target.domain).to eq(:collaboration)
12
+ expect(target.priority).to be_within(0.001).of(0.7)
13
+ expect(target.creator_agent_id).to eq('agent-1')
14
+ end
15
+
16
+ it 'assigns a uuid id' do
17
+ expect(target.id).to match(/\A[0-9a-f-]{36}\z/)
18
+ end
19
+
20
+ it 'assigns created_at timestamp' do
21
+ expect(target.created_at).to be_a(Time)
22
+ end
23
+
24
+ it 'initializes with empty attendees' do
25
+ expect(target.attendees).to be_empty
26
+ end
27
+
28
+ it 'clamps priority to 0..1' do
29
+ t = described_class.new(name: 'x', domain: :d, priority: 2.0, creator_agent_id: 'a')
30
+ expect(t.priority).to eq(1.0)
31
+
32
+ t2 = described_class.new(name: 'x', domain: :d, priority: -0.5, creator_agent_id: 'a')
33
+ expect(t2.priority).to eq(0.0)
34
+ end
35
+
36
+ it 'sets default focus_strength' do
37
+ const = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants::DEFAULT_FOCUS
38
+ expect(target.focus_strength).to eq(const)
39
+ end
40
+ end
41
+
42
+ describe '#add_attendee' do
43
+ it 'adds a new attendee and returns :joined' do
44
+ result = target.add_attendee(agent_id: 'agent-2')
45
+ expect(result).to eq(:joined)
46
+ expect(target.attendees).to have_key('agent-2')
47
+ end
48
+
49
+ it 'returns :already_attending when agent is already present' do
50
+ target.add_attendee(agent_id: 'agent-2')
51
+ result = target.add_attendee(agent_id: 'agent-2')
52
+ expect(result).to eq(:already_attending)
53
+ end
54
+
55
+ it 'stores gaze direction when provided' do
56
+ target.add_attendee(agent_id: 'agent-2', gaze: :risk_assessment)
57
+ expect(target.attendees['agent-2'][:gaze]).to eq(:risk_assessment)
58
+ end
59
+
60
+ it 'sets mutual_awareness to false by default' do
61
+ target.add_attendee(agent_id: 'agent-2')
62
+ expect(target.attendees['agent-2'][:mutual_awareness]).to be false
63
+ end
64
+
65
+ it 'returns :at_capacity when MAX_ATTENDEES_PER_TARGET is reached' do
66
+ max = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants::MAX_ATTENDEES_PER_TARGET
67
+ max.times { |i| target.add_attendee(agent_id: "agent-#{i + 100}") }
68
+ result = target.add_attendee(agent_id: 'overflow-agent')
69
+ expect(result).to eq(:at_capacity)
70
+ end
71
+ end
72
+
73
+ describe '#remove_attendee' do
74
+ before { target.add_attendee(agent_id: 'agent-2') }
75
+
76
+ it 'removes attendee and returns :removed' do
77
+ result = target.remove_attendee(agent_id: 'agent-2')
78
+ expect(result).to eq(:removed)
79
+ expect(target.attendees).not_to have_key('agent-2')
80
+ end
81
+
82
+ it 'returns :not_found for unknown agent' do
83
+ expect(target.remove_attendee(agent_id: 'unknown')).to eq(:not_found)
84
+ end
85
+ end
86
+
87
+ describe '#update_gaze' do
88
+ before { target.add_attendee(agent_id: 'agent-2') }
89
+
90
+ it 'updates gaze and returns :updated' do
91
+ result = target.update_gaze(agent_id: 'agent-2', gaze: :timeline)
92
+ expect(result).to eq(:updated)
93
+ expect(target.attendees['agent-2'][:gaze]).to eq(:timeline)
94
+ end
95
+
96
+ it 'returns :not_found for unknown agent' do
97
+ expect(target.update_gaze(agent_id: 'ghost', gaze: :something)).to eq(:not_found)
98
+ end
99
+ end
100
+
101
+ describe '#boost_focus' do
102
+ before { target.add_attendee(agent_id: 'agent-2') }
103
+
104
+ it 'increases focus for the agent' do
105
+ before_val = target.attendees['agent-2'][:focus]
106
+ target.boost_focus(agent_id: 'agent-2', amount: 0.2)
107
+ expect(target.attendees['agent-2'][:focus]).to be > before_val
108
+ end
109
+
110
+ it 'caps focus at 1.0' do
111
+ target.boost_focus(agent_id: 'agent-2', amount: 5.0)
112
+ expect(target.attendees['agent-2'][:focus]).to eq(1.0)
113
+ end
114
+
115
+ it 'returns :not_found for unknown agent' do
116
+ expect(target.boost_focus(agent_id: 'ghost', amount: 0.1)).to eq(:not_found)
117
+ end
118
+ end
119
+
120
+ describe '#establish_mutual_awareness' do
121
+ before do
122
+ target.add_attendee(agent_id: 'agent-1')
123
+ target.add_attendee(agent_id: 'agent-2')
124
+ end
125
+
126
+ it 'sets mutual_awareness for both agents and returns :established' do
127
+ result = target.establish_mutual_awareness(agent_a: 'agent-1', agent_b: 'agent-2')
128
+ expect(result).to eq(:established)
129
+ expect(target.attendees['agent-1'][:mutual_awareness]).to be true
130
+ expect(target.attendees['agent-2'][:mutual_awareness]).to be true
131
+ end
132
+
133
+ it 'boosts focus for both agents' do
134
+ before_a = target.attendees['agent-1'][:focus]
135
+ before_b = target.attendees['agent-2'][:focus]
136
+ target.establish_mutual_awareness(agent_a: 'agent-1', agent_b: 'agent-2')
137
+ expect(target.attendees['agent-1'][:focus]).to be > before_a
138
+ expect(target.attendees['agent-2'][:focus]).to be > before_b
139
+ end
140
+
141
+ it 'returns :not_found when one agent is missing' do
142
+ result = target.establish_mutual_awareness(agent_a: 'agent-1', agent_b: 'ghost')
143
+ expect(result).to eq(:not_found)
144
+ end
145
+ end
146
+
147
+ describe '#attendee_count' do
148
+ it 'returns 0 initially' do
149
+ expect(target.attendee_count).to eq(0)
150
+ end
151
+
152
+ it 'increments when attendees join' do
153
+ target.add_attendee(agent_id: 'agent-2')
154
+ target.add_attendee(agent_id: 'agent-3')
155
+ expect(target.attendee_count).to eq(2)
156
+ end
157
+ end
158
+
159
+ describe '#shared_awareness?' do
160
+ it 'returns false with no mutual awareness' do
161
+ target.add_attendee(agent_id: 'agent-2')
162
+ expect(target.shared_awareness?).to be false
163
+ end
164
+
165
+ it 'returns true when two or more agents have mutual awareness' do
166
+ target.add_attendee(agent_id: 'agent-1')
167
+ target.add_attendee(agent_id: 'agent-2')
168
+ target.establish_mutual_awareness(agent_a: 'agent-1', agent_b: 'agent-2')
169
+ expect(target.shared_awareness?).to be true
170
+ end
171
+ end
172
+
173
+ describe '#decay' do
174
+ before { target.add_attendee(agent_id: 'agent-2') }
175
+
176
+ it 'reduces attendee focus' do
177
+ before_val = target.attendees['agent-2'][:focus]
178
+ target.decay
179
+ expect(target.attendees['agent-2'][:focus]).to be < before_val
180
+ end
181
+
182
+ it 'does not drop focus below FOCUS_FLOOR' do
183
+ floor = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants::FOCUS_FLOOR
184
+ 200.times { target.decay }
185
+ expect(target.attendees['agent-2'][:focus]).to be >= floor
186
+ end
187
+
188
+ it 'updates overall focus_strength based on attendees' do
189
+ original = target.focus_strength
190
+ 200.times { target.decay }
191
+ expect(target.focus_strength).to be <= original
192
+ end
193
+ end
194
+
195
+ describe '#faded?' do
196
+ it 'returns false when focus is above floor or attendees present' do
197
+ expect(target.faded?).to be false
198
+ end
199
+
200
+ it 'returns true when focus is at floor and no attendees' do
201
+ 200.times { target.decay }
202
+ expect(target.faded?).to be true
203
+ end
204
+ end
205
+
206
+ describe '#prune_faded_attendees' do
207
+ it 'removes attendees whose focus is at or below FOCUS_FLOOR' do
208
+ target.add_attendee(agent_id: 'fading')
209
+ target.attendees['fading'][:focus] = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants::FOCUS_FLOOR
210
+ target.prune_faded_attendees
211
+ expect(target.attendees).not_to have_key('fading')
212
+ end
213
+
214
+ it 'keeps attendees above floor' do
215
+ target.add_attendee(agent_id: 'active')
216
+ target.prune_faded_attendees
217
+ expect(target.attendees).to have_key('active')
218
+ end
219
+ end
220
+
221
+ describe '#focus_label' do
222
+ it 'returns :locked_on for high focus' do
223
+ target.instance_variable_set(:@focus_strength, 0.9)
224
+ expect(target.focus_label).to eq(:locked_on)
225
+ end
226
+
227
+ it 'returns :focused for 0.6..0.8 range' do
228
+ target.instance_variable_set(:@focus_strength, 0.7)
229
+ expect(target.focus_label).to eq(:focused)
230
+ end
231
+
232
+ it 'returns :attending for 0.4..0.6 range' do
233
+ target.instance_variable_set(:@focus_strength, 0.5)
234
+ expect(target.focus_label).to eq(:attending)
235
+ end
236
+
237
+ it 'returns :fading for very low focus' do
238
+ target.instance_variable_set(:@focus_strength, 0.1)
239
+ expect(target.focus_label).to eq(:fading)
240
+ end
241
+ end
242
+
243
+ describe '#to_h' do
244
+ it 'returns a hash with all required fields' do
245
+ h = target.to_h
246
+ expect(h).to include(
247
+ :id, :name, :domain, :priority, :creator_agent_id,
248
+ :created_at, :focus_strength, :focus_label,
249
+ :attendee_count, :shared_awareness, :attendees
250
+ )
251
+ end
252
+
253
+ it 'rounds focus_strength to 4 decimal places' do
254
+ target.instance_variable_set(:@focus_strength, 0.123456789)
255
+ expect(target.to_h[:focus_strength]).to eq(0.1235)
256
+ end
257
+ end
258
+ end
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::JointAttention::Helpers::JointFocusManager do
4
+ subject(:manager) { described_class.new }
5
+
6
+ let!(:target) do
7
+ manager.create_target(name: 'task-alpha', domain: :planning, priority: 0.8, creator: 'agent-1')
8
+ end
9
+
10
+ describe '#create_target' do
11
+ it 'creates a target and returns an AttentionTarget' do
12
+ expect(target).to be_a(Legion::Extensions::Agentic::Social::JointAttention::Helpers::AttentionTarget)
13
+ expect(target.name).to eq('task-alpha')
14
+ end
15
+
16
+ it 'adds the target to @targets' do
17
+ expect(manager.targets).to have_key(target.id)
18
+ end
19
+
20
+ it 'auto-joins the creator' do
21
+ expect(target.attendees).to have_key('agent-1')
22
+ end
23
+
24
+ it 'records history' do
25
+ expect(manager.history).not_to be_empty
26
+ expect(manager.history.last[:event]).to eq(:agent_joined)
27
+ end
28
+
29
+ it 'increments target_count' do
30
+ expect(manager.target_count).to eq(1)
31
+ end
32
+ end
33
+
34
+ describe '#join_target' do
35
+ it 'adds a second agent to the target' do
36
+ result = manager.join_target(target_id: target.id, agent_id: 'agent-2')
37
+ expect(result).to eq(:joined)
38
+ expect(target.attendees).to have_key('agent-2')
39
+ end
40
+
41
+ it 'returns :target_not_found for unknown target' do
42
+ result = manager.join_target(target_id: 'bogus', agent_id: 'agent-2')
43
+ expect(result).to eq(:target_not_found)
44
+ end
45
+
46
+ it 'returns :already_attending when agent already there' do
47
+ manager.join_target(target_id: target.id, agent_id: 'agent-2')
48
+ result = manager.join_target(target_id: target.id, agent_id: 'agent-2')
49
+ expect(result).to eq(:already_attending)
50
+ end
51
+
52
+ it 'enforces MAX_SIMULTANEOUS_TARGETS per agent' do
53
+ max = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants::MAX_SIMULTANEOUS_TARGETS
54
+ max.times do |i|
55
+ t = manager.create_target(name: "agent-x-target-#{i}", domain: :d, priority: 0.5, creator: 'other')
56
+ manager.join_target(target_id: t.id, agent_id: 'agent-x')
57
+ end
58
+ extra = manager.create_target(name: 'overflow', domain: :d, priority: 0.5, creator: 'other2')
59
+ result = manager.join_target(target_id: extra.id, agent_id: 'agent-x')
60
+ expect(result).to eq(:capacity_exceeded)
61
+ end
62
+
63
+ it 'records join history' do
64
+ manager.join_target(target_id: target.id, agent_id: 'agent-3')
65
+ events = manager.history.map { |h| h[:event] }
66
+ expect(events).to include(:agent_joined)
67
+ end
68
+ end
69
+
70
+ describe '#leave_target' do
71
+ before { manager.join_target(target_id: target.id, agent_id: 'agent-2') }
72
+
73
+ it 'removes the agent and returns :removed' do
74
+ result = manager.leave_target(target_id: target.id, agent_id: 'agent-2')
75
+ expect(result).to eq(:removed)
76
+ expect(target.attendees).not_to have_key('agent-2')
77
+ end
78
+
79
+ it 'returns :target_not_found for unknown target' do
80
+ result = manager.leave_target(target_id: 'bogus', agent_id: 'agent-2')
81
+ expect(result).to eq(:target_not_found)
82
+ end
83
+
84
+ it 'returns :not_found when agent not attending' do
85
+ result = manager.leave_target(target_id: target.id, agent_id: 'never-joined')
86
+ expect(result).to eq(:not_found)
87
+ end
88
+
89
+ it 'records leave history' do
90
+ manager.leave_target(target_id: target.id, agent_id: 'agent-2')
91
+ events = manager.history.map { |h| h[:event] }
92
+ expect(events).to include(:agent_left)
93
+ end
94
+ end
95
+
96
+ describe '#direct_attention' do
97
+ before { manager.join_target(target_id: target.id, agent_id: 'agent-1') }
98
+
99
+ it 'joins recipient to target and returns :directed' do
100
+ result = manager.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: target.id)
101
+ expect(result).to eq(:directed)
102
+ expect(target.attendees).to have_key('agent-2')
103
+ end
104
+
105
+ it 'returns :target_not_found for unknown target' do
106
+ result = manager.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: 'bogus')
107
+ expect(result).to eq(:target_not_found)
108
+ end
109
+
110
+ it 'returns :referrer_not_attending when from_agent is not on target' do
111
+ result = manager.direct_attention(from_agent: 'nobody', to_agent: 'agent-2', target_id: target.id)
112
+ expect(result).to eq(:referrer_not_attending)
113
+ end
114
+
115
+ it 'boosts focus of recipient' do
116
+ manager.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: target.id)
117
+ const = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants
118
+ expected_min = const::DEFAULT_FOCUS + const::REFERRAL_BOOST
119
+ expect(target.attendees['agent-2'][:focus]).to be >= expected_min
120
+ end
121
+
122
+ it 'records direction history' do
123
+ manager.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: target.id)
124
+ events = manager.history.map { |h| h[:event] }
125
+ expect(events).to include(:attention_directed)
126
+ end
127
+ end
128
+
129
+ describe '#establish_shared' do
130
+ before do
131
+ manager.join_target(target_id: target.id, agent_id: 'agent-1')
132
+ manager.join_target(target_id: target.id, agent_id: 'agent-2')
133
+ end
134
+
135
+ it 'establishes mutual awareness and returns :established' do
136
+ result = manager.establish_shared(target_id: target.id, agent_a: 'agent-1', agent_b: 'agent-2')
137
+ expect(result).to eq(:established)
138
+ expect(target.attendees['agent-1'][:mutual_awareness]).to be true
139
+ expect(target.attendees['agent-2'][:mutual_awareness]).to be true
140
+ end
141
+
142
+ it 'returns :target_not_found for unknown target' do
143
+ result = manager.establish_shared(target_id: 'bogus', agent_a: 'agent-1', agent_b: 'agent-2')
144
+ expect(result).to eq(:target_not_found)
145
+ end
146
+
147
+ it 'records shared_awareness history event' do
148
+ manager.establish_shared(target_id: target.id, agent_a: 'agent-1', agent_b: 'agent-2')
149
+ events = manager.history.map { |h| h[:event] }
150
+ expect(events).to include(:shared_awareness)
151
+ end
152
+ end
153
+
154
+ describe '#update_gaze' do
155
+ before { manager.join_target(target_id: target.id, agent_id: 'agent-1') }
156
+
157
+ it 'updates gaze direction' do
158
+ result = manager.update_gaze(target_id: target.id, agent_id: 'agent-1', gaze: :timeline)
159
+ expect(result).to eq(:updated)
160
+ end
161
+
162
+ it 'returns :target_not_found for unknown target' do
163
+ result = manager.update_gaze(target_id: 'bogus', agent_id: 'agent-1', gaze: :x)
164
+ expect(result).to eq(:target_not_found)
165
+ end
166
+ end
167
+
168
+ describe '#targets_for_agent' do
169
+ it 'returns targets the agent is attending' do
170
+ targets = manager.targets_for_agent(agent_id: 'agent-1')
171
+ expect(targets).to include(target)
172
+ end
173
+
174
+ it 'returns empty array for unknown agent' do
175
+ expect(manager.targets_for_agent(agent_id: 'nobody')).to eq([])
176
+ end
177
+ end
178
+
179
+ describe '#attendees_for_target' do
180
+ before { manager.join_target(target_id: target.id, agent_id: 'agent-2') }
181
+
182
+ it 'returns attendee ids for target' do
183
+ ids = manager.attendees_for_target(target_id: target.id)
184
+ expect(ids).to include('agent-1', 'agent-2')
185
+ end
186
+
187
+ it 'returns empty array for unknown target' do
188
+ expect(manager.attendees_for_target(target_id: 'bogus')).to eq([])
189
+ end
190
+ end
191
+
192
+ describe '#shared_targets' do
193
+ it 'returns targets attended by both agents' do
194
+ manager.join_target(target_id: target.id, agent_id: 'agent-2')
195
+ shared = manager.shared_targets(agent_a: 'agent-1', agent_b: 'agent-2')
196
+ expect(shared).to include(target)
197
+ end
198
+
199
+ it 'returns empty array when no shared targets' do
200
+ shared = manager.shared_targets(agent_a: 'agent-1', agent_b: 'loner')
201
+ expect(shared).to be_empty
202
+ end
203
+ end
204
+
205
+ describe '#decay_all' do
206
+ it 'decays focus on all targets' do
207
+ focus_before = target.focus_strength
208
+ manager.decay_all
209
+ expect(target.focus_strength).to be <= focus_before
210
+ end
211
+
212
+ it 'prunes faded targets' do
213
+ t = manager.create_target(name: 'doomed', domain: :temp, priority: 0.1, creator: 'agent-x')
214
+ # Drain all attendees so target can become faded
215
+ manager.leave_target(target_id: t.id, agent_id: 'agent-x')
216
+ 200.times { manager.decay_all }
217
+ expect(manager.targets).not_to have_key(t.id)
218
+ end
219
+ end
220
+
221
+ describe '#target_count' do
222
+ it 'returns number of active targets' do
223
+ manager.create_target(name: 'b', domain: :d, priority: 0.5, creator: 'a')
224
+ expect(manager.target_count).to eq(2)
225
+ end
226
+ end
227
+
228
+ describe '#to_h' do
229
+ it 'returns a summary hash' do
230
+ h = manager.to_h
231
+ expect(h).to include(:target_count, :agent_count, :history_size, :targets)
232
+ end
233
+
234
+ it 'reflects correct target count' do
235
+ expect(manager.to_h[:target_count]).to eq(1)
236
+ end
237
+ end
238
+ end