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,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module LearningRate
8
+ module Runners
9
+ module LearningRate
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ def record_prediction(correct:, domain: :general, **)
14
+ rate_model.record_prediction(domain: domain, correct: correct)
15
+ rate = rate_model.rate_for(domain)
16
+ accuracy = rate_model.accuracy_for(domain)
17
+ Legion::Logging.debug "[learning_rate] prediction: domain=#{domain} correct=#{correct} rate=#{rate.round(3)} accuracy=#{accuracy.round(3)}"
18
+ {
19
+ success: true,
20
+ domain: domain,
21
+ rate: rate,
22
+ accuracy: accuracy,
23
+ label: rate_model.label_for(domain)
24
+ }
25
+ end
26
+
27
+ def record_surprise(magnitude:, domain: :general, **)
28
+ rate_model.record_surprise(domain: domain, magnitude: magnitude)
29
+ rate = rate_model.rate_for(domain)
30
+ Legion::Logging.debug "[learning_rate] surprise: domain=#{domain} magnitude=#{magnitude.round(3)} rate=#{rate.round(3)}"
31
+ { success: true, domain: domain, rate: rate, label: rate_model.label_for(domain) }
32
+ end
33
+
34
+ def record_error(magnitude:, domain: :general, **)
35
+ rate_model.record_error(domain: domain, magnitude: magnitude)
36
+ rate = rate_model.rate_for(domain)
37
+ Legion::Logging.debug "[learning_rate] error: domain=#{domain} magnitude=#{magnitude.round(3)} rate=#{rate.round(3)}"
38
+ { success: true, domain: domain, rate: rate, label: rate_model.label_for(domain) }
39
+ end
40
+
41
+ def current_rate(domain: :general, **)
42
+ rate = rate_model.rate_for(domain)
43
+ accuracy = rate_model.accuracy_for(domain)
44
+ {
45
+ success: true,
46
+ domain: domain,
47
+ rate: rate,
48
+ accuracy: accuracy,
49
+ label: rate_model.label_for(domain)
50
+ }
51
+ end
52
+
53
+ def fastest_domains(count: 5, **)
54
+ domains = rate_model.fastest_domains(count)
55
+ { success: true, domains: domains, count: domains.size }
56
+ end
57
+
58
+ def slowest_domains(count: 5, **)
59
+ domains = rate_model.slowest_domains(count)
60
+ { success: true, domains: domains, count: domains.size }
61
+ end
62
+
63
+ def update_learning_rate(**)
64
+ rate_model.decay
65
+ overall = rate_model.overall_rate
66
+ Legion::Logging.debug "[learning_rate] tick: domains=#{rate_model.domain_count} overall=#{overall.round(3)}"
67
+ { success: true, domain_count: rate_model.domain_count, overall_rate: overall }
68
+ end
69
+
70
+ def learning_rate_stats(**)
71
+ { success: true, stats: rate_model.to_h }
72
+ end
73
+
74
+ private
75
+
76
+ def rate_model
77
+ @rate_model ||= Helpers::RateModel.new
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ 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 LearningRate
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/learning_rate/version'
4
+ require 'legion/extensions/agentic/learning/learning_rate/helpers/constants'
5
+ require 'legion/extensions/agentic/learning/learning_rate/helpers/rate_model'
6
+ require 'legion/extensions/agentic/learning/learning_rate/runners/learning_rate'
7
+ require 'legion/extensions/agentic/learning/learning_rate/client'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Agentic
12
+ module Learning
13
+ module LearningRate
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/meta_learning/helpers/constants'
4
+ require 'legion/extensions/agentic/learning/meta_learning/helpers/learning_domain'
5
+ require 'legion/extensions/agentic/learning/meta_learning/helpers/strategy'
6
+ require 'legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine'
7
+ require 'legion/extensions/agentic/learning/meta_learning/runners/meta_learning'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Agentic
12
+ module Learning
13
+ module MetaLearning
14
+ class Client
15
+ include Runners::MetaLearning
16
+
17
+ private
18
+
19
+ def engine
20
+ @engine ||= Helpers::MetaLearningEngine.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module MetaLearning
8
+ module Helpers
9
+ module Constants
10
+ MAX_DOMAINS = 100
11
+ MAX_STRATEGIES = 50
12
+ MAX_EPISODES = 1000
13
+
14
+ DEFAULT_LEARNING_RATE = 0.1
15
+ RATE_BOOST = 0.02
16
+ RATE_DECAY = 0.01
17
+ TRANSFER_BONUS = 0.05
18
+
19
+ PROFICIENCY_LABELS = {
20
+ (0.8..) => :expert,
21
+ (0.6...0.8) => :proficient,
22
+ (0.4...0.6) => :intermediate,
23
+ (0.2...0.4) => :novice,
24
+ (..0.2) => :beginner
25
+ }.freeze
26
+
27
+ EFFICIENCY_LABELS = {
28
+ (0.8..) => :highly_efficient,
29
+ (0.6...0.8) => :efficient,
30
+ (0.4...0.6) => :moderate,
31
+ (0.2...0.4) => :slow,
32
+ (..0.2) => :struggling
33
+ }.freeze
34
+
35
+ STRATEGY_TYPES = %i[
36
+ repetition elaboration analogy decomposition
37
+ pattern_matching trial_and_error observation
38
+ interleaving spaced_practice retrieval_practice
39
+ ].freeze
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Learning
9
+ module MetaLearning
10
+ module Helpers
11
+ class LearningDomain
12
+ include Constants
13
+
14
+ attr_accessor :preferred_strategy
15
+ attr_reader :id, :name, :proficiency, :learning_rate, :episodes_count, :successes, :failures, :related_domains, :created_at
16
+
17
+ def initialize(name:, learning_rate: DEFAULT_LEARNING_RATE, related_domains: [])
18
+ @id = SecureRandom.uuid
19
+ @name = name
20
+ @proficiency = 0.0
21
+ @learning_rate = learning_rate.clamp(0.001, 1.0)
22
+ @episodes_count = 0
23
+ @successes = 0
24
+ @failures = 0
25
+ @preferred_strategy = nil
26
+ @related_domains = Array(related_domains).dup
27
+ @created_at = Time.now.utc
28
+ end
29
+
30
+ def record_success!
31
+ @successes += 1
32
+ @episodes_count += 1
33
+ @proficiency = (@proficiency + @learning_rate).clamp(0.0, 1.0).round(10)
34
+ end
35
+
36
+ def record_failure!
37
+ @failures += 1
38
+ @episodes_count += 1
39
+ penalty = (@learning_rate * 0.5).round(10)
40
+ @proficiency = (@proficiency - penalty).clamp(0.0, 1.0).round(10)
41
+ end
42
+
43
+ def efficiency
44
+ total = @successes + @failures
45
+ return 0.0 if total.zero?
46
+
47
+ (@successes.to_f / total).round(10)
48
+ end
49
+
50
+ def efficiency_label
51
+ EFFICIENCY_LABELS.find { |range, _| range.cover?(efficiency) }&.last || :struggling
52
+ end
53
+
54
+ def proficiency_label
55
+ PROFICIENCY_LABELS.find { |range, _| range.cover?(@proficiency) }&.last || :beginner
56
+ end
57
+
58
+ def adapt_rate!(delta:)
59
+ @learning_rate = (@learning_rate + delta).clamp(0.001, 1.0).round(10)
60
+ end
61
+
62
+ def to_h
63
+ {
64
+ id: @id,
65
+ name: @name,
66
+ proficiency: @proficiency,
67
+ proficiency_label: proficiency_label,
68
+ learning_rate: @learning_rate,
69
+ episodes_count: @episodes_count,
70
+ successes: @successes,
71
+ failures: @failures,
72
+ efficiency: efficiency,
73
+ efficiency_label: efficiency_label,
74
+ preferred_strategy: @preferred_strategy,
75
+ related_domains: @related_domains,
76
+ created_at: @created_at
77
+ }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module MetaLearning
8
+ module Helpers
9
+ class MetaLearningEngine
10
+ include Constants
11
+
12
+ attr_reader :domains, :strategies, :episodes
13
+
14
+ def initialize
15
+ @domains = {}
16
+ @strategies = {}
17
+ @episodes = []
18
+ end
19
+
20
+ def create_domain(name:, learning_rate: DEFAULT_LEARNING_RATE, related_domains: [])
21
+ return { error: :limit_reached } if @domains.size >= MAX_DOMAINS
22
+
23
+ domain = LearningDomain.new(name: name, learning_rate: learning_rate, related_domains: related_domains)
24
+ @domains[domain.id] = domain
25
+ domain
26
+ end
27
+
28
+ def create_strategy(name:, strategy_type:)
29
+ return { error: :limit_reached } if @strategies.size >= MAX_STRATEGIES
30
+ return { error: :invalid_strategy_type } unless STRATEGY_TYPES.include?(strategy_type)
31
+
32
+ strategy = Strategy.new(name: name, strategy_type: strategy_type)
33
+ @strategies[strategy.id] = strategy
34
+ strategy
35
+ end
36
+
37
+ def record_episode(domain_id:, success:, strategy_id: nil)
38
+ domain = @domains[domain_id]
39
+ return { error: :domain_not_found } unless domain
40
+
41
+ success ? domain.record_success! : domain.record_failure!
42
+
43
+ strategy = @strategies[strategy_id] if strategy_id
44
+ strategy&.use!(success: success, domain_name: domain.name)
45
+
46
+ if strategy && success
47
+ current_preferred_rate = preferred_strategy_rate_for(domain)
48
+ domain.preferred_strategy = strategy.name if strategy.success_rate > current_preferred_rate
49
+ end
50
+
51
+ episode = build_episode(domain, strategy_id, success)
52
+ @episodes << episode
53
+ @episodes.shift while @episodes.size > MAX_EPISODES
54
+
55
+ check_transfer_opportunities(domain)
56
+
57
+ episode
58
+ end
59
+
60
+ def recommend_strategy(domain_id:)
61
+ domain = @domains[domain_id]
62
+ return { error: :domain_not_found } unless domain
63
+
64
+ candidate = best_strategy_for_domain(domain)
65
+ return { recommendation: nil, reason: :no_data } if candidate.nil?
66
+
67
+ { recommendation: candidate.name, strategy_id: candidate.id, success_rate: candidate.success_rate }
68
+ end
69
+
70
+ def transfer_check(source_domain_id:, target_domain_id:)
71
+ source = @domains[source_domain_id]
72
+ target = @domains[target_domain_id]
73
+ return { error: :domain_not_found } unless source && target
74
+
75
+ eligible = source.proficiency >= 0.6 && target.related_domains.include?(source.name)
76
+ { eligible: eligible, source_proficiency: source.proficiency, target_domain: target.name }
77
+ end
78
+
79
+ def apply_transfer(source_domain_id:, target_domain_id:)
80
+ source = @domains[source_domain_id]
81
+ target = @domains[target_domain_id]
82
+ return { error: :domain_not_found } unless source && target
83
+
84
+ check = transfer_check(source_domain_id: source_domain_id, target_domain_id: target_domain_id)
85
+ return { applied: false, reason: :not_eligible } unless check[:eligible]
86
+
87
+ target.adapt_rate!(delta: TRANSFER_BONUS)
88
+ { applied: true, target_domain: target.name, new_learning_rate: target.learning_rate }
89
+ end
90
+
91
+ def domain_ranking(limit: 10)
92
+ @domains.values
93
+ .sort_by { |d| -d.proficiency }
94
+ .first(limit)
95
+ .map(&:to_h)
96
+ end
97
+
98
+ def strategy_ranking(limit: 10)
99
+ @strategies.values
100
+ .sort_by { |s| -s.success_rate }
101
+ .first(limit)
102
+ .map(&:to_h)
103
+ end
104
+
105
+ def overall_efficiency
106
+ return 0.0 if @domains.empty?
107
+
108
+ total = @domains.values.sum(&:efficiency)
109
+ (total / @domains.size).round(10)
110
+ end
111
+
112
+ def learning_curve(domain_id:)
113
+ domain = @domains[domain_id]
114
+ return { error: :domain_not_found } unless domain
115
+
116
+ domain_episodes = @episodes.select { |e| e[:domain_id] == domain_id }
117
+ { domain: domain.name, curve: domain_episodes }
118
+ end
119
+
120
+ def adapt_rates
121
+ adapted = []
122
+ @domains.each_value do |domain|
123
+ next if domain.episodes_count.zero?
124
+
125
+ if domain.efficiency >= 0.8
126
+ domain.adapt_rate!(delta: RATE_BOOST)
127
+ adapted << { domain: domain.name, direction: :boost, new_rate: domain.learning_rate }
128
+ elsif domain.efficiency < 0.2
129
+ domain.adapt_rate!(delta: -RATE_DECAY)
130
+ adapted << { domain: domain.name, direction: :decay, new_rate: domain.learning_rate }
131
+ end
132
+ end
133
+ { adapted: adapted, count: adapted.size }
134
+ end
135
+
136
+ def prune_stale_domains(min_episodes: 1)
137
+ before = @domains.size
138
+ @domains.reject! { |_, d| d.episodes_count < min_episodes }
139
+ pruned = before - @domains.size
140
+ { pruned: pruned, remaining: @domains.size }
141
+ end
142
+
143
+ def to_h
144
+ {
145
+ domain_count: @domains.size,
146
+ strategy_count: @strategies.size,
147
+ episode_count: @episodes.size,
148
+ overall_efficiency: overall_efficiency,
149
+ top_domain: @domains.values.max_by(&:proficiency)&.name,
150
+ top_strategy: @strategies.values.max_by(&:success_rate)&.name
151
+ }
152
+ end
153
+
154
+ private
155
+
156
+ def build_episode(domain, strategy_id, success)
157
+ {
158
+ id: SecureRandom.uuid,
159
+ domain_id: domain.id,
160
+ domain_name: domain.name,
161
+ strategy_id: strategy_id,
162
+ success: success,
163
+ proficiency: domain.proficiency,
164
+ recorded_at: Time.now.utc
165
+ }
166
+ end
167
+
168
+ def preferred_strategy_rate_for(domain)
169
+ return 0.0 unless domain.preferred_strategy
170
+
171
+ strategy = @strategies.values.find { |s| s.name == domain.preferred_strategy }
172
+ strategy&.success_rate || 0.0
173
+ end
174
+
175
+ def best_strategy_for_domain(domain)
176
+ direct = strategies_used_in_domain(domain.name)
177
+ return direct.max_by(&:success_rate) if direct.any?
178
+
179
+ related_strategies = domain.related_domains.flat_map { |rname| strategies_used_in_domain(rname) }.uniq
180
+ related_strategies.max_by(&:success_rate)
181
+ end
182
+
183
+ def strategies_used_in_domain(domain_name)
184
+ @strategies.values.select { |s| s.domains_used.include?(domain_name) }
185
+ end
186
+
187
+ def check_transfer_opportunities(domain)
188
+ @domains.each_value do |target|
189
+ next if target.id == domain.id
190
+ next unless target.related_domains.include?(domain.name)
191
+
192
+ check = transfer_check(source_domain_id: domain.id, target_domain_id: target.id)
193
+ apply_transfer(source_domain_id: domain.id, target_domain_id: target.id) if check[:eligible]
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Learning
9
+ module MetaLearning
10
+ module Helpers
11
+ class Strategy
12
+ include Constants
13
+
14
+ attr_reader :id, :name, :strategy_type, :usage_count,
15
+ :success_count, :domains_used, :created_at
16
+
17
+ def initialize(name:, strategy_type:)
18
+ @id = SecureRandom.uuid
19
+ @name = name
20
+ @strategy_type = strategy_type
21
+ @usage_count = 0
22
+ @success_count = 0
23
+ @domains_used = []
24
+ @created_at = Time.now.utc
25
+ end
26
+
27
+ def use!(success:, domain_name: nil)
28
+ @usage_count += 1
29
+ @success_count += 1 if success
30
+ @domains_used << domain_name if domain_name && !@domains_used.include?(domain_name)
31
+ end
32
+
33
+ def success_rate
34
+ return 0.0 if @usage_count.zero?
35
+
36
+ (@success_count.to_f / @usage_count).round(10)
37
+ end
38
+
39
+ def versatility
40
+ @domains_used.uniq.size
41
+ end
42
+
43
+ def to_h
44
+ {
45
+ id: @id,
46
+ name: @name,
47
+ strategy_type: @strategy_type,
48
+ usage_count: @usage_count,
49
+ success_count: @success_count,
50
+ success_rate: success_rate,
51
+ versatility: versatility,
52
+ domains_used: @domains_used,
53
+ created_at: @created_at
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module MetaLearning
8
+ module Runners
9
+ module MetaLearning
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ def create_learning_domain(name:, learning_rate: Helpers::Constants::DEFAULT_LEARNING_RATE,
14
+ related_domains: [], **)
15
+ result = engine.create_domain(name: name, learning_rate: learning_rate, related_domains: related_domains)
16
+ if result.is_a?(Hash) && result[:error]
17
+ Legion::Logging.warn "[meta_learning] create_domain failed: #{result[:error]}"
18
+ return result
19
+ end
20
+
21
+ Legion::Logging.debug "[meta_learning] domain created: #{result.name} id=#{result.id[0..7]}"
22
+ result.to_h
23
+ end
24
+
25
+ def register_learning_strategy(name:, strategy_type:, **)
26
+ result = engine.create_strategy(name: name, strategy_type: strategy_type)
27
+ if result.is_a?(Hash) && result[:error]
28
+ Legion::Logging.warn "[meta_learning] create_strategy failed: #{result[:error]}"
29
+ return result
30
+ end
31
+
32
+ Legion::Logging.debug "[meta_learning] strategy registered: #{result.name} type=#{result.strategy_type}"
33
+ result.to_h
34
+ end
35
+
36
+ def record_learning_episode(domain_id:, success:, strategy_id: nil, **)
37
+ result = engine.record_episode(domain_id: domain_id, strategy_id: strategy_id, success: success)
38
+ if result.is_a?(Hash) && result[:error]
39
+ Legion::Logging.warn "[meta_learning] record_episode failed: #{result[:error]}"
40
+ return result
41
+ end
42
+
43
+ Legion::Logging.debug "[meta_learning] episode recorded domain=#{result[:domain_name]} " \
44
+ "success=#{success} proficiency=#{result[:proficiency].round(4)}"
45
+ result
46
+ end
47
+
48
+ def recommend_learning_strategy(domain_id:, **)
49
+ result = engine.recommend_strategy(domain_id: domain_id)
50
+ Legion::Logging.debug "[meta_learning] strategy recommendation domain=#{domain_id[0..7]} " \
51
+ "recommendation=#{result[:recommendation]}"
52
+ result
53
+ end
54
+
55
+ def check_transfer_learning(source_domain_id:, target_domain_id:, **)
56
+ result = engine.transfer_check(source_domain_id: source_domain_id, target_domain_id: target_domain_id)
57
+ Legion::Logging.debug "[meta_learning] transfer check eligible=#{result[:eligible]}"
58
+ result
59
+ end
60
+
61
+ def apply_transfer_bonus(source_domain_id:, target_domain_id:, **)
62
+ result = engine.apply_transfer(source_domain_id: source_domain_id, target_domain_id: target_domain_id)
63
+ Legion::Logging.info "[meta_learning] transfer applied=#{result[:applied]}"
64
+ result
65
+ end
66
+
67
+ def learning_domain_ranking(limit: 10, **)
68
+ ranking = engine.domain_ranking(limit: limit)
69
+ Legion::Logging.debug "[meta_learning] domain ranking returned #{ranking.size} domains"
70
+ { ranking: ranking, count: ranking.size }
71
+ end
72
+
73
+ def learning_strategy_ranking(limit: 10, **)
74
+ ranking = engine.strategy_ranking(limit: limit)
75
+ Legion::Logging.debug "[meta_learning] strategy ranking returned #{ranking.size} strategies"
76
+ { ranking: ranking, count: ranking.size }
77
+ end
78
+
79
+ def learning_curve_report(domain_id:, **)
80
+ result = engine.learning_curve(domain_id: domain_id)
81
+ if result.is_a?(Hash) && result[:error]
82
+ Legion::Logging.warn "[meta_learning] learning_curve failed: #{result[:error]}"
83
+ return result
84
+ end
85
+
86
+ Legion::Logging.debug "[meta_learning] learning curve domain=#{result[:domain]} " \
87
+ "episodes=#{result[:curve].size}"
88
+ result
89
+ end
90
+
91
+ def update_meta_learning(**)
92
+ adapt_result = engine.adapt_rates
93
+ prune_result = engine.prune_stale_domains
94
+ stats = engine.to_h
95
+ Legion::Logging.info "[meta_learning] update: adapted=#{adapt_result[:count]} " \
96
+ "pruned=#{prune_result[:pruned]} domains=#{stats[:domain_count]}"
97
+ { adapt: adapt_result, prune: prune_result, stats: stats }
98
+ end
99
+
100
+ def meta_learning_stats(**)
101
+ stats = engine.to_h
102
+ Legion::Logging.debug "[meta_learning] stats domains=#{stats[:domain_count]} " \
103
+ "strategies=#{stats[:strategy_count]} efficiency=#{stats[:overall_efficiency]}"
104
+ stats
105
+ end
106
+
107
+ private
108
+
109
+ def engine
110
+ @engine ||= Helpers::MetaLearningEngine.new
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ 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 MetaLearning
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end