lex-mind-growth 0.2.5 → 0.2.7
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 +4 -4
- data/Gemfile +1 -0
- data/lib/legion/extensions/mind_growth/actors/growth_cycle.rb +3 -3
- data/lib/legion/extensions/mind_growth/helpers/composition_map.rb +4 -4
- data/lib/legion/extensions/mind_growth/helpers/concept_proposal.rb +1 -1
- data/lib/legion/extensions/mind_growth/helpers/phase_allocator.rb +1 -1
- data/lib/legion/extensions/mind_growth/runners/builder.rb +64 -22
- data/lib/legion/extensions/mind_growth/runners/competitive_evolver.rb +3 -2
- data/lib/legion/extensions/mind_growth/runners/composer.rb +3 -3
- data/lib/legion/extensions/mind_growth/runners/consensus_builder.rb +4 -3
- data/lib/legion/extensions/mind_growth/runners/dashboard.rb +2 -2
- data/lib/legion/extensions/mind_growth/runners/dream_ideation.rb +2 -2
- data/lib/legion/extensions/mind_growth/runners/evolver.rb +15 -8
- data/lib/legion/extensions/mind_growth/runners/governance.rb +2 -2
- data/lib/legion/extensions/mind_growth/runners/integration_tester.rb +4 -3
- data/lib/legion/extensions/mind_growth/runners/monitor.rb +2 -2
- data/lib/legion/extensions/mind_growth/runners/orchestrator.rb +2 -2
- data/lib/legion/extensions/mind_growth/runners/proposer.rb +25 -11
- data/lib/legion/extensions/mind_growth/runners/retrospective.rb +12 -7
- data/lib/legion/extensions/mind_growth/runners/risk_assessor.rb +2 -2
- data/lib/legion/extensions/mind_growth/runners/swarm_builder.rb +1 -1
- data/lib/legion/extensions/mind_growth/runners/wirer.rb +2 -2
- data/lib/legion/extensions/mind_growth/version.rb +1 -1
- data/lib/legion/extensions/mind_growth.rb +1 -1
- data/spec/legion/extensions/mind_growth/actors/growth_cycle_spec.rb +2 -2
- data/spec/legion/extensions/mind_growth/helpers/composition_map_spec.rb +1 -1
- data/spec/legion/extensions/mind_growth/helpers/proposal_store_spec.rb +2 -2
- data/spec/legion/extensions/mind_growth/runners/competitive_evolver_spec.rb +1 -1
- data/spec/legion/extensions/mind_growth/runners/governance_spec.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e8f21cd00a0fb432c27fd057addf7294b2d84425c7927d6298bab0c87496d868
|
|
4
|
+
data.tar.gz: c0a512a778e049b13d5442ab3f72bf513ce5104bc0be3632891eda965b1fa668
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f772d447b870acf41484209df88a82352e4b27b00a7f30335dfb0b5fee1e26c6cc7b06d6194aaf46d2d7506e55cb7e5d264aa9b005872db00c632f3caea1a4bf
|
|
7
|
+
data.tar.gz: d4aee3639b1cec1a35015c9a432cb7041715bd3f3ad0571534a9d441ce11e79481a6361e72295076fb06605cc2afd357805e385ff04bf28503302c7f003bcbd5
|
data/Gemfile
CHANGED
|
@@ -6,7 +6,7 @@ module Legion
|
|
|
6
6
|
module Extensions
|
|
7
7
|
module MindGrowth
|
|
8
8
|
module Actor
|
|
9
|
-
class GrowthCycle < Legion::Extensions::Actors::Every
|
|
9
|
+
class GrowthCycle < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/EveryActorRequiresTime
|
|
10
10
|
def runner_class
|
|
11
11
|
Legion::Extensions::MindGrowth::Runners::Orchestrator
|
|
12
12
|
end
|
|
@@ -19,7 +19,7 @@ module Legion
|
|
|
19
19
|
3600
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def enabled?
|
|
22
|
+
def enabled? # rubocop:disable Legion/Extension/ActorEnabledSideEffects
|
|
23
23
|
codegen_loaded? || exec_loaded?
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -32,7 +32,7 @@ module Legion
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def check_subtask?
|
|
35
|
-
|
|
35
|
+
true
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def generate_task?
|
|
@@ -7,7 +7,7 @@ module Legion
|
|
|
7
7
|
module CompositionMap
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
@rules = {}
|
|
10
|
+
@rules = {} # rubocop:disable ThreadSafety/MutableClassInstanceVariable
|
|
11
11
|
@mutex = Mutex.new
|
|
12
12
|
|
|
13
13
|
def add_rule(source_extension:, output_key:, target_extension:, target_method:, transform: nil, **)
|
|
@@ -19,7 +19,7 @@ module Legion
|
|
|
19
19
|
target_extension: target_extension.to_s,
|
|
20
20
|
target_method: target_method.to_sym,
|
|
21
21
|
transform: transform
|
|
22
|
-
}
|
|
22
|
+
}.freeze
|
|
23
23
|
@mutex.synchronize { @rules[rule_id] = rule }
|
|
24
24
|
{ success: true, rule_id: rule_id }
|
|
25
25
|
end
|
|
@@ -31,7 +31,7 @@ module Legion
|
|
|
31
31
|
|
|
32
32
|
def rules_for(source_extension:, **)
|
|
33
33
|
src = source_extension.to_s
|
|
34
|
-
@mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src } }
|
|
34
|
+
@mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src }.map(&:dup) }
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def all_rules
|
|
@@ -41,7 +41,7 @@ module Legion
|
|
|
41
41
|
def match_output(source_extension:, output:, **)
|
|
42
42
|
src = source_extension.to_s
|
|
43
43
|
out_h = output.is_a?(Hash) ? output : {}
|
|
44
|
-
rules = @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src } }
|
|
44
|
+
rules = @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src }.map(&:dup) }
|
|
45
45
|
|
|
46
46
|
rules.filter_map do |rule|
|
|
47
47
|
key = rule[:output_key]
|
|
@@ -12,7 +12,7 @@ module Legion
|
|
|
12
12
|
|
|
13
13
|
attr_reader(*FIELDS)
|
|
14
14
|
|
|
15
|
-
def initialize(name:, module_name:, category:, description:, metaphor: nil, helpers: [],
|
|
15
|
+
def initialize(name:, module_name:, category:, description:, metaphor: nil, helpers: [], # rubocop:disable Metrics/ParameterLists
|
|
16
16
|
runner_methods: [], rationale: nil, origin: :proposer)
|
|
17
17
|
@id = SecureRandom.uuid
|
|
18
18
|
@name = name
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Builder
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -59,13 +59,21 @@ module Legion
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def strip_lex_prefix(name)
|
|
62
|
-
name.to_s.
|
|
62
|
+
name.to_s.delete_prefix('lex-')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def proposal_id_for(proposal)
|
|
66
|
+
proposal.id if proposal.respond_to?(:id)
|
|
63
67
|
end
|
|
64
68
|
|
|
65
69
|
# --- Scaffold Stage ---
|
|
66
70
|
# Delegates to lex-codegen when loaded; stubs otherwise
|
|
67
71
|
def scaffold_stage(proposal, base_path)
|
|
68
|
-
|
|
72
|
+
unless codegen_available?
|
|
73
|
+
return { success: true, stage: :scaffold, files: 0, message: 'scaffold requires lex-codegen',
|
|
74
|
+
proposal_id: proposal_id_for(proposal),
|
|
75
|
+
path: ext_path(proposal, base_path) }
|
|
76
|
+
end
|
|
69
77
|
|
|
70
78
|
name = strip_lex_prefix(proposal.name)
|
|
71
79
|
result = Legion::Extensions::Codegen::Runners::Generate.scaffold_extension(
|
|
@@ -79,14 +87,18 @@ module Legion
|
|
|
79
87
|
)
|
|
80
88
|
|
|
81
89
|
{ success: result[:success], stage: :scaffold, files: result[:files_created] || 0,
|
|
82
|
-
path: result[:path], error: result[:error]
|
|
90
|
+
path: result[:path] || ext_path(proposal, base_path), error: result[:error],
|
|
91
|
+
proposal_id: proposal_id_for(proposal) }
|
|
83
92
|
end
|
|
84
93
|
|
|
85
94
|
# --- Implement Stage ---
|
|
86
95
|
# Delegates to lex-codegen FromGap when loaded; falls back to legion-llm; stubs otherwise
|
|
87
96
|
def implement_stage(proposal, base_path)
|
|
88
97
|
unless llm_available? || codegen_from_gap_available?
|
|
89
|
-
return { success: true, stage: :implement,
|
|
98
|
+
return { success: true, stage: :implement,
|
|
99
|
+
message: 'implementation requires legion-llm or lex-codegen',
|
|
100
|
+
proposal_id: proposal_id_for(proposal),
|
|
101
|
+
path: ext_path(proposal, base_path) }
|
|
90
102
|
end
|
|
91
103
|
|
|
92
104
|
path = ext_path(proposal, base_path)
|
|
@@ -94,7 +106,9 @@ module Legion
|
|
|
94
106
|
|
|
95
107
|
if target_files.empty?
|
|
96
108
|
return { success: true, stage: :implement, files_implemented: 0,
|
|
97
|
-
message: 'no implementation targets found'
|
|
109
|
+
message: 'no implementation targets found',
|
|
110
|
+
proposal_id: proposal_id_for(proposal),
|
|
111
|
+
path: path }
|
|
98
112
|
end
|
|
99
113
|
|
|
100
114
|
files_implemented = 0
|
|
@@ -111,43 +125,64 @@ module Legion
|
|
|
111
125
|
|
|
112
126
|
success = errors.empty?
|
|
113
127
|
{ success: success, stage: :implement, files_implemented: files_implemented,
|
|
114
|
-
total_files: target_files.size, error: success ? nil : errors.join('; ')
|
|
128
|
+
total_files: target_files.size, error: success ? nil : errors.join('; '),
|
|
129
|
+
proposal_id: proposal_id_for(proposal),
|
|
130
|
+
path: path }
|
|
115
131
|
end
|
|
116
132
|
|
|
117
133
|
# --- Test Stage ---
|
|
118
134
|
# Delegates to lex-exec bundler runners when loaded; stubs otherwise
|
|
119
135
|
def test_stage(proposal, base_path)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
136
|
+
unless exec_available?
|
|
137
|
+
return { success: true, stage: :test, message: 'testing requires lex-exec',
|
|
138
|
+
proposal_id: proposal_id_for(proposal),
|
|
139
|
+
path: ext_path(proposal, base_path) }
|
|
140
|
+
end
|
|
123
141
|
|
|
142
|
+
path = ext_path(proposal, base_path)
|
|
143
|
+
pid = proposal_id_for(proposal)
|
|
124
144
|
install = Legion::Extensions::Exec::Runners::Bundler.install(path: path)
|
|
125
145
|
unless install[:success]
|
|
126
146
|
return { success: false, stage: :test, step: :install,
|
|
127
|
-
error: install[:stderr] || install[:error]
|
|
147
|
+
error: install[:stderr] || install[:error],
|
|
148
|
+
proposal_id: pid, path: path }
|
|
128
149
|
end
|
|
129
150
|
|
|
151
|
+
run_test_suite(path: path, pid: pid)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def run_test_suite(path:, pid:)
|
|
130
155
|
rspec = Legion::Extensions::Exec::Runners::Bundler.exec_rspec(path: path)
|
|
131
156
|
rubocop = Legion::Extensions::Exec::Runners::Bundler.exec_rubocop(path: path)
|
|
132
157
|
|
|
133
158
|
rspec_ok = rspec[:success] && (rspec.dig(:parsed, :failures) || 0).zero?
|
|
134
159
|
rubocop_ok = rubocop[:success]
|
|
135
160
|
|
|
136
|
-
errors =
|
|
137
|
-
(rspec_ok ? nil : "rspec: #{rspec[:parsed] || rspec[:stderr]}"),
|
|
138
|
-
(rubocop_ok ? nil : "rubocop: #{rubocop[:parsed] || rubocop[:stderr]}")
|
|
139
|
-
].compact.join('; ')
|
|
161
|
+
errors = build_test_errors(rspec: rspec, rubocop: rubocop, rspec_ok: rspec_ok, rubocop_ok: rubocop_ok)
|
|
140
162
|
|
|
141
163
|
{ success: rspec_ok && rubocop_ok, stage: :test,
|
|
142
164
|
rspec: rspec[:parsed] || { raw: rspec[:stdout] },
|
|
143
165
|
rubocop: rubocop[:parsed] || { raw: rubocop[:stdout] },
|
|
144
|
-
error: errors.empty? ? nil : errors
|
|
166
|
+
error: errors.empty? ? nil : errors,
|
|
167
|
+
proposal_id: pid,
|
|
168
|
+
path: path }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def build_test_errors(rspec:, rubocop:, rspec_ok:, rubocop_ok:)
|
|
172
|
+
[
|
|
173
|
+
(rspec_ok ? nil : "rspec: #{rspec[:parsed] || rspec[:stderr]}"),
|
|
174
|
+
(rubocop_ok ? nil : "rubocop: #{rubocop[:parsed] || rubocop[:stderr]}")
|
|
175
|
+
].compact.join('; ')
|
|
145
176
|
end
|
|
146
177
|
|
|
147
178
|
# --- Validate Stage ---
|
|
148
179
|
# Delegates to lex-codegen validators when loaded; stubs otherwise
|
|
149
180
|
def validate_stage(proposal, base_path)
|
|
150
|
-
|
|
181
|
+
unless codegen_available?
|
|
182
|
+
return { success: true, stage: :validate, message: 'validation requires lex-codegen',
|
|
183
|
+
proposal_id: proposal_id_for(proposal),
|
|
184
|
+
path: ext_path(proposal, base_path) }
|
|
185
|
+
end
|
|
151
186
|
|
|
152
187
|
path = ext_path(proposal, base_path)
|
|
153
188
|
structure = Legion::Extensions::Codegen::Runners::Validate.validate_structure(path: path)
|
|
@@ -155,13 +190,19 @@ module Legion
|
|
|
155
190
|
|
|
156
191
|
valid = structure[:valid] && gemspec[:valid]
|
|
157
192
|
{ success: valid, stage: :validate, structure: structure, gemspec: gemspec,
|
|
158
|
-
error: valid ? nil : "structure: #{structure[:missing]}, gemspec: #{gemspec[:issues]}"
|
|
193
|
+
error: valid ? nil : "structure: #{structure[:missing]}, gemspec: #{gemspec[:issues]}",
|
|
194
|
+
proposal_id: proposal_id_for(proposal),
|
|
195
|
+
path: path }
|
|
159
196
|
end
|
|
160
197
|
|
|
161
198
|
# --- Register Stage ---
|
|
162
199
|
# Delegates to lex-metacognition registry when loaded; stubs otherwise
|
|
163
200
|
def register_stage(proposal)
|
|
164
|
-
|
|
201
|
+
unless registry_available?
|
|
202
|
+
return { success: true, stage: :register,
|
|
203
|
+
message: 'registration requires lex-metacognition registry',
|
|
204
|
+
proposal_id: proposal_id_for(proposal) }
|
|
205
|
+
end
|
|
165
206
|
|
|
166
207
|
result = Legion::Extensions::Metacognition::Runners::Registry.register_extension(
|
|
167
208
|
name: proposal.name,
|
|
@@ -170,7 +211,8 @@ module Legion
|
|
|
170
211
|
description: proposal.description
|
|
171
212
|
)
|
|
172
213
|
|
|
173
|
-
{ success: result[:success], stage: :register, error: result[:error]
|
|
214
|
+
{ success: result[:success], stage: :register, error: result[:error],
|
|
215
|
+
proposal_id: proposal_id_for(proposal) }
|
|
174
216
|
end
|
|
175
217
|
|
|
176
218
|
# --- LLM implementation helpers ---
|
|
@@ -205,7 +247,7 @@ module Legion
|
|
|
205
247
|
def legacy_implement_file(file_path, proposal)
|
|
206
248
|
stub_content = ::File.read(file_path)
|
|
207
249
|
|
|
208
|
-
chat = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'build' }, intent: { capability: :reasoning })
|
|
250
|
+
chat = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'build' }, intent: { capability: :reasoning }) # rubocop:disable Legion/HelperMigration/DirectLlm
|
|
209
251
|
chat.with_instructions(implementation_instructions)
|
|
210
252
|
response = chat.ask(file_implementation_prompt(stub_content, proposal))
|
|
211
253
|
code = extract_ruby_code(response.content)
|
|
@@ -7,7 +7,8 @@ module Legion
|
|
|
7
7
|
module CompetitiveEvolver
|
|
8
8
|
extend self
|
|
9
9
|
|
|
10
|
-
COMPETITION_STATUSES
|
|
10
|
+
COMPETITION_STATUSES = %i[pending active evaluating decided cancelled].freeze
|
|
11
|
+
ACTIVE_STATUSES = %i[pending active evaluating].freeze
|
|
11
12
|
MIN_TRIAL_ITERATIONS = 10
|
|
12
13
|
|
|
13
14
|
def create_competition(gap:, proposal_ids:, **)
|
|
@@ -108,7 +109,7 @@ module Legion
|
|
|
108
109
|
end
|
|
109
110
|
|
|
110
111
|
def active_competitions(**)
|
|
111
|
-
comps = all_competitions.select { |c|
|
|
112
|
+
comps = all_competitions.select { |c| ACTIVE_STATUSES.include?(c[:status]) }
|
|
112
113
|
{ success: true, competitions: comps.map { |c| { id: c[:id], gap: c[:gap], status: c[:status] } },
|
|
113
114
|
count: comps.size }
|
|
114
115
|
end
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Composer
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -108,7 +108,7 @@ module Legion
|
|
|
108
108
|
def suggest_with_llm(extensions)
|
|
109
109
|
suggestions = heuristic_suggestions(extensions)
|
|
110
110
|
{ success: true, suggestions: suggestions, count: suggestions.size }
|
|
111
|
-
rescue StandardError
|
|
111
|
+
rescue StandardError => _e
|
|
112
112
|
{ success: true, suggestions: [], count: 0 }
|
|
113
113
|
end
|
|
114
114
|
end
|
|
@@ -9,6 +9,7 @@ module Legion
|
|
|
9
9
|
|
|
10
10
|
CONSENSUS_THRESHOLD = 0.67
|
|
11
11
|
DISAGREEMENT_ESCALATION_THRESHOLD = 0.5
|
|
12
|
+
DECIDED_CONSENSUSES = %i[approved rejected].freeze
|
|
12
13
|
|
|
13
14
|
def propose_to_swarm(charter_id:, proposal_id:, proposer_agent_id:, **)
|
|
14
15
|
if swarm_available?
|
|
@@ -52,8 +53,8 @@ module Legion
|
|
|
52
53
|
def tally_swarm_votes(charter_id:, proposal_id:, **)
|
|
53
54
|
votes = fetch_votes(charter_id, proposal_id)
|
|
54
55
|
|
|
55
|
-
approve_count = votes.count { |v| [:
|
|
56
|
-
reject_count = votes.count { |v| [:
|
|
56
|
+
approve_count = votes.count { |v| v[:vote].to_s == 'approve' }
|
|
57
|
+
reject_count = votes.count { |v| v[:vote].to_s == 'reject' }
|
|
57
58
|
total = votes.size
|
|
58
59
|
|
|
59
60
|
consensus = if !total.zero? && (approve_count.to_f / total) >= CONSENSUS_THRESHOLD
|
|
@@ -95,7 +96,7 @@ module Legion
|
|
|
95
96
|
record = { proposal_id: pid, consensus: tally[:consensus],
|
|
96
97
|
approve_count: tally[:approve_count], reject_count: tally[:reject_count] }
|
|
97
98
|
|
|
98
|
-
if
|
|
99
|
+
if DECIDED_CONSENSUSES.include?(tally[:consensus])
|
|
99
100
|
decided << record
|
|
100
101
|
else
|
|
101
102
|
pending << record
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Dashboard
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
module_function
|
|
12
12
|
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module DreamIdeation
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -5,19 +5,20 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Evolver
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
13
|
-
BOTTOM_PERCENTILE
|
|
13
|
+
BOTTOM_PERCENTILE = 0.05
|
|
14
14
|
SPECIATION_DRIFT_THRESHOLD = 0.5
|
|
15
|
+
INELIGIBLE_STATUSES = %i[building testing].freeze
|
|
15
16
|
|
|
16
17
|
def select_for_improvement(extensions:, count: 3, **)
|
|
17
18
|
exts = Array(extensions)
|
|
18
19
|
return { success: true, candidates: [], count: 0, total_evaluated: 0 } if exts.empty?
|
|
19
20
|
|
|
20
|
-
eligible = exts.reject { |e|
|
|
21
|
+
eligible = exts.reject { |e| INELIGIBLE_STATUSES.include?((e[:status] || :active).to_sym) }
|
|
21
22
|
ranked = Helpers::FitnessEvaluator.rank(eligible)
|
|
22
23
|
bottom_n = ranked.last(count)
|
|
23
24
|
|
|
@@ -50,7 +51,7 @@ module Legion
|
|
|
50
51
|
name_a = extension_a[:name] || extension_a[:extension_name]
|
|
51
52
|
name_b = extension_b[:name] || extension_b[:extension_name]
|
|
52
53
|
cat_a = (extension_a[:category] || :cognition).to_sym
|
|
53
|
-
merged = merged_name || "lex-merged-#{name_a.to_s.
|
|
54
|
+
merged = merged_name || "lex-merged-#{name_a.to_s.delete_prefix('lex-')}-#{name_b.to_s.delete_prefix('lex-')}"
|
|
54
55
|
desc = "Merged extension combining capabilities of #{name_a} and #{name_b}"
|
|
55
56
|
|
|
56
57
|
proposal = Runners::Proposer.propose_concept(
|
|
@@ -126,11 +127,17 @@ module Legion
|
|
|
126
127
|
end
|
|
127
128
|
|
|
128
129
|
def llm_suggestions(name, fitness, weaknesses)
|
|
130
|
+
# rubocop:disable Legion/HelperMigration/DirectLlm
|
|
129
131
|
response = Legion::LLM.chat(
|
|
130
|
-
caller: {
|
|
132
|
+
caller: {
|
|
133
|
+
extension: 'lex-mind-growth',
|
|
134
|
+
operation: 'evolver',
|
|
135
|
+
phase: 'suggest'
|
|
136
|
+
}
|
|
131
137
|
).ask(improvement_prompt(name, fitness, weaknesses))
|
|
138
|
+
# rubocop:enable Legion/HelperMigration/DirectLlm
|
|
132
139
|
parse_llm_suggestions(response.content)
|
|
133
|
-
rescue StandardError
|
|
140
|
+
rescue StandardError => _e
|
|
134
141
|
nil
|
|
135
142
|
end
|
|
136
143
|
|
|
@@ -151,7 +158,7 @@ module Legion
|
|
|
151
158
|
return nil unless data.is_a?(Array)
|
|
152
159
|
|
|
153
160
|
data.map(&:to_s).reject(&:empty?)
|
|
154
|
-
rescue ::JSON::ParserError
|
|
161
|
+
rescue ::JSON::ParserError => _e
|
|
155
162
|
nil
|
|
156
163
|
end
|
|
157
164
|
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Governance
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module IntegrationTester
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -42,8 +42,9 @@ module Legion
|
|
|
42
42
|
|
|
43
43
|
def benchmark_tick(with_extension: nil, iterations: 5, **)
|
|
44
44
|
return { success: false, reason: :gaia_not_available } unless gaia_available?
|
|
45
|
+
return { success: false, reason: :invalid_iterations, iterations: iterations } unless iterations.is_a?(Integer) && iterations >= 1
|
|
45
46
|
|
|
46
|
-
timings = iterations
|
|
47
|
+
timings = Array.new(iterations) do
|
|
47
48
|
start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
48
49
|
Legion::Gaia.heartbeat if Legion::Gaia.respond_to?(:heartbeat)
|
|
49
50
|
finish = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Monitor
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Orchestrator
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -7,8 +7,8 @@ module Legion
|
|
|
7
7
|
module MindGrowth
|
|
8
8
|
module Runners
|
|
9
9
|
module Proposer
|
|
10
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
11
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
11
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
12
12
|
|
|
13
13
|
extend self
|
|
14
14
|
|
|
@@ -96,7 +96,7 @@ module Legion
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
def derive_module_name(gem_name)
|
|
99
|
-
gem_name.to_s.
|
|
99
|
+
gem_name.to_s.delete_prefix('lex-').split('-').map(&:capitalize).join
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def suggest_category
|
|
@@ -117,8 +117,15 @@ module Legion
|
|
|
117
117
|
def enrich_proposal(name, category, description)
|
|
118
118
|
return {} unless llm_available?
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
# rubocop:disable Legion/HelperMigration/DirectLlm
|
|
121
|
+
response = Legion::LLM.chat(
|
|
122
|
+
caller: {
|
|
123
|
+
extension: 'lex-mind-growth',
|
|
124
|
+
operation: 'propose',
|
|
125
|
+
phase: 'capability'
|
|
126
|
+
}
|
|
127
|
+
).ask(enrichment_prompt(name, category, description))
|
|
128
|
+
# rubocop:enable Legion/HelperMigration/DirectLlm
|
|
122
129
|
parse_enrichment(response.content)
|
|
123
130
|
rescue StandardError => e
|
|
124
131
|
log.debug "[mind_growth:proposer] LLM enrichment failed: #{e.message}"
|
|
@@ -151,7 +158,7 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
|
|
|
151
158
|
{ name: r[:name].to_s, params: Array(r[:params]).map(&:to_s), returns: r[:returns].to_s }
|
|
152
159
|
end
|
|
153
160
|
}
|
|
154
|
-
rescue ::JSON::ParserError, NoMethodError
|
|
161
|
+
rescue ::JSON::ParserError, NoMethodError => _e
|
|
155
162
|
{}
|
|
156
163
|
end
|
|
157
164
|
|
|
@@ -162,7 +169,7 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
|
|
|
162
169
|
def score_with_llm(proposal)
|
|
163
170
|
return nil unless llm_available?
|
|
164
171
|
|
|
165
|
-
response = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'propose', phase: 'score' }).ask(scoring_prompt(proposal))
|
|
172
|
+
response = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'propose', phase: 'score' }).ask(scoring_prompt(proposal)) # rubocop:disable Legion/HelperMigration/DirectLlm
|
|
166
173
|
parse_scores(response.content)
|
|
167
174
|
rescue StandardError => e
|
|
168
175
|
log.debug "[mind_growth:proposer] LLM scoring failed: #{e.message}"
|
|
@@ -203,7 +210,7 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
|
|
|
203
210
|
|
|
204
211
|
[dim, val.to_f.clamp(0.0, 1.0)]
|
|
205
212
|
end
|
|
206
|
-
rescue ::JSON::ParserError, NoMethodError
|
|
213
|
+
rescue ::JSON::ParserError, NoMethodError => _e
|
|
207
214
|
nil
|
|
208
215
|
end
|
|
209
216
|
|
|
@@ -225,8 +232,15 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
|
|
|
225
232
|
return nil unless llm_available?
|
|
226
233
|
|
|
227
234
|
candidates = existing.last(20).map { |p| { name: p.name, description: p.description } }
|
|
228
|
-
|
|
229
|
-
|
|
235
|
+
# rubocop:disable Legion/HelperMigration/DirectLlm
|
|
236
|
+
response = Legion::LLM.chat(
|
|
237
|
+
caller: {
|
|
238
|
+
extension: 'lex-mind-growth',
|
|
239
|
+
operation: 'propose',
|
|
240
|
+
phase: 'validate'
|
|
241
|
+
}
|
|
242
|
+
).ask(redundancy_prompt(name, description, candidates))
|
|
243
|
+
# rubocop:enable Legion/HelperMigration/DirectLlm
|
|
230
244
|
parse_redundancy(response.content)
|
|
231
245
|
rescue StandardError => e
|
|
232
246
|
log.debug "[mind_growth:proposer] LLM redundancy check failed: #{e.message}"
|
|
@@ -264,7 +278,7 @@ phase: 'validate' }).ask(redundancy_prompt(name, description, candidates))
|
|
|
264
278
|
similar_to: data[:similar_to],
|
|
265
279
|
score: score
|
|
266
280
|
}
|
|
267
|
-
rescue ::JSON::ParserError, NoMethodError
|
|
281
|
+
rescue ::JSON::ParserError, NoMethodError => _e
|
|
268
282
|
nil
|
|
269
283
|
end
|
|
270
284
|
end
|
|
@@ -5,19 +5,24 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Retrospective
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
13
|
+
BUILT_STATUSES = %i[passing wired active].freeze
|
|
14
|
+
FAILED_STATUSES = %i[build_failed rejected pruned].freeze
|
|
15
|
+
IN_PROGRESS_STATUSES = %i[proposed evaluating approved building testing].freeze
|
|
16
|
+
SUCCEEDED_STATUSES = BUILT_STATUSES
|
|
17
|
+
|
|
13
18
|
# Generates a summary of growth activity: proposals by status, recent builds, failures
|
|
14
19
|
def session_report(**)
|
|
15
20
|
proposals = Runners::Proposer.proposal_stats
|
|
16
21
|
recent = Runners::Proposer.list_proposals(limit: 10)
|
|
17
22
|
|
|
18
|
-
built
|
|
19
|
-
failed
|
|
20
|
-
in_progress = recent[:proposals].select { |p|
|
|
23
|
+
built = recent[:proposals].select { |p| BUILT_STATUSES.include?(p[:status]) }
|
|
24
|
+
failed = recent[:proposals].select { |p| FAILED_STATUSES.include?(p[:status]) }
|
|
25
|
+
in_progress = recent[:proposals].select { |p| IN_PROGRESS_STATUSES.include?(p[:status]) }
|
|
21
26
|
|
|
22
27
|
{
|
|
23
28
|
success: true,
|
|
@@ -64,7 +69,7 @@ module Legion
|
|
|
64
69
|
|
|
65
70
|
failed = proposals.select { |p| p[:status] == :build_failed }
|
|
66
71
|
rejected = proposals.select { |p| p[:status] == :rejected }
|
|
67
|
-
succeeded = proposals.select { |p|
|
|
72
|
+
succeeded = proposals.select { |p| SUCCEEDED_STATUSES.include?(p[:status]) }
|
|
68
73
|
|
|
69
74
|
# Category success rates
|
|
70
75
|
category_stats = compute_category_stats(proposals)
|
|
@@ -92,7 +97,7 @@ module Legion
|
|
|
92
97
|
def compute_category_stats(proposals)
|
|
93
98
|
by_category = proposals.group_by { |p| p[:category] }
|
|
94
99
|
by_category.transform_values do |cat_proposals|
|
|
95
|
-
succeeded = cat_proposals.count { |p|
|
|
100
|
+
succeeded = cat_proposals.count { |p| SUCCEEDED_STATUSES.include?(p[:status]) }
|
|
96
101
|
{
|
|
97
102
|
total: cat_proposals.size,
|
|
98
103
|
succeeded: succeeded,
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module RiskAssessor
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -67,7 +67,7 @@ module Legion
|
|
|
67
67
|
when :integration_sweep then execute_integration_sweep(charter_id)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
{ success: true, charter_type: charter_type, results: Array(results) }
|
|
70
|
+
{ success: true, charter_id: charter_id, charter_type: charter_type, results: Array(results) }
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def complete_build_swarm(charter_id:, outcome: :success, **)
|
|
@@ -5,8 +5,8 @@ module Legion
|
|
|
5
5
|
module MindGrowth
|
|
6
6
|
module Runners
|
|
7
7
|
module Wirer
|
|
8
|
-
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
-
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
10
10
|
|
|
11
11
|
extend self
|
|
12
12
|
|
|
@@ -34,7 +34,7 @@ require 'legion/extensions/mind_growth/client'
|
|
|
34
34
|
module Legion
|
|
35
35
|
module Extensions
|
|
36
36
|
module MindGrowth
|
|
37
|
-
extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core)
|
|
37
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core, false)
|
|
38
38
|
|
|
39
39
|
def self.remote_invocable?
|
|
40
40
|
false
|
|
@@ -68,8 +68,8 @@ RSpec.describe Legion::Extensions::MindGrowth::Actor::GrowthCycle do
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
describe '#check_subtask?' do
|
|
71
|
-
it 'returns
|
|
72
|
-
expect(actor.check_subtask?).to be
|
|
71
|
+
it 'returns true' do
|
|
72
|
+
expect(actor.check_subtask?).to be true
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
|
|
@@ -235,7 +235,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Helpers::CompositionMap do
|
|
|
235
235
|
|
|
236
236
|
describe 'thread safety' do
|
|
237
237
|
it 'records all rules when added concurrently' do
|
|
238
|
-
threads = 20
|
|
238
|
+
threads = Array.new(20) do |i|
|
|
239
239
|
Thread.new do
|
|
240
240
|
map.add_rule(source_extension: "lex-#{i}", output_key: :result,
|
|
241
241
|
target_extension: 'lex-target', target_method: :run)
|
|
@@ -160,7 +160,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Helpers::ProposalStore do
|
|
|
160
160
|
it 'evicts the oldest proposal when at capacity' do
|
|
161
161
|
stub_const("#{described_class}::MAX_PROPOSALS", 3)
|
|
162
162
|
small_store = described_class.new
|
|
163
|
-
proposals = 4
|
|
163
|
+
proposals = Array.new(4) do |i|
|
|
164
164
|
Legion::Extensions::MindGrowth::Helpers::ConceptProposal.new(
|
|
165
165
|
name: "lex-evict-#{i}", module_name: "E#{i}", category: :cognition, description: "evict #{i}"
|
|
166
166
|
)
|
|
@@ -188,7 +188,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Helpers::ProposalStore do
|
|
|
188
188
|
|
|
189
189
|
describe 'thread safety' do
|
|
190
190
|
it 'handles concurrent stores without error' do
|
|
191
|
-
threads = 10
|
|
191
|
+
threads = Array.new(10) do |i|
|
|
192
192
|
Thread.new do
|
|
193
193
|
p = Legion::Extensions::MindGrowth::Helpers::ConceptProposal.new(
|
|
194
194
|
name: "lex-thread-#{i}", module_name: "T#{i}", category: :cognition, description: "thread #{i}"
|
|
@@ -329,7 +329,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Runners::CompetitiveEvolver do
|
|
|
329
329
|
|
|
330
330
|
describe 'thread safety' do
|
|
331
331
|
it 'handles concurrent competition creation' do
|
|
332
|
-
threads = 10
|
|
332
|
+
threads = Array.new(10) do |i|
|
|
333
333
|
Thread.new { evolver.create_competition(gap: "gap-#{i}", proposal_ids: %w[a b]) }
|
|
334
334
|
end
|
|
335
335
|
results = threads.map(&:value)
|
|
@@ -154,7 +154,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Runners::Governance do
|
|
|
154
154
|
|
|
155
155
|
context 'thread safety' do
|
|
156
156
|
it 'records all votes when cast concurrently' do
|
|
157
|
-
threads = 10
|
|
157
|
+
threads = Array.new(10) do |i|
|
|
158
158
|
Thread.new { governance.vote_on_proposal(proposal_id: proposal.id, vote: :approve, agent_id: "t#{i}") }
|
|
159
159
|
end
|
|
160
160
|
threads.each(&:join)
|