lex-agentic-learning 0.1.7 → 0.1.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5e6816da7724d62662737aa4c9cb66b9b0baada3ffe3fdfb22a3e09083fe76d
4
- data.tar.gz: cb0236bff38a3146abc0cc14922c588ac99733612e8e9ad75b629f6b53005eeb
3
+ metadata.gz: 8f2bd98de70d5e11f07c18043483a22d4325508c7e2601fd2d1c3a3bdb9726bd
4
+ data.tar.gz: e1f9d5d06972b5fe01b932d973050d701aa82663bca6ff76709769df476ea80b
5
5
  SHA512:
6
- metadata.gz: b80674a59c3cd1980bfb3adc9358c11817fba0c6d15ca87538ff6c96486b9444666dc10755f535da85623006fa16999585999bda6c8bea788fd38a85e7bc8453
7
- data.tar.gz: b9242b3f42079bb82949da94fba9081d1d3d803766c2b20eb9ec375f3d630c436be5355a58377bae523e44e8d22560dffb69fbbb553870717dbc827e5ca129b5
6
+ metadata.gz: d5858c88e16679558b7bf3d2433f3d88810a85f5a41cb7cf37991ccc22195569f65fffad058dbeb2aeaf359b89855dd3ac3330759da49e36c18c489afc08b713
7
+ data.tar.gz: 55abe2021cd74cbd3885d75a2ff321febe189d369e802ea910eced3d86ac9398adf807414880f006ab23b0a5b869f81a304093fdc10a05da8dedc6352136611a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.9] - 2026-04-28
4
+ ### Fixed
5
+ - Curiosity self-inquiry now uses the current `Legion::LLM.ask` API before falling back to legacy `Legion::LLM.complete`, preserving compatibility with the LLM routing uplift.
6
+
7
+ ## [0.1.8] - 2026-04-22
8
+ ### Added
9
+ - 3 new decay actors: Curiosity::Decay (300s), EpistemicCuriosity::Decay (300s), Habit::Decay (300s)
10
+ - OutcomeListener documented in CLAUDE.md
11
+ ### Fixed
12
+ - CognitiveChrysalis `include Helpers::Lex` rescue now logs error instead of swallowing silently
13
+
3
14
  ## [0.1.7] - 2026-04-15
4
15
  ### Changed
5
16
  - Set `mcp_tools?`, `mcp_tools_deferred?`, and `transport_required?` to `false` — internal cognitive pipeline extension
data/README.md CHANGED
@@ -1,36 +1,43 @@
1
1
  # lex-agentic-learning
2
2
 
3
- Domain consolidation gem for learning, adaptation, and knowledge acquisition. Bundles 14 source extensions into one loadable unit under `Legion::Extensions::Agentic::Learning`.
3
+ Domain consolidation gem for learning, adaptation, and knowledge acquisition. Bundles 15 sub-modules into one loadable unit under `Legion::Extensions::Agentic::Learning`.
4
4
 
5
5
  ## Overview
6
6
 
7
7
  **Gem**: `lex-agentic-learning`
8
- **Version**: 0.1.7
8
+ **Version**: 0.1.9
9
9
  **Namespace**: `Legion::Extensions::Agentic::Learning`
10
10
 
11
11
  ## Sub-Modules
12
12
 
