legion-llm 0.6.15 → 0.6.17
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/llm/pipeline/executor.rb +27 -31
- data/lib/legion/llm/pipeline/mcp_tool_adapter.rb +16 -7
- data/lib/legion/llm/pipeline/profile.rb +3 -3
- data/lib/legion/llm/pipeline/steps/tool_discovery.rb +97 -0
- data/lib/legion/llm/pipeline/steps.rb +1 -1
- data/lib/legion/llm/pipeline/tool_adapter.rb +72 -0
- data/lib/legion/llm/pipeline.rb +1 -1
- data/lib/legion/llm/routes.rb +2 -0
- data/lib/legion/llm/version.rb +1 -1
- data/lib/legion/llm.rb +21 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 85bd29db06078f900c983a6f722cda55d6c3c5c6a72c6e4fdb8c4295c3debddb
|
|
4
|
+
data.tar.gz: 855d18648dbe9d8e02e886011c51e35dd5f7d0828a25529428fb6f865c9b5f62
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 063beb13698b8645a8c365ccc1bde00d599b7653df47304d311b4c829b7de277e13e9443c5d693fe22668ee5855d3c2d33187eb8ed4af71dc0f744a59cdceaed
|
|
7
|
+
data.tar.gz: 4244f8d0af82a82c3a45cc483c9939fe492ef7350e43cdbf2f4d5b933210b6154150e038f02931f52943c5ad8918d6b6247d4c8debc29b083ea55336c5daf570
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Added
|
|
6
|
+
- `Legion::LLM::Pipeline::ToolAdapter` - wraps Tools::Base for RubyLLM sessions
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- Renamed `McpToolAdapter` to `ToolAdapter` (backwards compat alias kept)
|
|
10
|
+
- Pipeline step `McpDiscovery` renamed to `ToolDiscovery`
|
|
11
|
+
- Executor reads from `Legion::Tools::Registry`
|
|
12
|
+
- `chat_single` wraps registry tools with ToolAdapter
|
|
13
|
+
- Routes: executor handles all tool injection, routes only pass client tools
|
|
14
|
+
|
|
15
|
+
### Removed
|
|
16
|
+
- MCP server dependency for tool injection in routes
|
|
17
|
+
|
|
18
|
+
## [0.6.16] - 2026-04-03
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- MCP tool adapter now correctly deserializes `MCP::Tool::Response` objects instead of returning raw `#<Response:0x...>` strings
|
|
22
|
+
- Removed `is_a?(Class)` guard in executor `inject_ruby_llm_tools` that silently dropped MCP adapter instances
|
|
23
|
+
- Added `cached_mcp_tools` to inference route with lazy caching (only persists when tools are available)
|
|
24
|
+
|
|
5
25
|
## [0.6.15] - 2026-04-03
|
|
6
26
|
|
|
7
27
|
### Changed
|
|
@@ -18,7 +18,7 @@ module Legion
|
|
|
18
18
|
:audit, :warnings, :discovered_tools, :confidence_score,
|
|
19
19
|
:escalation_chain
|
|
20
20
|
|
|
21
|
-
include Steps::
|
|
21
|
+
include Steps::ToolDiscovery
|
|
22
22
|
include Steps::ToolCalls
|
|
23
23
|
include Steps::KnowledgeCapture
|
|
24
24
|
include Steps::ConfidenceScoring
|
|
@@ -28,14 +28,14 @@ module Legion
|
|
|
28
28
|
|
|
29
29
|
STEPS = %i[
|
|
30
30
|
tracing_init idempotency conversation_uuid context_load
|
|
31
|
-
rbac classification billing gaia_advisory tier_assignment rag_context
|
|
31
|
+
rbac classification billing gaia_advisory tier_assignment rag_context tool_discovery
|
|
32
32
|
routing request_normalization token_budget provider_call response_normalization
|
|
33
33
|
debate confidence_scoring tool_calls context_store post_response knowledge_capture response_return
|
|
34
34
|
].freeze
|
|
35
35
|
|
|
36
36
|
PRE_PROVIDER_STEPS = %i[
|
|
37
37
|
tracing_init idempotency conversation_uuid context_load
|
|
38
|
-
rbac classification billing gaia_advisory tier_assignment rag_context
|
|
38
|
+
rbac classification billing gaia_advisory tier_assignment rag_context tool_discovery
|
|
39
39
|
routing request_normalization token_budget
|
|
40
40
|
].freeze
|
|
41
41
|
|
|
@@ -66,6 +66,8 @@ module Legion
|
|
|
66
66
|
legion_search_sessions
|
|
67
67
|
].freeze
|
|
68
68
|
|
|
69
|
+
private_constant :ALWAYS_LOADED_MCP_TOOLS
|
|
70
|
+
|
|
69
71
|
ASYNC_THREAD_POOL = Concurrent::FixedThreadPool.new(4, fallback_policy: :caller_runs)
|
|
70
72
|
|
|
71
73
|
def initialize(request)
|
|
@@ -104,16 +106,16 @@ module Legion
|
|
|
104
106
|
|
|
105
107
|
private
|
|
106
108
|
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
return unless server.respond_to?(:tool_registry)
|
|
109
|
+
def inject_registry_tools(session)
|
|
110
|
+
return unless defined?(::Legion::Tools::Registry)
|
|
110
111
|
|
|
111
112
|
requested = requested_deferred_tool_names
|
|
113
|
+
always_loaded = always_loaded_tool_names
|
|
112
114
|
injected_names = []
|
|
113
115
|
|
|
114
|
-
|
|
115
|
-
adapter =
|
|
116
|
-
next unless
|
|
116
|
+
::Legion::Tools::Registry.tools.each do |tool_class|
|
|
117
|
+
adapter = ToolAdapter.new(tool_class)
|
|
118
|
+
next unless always_loaded.include?(adapter.name) || requested.include?(adapter.name)
|
|
117
119
|
|
|
118
120
|
session.with_tool(adapter)
|
|
119
121
|
injected_names << adapter.name
|
|
@@ -123,8 +125,8 @@ module Legion
|
|
|
123
125
|
end
|
|
124
126
|
|
|
125
127
|
log.info(
|
|
126
|
-
"[llm][
|
|
127
|
-
"always_loaded=#{
|
|
128
|
+
"[llm][tools] inject request_id=#{@request.id} " \
|
|
129
|
+
"always_loaded=#{always_loaded.size} requested_deferred=#{requested.size} " \
|
|
128
130
|
"injected=#{injected_names.size} names=#{injected_names.first(25).join(',')}"
|
|
129
131
|
)
|
|
130
132
|
rescue StandardError => e
|
|
@@ -132,6 +134,18 @@ module Legion
|
|
|
132
134
|
handle_exception(e, level: :warn, operation: 'llm.pipeline.inject_tools')
|
|
133
135
|
end
|
|
134
136
|
|
|
137
|
+
# Backwards compatibility alias
|
|
138
|
+
alias inject_discovered_tools inject_registry_tools
|
|
139
|
+
|
|
140
|
+
def always_loaded_tool_names
|
|
141
|
+
return ALWAYS_LOADED_MCP_TOOLS unless defined?(::Legion::Tools::Registry)
|
|
142
|
+
|
|
143
|
+
names = ::Legion::Tools::Registry.always_loaded_names.map { |name| name.to_s.tr('.', '_') }
|
|
144
|
+
names.any? ? names : ALWAYS_LOADED_MCP_TOOLS
|
|
145
|
+
rescue StandardError
|
|
146
|
+
ALWAYS_LOADED_MCP_TOOLS
|
|
147
|
+
end
|
|
148
|
+
|
|
135
149
|
def execute_steps
|
|
136
150
|
executed = 0
|
|
137
151
|
skipped = 0
|
|
@@ -675,11 +689,10 @@ module Legion
|
|
|
675
689
|
|
|
676
690
|
def inject_ruby_llm_tools(session)
|
|
677
691
|
(@request.tools || []).each do |tool|
|
|
678
|
-
session.with_tool(tool)
|
|
692
|
+
session.with_tool(tool)
|
|
679
693
|
end
|
|
680
694
|
|
|
681
|
-
|
|
682
|
-
inject_discovered_tools(session)
|
|
695
|
+
inject_registry_tools(session)
|
|
683
696
|
end
|
|
684
697
|
|
|
685
698
|
def apply_ruby_llm_instructions(session)
|
|
@@ -864,23 +877,6 @@ module Legion
|
|
|
864
877
|
)
|
|
865
878
|
end
|
|
866
879
|
|
|
867
|
-
def mcp_server
|
|
868
|
-
return ::Legion::MCP.server if defined?(::Legion::MCP) && ::Legion::MCP.respond_to?(:server)
|
|
869
|
-
|
|
870
|
-
require 'legion/mcp'
|
|
871
|
-
return unless defined?(::Legion::MCP) && ::Legion::MCP.respond_to?(:server)
|
|
872
|
-
|
|
873
|
-
::Legion::MCP.server
|
|
874
|
-
rescue LoadError => e
|
|
875
|
-
@warnings << "MCP unavailable: #{e.message}"
|
|
876
|
-
handle_exception(e, level: :debug, operation: 'llm.pipeline.mcp_server.require')
|
|
877
|
-
nil
|
|
878
|
-
rescue StandardError => e
|
|
879
|
-
@warnings << "MCP server load error: #{e.message}"
|
|
880
|
-
handle_exception(e, level: :warn, operation: 'llm.pipeline.mcp_server')
|
|
881
|
-
nil
|
|
882
|
-
end
|
|
883
|
-
|
|
884
880
|
def requested_deferred_tool_names
|
|
885
881
|
metadata = @request.metadata || {}
|
|
886
882
|
requested = metadata[:requested_tools] || metadata['requested_tools'] || []
|
|
@@ -35,13 +35,7 @@ module Legion
|
|
|
35
35
|
def execute(**args)
|
|
36
36
|
log.info("[llm][tools] adapter.execute name=#{@tool_name} arguments=#{summarize_payload(args)}")
|
|
37
37
|
result = @mcp_tool_class.call(**args)
|
|
38
|
-
content =
|
|
39
|
-
result[:content].map { |c| c[:text] || c['text'] }.compact.join("\n")
|
|
40
|
-
elsif result.is_a?(String)
|
|
41
|
-
result
|
|
42
|
-
else
|
|
43
|
-
result.to_s
|
|
44
|
-
end
|
|
38
|
+
content = extract_content(result)
|
|
45
39
|
log.info("[llm][tools] adapter.result name=#{@tool_name} output=#{summarize_payload(content)}")
|
|
46
40
|
content
|
|
47
41
|
rescue StandardError => e
|
|
@@ -51,6 +45,21 @@ module Legion
|
|
|
51
45
|
|
|
52
46
|
private
|
|
53
47
|
|
|
48
|
+
def extract_content(result)
|
|
49
|
+
# MCP::Tool::Response — has .content array of {type: 'text', text: '...'}
|
|
50
|
+
if result.respond_to?(:content) && result.content.is_a?(Array)
|
|
51
|
+
result.content.filter_map { |c| c[:text] || c['text'] || c.to_s }.join("\n")
|
|
52
|
+
elsif result.is_a?(Hash) && result[:content].is_a?(Array)
|
|
53
|
+
result[:content].filter_map { |c| c[:text] || c['text'] }.join("\n")
|
|
54
|
+
elsif result.is_a?(Hash)
|
|
55
|
+
Legion::JSON.dump(result)
|
|
56
|
+
elsif result.is_a?(String)
|
|
57
|
+
result
|
|
58
|
+
else
|
|
59
|
+
result.to_s
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
54
63
|
def summarize_payload(payload)
|
|
55
64
|
payload.to_s[0, 200].inspect
|
|
56
65
|
end
|
|
@@ -6,18 +6,18 @@ module Legion
|
|
|
6
6
|
module Profile
|
|
7
7
|
GAIA_SKIP = %i[
|
|
8
8
|
idempotency conversation_uuid context_load rbac classification
|
|
9
|
-
billing gaia_advisory
|
|
9
|
+
billing gaia_advisory tool_discovery context_store post_response
|
|
10
10
|
].freeze
|
|
11
11
|
|
|
12
12
|
SYSTEM_SKIP = %i[
|
|
13
13
|
idempotency conversation_uuid context_load rbac classification
|
|
14
|
-
billing gaia_advisory rag_context
|
|
14
|
+
billing gaia_advisory rag_context tool_discovery context_store
|
|
15
15
|
post_response
|
|
16
16
|
].freeze
|
|
17
17
|
|
|
18
18
|
QUICK_REPLY_SKIP = %i[
|
|
19
19
|
idempotency conversation_uuid context_load classification
|
|
20
|
-
gaia_advisory rag_context
|
|
20
|
+
gaia_advisory rag_context tool_discovery confidence_scoring
|
|
21
21
|
tool_calls context_store post_response knowledge_capture
|
|
22
22
|
].freeze
|
|
23
23
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/logging/helper'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module LLM
|
|
7
|
+
module Pipeline
|
|
8
|
+
module Steps
|
|
9
|
+
module ToolDiscovery
|
|
10
|
+
include Legion::Logging::Helper
|
|
11
|
+
|
|
12
|
+
def step_tool_discovery
|
|
13
|
+
@discovered_tools ||= []
|
|
14
|
+
start_time = Time.now
|
|
15
|
+
|
|
16
|
+
discover_registry_tools
|
|
17
|
+
discover_client_tools
|
|
18
|
+
|
|
19
|
+
total = @discovered_tools.size
|
|
20
|
+
if total.positive?
|
|
21
|
+
sources = @discovered_tools.filter_map { |t| t.dig(:source, :server) || t.dig(:source, :type) }.uniq
|
|
22
|
+
@enrichments['tool:discovery'] = {
|
|
23
|
+
content: "#{total} tools from #{sources.length} sources",
|
|
24
|
+
data: { tool_count: total, sources: sources },
|
|
25
|
+
timestamp: Time.now
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
record_tool_discovery_timeline(total, start_time)
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
@warnings << "Tool discovery error: #{e.message}"
|
|
32
|
+
handle_exception(e, level: :warn, operation: 'llm.pipeline.steps.tool_discovery')
|
|
33
|
+
record_tool_discovery_timeline(0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Backwards compatibility alias — step name used in STEPS array is tool_discovery
|
|
37
|
+
alias step_mcp_discovery step_tool_discovery
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def discover_registry_tools
|
|
42
|
+
return unless defined?(::Legion::Tools::Registry)
|
|
43
|
+
|
|
44
|
+
::Legion::Tools::Registry.tools.each do |tool_class|
|
|
45
|
+
name = tool_class.respond_to?(:tool_name) ? tool_class.tool_name : tool_class.name
|
|
46
|
+
desc = tool_class.respond_to?(:description) ? tool_class.description : ''
|
|
47
|
+
schema = tool_class.respond_to?(:input_schema) ? tool_class.input_schema : {}
|
|
48
|
+
@discovered_tools << {
|
|
49
|
+
name: name,
|
|
50
|
+
description: desc,
|
|
51
|
+
parameters: schema,
|
|
52
|
+
source: { type: :registry, server: 'legion' }
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
log.info(
|
|
57
|
+
"[llm][tools] discover request_id=#{@request.id} " \
|
|
58
|
+
"registry_tools=#{::Legion::Tools::Registry.tools.size}"
|
|
59
|
+
)
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
@warnings << "Registry tool discovery error: #{e.message}"
|
|
62
|
+
handle_exception(e, level: :warn, operation: 'llm.pipeline.steps.tool_discovery.registry')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def discover_client_tools
|
|
66
|
+
return unless defined?(::Legion::MCP::Client::Pool)
|
|
67
|
+
|
|
68
|
+
::Legion::MCP::Client::Pool.all_tools.each do |tool|
|
|
69
|
+
@discovered_tools << {
|
|
70
|
+
name: tool[:name],
|
|
71
|
+
description: tool[:description],
|
|
72
|
+
parameters: tool[:input_schema],
|
|
73
|
+
source: tool[:source]
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
@warnings << "Client tool discovery error: #{e.message}"
|
|
78
|
+
handle_exception(e, level: :warn, operation: 'llm.pipeline.steps.tool_discovery.client')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def record_tool_discovery_timeline(count, start_time = nil)
|
|
82
|
+
duration = start_time ? ((Time.now - start_time) * 1000).to_i : 0
|
|
83
|
+
@timeline.record(
|
|
84
|
+
category: :enrichment, key: 'tool:discovery',
|
|
85
|
+
direction: :inbound, detail: "#{count} tools discovered",
|
|
86
|
+
from: 'tool_registry', to: 'pipeline',
|
|
87
|
+
duration_ms: duration
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Backwards compatibility alias
|
|
93
|
+
McpDiscovery = ToolDiscovery
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -17,7 +17,7 @@ require_relative 'steps/billing'
|
|
|
17
17
|
require_relative 'steps/gaia_advisory'
|
|
18
18
|
require_relative 'steps/tier_assigner'
|
|
19
19
|
require_relative 'steps/post_response'
|
|
20
|
-
require_relative 'steps/
|
|
20
|
+
require_relative 'steps/tool_discovery'
|
|
21
21
|
require_relative 'steps/tool_calls'
|
|
22
22
|
require_relative 'steps/rag_context'
|
|
23
23
|
require_relative 'steps/rag_guard'
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ruby_llm'
|
|
4
|
+
require 'legion/logging/helper'
|
|
5
|
+
|
|
6
|
+
module Legion
|
|
7
|
+
module LLM
|
|
8
|
+
module Pipeline
|
|
9
|
+
class ToolAdapter < RubyLLM::Tool
|
|
10
|
+
include Legion::Logging::Helper
|
|
11
|
+
|
|
12
|
+
def initialize(tool_class)
|
|
13
|
+
@tool_class = tool_class
|
|
14
|
+
raw_name = tool_class.respond_to?(:tool_name) ? tool_class.tool_name : tool_class.name.to_s
|
|
15
|
+
@tool_name = raw_name.tr('.', '_')
|
|
16
|
+
@tool_desc = tool_class.respond_to?(:description) ? tool_class.description.to_s : ''
|
|
17
|
+
@tool_schema = tool_class.respond_to?(:input_schema) ? tool_class.input_schema : nil
|
|
18
|
+
super()
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def name
|
|
22
|
+
@tool_name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def description
|
|
26
|
+
@tool_desc
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def params_schema
|
|
30
|
+
return @params_schema if defined?(@params_schema)
|
|
31
|
+
|
|
32
|
+
@params_schema = (RubyLLM::Utils.deep_stringify_keys(@tool_schema) if @tool_schema.is_a?(Hash))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def execute(**args)
|
|
36
|
+
log.info("[llm][tools] adapter.execute name=#{@tool_name} arguments=#{summarize_payload(args)}")
|
|
37
|
+
result = @tool_class.call(**args)
|
|
38
|
+
content = extract_content(result)
|
|
39
|
+
log.info("[llm][tools] adapter.result name=#{@tool_name} output=#{summarize_payload(content)}")
|
|
40
|
+
content
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
handle_exception(e, level: :warn, operation: 'llm.pipeline.tool_adapter.execute', tool_name: @tool_name)
|
|
43
|
+
"Tool error: #{e.message}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def extract_content(result)
|
|
49
|
+
# MCP::Tool::Response — has .content array of {type: 'text', text: '...'}
|
|
50
|
+
if result.respond_to?(:content) && result.content.is_a?(Array)
|
|
51
|
+
result.content.filter_map { |c| c[:text] || c['text'] || c.to_s }.join("\n")
|
|
52
|
+
elsif result.is_a?(Hash) && result[:content].is_a?(Array)
|
|
53
|
+
result[:content].filter_map { |c| c[:text] || c['text'] }.join("\n")
|
|
54
|
+
elsif result.is_a?(Hash)
|
|
55
|
+
Legion::JSON.dump(result)
|
|
56
|
+
elsif result.is_a?(String)
|
|
57
|
+
result
|
|
58
|
+
else
|
|
59
|
+
result.to_s
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def summarize_payload(payload)
|
|
64
|
+
payload.to_s[0, 200].inspect
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Backwards compatibility alias
|
|
69
|
+
McpToolAdapter = ToolAdapter
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/legion/llm/pipeline.rb
CHANGED
|
@@ -11,7 +11,7 @@ require_relative 'pipeline/gaia_caller'
|
|
|
11
11
|
require_relative 'pipeline/tool_dispatcher'
|
|
12
12
|
require_relative 'pipeline/enrichment_injector'
|
|
13
13
|
require_relative 'pipeline/steps'
|
|
14
|
-
require_relative 'pipeline/
|
|
14
|
+
require_relative 'pipeline/tool_adapter'
|
|
15
15
|
require_relative 'pipeline/executor'
|
|
16
16
|
|
|
17
17
|
module Legion
|
data/lib/legion/llm/routes.rb
CHANGED
|
@@ -477,6 +477,8 @@ module Legion
|
|
|
477
477
|
build_client_tool_class(ts[:name].to_s, ts[:description].to_s, ts[:parameters] || ts[:input_schema])
|
|
478
478
|
end
|
|
479
479
|
|
|
480
|
+
log.unknown "[llm][api] inference tools client=#{tool_declarations.size}"
|
|
481
|
+
|
|
480
482
|
streaming = body[:stream] == true && request.preferred_type.to_s.include?('text/event-stream')
|
|
481
483
|
normalized_caller = caller_context.respond_to?(:transform_keys) ? caller_context.transform_keys(&:to_sym) : {}
|
|
482
484
|
safe_caller_fields = normalized_caller.slice(:context, :session_id, :trace_id)
|
data/lib/legion/llm/version.rb
CHANGED
data/lib/legion/llm.rb
CHANGED
|
@@ -644,7 +644,7 @@ module Legion
|
|
|
644
644
|
|
|
645
645
|
def chat_single(model:, provider:, intent:, tier:, message: nil, **kwargs, &block)
|
|
646
646
|
explicit_tools = kwargs.delete(:tools)
|
|
647
|
-
tools = explicit_tools ||
|
|
647
|
+
tools = explicit_tools || adapted_registry_tools
|
|
648
648
|
tools = nil if tools.empty?
|
|
649
649
|
|
|
650
650
|
if (intent || tier) && Router.routing_enabled?
|
|
@@ -687,6 +687,26 @@ module Legion
|
|
|
687
687
|
response
|
|
688
688
|
end
|
|
689
689
|
|
|
690
|
+
def adapted_registry_tools
|
|
691
|
+
tool_classes = if defined?(::Legion::Tools::Registry)
|
|
692
|
+
::Legion::Tools::Registry.tools
|
|
693
|
+
elsif defined?(::Legion::LLM::ToolRegistry)
|
|
694
|
+
::Legion::LLM::ToolRegistry.tools
|
|
695
|
+
else
|
|
696
|
+
return []
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
tool_classes.map do |tool_class|
|
|
700
|
+
Pipeline::ToolAdapter.new(tool_class)
|
|
701
|
+
rescue StandardError => e
|
|
702
|
+
handle_exception(e, level: :warn, operation: 'llm.adapted_registry_tools', tool_class: tool_class.to_s)
|
|
703
|
+
nil
|
|
704
|
+
end.compact
|
|
705
|
+
rescue StandardError => e
|
|
706
|
+
handle_exception(e, level: :warn, operation: 'llm.adapted_registry_tools')
|
|
707
|
+
[]
|
|
708
|
+
end
|
|
709
|
+
|
|
690
710
|
def try_defer(intent:, urgency:, model:, provider:, message:, **)
|
|
691
711
|
return nil unless Scheduling.enabled? && Scheduling.should_defer?(intent: intent || :normal, urgency: urgency)
|
|
692
712
|
return nil unless defined?(Batch) && Batch.enabled?
|
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.6.
|
|
4
|
+
version: 0.6.17
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -287,7 +287,9 @@ files:
|
|
|
287
287
|
- lib/legion/llm/pipeline/steps/tier_assigner.rb
|
|
288
288
|
- lib/legion/llm/pipeline/steps/token_budget.rb
|
|
289
289
|
- lib/legion/llm/pipeline/steps/tool_calls.rb
|
|
290
|
+
- lib/legion/llm/pipeline/steps/tool_discovery.rb
|
|
290
291
|
- lib/legion/llm/pipeline/timeline.rb
|
|
292
|
+
- lib/legion/llm/pipeline/tool_adapter.rb
|
|
291
293
|
- lib/legion/llm/pipeline/tool_dispatcher.rb
|
|
292
294
|
- lib/legion/llm/pipeline/tracing.rb
|
|
293
295
|
- lib/legion/llm/provider_registry.rb
|