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,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/habit/helpers/constants'
4
+ require 'legion/extensions/agentic/learning/habit/helpers/action_sequence'
5
+ require 'legion/extensions/agentic/learning/habit/helpers/habit_store'
6
+ require 'legion/extensions/agentic/learning/habit/runners/habit'
7
+
8
+ module Legion
9
+ module Extensions
10
+ module Agentic
11
+ module Learning
12
+ module Habit
13
+ class Client
14
+ include Runners::Habit
15
+
16
+ attr_reader :habit_store
17
+
18
+ def initialize(habit_store: nil, **)
19
+ @habit_store = habit_store || Helpers::HabitStore.new
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Learning
9
+ module Habit
10
+ module Helpers
11
+ class ActionSequence
12
+ include Constants
13
+
14
+ attr_reader :id, :actions, :context, :execution_count, :success_count,
15
+ :strength, :maturity, :last_executed, :created_at
16
+
17
+ def initialize(actions:, context: {})
18
+ @id = SecureRandom.uuid
19
+ @actions = actions.map(&:to_sym)
20
+ @context = context
21
+ @execution_count = 0
22
+ @success_count = 0
23
+ @strength = 0.3
24
+ @maturity = :novel
25
+ @last_executed = nil
26
+ @created_at = Time.now.utc
27
+ end
28
+
29
+ def record_execution(success:)
30
+ @execution_count += 1
31
+ @success_count += 1 if success
32
+ @last_executed = Time.now.utc
33
+
34
+ @strength = if success
35
+ [@strength + Constants::REINFORCEMENT_RATE, 1.0].min
36
+ else
37
+ [@strength - Constants::REINFORCEMENT_RATE, 0.0].max
38
+ end
39
+
40
+ update_maturity
41
+ end
42
+
43
+ def cognitive_cost
44
+ Constants::COGNITIVE_COST[@maturity]
45
+ end
46
+
47
+ def success_rate
48
+ return 0.0 if @execution_count.zero?
49
+
50
+ @success_count.to_f / @execution_count
51
+ end
52
+
53
+ def matches_context?(ctx)
54
+ return true if ctx.empty?
55
+
56
+ relevant = Constants::CONTEXT_DIMENSIONS.select { |d| @context.key?(d) || ctx.key?(d) }
57
+ return true if relevant.empty?
58
+
59
+ matches = relevant.count { |d| @context[d] == ctx[d] }
60
+ matches.to_f / relevant.size >= 0.5
61
+ end
62
+
63
+ def decay
64
+ @strength -= Constants::DECAY_RATE
65
+ @strength >= Constants::HABIT_STRENGTH_FLOOR
66
+ end
67
+
68
+ def mature?
69
+ @maturity == :habitual || @maturity == :automatic
70
+ end
71
+
72
+ def stale?(threshold = 3600)
73
+ return true if @last_executed.nil?
74
+
75
+ (Time.now.utc - @last_executed) > threshold
76
+ end
77
+
78
+ def similarity(other)
79
+ set_a = @actions.uniq
80
+ set_b = other.actions.uniq
81
+ return 0.0 if set_a.empty? && set_b.empty?
82
+
83
+ intersection = (set_a & set_b).size
84
+ union = (set_a | set_b).size
85
+ return 0.0 if union.zero?
86
+
87
+ intersection.to_f / union
88
+ end
89
+
90
+ def to_h
91
+ {
92
+ id: @id,
93
+ actions: @actions,
94
+ context: @context,
95
+ execution_count: @execution_count,
96
+ success_count: @success_count,
97
+ strength: @strength,
98
+ maturity: @maturity,
99
+ cognitive_cost: cognitive_cost,
100
+ success_rate: success_rate,
101
+ last_executed: @last_executed,
102
+ created_at: @created_at
103
+ }
104
+ end
105
+
106
+ private
107
+
108
+ def update_maturity
109
+ new_stage = Constants::MATURITY_STAGES.reverse.find do |stage|
110
+ @execution_count >= Constants::MATURITY_THRESHOLDS[stage]
111
+ end
112
+ @maturity = new_stage || :novel
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Habit
8
+ module Helpers
9
+ module Constants
10
+ MATURITY_STAGES = %i[novel learning practiced habitual automatic].freeze
11
+
12
+ MATURITY_THRESHOLDS = {
13
+ novel: 0,
14
+ learning: 3,
15
+ practiced: 10,
16
+ habitual: 25,
17
+ automatic: 50
18
+ }.freeze
19
+
20
+ COGNITIVE_COST = {
21
+ novel: 1.0,
22
+ learning: 0.8,
23
+ practiced: 0.5,
24
+ habitual: 0.2,
25
+ automatic: 0.05
26
+ }.freeze
27
+
28
+ REINFORCEMENT_RATE = 0.1
29
+ DECAY_RATE = 0.02
30
+ MIN_SEQUENCE_LENGTH = 2
31
+ MAX_SEQUENCE_LENGTH = 10
32
+ MAX_HABITS = 200
33
+ SIMILARITY_THRESHOLD = 0.7
34
+ CHUNKING_THRESHOLD = 5
35
+ HABIT_STRENGTH_FLOOR = 0.1
36
+
37
+ CONTEXT_DIMENSIONS = %i[domain mood time_of_day trigger].freeze
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Habit
8
+ module Helpers
9
+ class HabitStore
10
+ include Constants
11
+
12
+ MAX_BUFFER_SIZE = 50
13
+
14
+ attr_reader :habits, :action_buffer
15
+
16
+ def initialize
17
+ @habits = {}
18
+ @action_buffer = []
19
+ end
20
+
21
+ def record_action(action, context: {})
22
+ @action_buffer << { action: action.to_sym, context: context }
23
+ @action_buffer.shift if @action_buffer.size > MAX_BUFFER_SIZE
24
+ end
25
+
26
+ def detect_patterns
27
+ new_habits = []
28
+ actions = @action_buffer.map { |e| e[:action] }
29
+ ctx = @action_buffer.last&.dig(:context) || {}
30
+
31
+ (Constants::MIN_SEQUENCE_LENGTH..Constants::MAX_SEQUENCE_LENGTH).each do |len|
32
+ next if actions.size < len
33
+
34
+ process_length(len, actions, ctx, new_habits)
35
+ end
36
+
37
+ new_habits
38
+ end
39
+
40
+ def find_matching(context: {})
41
+ @habits.values
42
+ .select { |h| h.matches_context?(context) }
43
+ .sort_by { |h| -h.strength }
44
+ end
45
+
46
+ def get(id)
47
+ @habits[id]
48
+ end
49
+
50
+ def reinforce(id, success:)
51
+ habit = @habits[id]
52
+ return unless habit
53
+
54
+ habit.record_execution(success: success)
55
+ end
56
+
57
+ def decay_all
58
+ removed = 0
59
+ @habits.each do |id, habit|
60
+ unless habit.decay
61
+ @habits.delete(id)
62
+ removed += 1
63
+ end
64
+ end
65
+ removed
66
+ end
67
+
68
+ def merge_similar
69
+ merged = 0
70
+ @habits.keys.combination(2).each do |id_a, id_b|
71
+ merged += 1 if merge_pair(id_a, id_b)
72
+ end
73
+ merged
74
+ end
75
+
76
+ def by_maturity(stage)
77
+ @habits.values.select { |h| h.maturity == stage }
78
+ end
79
+
80
+ def stats
81
+ habits_list = @habits.values
82
+ per_maturity = Constants::MATURITY_STAGES.to_h { |s| [s, 0] }
83
+ habits_list.each { |h| per_maturity[h.maturity] += 1 }
84
+ avg_strength = habits_list.empty? ? 0.0 : habits_list.sum(&:strength) / habits_list.size
85
+ oldest = habits_list.min_by(&:created_at)
86
+ { total: habits_list.size, per_maturity: per_maturity, avg_strength: avg_strength, oldest: oldest&.to_h }
87
+ end
88
+
89
+ def evict_if_needed
90
+ return unless @habits.size > Constants::MAX_HABITS
91
+
92
+ weakest_id = @habits.min_by { |_id, h| h.strength }.first
93
+ @habits.delete(weakest_id)
94
+ end
95
+
96
+ private
97
+
98
+ def process_length(len, actions, ctx, new_habits)
99
+ count_subsequences(actions, len).each do |subseq, count|
100
+ next if count < Constants::CHUNKING_THRESHOLD
101
+
102
+ record_or_reinforce(subseq, count, ctx, new_habits)
103
+ end
104
+ end
105
+
106
+ def count_subsequences(actions, len)
107
+ counts = Hash.new(0)
108
+ (0..(actions.size - len)).each { |i| counts[actions[i, len]] += 1 }
109
+ counts
110
+ end
111
+
112
+ def record_or_reinforce(subseq, count, ctx, new_habits)
113
+ existing = find_existing_sequence(subseq)
114
+ if existing
115
+ existing.record_execution(success: true)
116
+ else
117
+ create_habit(subseq, count, ctx, new_habits)
118
+ end
119
+ end
120
+
121
+ def create_habit(subseq, count, ctx, new_habits)
122
+ habit = ActionSequence.new(actions: subseq, context: ctx)
123
+ (count - 1).times { habit.record_execution(success: true) }
124
+ @habits[habit.id] = habit
125
+ evict_if_needed
126
+ new_habits << habit
127
+ end
128
+
129
+ def merge_pair(id_a, id_b)
130
+ habit_a = @habits[id_a]
131
+ habit_b = @habits[id_b]
132
+ return false unless habit_a && habit_b
133
+ return false if habit_a.similarity(habit_b) < Constants::SIMILARITY_THRESHOLD
134
+
135
+ @habits.delete(habit_a.strength >= habit_b.strength ? id_b : id_a)
136
+ true
137
+ end
138
+
139
+ def find_existing_sequence(actions)
140
+ @habits.values.find { |h| h.actions == actions.map(&:to_sym) }
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Habit
8
+ module Runners
9
+ module Habit
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ def observe_action(action:, context: {}, **)
14
+ Legion::Logging.debug "[habit] observe_action: action=#{action} context=#{context}"
15
+ habit_store.record_action(action, context: context)
16
+ detected = habit_store.detect_patterns
17
+ Legion::Logging.info "[habit] patterns detected: #{detected.size}" unless detected.empty?
18
+ {
19
+ recorded: true,
20
+ action: action,
21
+ new_habits_detected: detected.size,
22
+ habits: detected.map(&:to_h)
23
+ }
24
+ end
25
+
26
+ def suggest_habit(context: {}, **)
27
+ matches = habit_store.find_matching(context: context)
28
+ Legion::Logging.debug "[habit] suggest_habit: context=#{context} matches=#{matches.size}"
29
+ if matches.empty?
30
+ { suggestion: nil, reason: :no_matching_habits }
31
+ else
32
+ best = matches.first
33
+ {
34
+ suggestion: best.to_h,
35
+ cognitive_savings: 1.0 - best.cognitive_cost,
36
+ alternatives: matches[1..2]&.map(&:to_h) || []
37
+ }
38
+ end
39
+ end
40
+
41
+ def execute_habit(id:, success: true, **)
42
+ habit = habit_store.get(id)
43
+ return { error: :not_found } unless habit
44
+
45
+ habit.record_execution(success: success)
46
+ Legion::Logging.debug "[habit] execute_habit: id=#{id} success=#{success} maturity=#{habit.maturity}"
47
+ { executed: true, habit: habit.to_h, cognitive_cost: habit.cognitive_cost }
48
+ end
49
+
50
+ def decay_habits(**)
51
+ removed = habit_store.decay_all
52
+ Legion::Logging.debug "[habit] decay_habits: removed=#{removed}"
53
+ { decayed: true, removed_count: removed }
54
+ end
55
+
56
+ def merge_habits(**)
57
+ merged = habit_store.merge_similar
58
+ Legion::Logging.debug "[habit] merge_habits: merged=#{merged}"
59
+ { merged_count: merged }
60
+ end
61
+
62
+ def habit_stats(**)
63
+ habit_store.stats
64
+ end
65
+
66
+ def habit_repertoire(maturity: nil, limit: 20, **)
67
+ habits = maturity ? habit_store.by_maturity(maturity.to_sym) : habit_store.habits.values
68
+ Legion::Logging.debug "[habit] habit_repertoire: maturity=#{maturity} total=#{habits.size}"
69
+ {
70
+ habits: habits.sort_by { |h| -h.strength }.first(limit).map(&:to_h),
71
+ total: habits.size
72
+ }
73
+ end
74
+
75
+ private
76
+
77
+ def habit_store
78
+ @habit_store ||= Helpers::HabitStore.new
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ 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 Habit
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/habit/version'
4
+ require 'legion/extensions/agentic/learning/habit/helpers/constants'
5
+ require 'legion/extensions/agentic/learning/habit/helpers/action_sequence'
6
+ require 'legion/extensions/agentic/learning/habit/helpers/habit_store'
7
+ require 'legion/extensions/agentic/learning/habit/runners/habit'
8
+ require 'legion/extensions/agentic/learning/habit/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module Agentic
13
+ module Learning
14
+ module Habit
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/actors/every'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Learning
9
+ module Hebbian
10
+ module Actor
11
+ class Decay < Legion::Extensions::Actors::Every
12
+ def runner_class
13
+ Legion::Extensions::Agentic::Learning::Hebbian::Runners::HebbianAssembly
14
+ end
15
+
16
+ def runner_function
17
+ 'update_hebbian'
18
+ end
19
+
20
+ def time
21
+ 60
22
+ end
23
+
24
+ def run_now?
25
+ false
26
+ end
27
+
28
+ def use_runner?
29
+ false
30
+ end
31
+
32
+ def check_subtask?
33
+ false
34
+ end
35
+
36
+ def generate_task?
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/hebbian/helpers/constants'
4
+ require 'legion/extensions/agentic/learning/hebbian/helpers/unit'
5
+ require 'legion/extensions/agentic/learning/hebbian/helpers/assembly'
6
+ require 'legion/extensions/agentic/learning/hebbian/helpers/assembly_network'
7
+ require 'legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Agentic
12
+ module Learning
13
+ module Hebbian
14
+ class Client
15
+ include Runners::HebbianAssembly
16
+
17
+ def initialize(network: nil, **)
18
+ @network = network || Helpers::AssemblyNetwork.new
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :network
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Learning
7
+ module Hebbian
8
+ module Helpers
9
+ class Assembly
10
+ include Constants
11
+
12
+ attr_reader :id, :member_ids, :formed_at, :activation_count, :last_activated
13
+ attr_accessor :coherence
14
+
15
+ def initialize(id:, member_ids:)
16
+ @id = id
17
+ @member_ids = Array(member_ids).uniq
18
+ @coherence = 0.5
19
+ @formed_at = Time.now.utc
20
+ @activation_count = 0
21
+ @last_activated = nil
22
+ end
23
+
24
+ def activate
25
+ @activation_count += 1
26
+ @last_activated = Time.now.utc
27
+ end
28
+
29
+ def consolidate
30
+ @coherence = [@coherence + CONSOLIDATION_BOOST, MAX_WEIGHT].min
31
+ end
32
+
33
+ def decay
34
+ @coherence = [@coherence - WEIGHT_DECAY, 0.0].max
35
+ end
36
+
37
+ def dissolving?
38
+ @coherence < ASSEMBLY_MIN_WEIGHT
39
+ end
40
+
41
+ def member_count
42
+ @member_ids.size
43
+ end
44
+
45
+ def includes?(unit_id)
46
+ @member_ids.include?(unit_id)
47
+ end
48
+
49
+ def state
50
+ if @last_activated && (Time.now.utc - @last_activated) < CO_ACTIVATION_WINDOW
51
+ :active
52
+ elsif @last_activated && (Time.now.utc - @last_activated) < (CO_ACTIVATION_WINDOW * 3)
53
+ :primed
54
+ elsif dissolving?
55
+ :dissolving
56
+ elsif @coherence >= ASSEMBLY_MIN_WEIGHT
57
+ :dormant
58
+ else
59
+ :forming
60
+ end
61
+ end
62
+
63
+ def to_h
64
+ {
65
+ id: @id,
66
+ members: @member_ids.dup,
67
+ member_count: member_count,
68
+ coherence: @coherence.round(4),
69
+ state: state,
70
+ state_label: ASSEMBLY_STATE_LABELS[state],
71
+ activation_count: @activation_count,
72
+ formed_at: @formed_at,
73
+ last_activated: @last_activated
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end