13
- | Sub-Module | Source Gem | Purpose |
14
- |---|---|---|
15
- | `Learning::Curiosity` | `lex-curiosity` | Intrinsic curiosity — knowledge gap detection, wonder queue, salience decay |
16
- | `Learning::EpistemicCuriosity` | `lex-epistemic-curiosity` | Information-gap theory — specific vs. diversive curiosity |
17
- | `Learning::Hebbian` | `lex-hebbian-assembly` | Cell assembly formation — neurons that fire together wire together |
18
- | `Learning::Habit` | `lex-habit` | Habit formation — action sequence pattern recognition, maturity stages |
19
- | `Learning::LearningRate` | `lex-learning-rate` | Dynamic learning rate adaptation based on accuracy and stability |
20
- | `Learning::MetaLearning` | `lex-meta-learning` | Learning-to-learn — strategy selection per domain |
21
- | `Learning::PreferenceLearning` | `lex-preference-learning` | Learns stable preferences from choices over time |
22
- | `Learning::Procedural` | `lex-procedural-learning` | Skill acquisition through practice — automatization |
23
- | `Learning::Anchoring` | `lex-anchoring` | Anchoring bias in estimation |
24
- | `Learning::Plasticity` | `lex-cognitive-plasticity` | Neural-style plasticity — synaptic weight adjustment |
25
- | `Learning::Scaffolding` | `lex-cognitive-scaffolding` | Temporary learning assists that fade as competence grows |
26
- | `Learning::Fermentation` | `lex-cognitive-fermentation` | Time-based transformation of knowledge |
27
- | `Learning::Chrysalis` | `lex-cognitive-chrysalis` | Metamorphic state change — transformation through withdrawal |
28
- | `Learning::Catalyst` | `lex-cognitive-catalyst` | Accelerating cognitive transformation |
13
+ | Sub-Module | Purpose |
14
+ |---|---|
15
+ | `Learning::Curiosity` | Intrinsic curiosity — knowledge gap detection, wonder queue, salience decay |
16
+ | `Learning::EpistemicCuriosity` | Information-gap theory — specific vs. diversive curiosity |
17
+ | `Learning::Hebbian` | Cell assembly formation — neurons that fire together wire together |
18
+ | `Learning::Habit` | Habit formation — action sequence pattern recognition, maturity stages |
19
+ | `Learning::LearningRate` | Dynamic learning rate adaptation based on accuracy and stability |
20
+ | `Learning::MetaLearning` | Learning-to-learn — strategy selection per domain |
21
+ | `Learning::PreferenceLearning` | Learns stable preferences from choices over time |
22
+ | `Learning::Procedural` | Skill acquisition through practice — automatization |
23
+ | `Learning::Anchoring` | Anchoring bias in estimation |
24
+ | `Learning::Plasticity` | Neural-style plasticity — synaptic weight adjustment |
25
+ | `Learning::Scaffolding` | Temporary learning assists that fade as competence grows |
26
+ | `Learning::Fermentation` | Time-based transformation of knowledge |
27
+ | `Learning::Chrysalis` | Metamorphic state change — transformation through withdrawal |
28
+ | `Learning::Catalyst` | Accelerating cognitive transformation |
29
+ | `Learning::OutcomeListener` | Outcome-gated learning — listens for task completions and updates meta-learning, learning rate, and scaffolding models |
29
30
 
30
31
  ## Actors
31
32
 
32
- - `Learning::Hebbian::Actors::Decay` interval actor, decays Hebbian assembly connection strength
33
- - `Learning::PreferenceLearning::Actors::Decay` — interval actor, decays older preference observations
33
+ 6 actors handle autonomous background processing:
34
+
35
+ - `Learning::Curiosity::Actor::Decay` — every 300s, decays wonder salience
36
+ - `Learning::EpistemicCuriosity::Actor::Decay` — every 300s, decays knowledge gaps
37
+ - `Learning::Habit::Actor::Decay` — every 300s, prunes stale habits
38
+ - `Learning::Hebbian::Actors::Decay` — every 60s, decays Hebbian assembly connection strength
39
+ - `Learning::PreferenceLearning::Actors::Decay` — every 300s, decays older preference observations
40
+ - `Learning::OutcomeListener::Actor::OutcomeListener` — **subscription** actor, receives task outcome events and triggers cross-model learning updates; writes lessons to Apollo when enabled
34
41
 
35
42
  ## Installation
36
43
 
@@ -42,8 +49,8 @@ gem 'lex-agentic-learning'
42
49
 
43
50
  ```bash
44
51
  bundle install
45
- bundle exec rspec # 1316 examples, 0 failures
46
- bundle exec rubocop # 0 offenses
52
+ bundle exec rspec
53
+ bundle exec rubocop
47
54
  ```
48
55
 
49
56
  ## License
@@ -9,10 +9,14 @@ module Legion
9
9
  module CognitiveChrysalis
10
10
  extend self
11
11
 
12
+ def log
13
+ Legion::Logging
14
+ end
15
+
12
16
  begin
13
17
  include Legion::Extensions::Helpers::Lex # rubocop:disable Layout/EmptyLinesAfterModuleInclusion
14
- rescue StandardError => _e
15
- nil
18
+ rescue StandardError => e
19
+ log.error "[cognitive_chrysalis] failed to include Helpers::Lex: #{e.class}: #{e.message}"
16
20
  end
17
21
 
18
22
  def create_chrysalis(chrysalis_type: :silk, content: '', engine: nil, **)
