lex-agentic-learning 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 (192) 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-learning.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/learning/anchoring/client.rb +26 -0
  8. data/lib/legion/extensions/agentic/learning/anchoring/helpers/anchor.rb +65 -0
  9. data/lib/legion/extensions/agentic/learning/anchoring/helpers/anchor_store.rb +132 -0
  10. data/lib/legion/extensions/agentic/learning/anchoring/helpers/constants.rb +31 -0
  11. data/lib/legion/extensions/agentic/learning/anchoring/runners/anchoring.rb +100 -0
  12. data/lib/legion/extensions/agentic/learning/anchoring/version.rb +13 -0
  13. data/lib/legion/extensions/agentic/learning/anchoring.rb +19 -0
  14. data/lib/legion/extensions/agentic/learning/catalyst/client.rb +15 -0
  15. data/lib/legion/extensions/agentic/learning/catalyst/helpers/catalyst.rb +87 -0
  16. data/lib/legion/extensions/agentic/learning/catalyst/helpers/catalyst_engine.rb +153 -0
  17. data/lib/legion/extensions/agentic/learning/catalyst/helpers/constants.rb +55 -0
  18. data/lib/legion/extensions/agentic/learning/catalyst/helpers/reaction.rb +87 -0
  19. data/lib/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst.rb +103 -0
  20. data/lib/legion/extensions/agentic/learning/catalyst/version.rb +13 -0
  21. data/lib/legion/extensions/agentic/learning/catalyst.rb +22 -0
  22. data/lib/legion/extensions/agentic/learning/chrysalis/client.rb +22 -0
  23. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis.rb +137 -0
  24. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/cocoon.rb +89 -0
  25. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/constants.rb +49 -0
  26. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine.rb +157 -0
  27. data/lib/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis.rb +129 -0
  28. data/lib/legion/extensions/agentic/learning/chrysalis/version.rb +13 -0
  29. data/lib/legion/extensions/agentic/learning/chrysalis.rb +21 -0
  30. data/lib/legion/extensions/agentic/learning/curiosity/client.rb +28 -0
  31. data/lib/legion/extensions/agentic/learning/curiosity/helpers/constants.rb +30 -0
  32. data/lib/legion/extensions/agentic/learning/curiosity/helpers/gap_detector.rb +167 -0
  33. data/lib/legion/extensions/agentic/learning/curiosity/helpers/wonder.rb +73 -0
  34. data/lib/legion/extensions/agentic/learning/curiosity/helpers/wonder_store.rb +149 -0
  35. data/lib/legion/extensions/agentic/learning/curiosity/runners/curiosity.rb +163 -0
  36. data/lib/legion/extensions/agentic/learning/curiosity/version.rb +13 -0
  37. data/lib/legion/extensions/agentic/learning/curiosity.rb +21 -0
  38. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/client.rb +28 -0
  39. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants.rb +31 -0
  40. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine.rb +122 -0
  41. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap.rb +70 -0
  42. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity.rb +106 -0
  43. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/version.rb +13 -0
  44. data/lib/legion/extensions/agentic/learning/epistemic_curiosity.rb +19 -0
  45. data/lib/legion/extensions/agentic/learning/fermentation/client.rb +19 -0
  46. data/lib/legion/extensions/agentic/learning/fermentation/helpers/batch.rb +75 -0
  47. data/lib/legion/extensions/agentic/learning/fermentation/helpers/constants.rb +78 -0
  48. data/lib/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine.rb +147 -0
  49. data/lib/legion/extensions/agentic/learning/fermentation/helpers/substrate.rb +108 -0
  50. data/lib/legion/extensions/agentic/learning/fermentation/runners/cognitive_fermentation.rb +60 -0
  51. data/lib/legion/extensions/agentic/learning/fermentation/version.rb +13 -0
  52. data/lib/legion/extensions/agentic/learning/fermentation.rb +22 -0
  53. data/lib/legion/extensions/agentic/learning/habit/client.rb +26 -0
  54. data/lib/legion/extensions/agentic/learning/habit/helpers/action_sequence.rb +120 -0
  55. data/lib/legion/extensions/agentic/learning/habit/helpers/constants.rb +44 -0
  56. data/lib/legion/extensions/agentic/learning/habit/helpers/habit_store.rb +148 -0
  57. data/lib/legion/extensions/agentic/learning/habit/runners/habit.rb +86 -0
  58. data/lib/legion/extensions/agentic/learning/habit/version.rb +13 -0
  59. data/lib/legion/extensions/agentic/learning/habit.rb +19 -0
  60. data/lib/legion/extensions/agentic/learning/hebbian/actors/decay.rb +45 -0
  61. data/lib/legion/extensions/agentic/learning/hebbian/client.rb +29 -0
  62. data/lib/legion/extensions/agentic/learning/hebbian/helpers/assembly.rb +82 -0
  63. data/lib/legion/extensions/agentic/learning/hebbian/helpers/assembly_network.rb +190 -0
  64. data/lib/legion/extensions/agentic/learning/hebbian/helpers/constants.rb +50 -0
  65. data/lib/legion/extensions/agentic/learning/hebbian/helpers/unit.rb +94 -0
  66. data/lib/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly.rb +94 -0
  67. data/lib/legion/extensions/agentic/learning/hebbian/version.rb +13 -0
  68. data/lib/legion/extensions/agentic/learning/hebbian.rb +20 -0
  69. data/lib/legion/extensions/agentic/learning/learning_rate/client.rb +25 -0
  70. data/lib/legion/extensions/agentic/learning/learning_rate/helpers/constants.rb +35 -0
  71. data/lib/legion/extensions/agentic/learning/learning_rate/helpers/rate_model.rb +133 -0
  72. data/lib/legion/extensions/agentic/learning/learning_rate/runners/learning_rate.rb +85 -0
  73. data/lib/legion/extensions/agentic/learning/learning_rate/version.rb +13 -0
  74. data/lib/legion/extensions/agentic/learning/learning_rate.rb +18 -0
  75. data/lib/legion/extensions/agentic/learning/meta_learning/client.rb +27 -0
  76. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/constants.rb +46 -0
  77. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/learning_domain.rb +85 -0
  78. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine.rb +202 -0
  79. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/strategy.rb +62 -0
  80. data/lib/legion/extensions/agentic/learning/meta_learning/runners/meta_learning.rb +118 -0
  81. data/lib/legion/extensions/agentic/learning/meta_learning/version.rb +13 -0
  82. data/lib/legion/extensions/agentic/learning/meta_learning.rb +20 -0
  83. data/lib/legion/extensions/agentic/learning/plasticity/client.rb +15 -0
  84. data/lib/legion/extensions/agentic/learning/plasticity/helpers/constants.rb +45 -0
  85. data/lib/legion/extensions/agentic/learning/plasticity/helpers/neural_pathway.rb +85 -0
  86. data/lib/legion/extensions/agentic/learning/plasticity/helpers/plasticity_engine.rb +130 -0
  87. data/lib/legion/extensions/agentic/learning/plasticity/runners/cognitive_plasticity.rb +85 -0
  88. data/lib/legion/extensions/agentic/learning/plasticity/version.rb +13 -0
  89. data/lib/legion/extensions/agentic/learning/plasticity.rb +19 -0
  90. data/lib/legion/extensions/agentic/learning/preference_learning/actors/decay.rb +45 -0
  91. data/lib/legion/extensions/agentic/learning/preference_learning/client.rb +28 -0
  92. data/lib/legion/extensions/agentic/learning/preference_learning/helpers/constants.rb +35 -0
  93. data/lib/legion/extensions/agentic/learning/preference_learning/helpers/option.rb +78 -0
  94. data/lib/legion/extensions/agentic/learning/preference_learning/helpers/preference_engine.rb +121 -0
  95. data/lib/legion/extensions/agentic/learning/preference_learning/runners/preference_learning.rb +84 -0
  96. data/lib/legion/extensions/agentic/learning/preference_learning/version.rb +13 -0
  97. data/lib/legion/extensions/agentic/learning/preference_learning.rb +19 -0
  98. data/lib/legion/extensions/agentic/learning/procedural/client.rb +19 -0
  99. data/lib/legion/extensions/agentic/learning/procedural/helpers/constants.rb +46 -0
  100. data/lib/legion/extensions/agentic/learning/procedural/helpers/learning_engine.rb +160 -0
  101. data/lib/legion/extensions/agentic/learning/procedural/helpers/production.rb +66 -0
  102. data/lib/legion/extensions/agentic/learning/procedural/helpers/skill.rb +101 -0
  103. data/lib/legion/extensions/agentic/learning/procedural/runners/procedural_learning.rb +96 -0
  104. data/lib/legion/extensions/agentic/learning/procedural/version.rb +13 -0
  105. data/lib/legion/extensions/agentic/learning/procedural.rb +20 -0
  106. data/lib/legion/extensions/agentic/learning/scaffolding/client.rb +26 -0
  107. data/lib/legion/extensions/agentic/learning/scaffolding/helpers/constants.rb +42 -0
  108. data/lib/legion/extensions/agentic/learning/scaffolding/helpers/scaffold.rb +136 -0
  109. data/lib/legion/extensions/agentic/learning/scaffolding/helpers/scaffolding_engine.rb +112 -0
  110. data/lib/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding.rb +107 -0
  111. data/lib/legion/extensions/agentic/learning/scaffolding/version.rb +13 -0
  112. data/lib/legion/extensions/agentic/learning/scaffolding.rb +19 -0
  113. data/lib/legion/extensions/agentic/learning/version.rb +11 -0
  114. data/lib/legion/extensions/agentic/learning.rb +31 -0
  115. data/spec/legion/extensions/agentic/learning/anchoring/client_spec.rb +32 -0
  116. data/spec/legion/extensions/agentic/learning/anchoring/helpers/anchor_spec.rb +130 -0
  117. data/spec/legion/extensions/agentic/learning/anchoring/helpers/anchor_store_spec.rb +201 -0
  118. data/spec/legion/extensions/agentic/learning/anchoring/helpers/constants_spec.rb +63 -0
  119. data/spec/legion/extensions/agentic/learning/anchoring/runners/anchoring_spec.rb +199 -0
  120. data/spec/legion/extensions/agentic/learning/catalyst/client_spec.rb +58 -0
  121. data/spec/legion/extensions/agentic/learning/catalyst/cognitive_catalyst_spec.rb +49 -0
  122. data/spec/legion/extensions/agentic/learning/catalyst/helpers/catalyst_engine_spec.rb +263 -0
  123. data/spec/legion/extensions/agentic/learning/catalyst/helpers/catalyst_spec.rb +214 -0
  124. data/spec/legion/extensions/agentic/learning/catalyst/helpers/reaction_spec.rb +223 -0
  125. data/spec/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst_spec.rb +217 -0
  126. data/spec/legion/extensions/agentic/learning/chrysalis/client_spec.rb +83 -0
  127. data/spec/legion/extensions/agentic/learning/chrysalis/cognitive_chrysalis_spec.rb +15 -0
  128. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis_engine_spec.rb +57 -0
  129. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis_spec.rb +305 -0
  130. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/cocoon_spec.rb +206 -0
  131. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/constants_spec.rb +109 -0
  132. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/metamorphic_cycle_spec.rb +76 -0
  133. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine_spec.rb +247 -0
  134. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/transformation_phase_spec.rb +98 -0
  135. data/spec/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis_spec.rb +180 -0
  136. data/spec/legion/extensions/agentic/learning/chrysalis/runners/reporting_spec.rb +81 -0
  137. data/spec/legion/extensions/agentic/learning/chrysalis/runners/transformation_spec.rb +74 -0
  138. data/spec/legion/extensions/agentic/learning/curiosity/client_spec.rb +27 -0
  139. data/spec/legion/extensions/agentic/learning/curiosity/helpers/gap_detector_spec.rb +118 -0
  140. data/spec/legion/extensions/agentic/learning/curiosity/helpers/wonder_spec.rb +130 -0
  141. data/spec/legion/extensions/agentic/learning/curiosity/helpers/wonder_store_spec.rb +136 -0
  142. data/spec/legion/extensions/agentic/learning/curiosity/runners/curiosity_spec.rb +159 -0
  143. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/client_spec.rb +47 -0
  144. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants_spec.rb +45 -0
  145. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine_spec.rb +229 -0
  146. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap_spec.rb +188 -0
  147. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity_spec.rb +175 -0
  148. data/spec/legion/extensions/agentic/learning/fermentation/client_spec.rb +36 -0
  149. data/spec/legion/extensions/agentic/learning/fermentation/helpers/batch_spec.rb +72 -0
  150. data/spec/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine_spec.rb +138 -0
  151. data/spec/legion/extensions/agentic/learning/fermentation/helpers/substrate_spec.rb +146 -0
  152. data/spec/legion/extensions/agentic/learning/habit/client_spec.rb +50 -0
  153. data/spec/legion/extensions/agentic/learning/habit/helpers/action_sequence_spec.rb +276 -0
  154. data/spec/legion/extensions/agentic/learning/habit/helpers/constants_spec.rb +115 -0
  155. data/spec/legion/extensions/agentic/learning/habit/helpers/habit_store_spec.rb +274 -0
  156. data/spec/legion/extensions/agentic/learning/habit/runners/habit_spec.rb +228 -0
  157. data/spec/legion/extensions/agentic/learning/hebbian/client_spec.rb +38 -0
  158. data/spec/legion/extensions/agentic/learning/hebbian/helpers/assembly_network_spec.rb +142 -0
  159. data/spec/legion/extensions/agentic/learning/hebbian/helpers/assembly_spec.rb +89 -0
  160. data/spec/legion/extensions/agentic/learning/hebbian/helpers/unit_spec.rb +119 -0
  161. data/spec/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly_spec.rb +109 -0
  162. data/spec/legion/extensions/agentic/learning/learning_rate/client_spec.rb +51 -0
  163. data/spec/legion/extensions/agentic/learning/learning_rate/helpers/constants_spec.rb +29 -0
  164. data/spec/legion/extensions/agentic/learning/learning_rate/helpers/rate_model_spec.rb +151 -0
  165. data/spec/legion/extensions/agentic/learning/learning_rate/runners/learning_rate_spec.rb +92 -0
  166. data/spec/legion/extensions/agentic/learning/meta_learning/client_spec.rb +27 -0
  167. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/constants_spec.rb +43 -0
  168. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/learning_domain_spec.rb +146 -0
  169. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine_spec.rb +309 -0
  170. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/strategy_spec.rb +82 -0
  171. data/spec/legion/extensions/agentic/learning/meta_learning/runners/meta_learning_spec.rb +185 -0
  172. data/spec/legion/extensions/agentic/learning/plasticity/helpers/constants_spec.rb +54 -0
  173. data/spec/legion/extensions/agentic/learning/plasticity/helpers/neural_pathway_spec.rb +136 -0
  174. data/spec/legion/extensions/agentic/learning/plasticity/helpers/plasticity_engine_spec.rb +157 -0
  175. data/spec/legion/extensions/agentic/learning/plasticity/runners/cognitive_plasticity_spec.rb +83 -0
  176. data/spec/legion/extensions/agentic/learning/preference_learning/client_spec.rb +17 -0
  177. data/spec/legion/extensions/agentic/learning/preference_learning/helpers/constants_spec.rb +67 -0
  178. data/spec/legion/extensions/agentic/learning/preference_learning/helpers/option_spec.rb +104 -0
  179. data/spec/legion/extensions/agentic/learning/preference_learning/helpers/preference_engine_spec.rb +151 -0
  180. data/spec/legion/extensions/agentic/learning/preference_learning/runners/preference_learning_spec.rb +86 -0
  181. data/spec/legion/extensions/agentic/learning/procedural/client_spec.rb +22 -0
  182. data/spec/legion/extensions/agentic/learning/procedural/helpers/learning_engine_spec.rb +135 -0
  183. data/spec/legion/extensions/agentic/learning/procedural/helpers/production_spec.rb +66 -0
  184. data/spec/legion/extensions/agentic/learning/procedural/helpers/skill_spec.rb +102 -0
  185. data/spec/legion/extensions/agentic/learning/procedural/runners/procedural_learning_spec.rb +94 -0
  186. data/spec/legion/extensions/agentic/learning/scaffolding/client_spec.rb +20 -0
  187. data/spec/legion/extensions/agentic/learning/scaffolding/helpers/constants_spec.rb +36 -0
  188. data/spec/legion/extensions/agentic/learning/scaffolding/helpers/scaffold_spec.rb +187 -0
  189. data/spec/legion/extensions/agentic/learning/scaffolding/helpers/scaffolding_engine_spec.rb +159 -0
  190. data/spec/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding_spec.rb +163 -0
  191. data/spec/spec_helper.rb +46 -0
  192. metadata +277 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Chrysalis
