legion-llm 0.6.16 → 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 +13 -0
- data/lib/legion/llm/pipeline/executor.rb +26 -30
- 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 -39
- 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,19 @@
|
|
|
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
|
+
|
|
5
18
|
## [0.6.16] - 2026-04-03
|
|
6
19
|
|
|
7
20
|
### Fixed
|
|
@@ -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
|
|
@@ -678,8 +692,7 @@ module Legion
|
|
|
678
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'] || []
|
|
@@ -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
|
@@ -214,34 +214,6 @@ module Legion
|
|
|
214
214
|
end
|
|
215
215
|
# rubocop:enable Metrics/BlockLength
|
|
216
216
|
|
|
217
|
-
define_method(:cached_mcp_tools) do
|
|
218
|
-
@@llm_cached_mcp_tools ||= begin # rubocop:disable Style/ClassVars
|
|
219
|
-
all = []
|
|
220
|
-
if defined?(Legion::MCP) && Legion::MCP.respond_to?(:server)
|
|
221
|
-
Legion::MCP.server
|
|
222
|
-
if defined?(Legion::MCP::Server) && Legion::MCP::Server.respond_to?(:tool_registry)
|
|
223
|
-
require 'legion/llm/pipeline/mcp_tool_adapter' unless defined?(Legion::LLM::Pipeline::McpToolAdapter)
|
|
224
|
-
Legion::MCP::Server.tool_registry.each do |tc|
|
|
225
|
-
all << Legion::LLM::Pipeline::McpToolAdapter.new(tc)
|
|
226
|
-
rescue StandardError
|
|
227
|
-
nil
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
always_names = %w[legion_do legion_get_status legion_run_task legion_describe_runner
|
|
232
|
-
legion_list_extensions legion_get_extension legion_list_tasks
|
|
233
|
-
legion_get_task legion_get_task_logs legion_query_knowledge
|
|
234
|
-
legion_knowledge_health legion_knowledge_context legion_list_workers
|
|
235
|
-
legion_show_worker legion_mesh_status legion_list_peers
|
|
236
|
-
legion_tools legion_search_sessions]
|
|
237
|
-
{
|
|
238
|
-
always: all.select { |t| always_names.include?(t.name) }.freeze,
|
|
239
|
-
deferred: all.reject { |t| always_names.include?(t.name) }.freeze,
|
|
240
|
-
all: all.freeze
|
|
241
|
-
}.freeze
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
217
|
define_method(:extract_tool_calls) do |pipeline_response|
|
|
246
218
|
tools_data = pipeline_response.tools
|
|
247
219
|
return [] unless tools_data.is_a?(Array) && !tools_data.empty?
|
|
@@ -505,16 +477,7 @@ module Legion
|
|
|
505
477
|
build_client_tool_class(ts[:name].to_s, ts[:description].to_s, ts[:parameters] || ts[:input_schema])
|
|
506
478
|
end
|
|
507
479
|
|
|
508
|
-
|
|
509
|
-
all_tools = tool_declarations.dup
|
|
510
|
-
begin
|
|
511
|
-
mcp_tools = cached_mcp_tools
|
|
512
|
-
mcp_to_inject = Array(requested_tools).empty? ? mcp_tools[:always] : mcp_tools[:all]
|
|
513
|
-
all_tools.concat(mcp_to_inject) if mcp_to_inject&.any?
|
|
514
|
-
log.unknown "[llm][api] inference tools client=#{tool_declarations.size} mcp=#{mcp_to_inject&.size || 0} total=#{all_tools.size}"
|
|
515
|
-
rescue StandardError => e
|
|
516
|
-
handle_exception(e, level: :warn, operation: 'llm.routes.mcp_tool_injection', request_id: request_id)
|
|
517
|
-
end
|
|
480
|
+
log.unknown "[llm][api] inference tools client=#{tool_declarations.size}"
|
|
518
481
|
|
|
519
482
|
streaming = body[:stream] == true && request.preferred_type.to_s.include?('text/event-stream')
|
|
520
483
|
normalized_caller = caller_context.respond_to?(:transform_keys) ? caller_context.transform_keys(&:to_sym) : {}
|
|
@@ -541,7 +504,7 @@ module Legion
|
|
|
541
504
|
messages: messages,
|
|
542
505
|
system: body[:system],
|
|
543
506
|
routing: { provider: provider, model: model },
|
|
544
|
-
tools:
|
|
507
|
+
tools: tool_declarations,
|
|
545
508
|
caller: effective_caller,
|
|
546
509
|
conversation_id: conversation_id,
|
|
547
510
|
metadata: { requested_tools: requested_tools },
|
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
|