@@ -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 Curiosity
10
+ module Actor
11
+ class Decay < Legion::Extensions::Actors::Every
12
+ def runner_class
13
+ Legion::Extensions::Agentic::Learning::Curiosity::Runners::Curiosity
14
+ end
15
+
16
+ def runner_function
17
+ 'decay_wonders'
18
+ end
19
+
20
+ def time
21
+ 300
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
@@ -83,12 +83,114 @@ module Legion
83
83
  { pruned: pruned, remaining: wonder_store.active_count }
84
84
  end
85
85
 
86
+ # Autonomous self-inquiry: picks the top explorable wonder, asks the LLM,
87
+ # stores the insight in Apollo, and resolves the wonder.
88
+ # This closes the curiosity->intention->action loop so GAIA can act on
89
+ # her own questions rather than spinning indefinitely.
90
+ def self_inquire(max_wonders: 1, **)
91
+ candidates = wonder_store.active_wonders
92
+ .select { |w| Helpers::Wonder.explorable?(w) }
93
+ .sort_by { |w| -Helpers::Wonder.score(w) }
94
+ .first(max_wonders)
95
+
96
+ return { inquired: 0, reason: :no_explorable_wonders } if candidates.empty?
97
+
98
+ results = candidates.filter_map { |wonder| execute_self_inquiry(wonder) }
99
+ { inquired: results.size, results: results }
100
+ end
101
+
86
102
  private
87
103
 
88
104
  def wonder_store
89
105
  @wonder_store ||= Helpers::WonderStore.new
90
106
  end
91
107
 
108
+ def execute_self_inquiry(wonder)
109
+ wonder_id = wonder[:wonder_id]
110
+ question = wonder[:question]
111
+ domain = wonder[:domain]
112
+
113
+ # Mark as being explored (increments attempts, sets cooldown)
114
+ wonder_store.update(wonder_id, attempts: wonder[:attempts] + 1, last_explored_at: Time.now.utc)
115
+ log.info "[curiosity:self_inquiry] asking: #{question} (domain=#{domain})"
116
+
117
+ insight = query_llm_for_wonder(question, domain)
118
+
119
+ if insight
120
+ store_insight_in_apollo(question, insight, domain)
121
+ wonder_store.mark_resolved(wonder_id, resolution: insight, actual_gain: 0.6)
122
+ log.info "[curiosity:self_inquiry] resolved wonder=#{wonder_id} domain=#{domain}"
123
+ { wonder_id: wonder_id, question: question, domain: domain, resolved: true,
124
+ insight: insight[0..120] }
125
+ else
126
+ log.warn "[curiosity:self_inquiry] LLM unavailable for wonder=#{wonder_id}, will retry later"
127
+ { wonder_id: wonder_id, question: question, domain: domain, resolved: false,
128
+ reason: :llm_unavailable }
129
+ end
130
+ rescue StandardError => e
131
+ log.error "[curiosity:self_inquiry] error wonder=#{wonder[:wonder_id]} " \
132
+ "error=#{e.class}: #{e.message}"
133
+ nil
134
+ end
135
+
136
+ def query_llm_for_wonder(question, domain)
137
+ prompt = build_self_inquiry_prompt(question, domain)
138
+
139
+ # Try via Lex helper (primary path inside Legion runtime)
140
+ if respond_to?(:lex, true)
141
+ result = lex(:llm, :complete, prompt: prompt, max_tokens: 300)
142
+ text = extract_llm_text(result)
143
+ return text if text && !text.empty?
144
+ end
145
+
146
+ # Direct LLM fallback for current legion-llm; complete is kept for older installs.
147
+ if defined?(Legion::LLM) && Legion::LLM.respond_to?(:ask)
148
+ result = Legion::LLM.ask(message: prompt) # rubocop:disable Legion/HelperMigration/DirectLlm
149
+ text = extract_llm_text(result)
150
+ return text if text && !text.empty?
151
+ elsif defined?(Legion::LLM) && Legion::LLM.respond_to?(:complete)
152
+ result = Legion::LLM.complete(prompt: prompt, max_tokens: 300)
153
+ text = extract_llm_text(result)
154
+ return text if text && !text.empty?
155
+ end
156
+
157
+ nil
158
+ rescue StandardError => e
159
+ log.warn "[curiosity:self_inquiry] LLM query failed: #{e.class}: #{e.message}"
160
+ nil
161
+ end
162
+
163
+ def extract_llm_text(result)
164
+ return result.strip if result.is_a?(String)
165
+ return nil unless result.is_a?(Hash)
166
+
167
+ text = result[:response] || result[:content] || result[:text] || result[:completion]
168
+ text&.to_s&.strip
169
+ end
170
+
171
+ def build_self_inquiry_prompt(question, domain)
172
+ <<~PROMPT.strip
173
+ You are GAIA, a thinking, curious AI. You are reflecting on a knowledge gap you detected in yourself.
174
+
175
+ Domain: #{domain}
176
+ Question: #{question}
177
+
178
+ Reflect honestly and briefly (2-3 sentences). What do you actually know or think about this? What would you want to explore further?
179
+ PROMPT
180
+ end
181
+
182
+ def store_insight_in_apollo(question, insight, domain)
183
+ return unless defined?(Legion::Extensions::Apollo)
184
+
185
+ Legion::Extensions::Apollo.store(
186
+ content: "Self-inquiry insight [#{domain}]: #{question}\n\n#{insight}",
187
+ content_type: :observation,
188
+ tags: ['gaia-self-inquiry', "domain-#{domain}", 'autonomous-thought']
189
+ )
190
+ rescue StandardError => e
191
+ log.warn "[curiosity:self_inquiry] Apollo store failed: #{e.class}: #{e.message}"
192
+ end
193
+
92
194
  def create_wonders_from_gaps(gaps)
