legion-llm 0.3.20 → 0.3.21
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 +10 -0
- data/lib/legion/llm/cost_tracker.rb +1 -1
- data/lib/legion/llm/shadow_eval.rb +3 -3
- data/lib/legion/llm/tool_registry.rb +26 -0
- data/lib/legion/llm/version.rb +1 -1
- data/lib/legion/llm.rb +18 -2
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b13e641291a41a378dba7a7eca32aaf67c46bc45cb5d459ded5bc3bdab8e0b0
|
|
4
|
+
data.tar.gz: cc8c372089f5de6518222d608255d65f58968bb97d6eb4f77aac61bb475149d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b8f38cc2091b3f09f55325192cc6d92bda63aeddbdbe1548ebb04e6c68037219d7c1a892e86dd5663ef0334289c7107c2f8326cc30faf218e53dee0c4b19e1b9
|
|
7
|
+
data.tar.gz: 50c0618742b5006211029aef080fd04c044b20f6b5e33a6bd6d5c070c8971defb3b21bf0f70341ac23900b20f3e80df2071505edf66879519e913a7e95ea1d33
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Legion LLM Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.21] - 2026-03-23
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Legion::LLM::ToolRegistry` thread-safe tool class registry for auto-attaching tools to chat sessions
|
|
7
|
+
- Wire ToolRegistry into `chat_single` so globally registered tools are available in every session
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Fix `CostTracker.settings_pricing` reading from wrong settings key (`:'legion-llm'` instead of `:llm`)
|
|
11
|
+
- Fix `ShadowEval.evaluate` not passing `messages:` to shadow model (shadow got no context to respond to)
|
|
12
|
+
|
|
3
13
|
## [0.3.20] - 2026-03-22
|
|
4
14
|
|
|
5
15
|
### Changed
|
|
@@ -84,7 +84,7 @@ module Legion
|
|
|
84
84
|
def settings_pricing
|
|
85
85
|
return {} unless defined?(Legion::Settings)
|
|
86
86
|
|
|
87
|
-
pricing = Legion::Settings.dig(:
|
|
87
|
+
pricing = Legion::Settings.dig(:llm, :pricing)
|
|
88
88
|
pricing.is_a?(Hash) ? pricing : {}
|
|
89
89
|
rescue StandardError => e
|
|
90
90
|
Legion::Logging.warn("CostTracker settings unavailable: #{e.message}") if defined?(Legion::Logging)
|
|
@@ -15,14 +15,14 @@ module Legion
|
|
|
15
15
|
rand < rate
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def evaluate(primary_response:, messages: nil, shadow_model: nil)
|
|
18
|
+
def evaluate(primary_response:, messages: nil, shadow_model: nil)
|
|
19
19
|
shadow_model ||= Legion::Settings.dig(:llm, :shadow, :model) || 'gpt-4o-mini'
|
|
20
20
|
Legion::Logging.debug("ShadowEval triggered primary_model=#{primary_response[:model]} shadow_model=#{shadow_model}") if defined?(Legion::Logging)
|
|
21
21
|
|
|
22
22
|
shadow_response = Legion::LLM.send(:chat_single,
|
|
23
23
|
model: shadow_model, provider: nil,
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
messages: messages, intent: nil,
|
|
25
|
+
tier: nil)
|
|
26
26
|
|
|
27
27
|
comparison = compare(primary_response, shadow_response, shadow_model)
|
|
28
28
|
Legion::Events.emit('llm.shadow_eval', comparison) if defined?(Legion::Events)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module LLM
|
|
5
|
+
module ToolRegistry
|
|
6
|
+
@tools = []
|
|
7
|
+
@mutex = Mutex.new
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def register(tool_class)
|
|
11
|
+
@mutex.synchronize do
|
|
12
|
+
@tools << tool_class unless @tools.include?(tool_class)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def tools
|
|
17
|
+
@mutex.synchronize { @tools.dup }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def clear
|
|
21
|
+
@mutex.synchronize { @tools.clear }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/legion/llm/version.rb
CHANGED
data/lib/legion/llm.rb
CHANGED
|
@@ -17,6 +17,7 @@ require_relative 'llm/batch'
|
|
|
17
17
|
require_relative 'llm/scheduling'
|
|
18
18
|
require_relative 'llm/off_peak'
|
|
19
19
|
require_relative 'llm/cost_tracker'
|
|
20
|
+
require_relative 'llm/tool_registry'
|
|
20
21
|
|
|
21
22
|
begin
|
|
22
23
|
require 'legion/extensions/llm/gateway'
|
|
@@ -119,6 +120,9 @@ module Legion
|
|
|
119
120
|
end
|
|
120
121
|
end
|
|
121
122
|
|
|
123
|
+
if defined?(Legion::Logging)
|
|
124
|
+
Legion::Logging.debug "[LLM] chat_direct escalate=#{escalate} message_present=#{!message.nil?} model=#{model} provider=#{provider}"
|
|
125
|
+
end
|
|
122
126
|
result = if escalate && message
|
|
123
127
|
chat_with_escalation(
|
|
124
128
|
model: model, provider: provider, intent: intent, tier: tier,
|
|
@@ -129,6 +133,7 @@ module Legion
|
|
|
129
133
|
chat_single(model: model, provider: provider, intent: intent, tier: tier,
|
|
130
134
|
temperature: temperature, message: message, **kwargs)
|
|
131
135
|
end
|
|
136
|
+
Legion::Logging.debug "[LLM] chat_direct result_class=#{result.class} result_nil=#{result.nil?}" if defined?(Legion::Logging)
|
|
132
137
|
|
|
133
138
|
if cache_key && result.is_a?(Hash)
|
|
134
139
|
ttl = settings.dig(:prompt_caching, :response_cache, :ttl_seconds) || Cache::DEFAULT_TTL
|
|
@@ -283,7 +288,11 @@ module Legion
|
|
|
283
288
|
Legion::Extensions::LLM::Gateway::Runners::Inference.chat(**)
|
|
284
289
|
end
|
|
285
290
|
|
|
286
|
-
def chat_single(model:, provider:, intent:, tier:, message: nil, **kwargs)
|
|
291
|
+
def chat_single(model:, provider:, intent:, tier:, message: nil, **kwargs) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
292
|
+
explicit_tools = kwargs.delete(:tools)
|
|
293
|
+
tools = explicit_tools || ToolRegistry.tools
|
|
294
|
+
tools = nil if tools.empty?
|
|
295
|
+
|
|
287
296
|
if (intent || tier) && Router.routing_enabled?
|
|
288
297
|
resolution = Router.resolve(intent: intent, tier: tier, model: model, provider: provider)
|
|
289
298
|
if resolution
|
|
@@ -307,10 +316,17 @@ module Legion
|
|
|
307
316
|
|
|
308
317
|
inject_anthropic_cache_control!(opts, provider)
|
|
309
318
|
|
|
319
|
+
if defined?(Legion::Logging)
|
|
320
|
+
Legion::Logging.debug "[LLM] chat_single model=#{opts[:model]} provider=#{opts[:provider]} message_present=#{!message.nil?} tools=#{tools&.size || 0}"
|
|
321
|
+
end
|
|
310
322
|
session = RubyLLM.chat(**opts)
|
|
323
|
+
tools&.each { |tool| session.with_tool(tool) }
|
|
311
324
|
return session unless message
|
|
312
325
|
|
|
313
|
-
session.ask(
|
|
326
|
+
Legion::Logging.debug '[LLM] chat_single calling session.ask' if defined?(Legion::Logging)
|
|
327
|
+
response = session.ask(message)
|
|
328
|
+
Legion::Logging.debug "[LLM] chat_single response_class=#{response.class} response_nil=#{response.nil?}" if defined?(Legion::Logging)
|
|
329
|
+
response
|
|
314
330
|
end
|
|
315
331
|
|
|
316
332
|
def chat_with_escalation(model:, provider:, intent:, tier:, max_escalations:, quality_check:, message:, **kwargs)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-llm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.21
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -161,6 +161,7 @@ files:
|
|
|
161
161
|
- lib/legion/llm/settings.rb
|
|
162
162
|
- lib/legion/llm/shadow_eval.rb
|
|
163
163
|
- lib/legion/llm/structured_output.rb
|
|
164
|
+
- lib/legion/llm/tool_registry.rb
|
|
164
165
|
- lib/legion/llm/transport/exchanges/escalation.rb
|
|
165
166
|
- lib/legion/llm/transport/messages/escalation_event.rb
|
|
166
167
|
- lib/legion/llm/version.rb
|