legion-llm 0.3.18 → 0.3.19
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 +19 -0
- data/lib/legion/llm/arbitrage.rb +2 -1
- data/lib/legion/llm/batch.rb +2 -1
- data/lib/legion/llm/cache.rb +2 -1
- data/lib/legion/llm/claude_config_loader.rb +2 -1
- data/lib/legion/llm/cost_tracker.rb +2 -1
- data/lib/legion/llm/daemon_client.rb +6 -3
- data/lib/legion/llm/discovery/ollama.rb +4 -2
- data/lib/legion/llm/discovery/system.rb +2 -1
- data/lib/legion/llm/embeddings.rb +1 -0
- data/lib/legion/llm/hooks/rag_guard.rb +2 -1
- data/lib/legion/llm/hooks.rb +4 -2
- data/lib/legion/llm/providers.rb +2 -1
- data/lib/legion/llm/quality_checker.rb +2 -1
- data/lib/legion/llm/router/gateway_interceptor.rb +2 -1
- data/lib/legion/llm/router.rb +2 -1
- data/lib/legion/llm/scheduling.rb +4 -2
- data/lib/legion/llm/structured_output.rb +1 -0
- data/lib/legion/llm/version.rb +1 -1
- data/lib/legion/llm.rb +7 -3
- 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: ebb55fbba1beba05df5f7924a37d5d2867a0d70d238d1b6cd52913e456e29617
|
|
4
|
+
data.tar.gz: c6cce34a4b0fbf6d1c77a112326750fa536753f87bf8f80df5197adea8d1f750
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21ff9a0a266f9115e338c5a28337e3108ae52f4318432be07a78e39b62bd20f814c866781cc06249d458a2004575804d67189c8c8934de2bc27eb512b159dda5
|
|
7
|
+
data.tar.gz: 127ab33e4a23e3451913247a5ea83b387c9d2e7f451469b78cb777d26b62cad022ddbd0301a54c611b48f58b1ea7c867d4de3a0f507d870c9b1d297b64f36c9c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Legion LLM Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.19] - 2026-03-22
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Added `Legion::Logging` calls to all silent rescue blocks (28 total) so no exception is swallowed without a trace
|
|
7
|
+
- `arbitrage.rb`, `batch.rb`, `scheduling.rb`, `router.rb`, `gateway_interceptor.rb`: `.warn` on settings unavailable
|
|
8
|
+
- `cache.rb`: `.warn` on llm_settings failure
|
|
9
|
+
- `claude_config_loader.rb`: `.debug` on JSON read failure (expected for missing files)
|
|
10
|
+
- `cost_tracker.rb`: `.warn` on settings_pricing failure
|
|
11
|
+
- `daemon_client.rb`: `.warn` on health check failure and fetch_daemon_url failure, `.debug` on JSON parse failure
|
|
12
|
+
- `discovery/ollama.rb`: `.debug` on base_url and discovery_settings failures
|
|
13
|
+
- `discovery/system.rb`: `.debug` on discovery_settings failure
|
|
14
|
+
- `embeddings.rb`: `.warn` on batch embedding failure
|
|
15
|
+
- `hooks/rag_guard.rb`: `.debug` on individual evaluator failure
|
|
16
|
+
- `hooks.rb`: `.warn` on before_chat and after_chat hook failures
|
|
17
|
+
- `providers.rb`: `.debug` on Ollama connection check failure
|
|
18
|
+
- `quality_checker.rb`: `.debug` on JSON validation failure
|
|
19
|
+
- `structured_output.rb`: `.warn` on retry failure
|
|
20
|
+
- `llm.rb`: `.debug` on lex-llm-gateway LoadError, `.warn` on escalation attempt failure, publish_escalation_event failure, and apply_response_guards failure
|
|
21
|
+
|
|
3
22
|
## [0.3.18] - 2026-03-22
|
|
4
23
|
|
|
5
24
|
### Added
|
data/lib/legion/llm/arbitrage.rb
CHANGED
|
@@ -82,7 +82,8 @@ module Legion
|
|
|
82
82
|
|
|
83
83
|
arb = llm[:arbitrage] || llm['arbitrage'] || {}
|
|
84
84
|
arb.is_a?(Hash) ? arb.transform_keys(&:to_sym) : {}
|
|
85
|
-
rescue StandardError
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
Legion::Logging.warn("Arbitrage settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
86
87
|
{}
|
|
87
88
|
end
|
|
88
89
|
|
data/lib/legion/llm/batch.rb
CHANGED
|
@@ -95,7 +95,8 @@ module Legion
|
|
|
95
95
|
|
|
96
96
|
b = llm[:batch] || llm['batch'] || {}
|
|
97
97
|
b.is_a?(Hash) ? b.transform_keys(&:to_sym) : {}
|
|
98
|
-
rescue StandardError
|
|
98
|
+
rescue StandardError => e
|
|
99
|
+
Legion::Logging.warn("Batch settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
99
100
|
{}
|
|
100
101
|
end
|
|
101
102
|
|
data/lib/legion/llm/cache.rb
CHANGED
|
@@ -20,7 +20,8 @@ module Legion
|
|
|
20
20
|
|
|
21
21
|
require 'json'
|
|
22
22
|
::JSON.parse(File.read(path), symbolize_names: true)
|
|
23
|
-
rescue StandardError
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
Legion::Logging.debug("ClaudeConfigLoader could not read #{path}: #{e.message}") if defined?(Legion::Logging)
|
|
24
25
|
{}
|
|
25
26
|
end
|
|
26
27
|
|
|
@@ -86,7 +86,8 @@ module Legion
|
|
|
86
86
|
|
|
87
87
|
pricing = Legion::Settings.dig(:'legion-llm', :pricing)
|
|
88
88
|
pricing.is_a?(Hash) ? pricing : {}
|
|
89
|
-
rescue StandardError
|
|
89
|
+
rescue StandardError => e
|
|
90
|
+
Legion::Logging.warn("CostTracker settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
90
91
|
{}
|
|
91
92
|
end
|
|
92
93
|
end
|
|
@@ -78,7 +78,8 @@ module Legion
|
|
|
78
78
|
@health_checked_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
|
79
79
|
Legion::Logging.info("Daemon health check result=#{healthy ? 'healthy' : 'unhealthy'} url=#{daemon_url}") if defined?(Legion::Logging)
|
|
80
80
|
healthy
|
|
81
|
-
rescue StandardError
|
|
81
|
+
rescue StandardError => e
|
|
82
|
+
Legion::Logging.warn("Daemon health check failed: #{e.message}") if defined?(Legion::Logging)
|
|
82
83
|
mark_unhealthy
|
|
83
84
|
false
|
|
84
85
|
end
|
|
@@ -155,7 +156,8 @@ module Legion
|
|
|
155
156
|
return nil unless daemon.is_a?(Hash)
|
|
156
157
|
|
|
157
158
|
daemon[:url]
|
|
158
|
-
rescue StandardError
|
|
159
|
+
rescue StandardError => e
|
|
160
|
+
Legion::Logging.warn("DaemonClient fetch_daemon_url failed: #{e.message}") if defined?(Legion::Logging)
|
|
159
161
|
nil
|
|
160
162
|
end
|
|
161
163
|
|
|
@@ -163,7 +165,8 @@ module Legion
|
|
|
163
165
|
return {} if body.nil? || body.strip.empty?
|
|
164
166
|
|
|
165
167
|
::JSON.parse(body, symbolize_names: true)
|
|
166
|
-
rescue ::JSON::ParserError
|
|
168
|
+
rescue ::JSON::ParserError => e
|
|
169
|
+
Legion::Logging.debug("DaemonClient JSON parse failed for response body: #{e.message}") if defined?(Legion::Logging)
|
|
167
170
|
{}
|
|
168
171
|
end
|
|
169
172
|
|
|
@@ -73,7 +73,8 @@ module Legion
|
|
|
73
73
|
return 'http://localhost:11434' unless Legion.const_defined?('Settings')
|
|
74
74
|
|
|
75
75
|
Legion::Settings[:llm].dig(:providers, :ollama, :base_url) || 'http://localhost:11434'
|
|
76
|
-
rescue StandardError
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
Legion::Logging.debug("Discovery::Ollama base_url lookup failed, using default: #{e.message}") if defined?(Legion::Logging)
|
|
77
78
|
'http://localhost:11434'
|
|
78
79
|
end
|
|
79
80
|
|
|
@@ -81,7 +82,8 @@ module Legion
|
|
|
81
82
|
return {} unless Legion.const_defined?('Settings')
|
|
82
83
|
|
|
83
84
|
Legion::Settings[:llm][:discovery] || {}
|
|
84
|
-
rescue StandardError
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
Legion::Logging.debug("Discovery::Ollama discovery_settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
85
87
|
{}
|
|
86
88
|
end
|
|
87
89
|
end
|
|
@@ -133,7 +133,8 @@ module Legion
|
|
|
133
133
|
return {} unless Legion.const_defined?('Settings')
|
|
134
134
|
|
|
135
135
|
Legion::Settings[:llm][:discovery] || {}
|
|
136
|
-
rescue StandardError
|
|
136
|
+
rescue StandardError => e
|
|
137
|
+
Legion::Logging.debug("Discovery::System discovery_settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
137
138
|
{}
|
|
138
139
|
end
|
|
139
140
|
end
|
|
@@ -31,6 +31,7 @@ module Legion
|
|
|
31
31
|
{ vector: vec, model: model, dimensions: vec&.size || 0, index: i }
|
|
32
32
|
end
|
|
33
33
|
rescue StandardError => e
|
|
34
|
+
Legion::Logging.warn("Batch embedding failed: #{e.message}") if defined?(Legion::Logging)
|
|
34
35
|
texts.map { |_| { vector: nil, model: model, error: e.message } }
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -56,7 +56,8 @@ module Legion
|
|
|
56
56
|
inputs: [{ input: context.to_s, output: response.to_s, expected: nil }]
|
|
57
57
|
)
|
|
58
58
|
result.dig(:summary, :avg_score) || 0.0
|
|
59
|
-
rescue StandardError
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
Legion::Logging.debug("RagGuard evaluator #{evaluator_name} failed: #{e.message}") if defined?(Legion::Logging)
|
|
60
61
|
0.0
|
|
61
62
|
end
|
|
62
63
|
|
data/lib/legion/llm/hooks.rb
CHANGED
|
@@ -24,7 +24,8 @@ module Legion
|
|
|
24
24
|
return result if result.is_a?(Hash) && result[:action] == :block
|
|
25
25
|
end
|
|
26
26
|
nil
|
|
27
|
-
rescue StandardError
|
|
27
|
+
rescue StandardError => e
|
|
28
|
+
Legion::Logging.warn("LLM before_chat hook failed: #{e.message}") if defined?(Legion::Logging)
|
|
28
29
|
nil
|
|
29
30
|
end
|
|
30
31
|
|
|
@@ -34,7 +35,8 @@ module Legion
|
|
|
34
35
|
return result if result.is_a?(Hash) && result[:action] == :block
|
|
35
36
|
end
|
|
36
37
|
nil
|
|
37
|
-
rescue StandardError
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
Legion::Logging.warn("LLM after_chat hook failed: #{e.message}") if defined?(Legion::Logging)
|
|
38
40
|
nil
|
|
39
41
|
end
|
|
40
42
|
|
data/lib/legion/llm/providers.rb
CHANGED
|
@@ -41,7 +41,8 @@ module Legion
|
|
|
41
41
|
port = (host_part[1] || '11434').to_i
|
|
42
42
|
Socket.tcp(addr, port, connect_timeout: 1).close
|
|
43
43
|
true
|
|
44
|
-
rescue StandardError
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
Legion::Logging.debug("Ollama connection check failed: #{e.message}") if defined?(Legion::Logging)
|
|
45
46
|
false
|
|
46
47
|
end
|
|
47
48
|
|
|
@@ -47,7 +47,8 @@ module Legion
|
|
|
47
47
|
def valid_json?(content)
|
|
48
48
|
::JSON.parse(content)
|
|
49
49
|
true
|
|
50
|
-
rescue ::JSON::ParserError
|
|
50
|
+
rescue ::JSON::ParserError => e
|
|
51
|
+
Legion::Logging.debug("QualityChecker JSON validation failed: #{e.message}") if defined?(Legion::Logging)
|
|
51
52
|
false
|
|
52
53
|
end
|
|
53
54
|
end
|
|
@@ -56,7 +56,8 @@ module Legion
|
|
|
56
56
|
return {} unless llm.is_a?(Hash)
|
|
57
57
|
|
|
58
58
|
(llm[:gateway] || {}).transform_keys(&:to_sym)
|
|
59
|
-
rescue StandardError
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
Legion::Logging.warn("GatewayInterceptor settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
60
61
|
{}
|
|
61
62
|
end
|
|
62
63
|
end
|
data/lib/legion/llm/router.rb
CHANGED
|
@@ -177,7 +177,8 @@ module Legion
|
|
|
177
177
|
return {} unless llm.is_a?(Hash)
|
|
178
178
|
|
|
179
179
|
(llm[:discovery] || {}).transform_keys(&:to_sym)
|
|
180
|
-
rescue StandardError
|
|
180
|
+
rescue StandardError => e
|
|
181
|
+
Legion::Logging.warn("Router discovery_settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
181
182
|
{}
|
|
182
183
|
end
|
|
183
184
|
|
|
@@ -67,7 +67,8 @@ module Legion
|
|
|
67
67
|
|
|
68
68
|
s = llm[:scheduling] || llm['scheduling'] || {}
|
|
69
69
|
s.is_a?(Hash) ? s.transform_keys(&:to_sym) : {}
|
|
70
|
-
rescue StandardError
|
|
70
|
+
rescue StandardError => e
|
|
71
|
+
Legion::Logging.warn("Scheduling settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
71
72
|
{}
|
|
72
73
|
end
|
|
73
74
|
|
|
@@ -81,7 +82,8 @@ module Legion
|
|
|
81
82
|
start_h = Integer(parts[0], 10)
|
|
82
83
|
end_h = Integer(parts[1], 10)
|
|
83
84
|
(start_h..end_h)
|
|
84
|
-
rescue ArgumentError
|
|
85
|
+
rescue ArgumentError => e
|
|
86
|
+
Legion::Logging.debug("Scheduling peak_hours_utc parse failed, using default: #{e.message}") if defined?(Legion::Logging)
|
|
85
87
|
DEFAULT_PEAK_RANGE
|
|
86
88
|
end
|
|
87
89
|
|
|
@@ -57,6 +57,7 @@ module Legion
|
|
|
57
57
|
parsed = Legion::JSON.load(result[:content])
|
|
58
58
|
{ data: parsed, raw: result[:content], model: result[:model], valid: true, retried: true }
|
|
59
59
|
rescue StandardError => e
|
|
60
|
+
Legion::Logging.warn("StructuredOutput retry failed: #{e.message}") if defined?(Legion::Logging)
|
|
60
61
|
{ data: nil, error: e.message, valid: false }
|
|
61
62
|
end
|
|
62
63
|
|
data/lib/legion/llm/version.rb
CHANGED
data/lib/legion/llm.rb
CHANGED
|
@@ -20,7 +20,8 @@ require_relative 'llm/cost_tracker'
|
|
|
20
20
|
|
|
21
21
|
begin
|
|
22
22
|
require 'legion/extensions/llm/gateway'
|
|
23
|
-
rescue LoadError
|
|
23
|
+
rescue LoadError => e
|
|
24
|
+
Legion::Logging.debug("lex-llm-gateway not available: #{e.message}") if defined?(Legion::Logging)
|
|
24
25
|
nil
|
|
25
26
|
end
|
|
26
27
|
|
|
@@ -344,6 +345,7 @@ module Legion
|
|
|
344
345
|
end
|
|
345
346
|
rescue StandardError => e
|
|
346
347
|
duration_ms = ((Time.now - start_time) * 1000).round
|
|
348
|
+
Legion::Logging.warn("Escalation attempt failed model=#{resolution.model}: #{e.message}") if defined?(Legion::Logging)
|
|
347
349
|
report_health(:error, resolution, duration_ms)
|
|
348
350
|
history << build_attempt(resolution, :error, [e.class.name], duration_ms)
|
|
349
351
|
end
|
|
@@ -380,7 +382,8 @@ module Legion
|
|
|
380
382
|
return unless defined?(Legion::Transport)
|
|
381
383
|
|
|
382
384
|
Legion::Logging.debug("Escalation event: #{final_outcome}, #{history.size} attempts") if Legion.const_defined?('Logging')
|
|
383
|
-
rescue StandardError
|
|
385
|
+
rescue StandardError => e
|
|
386
|
+
Legion::Logging.warn("publish_escalation_event failed: #{e.message}") if defined?(Legion::Logging)
|
|
384
387
|
nil
|
|
385
388
|
end
|
|
386
389
|
|
|
@@ -398,7 +401,8 @@ module Legion
|
|
|
398
401
|
Legion::Logging.warn "Response guard failed: #{guard_result.inspect}" if !guard_result[:passed] && Legion.const_defined?('Logging')
|
|
399
402
|
|
|
400
403
|
result.merge(_guard_result: guard_result)
|
|
401
|
-
rescue StandardError
|
|
404
|
+
rescue StandardError => e
|
|
405
|
+
Legion::Logging.warn("apply_response_guards failed: #{e.message}") if defined?(Legion::Logging)
|
|
402
406
|
result
|
|
403
407
|
end
|
|
404
408
|
|