93
195
  gaps.each_with_object([]) do |gap, created|
94
196
  next if duplicate_wonder?(gap)
@@ -106,7 +208,10 @@ module Legion
106
208
  top = wonder_store.top_balanced(limit: 3)
107
209
  log.debug "[curiosity] intensity=#{intensity.round(3)} active=#{wonder_store.active_count}"
108
210
  { gaps_detected: gaps.size, wonders_created: created.size, curiosity_intensity: intensity,
109
- top_wonders: top.map { |w| { wonder_id: w[:wonder_id], question: w[:question], score: Helpers::Wonder.score(w).round(3) } },
211
+ top_wonders: top.map do |w|
212
+ { wonder_id: w[:wonder_id], question: w[:question],
213
+ score: Helpers::Wonder.score(w).round(3) }
214
+ end,
110
215
  active_count: wonder_store.active_count }
111
216
  end
112
217
 
@@ -128,7 +233,8 @@ module Legion
128
233
  def format_agenda_item(wonder)
129
234
  { type: :curious, source: :curiosity, weight: Helpers::Wonder.score(wonder),
130
235
  summary: wonder[:question],
131
- metadata: { wonder_id: wonder[:wonder_id], domain: wonder[:domain], gap_type: wonder[:gap_type] } }
236
+ metadata: { wonder_id: wonder[:wonder_id], domain: wonder[:domain],
237
+ gap_type: wonder[:gap_type] } }
132
238
  end
133
239
 
134
240
  def compute_intensity
@@ -6,6 +6,7 @@ require 'legion/extensions/agentic/learning/curiosity/helpers/wonder'
6
6
  require 'legion/extensions/agentic/learning/curiosity/helpers/wonder_store'
7
7
  require 'legion/extensions/agentic/learning/curiosity/helpers/gap_detector'
8
8
  require 'legion/extensions/agentic/learning/curiosity/runners/curiosity'
9
+ require 'legion/extensions/agentic/learning/curiosity/actors/decay'
9
10
  require 'legion/extensions/agentic/learning/curiosity/client'
10
11
 
11
12
  module Legion
@@ -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 EpistemicCuriosity
10
+ module Actor
11
+ class Decay < Legion::Extensions::Actors::Every
12
+ def runner_class
13
+ Legion::Extensions::Agentic::Learning::EpistemicCuriosity::Runners::EpistemicCuriosity
14
+ end
15
+
16
+ def runner_function
17
+ 'decay_gaps'
18
+ end
19
+
20
+ def time
21
+ 300
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
@@ -5,6 +5,7 @@ require 'legion/extensions/agentic/learning/epistemic_curiosity/helpers/constant
5
5
  require 'legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap'
6
6
  require 'legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine'
7
7
  require 'legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity'
8
+ require 'legion/extensions/agentic/learning/epistemic_curiosity/actors/decay'
8
9
  require 'legion/extensions/agentic/learning/epistemic_curiosity/client'
9
10
 
10
11
  module Legion