8
+ module Helpers
9
+ module Constants
10
+ LIFE_STAGES = %i[larva spinning cocooned transforming emerging butterfly].freeze
11
+ CHRYSALIS_TYPES = %i[silk paper bark leaf underground].freeze
12
+
13
+ MAX_CHRYSALISES = 200
14
+ MAX_BUTTERFLIES = 500
15
+ TRANSFORMATION_RATE = 0.08
16
+ PROTECTION_DECAY = 0.03
17
+ EMERGENCE_THRESHOLD = 0.9
18
+ PREMATURE_PENALTY = 0.4
19
+
20
+ STAGE_LABELS = {
21
+ (0.0...0.20) => :larva,
22
+ (0.20...0.40) => :spinning,
23
+ (0.40...0.60) => :cocooned,
24
+ (0.60...0.80) => :transforming,
25
+ (0.80...0.90) => :emerging,
26
+ (0.90..1.0) => :butterfly
27
+ }.freeze
28
+
29
+ BEAUTY_LABELS = {
30
+ (0.0...0.20) => :dull,
31
+ (0.20...0.40) => :plain,
32
+ (0.40...0.65) => :striking,
33
+ (0.65...0.85) => :beautiful,
34
+ (0.85..1.0) => :magnificent
35
+ }.freeze
36
+
37
+ def self.label_for(table, value)
38
+ table.each do |range, label|
39
+ return label if range.cover?(value)
40
+ end
41
+ table.values.last
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Chrysalis
8
+ module Helpers
9
+ class MetamorphosisEngine
10
+ def initialize
11
+ @chrysalises = {}
12
+ @cocoons = {}
13
+ @sheltered = {} # chrysalis_id => cocoon_id
14
+ end
15
+
16
+ def create_chrysalis(chrysalis_type:, content:, **)
17
+ return { success: false, reason: :capacity_exceeded } if @chrysalises.size >= Helpers::Constants::MAX_CHRYSALISES
18
+
19
+ c = Chrysalis.new(chrysalis_type: chrysalis_type, content: content)
20
+ @chrysalises[c.id] = c
21
+ { success: true, chrysalis: c.to_h }
22
+ end
23
+
24
+ def create_cocoon(environment:, **)
25
+ cocoon = Cocoon.new(environment: environment)
26
+ @cocoons[cocoon.id] = cocoon
27
+ { success: true, cocoon: cocoon.to_h }
28
+ end
29
+
30
+ def spin(chrysalis_id:, **)
31
+ c = @chrysalises.fetch(chrysalis_id, nil)
32
+ return { success: false, reason: :not_found } unless c
33
+
34
+ c.spin!
35
+ { success: true, stage: c.stage }
36
+ rescue ArgumentError => e
37
+ { success: false, reason: e.message }
38
+ end
39
+
40
+ def enclose(chrysalis_id:, cocoon_id:, **)
41
+ c = @chrysalises.fetch(chrysalis_id, nil)
42
+ cocoon = @cocoons.fetch(cocoon_id, nil)
43
+ return { success: false, reason: :chrysalis_not_found } unless c
44
+ return { success: false, reason: :cocoon_not_found } unless cocoon
45
+
46
+ c.spin! if c.stage == :larva
47
+ c.cocoon! if c.stage == :spinning
48
+ cocoon.shelter(chrysalis_id)
49
+ @sheltered[chrysalis_id] = cocoon_id
50
+ { success: true, stage: c.stage, cocoon_id: cocoon_id }
51
+ rescue ArgumentError => e
52
+ { success: false, reason: e.message }
53
+ end
54
+
55
+ def incubate(chrysalis_id:, **)
56
+ c = @chrysalises.fetch(chrysalis_id, nil)
57
+ return { success: false, reason: :not_found } unless c
58
+ return { success: false, reason: :already_butterfly } if c.butterfly?
59
+
60
+ rate = Helpers::Constants::TRANSFORMATION_RATE
61
+ if (cid = @sheltered[chrysalis_id])
62
+ cocoon = @cocoons[cid]
63
+ rate += cocoon.growth_modifier if cocoon
64
+ end
65
+
66
+ c.transform!(rate)
67
+ { success: true, progress: c.transformation_progress, stage: c.stage }
68
+ end
69
+
70
+ def force_emerge(chrysalis_id:, **)
71
+ c = @chrysalises.fetch(chrysalis_id, nil)
72
+ return { success: false, reason: :not_found } unless c
73
+
74
+ c.emerge!(force: true)
75
+ { success: true, stage: c.stage, beauty: c.beauty, premature: c.premature? }
76
+ end
77
+
78
+ def natural_emerge(chrysalis_id:, **)
79
+ c = @chrysalises.fetch(chrysalis_id, nil)
80
+ return { success: false, reason: :not_found } unless c
81
+
82
+ result = c.emerge!
83
+ return { success: false, reason: :not_ready, progress: c.transformation_progress } unless result
84
+
85
+ { success: true, stage: c.stage, beauty: c.beauty, premature: c.premature? }
86
+ end
87
+
88
+ def disturb_cocoon(cocoon_id:, force:, **)
89
+ cocoon = @cocoons.fetch(cocoon_id, nil)
90
+ return { success: false, reason: :not_found } unless cocoon
91
+
92
+ disturbed = []
93
+ cocoon.chrysalis_ids.each do |cid|
94
+ c = @chrysalises[cid]
95
+ next unless c
96
+
97
+ c.disturb!(force.to_f)
98
+ disturbed << { chrysalis_id: cid, protection: c.protection, stage: c.stage }
99
+ end
100
+ { success: true, disturbed: disturbed, force: force }
101
+ end
102
+
103
+ def incubate_all!(**)
104
+ results = []
105
+ @chrysalises.each_value do |c|
106
+ next unless %i[cocooned transforming].include?(c.stage)
107
+
108
+ rate = Helpers::Constants::TRANSFORMATION_RATE
109
+ if (cid = @sheltered[c.id])
110
+ cocoon = @cocoons[cid]
111
+ rate += cocoon.growth_modifier if cocoon
112
+ end
113
+ c.transform!(rate)
114
+ results << { chrysalis_id: c.id, progress: c.transformation_progress, stage: c.stage }
115
+ end
116
+ { success: true, incubated: results.size, results: results }
117
+ end
118
+
119
+ def butterflies
120
+ @chrysalises.values.select(&:butterfly?)
121
+ end
122
+
123
+ def metamorphosis_report(**)
124
+ all = @chrysalises.values
125
+ butterfly_list = all.select(&:butterfly?)
126
+ {
127
+ total_chrysalises: all.size,
128
+ total_cocoons: @cocoons.size,
129
+ butterflies_count: butterfly_list.size,
130
+ premature_count: butterfly_list.count(&:premature?),
131
+ avg_beauty: avg_beauty(butterfly_list),
132
+ avg_progress: avg_progress(all),
133
+ cocooned_count: all.count(&:cocooned?),
134
+ transforming_count: all.count(&:transforming?)
135
+ }
136
+ end
137
+
138
+ private
139
+
140
+ def avg_beauty(list)
141
+ return 0.0 if list.empty?
142
+
143
+ (list.sum(&:beauty) / list.size).round(10)
144
+ end
145
+
146
+ def avg_progress(list)
147
+ return 0.0 if list.empty?
148
+
149
+ (list.sum(&:transformation_progress) / list.size).round(10)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Chrysalis
8
+ module Runners
9
+ module CognitiveChrysalis
10
+ extend self
11
+
12
+ begin
13
+ include Legion::Extensions::Helpers::Lex # rubocop:disable Layout/EmptyLinesAfterModuleInclusion
14
+ rescue StandardError
15
+ nil
16
+ end
17
+
18
+ def create_chrysalis(chrysalis_type: :silk, content: '', engine: nil, **)
19
+ engine ||= default_engine
20
+ type = chrysalis_type.to_sym
21
+ unless Helpers::Constants::CHRYSALIS_TYPES.include?(type)
22
+ return { success: false, reason: :invalid_type, valid_types: Helpers::Constants::CHRYSALIS_TYPES }
23
+ end
24
+
25
+ Legion::Logging.debug "[cognitive_chrysalis] creating chrysalis type=#{type}"
26
+ engine.create_chrysalis(chrysalis_type: type, content: content)
27
+ rescue ArgumentError => e
28
+ { success: false, reason: e.message }
29
+ end
30
+
31
+ def create_cocoon(environment: 'default', temperature: 0.5, humidity: 0.5, engine: nil, **)
32
+ engine ||= default_engine
33
+ Legion::Logging.debug "[cognitive_chrysalis] creating cocoon environment=#{environment}"
34
+ engine.create_cocoon(environment: environment, temperature: temperature, humidity: humidity)
35
+ rescue ArgumentError => e
36
+ { success: false, reason: e.message }
37
+ end
38
+
39
+ def spin(chrysalis_id:, engine: nil, **)
40
+ return { success: false, reason: :missing_chrysalis_id } if chrysalis_id.nil?
41
+
42
+ engine ||= default_engine
43
+ Legion::Logging.debug "[cognitive_chrysalis] spinning chrysalis=#{chrysalis_id}"
44
+ engine.spin(chrysalis_id: chrysalis_id)
45
+ rescue ArgumentError => e
46
+ { success: false, reason: e.message }
47
+ end
48
+
49
+ def enclose(chrysalis_id:, cocoon_id:, engine: nil, **)
50
+ return { success: false, reason: :missing_chrysalis_id } if chrysalis_id.nil?
51
+ return { success: false, reason: :missing_cocoon_id } if cocoon_id.nil?
52
+
53
+ engine ||= default_engine
54
+ Legion::Logging.debug "[cognitive_chrysalis] enclosing chrysalis=#{chrysalis_id} in cocoon=#{cocoon_id}"
55
+ engine.enclose(chrysalis_id: chrysalis_id, cocoon_id: cocoon_id)
56
+ rescue ArgumentError => e
57
+ { success: false, reason: e.message }
58
+ end
59
+
60
+ def incubate(chrysalis_id:, engine: nil, **)
61
+ return { success: false, reason: :missing_chrysalis_id } if chrysalis_id.nil?
62
+
63
+ engine ||= default_engine
64
+ Legion::Logging.debug "[cognitive_chrysalis] incubating chrysalis=#{chrysalis_id}"
65
+ engine.incubate(chrysalis_id: chrysalis_id)
66
+ rescue ArgumentError => e
67
+ { success: false, reason: e.message }
68
+ end
69
+
70
+ def incubate_all(engine: nil, **)
71
+ engine ||= default_engine
72
+ Legion::Logging.debug '[cognitive_chrysalis] incubating all eligible chrysalises'
73
+ engine.incubate_all!
74
+ rescue ArgumentError => e
75
+ { success: false, reason: e.message }
76
+ end
77
+
78
+ def emerge(chrysalis_id:, force: false, engine: nil, **)
79
+ return { success: false, reason: :missing_chrysalis_id } if chrysalis_id.nil?
80
+
81
+ engine ||= default_engine
82
+ Legion::Logging.debug "[cognitive_chrysalis] emerging chrysalis=#{chrysalis_id} force=#{force}"
83
+ if force
84
+ engine.force_emerge(chrysalis_id: chrysalis_id)
85
+ else
86
+ engine.natural_emerge(chrysalis_id: chrysalis_id)
87
+ end
88
+ rescue ArgumentError => e
89
+ { success: false, reason: e.message }
90
+ end
91
+
92
+ def disturb(cocoon_id:, force: 0.1, engine: nil, **)
93
+ return { success: false, reason: :missing_cocoon_id } if cocoon_id.nil?
94
+
95
+ engine ||= default_engine
96
+ Legion::Logging.debug "[cognitive_chrysalis] disturbing cocoon=#{cocoon_id} force=#{force}"
97
+ engine.disturb_cocoon(cocoon_id: cocoon_id, force: force)
98
+ rescue ArgumentError => e
99
+ { success: false, reason: e.message }
100
+ end
101
+
102
+ def list_chrysalises(engine: nil, **)
103
+ engine ||= default_engine
104
+ all = engine.instance_variable_get(:@chrysalises) || {}
105
+ { success: true, chrysalises: all.values.map(&:to_h), count: all.size }
106
+ rescue ArgumentError => e
107
+ { success: false, reason: e.message }
108
+ end
109
+
110
+ def metamorphosis_status(engine: nil, **)
111
+ engine ||= default_engine
112
+ report = engine.metamorphosis_report
113
+ { success: true }.merge(report)
114
+ rescue ArgumentError => e
115
+ { success: false, reason: e.message }
116
+ end
117
+
118
+ private
119
+
120
+ def default_engine
121
+ @default_engine ||= Helpers::MetamorphosisEngine.new
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Chrysalis
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'legion/extensions/agentic/learning/chrysalis/version'
5
+ require 'legion/extensions/agentic/learning/chrysalis/helpers/constants'
6
+ require 'legion/extensions/agentic/learning/chrysalis/helpers/chrysalis'
7
+ require 'legion/extensions/agentic/learning/chrysalis/helpers/cocoon'
8
+ require 'legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine'
9
+ require 'legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis'
10
+ require 'legion/extensions/agentic/learning/chrysalis/client'
11
+
12
+ module Legion
13
+ module Extensions
14
+ module Agentic
15
+ module Learning
16
+ module Chrysalis
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/curiosity/helpers/constants'
4
+ require 'legion/extensions/agentic/learning/curiosity/helpers/wonder'
5
+ require 'legion/extensions/agentic/learning/curiosity/helpers/wonder_store'
6
+ require 'legion/extensions/agentic/learning/curiosity/helpers/gap_detector'
7
+ require 'legion/extensions/agentic/learning/curiosity/runners/curiosity'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Agentic
12
+ module Learning
13
+ module Curiosity
14
+ # Standalone client for curiosity operations without the full framework.
15
+ class Client
16
+ include Runners::Curiosity
17
+
18
+ attr_reader :wonder_store
19
+
20
+ def initialize(store: nil, **)
21
+ @wonder_store = store || Helpers::WonderStore.new
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Curiosity
8
+ module Helpers
9
+ module Constants
10
+ GAP_TYPES = %i[unknown uncertain contradictory incomplete].freeze
11
+
12
+ MAX_WONDERS = 20
13
+ WONDER_DECAY_RATE = 0.02 # salience decay per hour
14
+ WONDER_STALE_THRESHOLD = 259_200 # 3 days in seconds
15
+ MAX_EXPLORATION_ATTEMPTS = 5
16
+ INFORMATION_GAIN_THRESHOLD = 0.3 # minimum expected gain to create wonder
17
+ CURIOSITY_REWARD_MULTIPLIER = 1.5 # emotional reward on resolution
18
+ DOMAIN_BALANCE_FACTOR = 0.7 # penalize overrepresented domains
19
+ DIVERSIVE_NOVELTY_THRESHOLD = 0.6 # novelty above which diversive curiosity triggers
20
+ SPECIFIC_GAP_THRESHOLD = 0.5 # gap score above which specific curiosity triggers
21
+ EXPLORATION_COOLDOWN = 300 # seconds between re-exploration of same wonder
22
+ LOW_CONFIDENCE_THRESHOLD = 0.5 # prediction confidence below this triggers wonder
23
+ EMPTY_RETRIEVAL_THRESHOLD = 2 # fewer traces than this = unknown domain
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Curiosity
8
+ module Helpers
9
+ # Analyzes tick phase results for knowledge gaps that drive curiosity.
10
+ module GapDetector
11
+ module_function
12
+
13
+ def detect(prior_results)
14
+ detectors = %i[memory_retrieval prediction_engine emotional_evaluation contradiction_resolution]
15
+ methods = %i[detect_memory_gaps detect_prediction_gaps detect_emotional_gaps detect_contradiction_gaps]
16
+
17
+ gaps = detectors.zip(methods).flat_map { |key, method| send(method, prior_results[key]) }
18
+
19
+ gaps
20
+ .select { |g| g[:information_gain] >= Constants::INFORMATION_GAIN_THRESHOLD }
21
+ .sort_by { |g| -((g[:salience] * 0.6) + (g[:information_gain] * 0.4)) }
22
+ end
23
+
24
+ def detect_memory_gaps(result)
25
+ return [] unless result.is_a?(Hash)
26
+
27
+ gaps = []
28
+ traces = result[:traces]
29
+ domain = result[:domain] || :general
30
+
31
+ gaps << unknown_domain_gap(traces, domain) if sparse_traces?(traces)
32
+ gaps << incomplete_knowledge_gap(traces, domain) if weak_traces?(traces)
33
+ gaps.compact
34
+ end
35
+
36
+ def detect_prediction_gaps(result)
37
+ return [] unless result.is_a?(Hash)
38
+
39
+ gaps = []
40
+ gaps << low_confidence_gap(result) if low_confidence?(result)
41
+ gaps << failed_prediction_gap(result) if failed_prediction?(result)
42
+ gaps
43
+ end
44
+
45
+ def detect_emotional_gaps(result)
46
+ return [] unless result.is_a?(Hash)
47
+
48
+ valence = result[:valence]
49
+ return [] unless valence.is_a?(Hash) && novel_unfamiliar?(valence)
50
+
51
+ [novel_unfamiliar_gap(result, valence)]
52
+ end
53
+
54
+ def detect_contradiction_gaps(result)
55
+ return [] unless result.is_a?(Hash)
56
+
57
+ conflicts = result[:active_conflicts] || result[:conflicts]
58
+ return [] unless conflicts.is_a?(Array) && !conflicts.empty?
59
+
60
+ conflicts.first(3).map { |c| contradiction_gap(c) }
61
+ end
62
+
63
+ # -- private helpers below --
64
+
65
+ def sparse_traces?(traces)
66
+ traces.is_a?(Array) && traces.size < Constants::EMPTY_RETRIEVAL_THRESHOLD
67
+ end
68
+
69
+ def weak_traces?(traces)
70
+ return false unless traces.is_a?(Array)
71
+
72
+ traces.any? { |t| t.is_a?(Hash) && (t[:strength] || 1.0) < 0.3 }
73
+ end
74
+
75
+ def low_confidence?(result)
76
+ c = result[:confidence]
77
+ c.is_a?(Numeric) && c < Constants::LOW_CONFIDENCE_THRESHOLD
78
+ end
79
+
80
+ def failed_prediction?(result)
81
+ result[:status] == :failed || result[:error]
82
+ end
83
+
84
+ def novel_unfamiliar?(valence)
85
+ (valence[:novelty] || 0.0) > Constants::DIVERSIVE_NOVELTY_THRESHOLD &&
86
+ (valence[:familiarity] || 1.0) < 0.3
87
+ end
88
+
89
+ def unknown_domain_gap(traces, domain)
90
+ {
91
+ gap_type: :unknown,
92
+ domain: domain,
93
+ question: "What do I know about #{domain}?",
94
+ salience: 0.6,
95
+ information_gain: 0.7,
96
+ source_trace_ids: traces&.filter_map { |t| t[:trace_id] } || []
97
+ }
98
+ end
99
+
100
+ def incomplete_knowledge_gap(traces, domain)
101
+ weak = traces.select { |t| t.is_a?(Hash) && (t[:strength] || 1.0) < 0.3 }
102
+ return nil if weak.empty?
103
+
104
+ {
105
+ gap_type: :incomplete,
106
+ domain: domain,
107
+ question: 'Why are my memories about this topic weak?',
108
+ salience: 0.4,
109
+ information_gain: 0.5,
110
+ source_trace_ids: weak.filter_map { |t| t[:trace_id] }
111
+ }
112
+ end
113
+
114
+ def low_confidence_gap(result)
115
+ confidence = result[:confidence]
116
+ {
117
+ gap_type: :uncertain,
118
+ domain: result[:domain] || :general,
119
+ question: "Why is my prediction confidence low (#{(confidence * 100).round}%)?",
120
+ salience: 0.7,
121
+ information_gain: 0.6,
122
+ source_trace_ids: []
123
+ }
124
+ end
125
+
126
+ def failed_prediction_gap(result)
127
+ {
128
+ gap_type: :uncertain,
129
+ domain: result[:domain] || :general,
130
+ question: 'What caused this prediction failure?',
131
+ salience: 0.8,
132
+ information_gain: 0.7,
133
+ source_trace_ids: []
134
+ }
135
+ end
136
+
137
+ def novel_unfamiliar_gap(result, valence)
138
+ novelty = valence[:novelty] || 0.0
139
+ familiarity = valence[:familiarity] || 1.0
140
+ {
141
+ gap_type: :unknown,
142
+ domain: result[:domain] || :general,
143
+ question: 'This is novel and unfamiliar — what is it?',
144
+ salience: novelty,
145
+ information_gain: (1.0 - familiarity) * 0.8,
146
+ source_trace_ids: []
147
+ }
148
+ end
149
+
150
+ def contradiction_gap(conflict)
151
+ domain = conflict.is_a?(Hash) ? (conflict[:domain] || :general) : :general
152
+ {
153
+ gap_type: :contradictory,
154
+ domain: domain,
155
+ question: "Why do I have contradictory knowledge about #{domain}?",
156
+ salience: 0.8,
157
+ information_gain: 0.7,
158
+ source_trace_ids: conflict.is_a?(Hash) ? Array(conflict[:trace_ids]) : []
159
+ }
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Learning
9
+ module Curiosity
10
+ module Helpers
11
+ module Wonder
12
+ module_function
13
+
14
+ def new_wonder(question:, domain: :general, gap_type: :unknown,
15
+ salience: 0.5, information_gain: 0.5,
16
+ source_trace_ids: [], emotional_valence: {})
17
+ raise ArgumentError, "invalid gap_type: #{gap_type}" unless Constants::GAP_TYPES.include?(gap_type)
18
+
19
+ {
20
+ wonder_id: SecureRandom.uuid,
21
+ question: question,
22
+ domain: domain.to_sym,
23
+ gap_type: gap_type,
24
+ salience: salience.clamp(0.0, 1.0),
25
+ information_gain: information_gain.clamp(0.0, 1.0),
26
+ attempts: 0,
27
+ created_at: Time.now.utc,
28
+ last_explored_at: nil,
29
+ resolved: false,
30
+ resolution: nil,
31
+ source_trace_ids: Array(source_trace_ids),
32
+ emotional_valence: emotional_valence
33
+ }
34
+ end
35
+
36
+ def score(wonder)
37
+ return 0.0 if wonder[:resolved]
38
+
39
+ base = (wonder[:salience] * 0.6) + (wonder[:information_gain] * 0.4)
40
+ attempt_penalty = [wonder[:attempts] * 0.1, 0.5].min
41
+ base - attempt_penalty
42
+ end
43
+
44
+ def stale?(wonder)
45
+ age = Time.now.utc - wonder[:created_at]
46
+ age > Constants::WONDER_STALE_THRESHOLD
47
+ end
48
+
49
+ def explorable?(wonder)
50
+ return false if wonder[:resolved]
51
+ return false if wonder[:attempts] >= Constants::MAX_EXPLORATION_ATTEMPTS
52
+
53
+ if wonder[:last_explored_at]
54
+ cooldown = Constants::EXPLORATION_COOLDOWN * (2**[wonder[:attempts] - 1, 0].max)
55
+ return false if (Time.now.utc - wonder[:last_explored_at]) < cooldown
56
+ end
57
+
58
+ true
59
+ end
60
+
61
+ def decay_salience(wonder, hours_elapsed: 1.0)
62
+ return wonder if wonder[:resolved]
63
+
64
+ decayed = wonder[:salience] - (Constants::WONDER_DECAY_RATE * hours_elapsed)
65
+ wonder.merge(salience: [decayed, 0.0].max)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end