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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/lex-agentic-learning.gemspec +30 -0
- data/lib/legion/extensions/agentic/learning/anchoring/client.rb +26 -0
- data/lib/legion/extensions/agentic/learning/anchoring/helpers/anchor.rb +65 -0
- data/lib/legion/extensions/agentic/learning/anchoring/helpers/anchor_store.rb +132 -0
- data/lib/legion/extensions/agentic/learning/anchoring/helpers/constants.rb +31 -0
- data/lib/legion/extensions/agentic/learning/anchoring/runners/anchoring.rb +100 -0
- data/lib/legion/extensions/agentic/learning/anchoring/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/anchoring.rb +19 -0
- data/lib/legion/extensions/agentic/learning/catalyst/client.rb +15 -0
- data/lib/legion/extensions/agentic/learning/catalyst/helpers/catalyst.rb +87 -0
- data/lib/legion/extensions/agentic/learning/catalyst/helpers/catalyst_engine.rb +153 -0
- data/lib/legion/extensions/agentic/learning/catalyst/helpers/constants.rb +55 -0
- data/lib/legion/extensions/agentic/learning/catalyst/helpers/reaction.rb +87 -0
- data/lib/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst.rb +103 -0
- data/lib/legion/extensions/agentic/learning/catalyst/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/catalyst.rb +22 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/client.rb +22 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis.rb +137 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/helpers/cocoon.rb +89 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/helpers/constants.rb +49 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine.rb +157 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis.rb +129 -0
- data/lib/legion/extensions/agentic/learning/chrysalis/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/chrysalis.rb +21 -0
- data/lib/legion/extensions/agentic/learning/curiosity/client.rb +28 -0
- data/lib/legion/extensions/agentic/learning/curiosity/helpers/constants.rb +30 -0
- data/lib/legion/extensions/agentic/learning/curiosity/helpers/gap_detector.rb +167 -0
- data/lib/legion/extensions/agentic/learning/curiosity/helpers/wonder.rb +73 -0
- data/lib/legion/extensions/agentic/learning/curiosity/helpers/wonder_store.rb +149 -0
- data/lib/legion/extensions/agentic/learning/curiosity/runners/curiosity.rb +163 -0
- data/lib/legion/extensions/agentic/learning/curiosity/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/curiosity.rb +21 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity/client.rb +28 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants.rb +31 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine.rb +122 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap.rb +70 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity.rb +106 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/epistemic_curiosity.rb +19 -0
- data/lib/legion/extensions/agentic/learning/fermentation/client.rb +19 -0
- data/lib/legion/extensions/agentic/learning/fermentation/helpers/batch.rb +75 -0
- data/lib/legion/extensions/agentic/learning/fermentation/helpers/constants.rb +78 -0
- data/lib/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine.rb +147 -0
- data/lib/legion/extensions/agentic/learning/fermentation/helpers/substrate.rb +108 -0
- data/lib/legion/extensions/agentic/learning/fermentation/runners/cognitive_fermentation.rb +60 -0
- data/lib/legion/extensions/agentic/learning/fermentation/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/fermentation.rb +22 -0
- data/lib/legion/extensions/agentic/learning/habit/client.rb +26 -0
- data/lib/legion/extensions/agentic/learning/habit/helpers/action_sequence.rb +120 -0
- data/lib/legion/extensions/agentic/learning/habit/helpers/constants.rb +44 -0
- data/lib/legion/extensions/agentic/learning/habit/helpers/habit_store.rb +148 -0
- data/lib/legion/extensions/agentic/learning/habit/runners/habit.rb +86 -0
- data/lib/legion/extensions/agentic/learning/habit/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/habit.rb +19 -0
- data/lib/legion/extensions/agentic/learning/hebbian/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/learning/hebbian/client.rb +29 -0
- data/lib/legion/extensions/agentic/learning/hebbian/helpers/assembly.rb +82 -0
- data/lib/legion/extensions/agentic/learning/hebbian/helpers/assembly_network.rb +190 -0
- data/lib/legion/extensions/agentic/learning/hebbian/helpers/constants.rb +50 -0
- data/lib/legion/extensions/agentic/learning/hebbian/helpers/unit.rb +94 -0
- data/lib/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly.rb +94 -0
- data/lib/legion/extensions/agentic/learning/hebbian/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/hebbian.rb +20 -0
- data/lib/legion/extensions/agentic/learning/learning_rate/client.rb +25 -0
- data/lib/legion/extensions/agentic/learning/learning_rate/helpers/constants.rb +35 -0
- data/lib/legion/extensions/agentic/learning/learning_rate/helpers/rate_model.rb +133 -0
- data/lib/legion/extensions/agentic/learning/learning_rate/runners/learning_rate.rb +85 -0
- data/lib/legion/extensions/agentic/learning/learning_rate/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/learning_rate.rb +18 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/client.rb +27 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/helpers/constants.rb +46 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/helpers/learning_domain.rb +85 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine.rb +202 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/helpers/strategy.rb +62 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/runners/meta_learning.rb +118 -0
- data/lib/legion/extensions/agentic/learning/meta_learning/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/meta_learning.rb +20 -0
- data/lib/legion/extensions/agentic/learning/plasticity/client.rb +15 -0
- data/lib/legion/extensions/agentic/learning/plasticity/helpers/constants.rb +45 -0
- data/lib/legion/extensions/agentic/learning/plasticity/helpers/neural_pathway.rb +85 -0
- data/lib/legion/extensions/agentic/learning/plasticity/helpers/plasticity_engine.rb +130 -0
- data/lib/legion/extensions/agentic/learning/plasticity/runners/cognitive_plasticity.rb +85 -0
- data/lib/legion/extensions/agentic/learning/plasticity/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/plasticity.rb +19 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/client.rb +28 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/helpers/constants.rb +35 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/helpers/option.rb +78 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/helpers/preference_engine.rb +121 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/runners/preference_learning.rb +84 -0
- data/lib/legion/extensions/agentic/learning/preference_learning/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/preference_learning.rb +19 -0
- data/lib/legion/extensions/agentic/learning/procedural/client.rb +19 -0
- data/lib/legion/extensions/agentic/learning/procedural/helpers/constants.rb +46 -0
- data/lib/legion/extensions/agentic/learning/procedural/helpers/learning_engine.rb +160 -0
- data/lib/legion/extensions/agentic/learning/procedural/helpers/production.rb +66 -0
- data/lib/legion/extensions/agentic/learning/procedural/helpers/skill.rb +101 -0
- data/lib/legion/extensions/agentic/learning/procedural/runners/procedural_learning.rb +96 -0
- data/lib/legion/extensions/agentic/learning/procedural/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/procedural.rb +20 -0
- data/lib/legion/extensions/agentic/learning/scaffolding/client.rb +26 -0
- data/lib/legion/extensions/agentic/learning/scaffolding/helpers/constants.rb +42 -0
- data/lib/legion/extensions/agentic/learning/scaffolding/helpers/scaffold.rb +136 -0
- data/lib/legion/extensions/agentic/learning/scaffolding/helpers/scaffolding_engine.rb +112 -0
- data/lib/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding.rb +107 -0
- data/lib/legion/extensions/agentic/learning/scaffolding/version.rb +13 -0
- data/lib/legion/extensions/agentic/learning/scaffolding.rb +19 -0
- data/lib/legion/extensions/agentic/learning/version.rb +11 -0
- data/lib/legion/extensions/agentic/learning.rb +31 -0
- data/spec/legion/extensions/agentic/learning/anchoring/client_spec.rb +32 -0
- data/spec/legion/extensions/agentic/learning/anchoring/helpers/anchor_spec.rb +130 -0
- data/spec/legion/extensions/agentic/learning/anchoring/helpers/anchor_store_spec.rb +201 -0
- data/spec/legion/extensions/agentic/learning/anchoring/helpers/constants_spec.rb +63 -0
- data/spec/legion/extensions/agentic/learning/anchoring/runners/anchoring_spec.rb +199 -0
- data/spec/legion/extensions/agentic/learning/catalyst/client_spec.rb +58 -0
- data/spec/legion/extensions/agentic/learning/catalyst/cognitive_catalyst_spec.rb +49 -0
- data/spec/legion/extensions/agentic/learning/catalyst/helpers/catalyst_engine_spec.rb +263 -0
- data/spec/legion/extensions/agentic/learning/catalyst/helpers/catalyst_spec.rb +214 -0
- data/spec/legion/extensions/agentic/learning/catalyst/helpers/reaction_spec.rb +223 -0
- data/spec/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst_spec.rb +217 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/client_spec.rb +83 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/cognitive_chrysalis_spec.rb +15 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis_engine_spec.rb +57 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis_spec.rb +305 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/cocoon_spec.rb +206 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/constants_spec.rb +109 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/metamorphic_cycle_spec.rb +76 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine_spec.rb +247 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/helpers/transformation_phase_spec.rb +98 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis_spec.rb +180 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/runners/reporting_spec.rb +81 -0
- data/spec/legion/extensions/agentic/learning/chrysalis/runners/transformation_spec.rb +74 -0
- data/spec/legion/extensions/agentic/learning/curiosity/client_spec.rb +27 -0
- data/spec/legion/extensions/agentic/learning/curiosity/helpers/gap_detector_spec.rb +118 -0
- data/spec/legion/extensions/agentic/learning/curiosity/helpers/wonder_spec.rb +130 -0
- data/spec/legion/extensions/agentic/learning/curiosity/helpers/wonder_store_spec.rb +136 -0
- data/spec/legion/extensions/agentic/learning/curiosity/runners/curiosity_spec.rb +159 -0
- data/spec/legion/extensions/agentic/learning/epistemic_curiosity/client_spec.rb +47 -0
- data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants_spec.rb +45 -0
- data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine_spec.rb +229 -0
- data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap_spec.rb +188 -0
- data/spec/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity_spec.rb +175 -0
- data/spec/legion/extensions/agentic/learning/fermentation/client_spec.rb +36 -0
- data/spec/legion/extensions/agentic/learning/fermentation/helpers/batch_spec.rb +72 -0
- data/spec/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine_spec.rb +138 -0
- data/spec/legion/extensions/agentic/learning/fermentation/helpers/substrate_spec.rb +146 -0
- data/spec/legion/extensions/agentic/learning/habit/client_spec.rb +50 -0
- data/spec/legion/extensions/agentic/learning/habit/helpers/action_sequence_spec.rb +276 -0
- data/spec/legion/extensions/agentic/learning/habit/helpers/constants_spec.rb +115 -0
- data/spec/legion/extensions/agentic/learning/habit/helpers/habit_store_spec.rb +274 -0
- data/spec/legion/extensions/agentic/learning/habit/runners/habit_spec.rb +228 -0
- data/spec/legion/extensions/agentic/learning/hebbian/client_spec.rb +38 -0
- data/spec/legion/extensions/agentic/learning/hebbian/helpers/assembly_network_spec.rb +142 -0
- data/spec/legion/extensions/agentic/learning/hebbian/helpers/assembly_spec.rb +89 -0
- data/spec/legion/extensions/agentic/learning/hebbian/helpers/unit_spec.rb +119 -0
- data/spec/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly_spec.rb +109 -0
- data/spec/legion/extensions/agentic/learning/learning_rate/client_spec.rb +51 -0
- data/spec/legion/extensions/agentic/learning/learning_rate/helpers/constants_spec.rb +29 -0
- data/spec/legion/extensions/agentic/learning/learning_rate/helpers/rate_model_spec.rb +151 -0
- data/spec/legion/extensions/agentic/learning/learning_rate/runners/learning_rate_spec.rb +92 -0
- data/spec/legion/extensions/agentic/learning/meta_learning/client_spec.rb +27 -0
- data/spec/legion/extensions/agentic/learning/meta_learning/helpers/constants_spec.rb +43 -0
- data/spec/legion/extensions/agentic/learning/meta_learning/helpers/learning_domain_spec.rb +146 -0
- data/spec/legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine_spec.rb +309 -0
- data/spec/legion/extensions/agentic/learning/meta_learning/helpers/strategy_spec.rb +82 -0
- data/spec/legion/extensions/agentic/learning/meta_learning/runners/meta_learning_spec.rb +185 -0
- data/spec/legion/extensions/agentic/learning/plasticity/helpers/constants_spec.rb +54 -0
- data/spec/legion/extensions/agentic/learning/plasticity/helpers/neural_pathway_spec.rb +136 -0
- data/spec/legion/extensions/agentic/learning/plasticity/helpers/plasticity_engine_spec.rb +157 -0
- data/spec/legion/extensions/agentic/learning/plasticity/runners/cognitive_plasticity_spec.rb +83 -0
- data/spec/legion/extensions/agentic/learning/preference_learning/client_spec.rb +17 -0
- data/spec/legion/extensions/agentic/learning/preference_learning/helpers/constants_spec.rb +67 -0
- data/spec/legion/extensions/agentic/learning/preference_learning/helpers/option_spec.rb +104 -0
- data/spec/legion/extensions/agentic/learning/preference_learning/helpers/preference_engine_spec.rb +151 -0
- data/spec/legion/extensions/agentic/learning/preference_learning/runners/preference_learning_spec.rb +86 -0
- data/spec/legion/extensions/agentic/learning/procedural/client_spec.rb +22 -0
- data/spec/legion/extensions/agentic/learning/procedural/helpers/learning_engine_spec.rb +135 -0
- data/spec/legion/extensions/agentic/learning/procedural/helpers/production_spec.rb +66 -0
- data/spec/legion/extensions/agentic/learning/procedural/helpers/skill_spec.rb +102 -0
- data/spec/legion/extensions/agentic/learning/procedural/runners/procedural_learning_spec.rb +94 -0
- data/spec/legion/extensions/agentic/learning/scaffolding/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/learning/scaffolding/helpers/constants_spec.rb +36 -0
- data/spec/legion/extensions/agentic/learning/scaffolding/helpers/scaffold_spec.rb +187 -0
- data/spec/legion/extensions/agentic/learning/scaffolding/helpers/scaffolding_engine_spec.rb +159 -0
- data/spec/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding_spec.rb +163 -0
- data/spec/spec_helper.rb +46 -0
- 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,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
|