legion-tty 0.4.38 → 0.4.39
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 +8 -0
- data/lib/legion/tty/background/llm_probe.rb +26 -2
- data/lib/legion/tty/components/wizard_prompt.rb +6 -2
- data/lib/legion/tty/screens/onboarding.rb +83 -25
- data/lib/legion/tty/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: 7a46889a85e5da8000964e9ac91d0c8e8fba67591fc12ca4bc8a4057339ed09b
|
|
4
|
+
data.tar.gz: d769157e7b76054bc01148650474b0e621a22173428628ce2edf41e2c58aafc8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cfb3a079a43835daf8cb922627ccb2f19e36c9fcfd0577f9cfa9a468f38d0ff1f658eaaeeda82ff202b6213013442e798cca11e9b61ca544ce171173ada7ce8e
|
|
7
|
+
data.tar.gz: 4bc9d5d5e2b7173740d4d1a72193e31d77c7bd22bfa745cd39861704804d2f78489dafc915c5a35b916252a554b80df685b4e0bb6136f0cc1bef356b24e57a0f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.39] - 2026-03-28
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Onboarding wizard now installs GAIA cognitive extension gems when waking GAIA: after the daemon starts (or is already running), `offer_gaia_gems` checks for the 21 agentic/GAIA-tier gems via `Gem::Specification.find_by_name` and prompts the user to install any that are missing
|
|
7
|
+
- `LlmProbe` now returns `:configured` status (instead of `:error`) when a provider is enabled but the ping fails (e.g. Vault-injected providers unknown to `apply_provider_config`); these providers are shown with a key icon and "configured, not validated" label and are selectable as the default when no fully-validated `:ok` providers exist
|
|
8
|
+
- `LlmProbe` accepts a `wait_queue:` argument so it waits for the bootstrap config thread to complete before probing, ensuring Vault-sourced provider settings are written to `~/.legionio/settings/llm.json` first
|
|
9
|
+
- `select_provider_default` falls back to `:configured` providers when no `:ok` providers exist, so Vault-resolved providers are usable as the chat default
|
|
10
|
+
|
|
3
11
|
## [0.4.38] - 2026-03-26
|
|
4
12
|
|
|
5
13
|
### Added
|
|
@@ -4,12 +4,14 @@ module Legion
|
|
|
4
4
|
module TTY
|
|
5
5
|
module Background
|
|
6
6
|
class LlmProbe
|
|
7
|
-
def initialize(logger: nil)
|
|
7
|
+
def initialize(logger: nil, wait_queue: nil)
|
|
8
8
|
@log = logger
|
|
9
|
+
@wait_queue = wait_queue
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def run_async(queue)
|
|
12
13
|
Thread.new do
|
|
14
|
+
wait_for_bootstrap if @wait_queue
|
|
13
15
|
result = probe_providers
|
|
14
16
|
queue.push({ data: result })
|
|
15
17
|
rescue StandardError => e
|
|
@@ -20,6 +22,28 @@ module Legion
|
|
|
20
22
|
|
|
21
23
|
private
|
|
22
24
|
|
|
25
|
+
def wait_for_bootstrap
|
|
26
|
+
deadline = Time.now + 15
|
|
27
|
+
timed_out = false
|
|
28
|
+
loop do
|
|
29
|
+
break unless @wait_queue.empty?
|
|
30
|
+
|
|
31
|
+
if Time.now >= deadline
|
|
32
|
+
timed_out = true
|
|
33
|
+
break
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
sleep 0.2
|
|
37
|
+
end
|
|
38
|
+
if timed_out
|
|
39
|
+
@log&.log('llm_probe', 'bootstrap wait timed out')
|
|
40
|
+
else
|
|
41
|
+
@log&.log('llm_probe', 'bootstrap wait complete')
|
|
42
|
+
end
|
|
43
|
+
rescue StandardError => e
|
|
44
|
+
@log&.log('llm_probe', "bootstrap wait error: #{e.message}")
|
|
45
|
+
end
|
|
46
|
+
|
|
23
47
|
def probe_providers
|
|
24
48
|
require 'legion/llm'
|
|
25
49
|
require 'legion/settings'
|
|
@@ -54,7 +78,7 @@ module Legion
|
|
|
54
78
|
rescue StandardError => e
|
|
55
79
|
latency = ((Time.now - start_time) * 1000).round
|
|
56
80
|
Legion::Logging.debug("ping_provider #{name} failed: #{e.message}") if defined?(Legion::Logging)
|
|
57
|
-
{ name: name, model: model, status: :
|
|
81
|
+
{ name: name, model: model, status: :configured, latency_ms: latency, error: e.message }
|
|
58
82
|
end
|
|
59
83
|
end
|
|
60
84
|
end
|
|
@@ -56,10 +56,14 @@ module Legion
|
|
|
56
56
|
|
|
57
57
|
def display_provider_results(providers)
|
|
58
58
|
providers.each do |p|
|
|
59
|
-
icon = p[:status]
|
|
59
|
+
icon = case p[:status]
|
|
60
|
+
when :ok then "\u2705"
|
|
61
|
+
when :configured then "\U0001F511"
|
|
62
|
+
else "\u274C"
|
|
63
|
+
end
|
|
60
64
|
latency = "#{p[:latency_ms]}ms"
|
|
61
65
|
label = "#{icon} #{p[:name]} (#{p[:model]}) \u2014 #{latency}"
|
|
62
|
-
label += " [#{p[:error]}]" if p[:error]
|
|
66
|
+
label += p[:status] == :configured ? ' [configured, not validated]' : " [#{p[:error]}]" if p[:error]
|
|
63
67
|
@prompt.say(label)
|
|
64
68
|
end
|
|
65
69
|
end
|
|
@@ -17,6 +17,17 @@ module Legion
|
|
|
17
17
|
class Onboarding < Base
|
|
18
18
|
TYPED_DELAY = 0.05
|
|
19
19
|
|
|
20
|
+
GAIA_GEMS = %w[
|
|
21
|
+
lex-agentic-self lex-agentic-affect lex-agentic-attention
|
|
22
|
+
lex-agentic-defense lex-agentic-executive lex-agentic-homeostasis
|
|
23
|
+
lex-agentic-imagination lex-agentic-inference lex-agentic-integration
|
|
24
|
+
lex-agentic-language lex-agentic-learning lex-agentic-memory
|
|
25
|
+
lex-agentic-social
|
|
26
|
+
lex-tick lex-extinction lex-mind-growth lex-mesh
|
|
27
|
+
lex-synapse lex-react
|
|
28
|
+
legion-gaia legion-apollo
|
|
29
|
+
].freeze
|
|
30
|
+
|
|
20
31
|
def initialize(app, wizard: nil, output: $stdout, skip_rain: false)
|
|
21
32
|
super(app)
|
|
22
33
|
@wizard = wizard || Components::WizardPrompt.new
|
|
@@ -119,6 +130,7 @@ module Legion
|
|
|
119
130
|
|
|
120
131
|
def select_provider_default(providers)
|
|
121
132
|
working = providers.select { |p| p[:status] == :ok }
|
|
133
|
+
working = providers.select { |p| p[:status] == :configured } if working.empty?
|
|
122
134
|
if working.any?
|
|
123
135
|
default = @wizard.select_default_provider(working)
|
|
124
136
|
sleep 0.5
|
|
@@ -139,7 +151,7 @@ module Legion
|
|
|
139
151
|
@kerberos_probe.run_async(@kerberos_queue)
|
|
140
152
|
@github_probe.run_quick_async(@github_quick_queue)
|
|
141
153
|
require_relative '../background/llm_probe'
|
|
142
|
-
@llm_probe = Background::LlmProbe.new(logger: @log)
|
|
154
|
+
@llm_probe = Background::LlmProbe.new(logger: @log, wait_queue: @bootstrap_queue)
|
|
143
155
|
@llm_probe.run_async(@llm_queue)
|
|
144
156
|
@bootstrap_probe = Background::BootstrapConfig.new(logger: @log)
|
|
145
157
|
@bootstrap_probe.run_async(@bootstrap_queue)
|
|
@@ -196,37 +208,42 @@ module Legion
|
|
|
196
208
|
end
|
|
197
209
|
end
|
|
198
210
|
|
|
199
|
-
# rubocop:disable Metrics/AbcSize
|
|
200
211
|
def run_gaia_awakening
|
|
201
212
|
typed_output('Scanning for active cognition threads...')
|
|
202
213
|
sleep 1.2
|
|
203
214
|
@output.puts
|
|
204
215
|
|
|
205
|
-
if legionio_running?
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if @wizard.confirm('Shall I wake her?')
|
|
216
|
-
started = start_legionio_daemon
|
|
217
|
-
if started
|
|
218
|
-
typed_output('... initializing cognitive substrate...')
|
|
219
|
-
sleep 1
|
|
220
|
-
typed_output('GAIA online. All systems nominal.')
|
|
221
|
-
else
|
|
222
|
-
typed_output("Could not start daemon. Run 'legionio start' manually.")
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
end
|
|
216
|
+
gaia_active = if legionio_running?
|
|
217
|
+
typed_output('GAIA is awake.')
|
|
218
|
+
sleep 0.5
|
|
219
|
+
typed_output('Heuristic mesh: nominal.')
|
|
220
|
+
sleep 0.8
|
|
221
|
+
typed_output('Cognitive threads synchronized.')
|
|
222
|
+
true
|
|
223
|
+
else
|
|
224
|
+
wake_gaia_daemon
|
|
225
|
+
end
|
|
226
226
|
|
|
227
|
+
offer_gaia_gems if gaia_active
|
|
227
228
|
@output.puts
|
|
228
229
|
end
|
|
229
|
-
|
|
230
|
+
|
|
231
|
+
def wake_gaia_daemon
|
|
232
|
+
typed_output('GAIA is dormant.')
|
|
233
|
+
sleep 1
|
|
234
|
+
@output.puts
|
|
235
|
+
return unless @wizard.confirm('Shall I wake her?')
|
|
236
|
+
|
|
237
|
+
started = start_legionio_daemon
|
|
238
|
+
if started
|
|
239
|
+
typed_output('... initializing cognitive substrate...')
|
|
240
|
+
sleep 1
|
|
241
|
+
typed_output('GAIA online. All systems nominal.')
|
|
242
|
+
else
|
|
243
|
+
typed_output("Could not start daemon. Run 'legionio start' manually.")
|
|
244
|
+
end
|
|
245
|
+
started
|
|
246
|
+
end
|
|
230
247
|
|
|
231
248
|
def collect_background_results
|
|
232
249
|
@log.log('collect', 'waiting for scanner results (10s timeout)')
|
|
@@ -392,7 +409,7 @@ module Legion
|
|
|
392
409
|
|
|
393
410
|
def store_teams_token(result)
|
|
394
411
|
require 'legion/extensions/microsoft_teams/helpers/token_cache'
|
|
395
|
-
cache = Legion::Extensions::MicrosoftTeams::Helpers::TokenCache.
|
|
412
|
+
cache = Legion::Extensions::MicrosoftTeams::Helpers::TokenCache.instance
|
|
396
413
|
cache.store_delegated_token(result)
|
|
397
414
|
cache.save_to_vault
|
|
398
415
|
rescue StandardError => e
|
|
@@ -400,6 +417,47 @@ module Legion
|
|
|
400
417
|
nil
|
|
401
418
|
end
|
|
402
419
|
|
|
420
|
+
def offer_gaia_gems
|
|
421
|
+
missing = missing_gaia_gems
|
|
422
|
+
return if missing.empty?
|
|
423
|
+
|
|
424
|
+
@output.puts
|
|
425
|
+
typed_output("#{missing.size} cognitive extension#{'s' if missing.size != 1} not installed.")
|
|
426
|
+
@output.puts
|
|
427
|
+
return unless @wizard.confirm('Install cognitive extensions?')
|
|
428
|
+
|
|
429
|
+
install_gaia_gems(missing)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def missing_gaia_gems
|
|
433
|
+
GAIA_GEMS.reject do |gem_name|
|
|
434
|
+
Gem::Specification.find_by_name(gem_name)
|
|
435
|
+
true
|
|
436
|
+
rescue Gem::LoadError
|
|
437
|
+
false
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def install_gaia_gems(gems)
|
|
442
|
+
failed = []
|
|
443
|
+
gems.each do |gem_name|
|
|
444
|
+
typed_output(" installing #{gem_name}...")
|
|
445
|
+
@output.puts
|
|
446
|
+
Gem.install(gem_name)
|
|
447
|
+
rescue StandardError => e
|
|
448
|
+
@log.log('gaia_gems', "failed to install #{gem_name}: #{e.message}")
|
|
449
|
+
typed_output(" failed: #{gem_name}")
|
|
450
|
+
@output.puts
|
|
451
|
+
failed << gem_name
|
|
452
|
+
end
|
|
453
|
+
if failed.empty?
|
|
454
|
+
typed_output('Cognitive extensions installed.')
|
|
455
|
+
else
|
|
456
|
+
typed_output("Cognitive extensions installed with #{failed.size} failure#{'s' if failed.size != 1}.")
|
|
457
|
+
end
|
|
458
|
+
@output.puts
|
|
459
|
+
end
|
|
460
|
+
|
|
403
461
|
def detect_gem_available?
|
|
404
462
|
require 'legion/extensions/detect'
|
|
405
463
|
true
|
data/lib/legion/tty/version.rb
CHANGED