legionio 1.4.68 → 1.4.70
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/CHANGELOG.md +20 -0
- data/lib/legion/extensions/actors/subscription.rb +2 -2
- data/lib/legion/extensions/helpers/transport.rb +2 -2
- data/lib/legion/extensions/transport.rb +4 -4
- data/lib/legion/extensions.rb +18 -5
- data/lib/legion/readiness.rb +1 -1
- data/lib/legion/service.rb +30 -1
- data/lib/legion/version.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: 6f924192ddb882e9dd08fa0ada9088c4f9f468ef8d782df7a06888774ebe5b9d
|
|
4
|
+
data.tar.gz: f7eab58ceaf4f9119dad859f9b5d47945b57854a2e65e7f68484660da9c2f3a9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5b120a8843d8626da5508cfef24fa2791539c135d090a83a1519e9db99d3fb78aac7b52fde48b2c844435687114dada9b9622d73f6ab204607e73f422f2a9b90
|
|
7
|
+
data.tar.gz: 6965a20d9389f2b8e16be7e83fdac2835c6b18d47269bb9bf9f102588d03ed7df72b62cc119afeb1f7b0c29695efd0654e60af093bff4e00d3e2eefc76f76723
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.70] - 2026-03-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- GAIA cognitive layer as a core boot phase: `setup_gaia` runs between LLM and telemetry in the startup sequence
|
|
7
|
+
- Two-phase extension loading: all extensions are fully loaded (require + autobuild) before any actors are hooked (AMQP subscriptions, timers, etc.), preventing race conditions during boot
|
|
8
|
+
- `gaia: true` parameter on `Service.new` to control GAIA initialization
|
|
9
|
+
- GAIA graceful shutdown and reload support (shuts down before extensions, restarts after data)
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Boot order is now deterministic: Logging -> Settings -> Crypt -> Transport -> Cache -> Data -> RBAC -> LLM -> GAIA -> Telemetry -> Extensions -> API
|
|
13
|
+
- Extension actors are collected into `@pending_actors` during `load_extensions`, then started all at once via `hook_all_actors`
|
|
14
|
+
|
|
15
|
+
## [1.4.69] - 2026-03-19
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Constant resolution bug in transport/subscription layers: `const_defined?` and `const_get` now pass `inherit: false` to prevent Ruby from finding top-level gem constants (`::Redis`, `::Vault`, `::Data`) through `Object` when checking dynamically created `Module.new` namespaces (`Transport::Exchanges`, `Transport::Queues`)
|
|
19
|
+
- `Subscription#queue` now uses `queues.const_get(actor_const, false)` instead of `Kernel.const_get(queue_string)` to search only the Queues module's own constants
|
|
20
|
+
- Added `llm-gateway` to `core_extension_names` so it is included under `:core` role profile
|
|
21
|
+
- `build_extension_entry` now forces nesting for multi-segment gem names (e.g. `lex-llm-gateway`) to produce correct require paths regardless of call-site `nesting:` argument
|
|
22
|
+
|
|
3
23
|
## [1.4.68] - 2026-03-19
|
|
4
24
|
|
|
5
25
|
### Added
|
|
@@ -30,8 +30,8 @@ module Legion
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def queue
|
|
33
|
-
create_queue unless queues.const_defined?(actor_const)
|
|
34
|
-
|
|
33
|
+
create_queue unless queues.const_defined?(actor_const, false)
|
|
34
|
+
queues.const_get(actor_const, false)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def queue_string
|
|
@@ -33,13 +33,13 @@ module Legion
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def build_default_exchange
|
|
36
|
-
return transport_class::Exchanges.const_get(lex_const) if transport_class::Exchanges.const_defined?
|
|
36
|
+
return transport_class::Exchanges.const_get(lex_const, false) if transport_class::Exchanges.const_defined?(lex_const, false)
|
|
37
37
|
|
|
38
38
|
amqp = amqp_prefix
|
|
39
39
|
transport_class::Exchanges.const_set(lex_const, Class.new(Legion::Transport::Exchange) do
|
|
40
40
|
define_method(:exchange_name) { amqp }
|
|
41
41
|
end)
|
|
42
|
-
@default_exchange = transport_class::Exchanges.const_get(lex_const)
|
|
42
|
+
@default_exchange = transport_class::Exchanges.const_get(lex_const, false)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -27,9 +27,9 @@ module Legion
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def generate_base_modules
|
|
30
|
-
lex_class.const_set('Transport', Module.new) unless lex_class.const_defined?('Transport')
|
|
30
|
+
lex_class.const_set('Transport', Module.new) unless lex_class.const_defined?('Transport', false)
|
|
31
31
|
%w[Queues Exchanges Messages Consumers].each do |thing|
|
|
32
|
-
next if transport_class.const_defined?
|
|
32
|
+
next if transport_class.const_defined?(thing, false)
|
|
33
33
|
|
|
34
34
|
transport_class.const_set(thing, Module.new)
|
|
35
35
|
end
|
|
@@ -68,7 +68,7 @@ module Legion
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def auto_create_dlx_exchange
|
|
71
|
-
dlx = if transport_class::Exchanges.const_defined?
|
|
71
|
+
dlx = if transport_class::Exchanges.const_defined?('Dlx', false)
|
|
72
72
|
transport_class::Exchanges::Dlx
|
|
73
73
|
else
|
|
74
74
|
transport_class::Exchanges.const_set('Dlx', Class.new(default_exchange) do
|
|
@@ -86,7 +86,7 @@ module Legion
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def auto_create_dlx_queue
|
|
89
|
-
return if transport_class::Queues.const_defined?('Dlx')
|
|
89
|
+
return if transport_class::Queues.const_defined?('Dlx', false)
|
|
90
90
|
|
|
91
91
|
special_name = default_exchange.new.exchange_name
|
|
92
92
|
dlx_queue = Legion::Transport::Queue.new "#{special_name}.dlx", auto_delete: false
|
data/lib/legion/extensions.rb
CHANGED
|
@@ -18,9 +18,11 @@ module Legion
|
|
|
18
18
|
@subscription_tasks = []
|
|
19
19
|
@local_tasks = []
|
|
20
20
|
@actors = []
|
|
21
|
+
@pending_actors = []
|
|
21
22
|
|
|
22
23
|
find_extensions
|
|
23
24
|
load_extensions
|
|
25
|
+
hook_all_actors
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
attr_reader :local_tasks
|
|
@@ -124,14 +126,14 @@ module Legion
|
|
|
124
126
|
|
|
125
127
|
if extension.respond_to?(:meta_actors) && extension.meta_actors.is_a?(Hash)
|
|
126
128
|
extension.meta_actors.each_value do |actor|
|
|
127
|
-
extension.log.debug("
|
|
128
|
-
|
|
129
|
+
extension.log.debug("deferring meta actor: #{actor}") if has_logger
|
|
130
|
+
@pending_actors << actor
|
|
129
131
|
end
|
|
130
132
|
end
|
|
131
133
|
|
|
132
134
|
extension.actors.each_value do |actor|
|
|
133
|
-
extension.log.debug("
|
|
134
|
-
|
|
135
|
+
extension.log.debug("deferring literal actor: #{actor}") if has_logger
|
|
136
|
+
@pending_actors << actor
|
|
135
137
|
end
|
|
136
138
|
extension.log.info "Loaded v#{extension::VERSION}"
|
|
137
139
|
Legion::Events.emit('extension.loaded', name: ext_name, version: entry[:gem_name])
|
|
@@ -161,6 +163,14 @@ module Legion
|
|
|
161
163
|
false
|
|
162
164
|
end
|
|
163
165
|
|
|
166
|
+
def hook_all_actors
|
|
167
|
+
return if @pending_actors.nil? || @pending_actors.empty?
|
|
168
|
+
|
|
169
|
+
Legion::Logging.info "Hooking #{@pending_actors.size} deferred actors"
|
|
170
|
+
@pending_actors.each { |actor| hook_actor(**actor) }
|
|
171
|
+
@pending_actors = []
|
|
172
|
+
end
|
|
173
|
+
|
|
164
174
|
def hook_actor(extension:, extension_name:, actor_class:, size: 1, **opts)
|
|
165
175
|
size = if Legion::Settings[:extensions].key?(extension_name.to_sym) && Legion::Settings[:extensions][extension_name.to_sym].key?(:workers)
|
|
166
176
|
Legion::Settings[:extensions][extension_name.to_sym][:workers]
|
|
@@ -303,7 +313,7 @@ module Legion
|
|
|
303
313
|
end
|
|
304
314
|
|
|
305
315
|
def core_extension_names
|
|
306
|
-
%w[codegen conditioner exec health lex log metering node ping scheduler tasker task_pruner telemetry
|
|
316
|
+
%w[codegen conditioner exec health lex llm-gateway log metering node ping scheduler tasker task_pruner telemetry
|
|
307
317
|
transformer].freeze
|
|
308
318
|
end
|
|
309
319
|
|
|
@@ -450,6 +460,9 @@ module Legion
|
|
|
450
460
|
segments = Helpers::Segments.derive_segments(gem_name)
|
|
451
461
|
tier = category == :default ? 5 : (categories.dig(category, :tier) || 5)
|
|
452
462
|
|
|
463
|
+
# Multi-segment gem names always need nesting for correct require paths
|
|
464
|
+
nesting = true if segments.length > 1
|
|
465
|
+
|
|
453
466
|
if nesting
|
|
454
467
|
const_path = Helpers::Segments.derive_const_path(gem_name)
|
|
455
468
|
require_path = Helpers::Segments.derive_require_path(gem_name)
|
data/lib/legion/readiness.rb
CHANGED
data/lib/legion/service.rb
CHANGED
|
@@ -7,11 +7,12 @@ module Legion
|
|
|
7
7
|
def modules
|
|
8
8
|
base = [Legion::Crypt, Legion::Transport, Legion::Cache, Legion::Data, Legion::Supervision]
|
|
9
9
|
base << Legion::LLM if defined?(Legion::LLM)
|
|
10
|
+
base << Legion::Gaia if defined?(Legion::Gaia)
|
|
10
11
|
base.freeze
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def initialize(transport: true, cache: true, data: true, supervision: true, extensions: true, # rubocop:disable Metrics/ParameterLists
|
|
14
|
-
crypt: true, api: true, llm: true, log_level: 'info', http_port: nil)
|
|
15
|
+
crypt: true, api: true, llm: true, gaia: true, log_level: 'info', http_port: nil)
|
|
15
16
|
setup_logging(log_level: log_level)
|
|
16
17
|
Legion::Logging.debug('Starting Legion::Service')
|
|
17
18
|
setup_settings
|
|
@@ -51,6 +52,11 @@ module Legion
|
|
|
51
52
|
Legion::Readiness.mark_ready(:llm)
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
if gaia
|
|
56
|
+
setup_gaia
|
|
57
|
+
Legion::Readiness.mark_ready(:gaia)
|
|
58
|
+
end
|
|
59
|
+
|
|
54
60
|
setup_telemetry
|
|
55
61
|
setup_supervision if supervision
|
|
56
62
|
|
|
@@ -210,6 +216,16 @@ module Legion
|
|
|
210
216
|
Legion::Logging.warn "Legion::LLM failed to load: #{e.message}"
|
|
211
217
|
end
|
|
212
218
|
|
|
219
|
+
def setup_gaia
|
|
220
|
+
require 'legion/gaia'
|
|
221
|
+
Legion::Settings.merge_settings('gaia', Legion::Gaia::Settings.default)
|
|
222
|
+
Legion::Gaia.boot
|
|
223
|
+
rescue LoadError
|
|
224
|
+
Legion::Logging.info 'Legion::Gaia gem is not installed, starting without cognitive layer'
|
|
225
|
+
rescue StandardError => e
|
|
226
|
+
Legion::Logging.warn "Legion::Gaia failed to load: #{e.message}"
|
|
227
|
+
end
|
|
228
|
+
|
|
213
229
|
def setup_transport
|
|
214
230
|
require 'legion/transport'
|
|
215
231
|
Legion::Settings.merge_settings('transport', Legion::Transport::Settings.default)
|
|
@@ -295,6 +311,11 @@ module Legion
|
|
|
295
311
|
|
|
296
312
|
Legion::Metrics.reset! if defined?(Legion::Metrics)
|
|
297
313
|
|
|
314
|
+
if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
315
|
+
Legion::Gaia.shutdown
|
|
316
|
+
Legion::Readiness.mark_not_ready(:gaia)
|
|
317
|
+
end
|
|
318
|
+
|
|
298
319
|
Legion::Extensions.shutdown
|
|
299
320
|
Legion::Readiness.mark_not_ready(:extensions)
|
|
300
321
|
|
|
@@ -330,6 +351,11 @@ module Legion
|
|
|
330
351
|
|
|
331
352
|
shutdown_api
|
|
332
353
|
|
|
354
|
+
if defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
355
|
+
Legion::Gaia.shutdown
|
|
356
|
+
Legion::Readiness.mark_not_ready(:gaia)
|
|
357
|
+
end
|
|
358
|
+
|
|
333
359
|
Legion::Extensions.shutdown
|
|
334
360
|
Legion::Readiness.mark_not_ready(:extensions)
|
|
335
361
|
|
|
@@ -357,6 +383,9 @@ module Legion
|
|
|
357
383
|
setup_data
|
|
358
384
|
Legion::Readiness.mark_ready(:data)
|
|
359
385
|
|
|
386
|
+
setup_gaia
|
|
387
|
+
Legion::Readiness.mark_ready(:gaia)
|
|
388
|
+
|
|
360
389
|
setup_supervision
|
|
361
390
|
|
|
362
391
|
load_extensions
|
data/lib/legion/version.rb
CHANGED