@@ -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 Habit
10
+ module Actor
11
+ class Decay < Legion::Extensions::Actors::Every
12
+ def runner_class
13
+ Legion::Extensions::Agentic::Learning::Habit::Runners::Habit
14
+ end
15
+
16
+ def runner_function
17
+ 'decay_habits'
18
+ end
19
+
20
+ def time
21
+ 300
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
@@ -5,6 +5,7 @@ require 'legion/extensions/agentic/learning/habit/helpers/constants'
5
5
  require 'legion/extensions/agentic/learning/habit/helpers/action_sequence'
6
6
  require 'legion/extensions/agentic/learning/habit/helpers/habit_store'
7
7
  require 'legion/extensions/agentic/learning/habit/runners/habit'
8
+ require 'legion/extensions/agentic/learning/habit/actors/decay'
8
9
  require 'legion/extensions/agentic/learning/habit/client'
9
10
 
10
11
  module Legion
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Learning
7
- VERSION = '0.1.7'
7
+ VERSION = '0.1.9'
8
8
  end
9
9
  end
10
10
  end
@@ -156,4 +156,37 @@ RSpec.describe Legion::Extensions::Agentic::Learning::Curiosity::Runners::Curios
156
156
  expect(result[:pruned]).to eq(1)
157
157
  end
158
158
  end
159
+
160
+ describe '#query_llm_for_wonder' do
161
+ before do
162
+ allow(client).to receive(:respond_to?).and_call_original
163
+ allow(client).to receive(:respond_to?).with(:lex, true).and_return(false)
164
+ end
165
+
166
+ it 'uses Legion::LLM.ask response hashes for current legion-llm' do
167
+ llm = Module.new do
168
+ def self.ask(message:)
169
+ raise 'missing prompt' if message.to_s.empty?
170
+
171
+ { response: ' useful insight ' }
172
+ end
173
+ end
174
+ stub_const('Legion::LLM', llm)
175
+
176
+ expect(client.send(:query_llm_for_wonder, 'why?', :curiosity)).to eq('useful insight')
177
+ end
178
+
179
+ it 'keeps legacy Legion::LLM.complete fallback for older installs' do
180
+ llm = Module.new do
181
+ def self.complete(prompt:, max_tokens:)
182
+ raise 'missing prompt' if prompt.to_s.empty? || max_tokens != 300
183
+
184
+ { content: 'legacy insight' }
185
+ end
186
+ end
187
+ stub_const('Legion::LLM', llm)
188
+
189
+ expect(client.send(:query_llm_for_wonder, 'why?', :curiosity)).to eq('legacy insight')
190
+ end
191
+ end
159
192
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-agentic-learning
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -201,6 +201,7 @@ files:
201
201
  - lib/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis.rb
202
202
  - lib/legion/extensions/agentic/learning/chrysalis/version.rb
203
203
  - lib/legion/extensions/agentic/learning/curiosity.rb
204
+ - lib/legion/extensions/agentic/learning/curiosity/actors/decay.rb
204
205
  - lib/legion/extensions/agentic/learning/curiosity/client.rb
205
206
  - lib/legion/extensions/agentic/learning/curiosity/helpers/constants.rb
206
207
  - lib/legion/extensions/agentic/learning/curiosity/helpers/gap_detector.rb
@@ -209,6 +210,7 @@ files:
209
210
  - lib/legion/extensions/agentic/learning/curiosity/runners/curiosity.rb
210
211
  - lib/legion/extensions/agentic/learning/curiosity/version.rb
211
212
  - lib/legion/extensions/agentic/learning/epistemic_curiosity.rb
213
+ - lib/legion/extensions/agentic/learning/epistemic_curiosity/actors/decay.rb
212
214
  - lib/legion/extensions/agentic/learning/epistemic_curiosity/client.rb
213
215
  - lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants.rb
214
216
  - lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine.rb
@@ -224,6 +226,7 @@ files:
224
226
  - lib/legion/extensions/agentic/learning/fermentation/runners/cognitive_fermentation.rb
225
227
  - lib/legion/extensions/agentic/learning/fermentation/version.rb
226
228
  - lib/legion/extensions/agentic/learning/habit.rb
229
+ - lib/legion/extensions/agentic/learning/habit/actors/decay.rb
227
230
  - lib/legion/extensions/agentic/learning/habit/client.rb
228
231
  - lib/legion/extensions/agentic/learning/habit/helpers/action_sequence.rb
229
232
  - lib/legion/extensions/agentic/learning/habit/helpers/constants.rb