legion-llm 0.6.15 → 0.6.16
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 +7 -0
- data/lib/legion/llm/pipeline/executor.rb +1 -1
- data/lib/legion/llm/pipeline/mcp_tool_adapter.rb +16 -7
- data/lib/legion/llm/routes.rb +40 -1
- data/lib/legion/llm/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: 0fe6246015e9967dec5bbe428ab2cb5869b4a359c4a5b40c0a8206d0fe7b516d
|
|
4
|
+
data.tar.gz: f803de963b1887d064506187c3d7c8fa00b437613f5456bcbf87adae1d53a3a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e7f65ec573b55b840b7b07b9a9c83c7aa189696b162936e63ad65ddf508be3240eb056fc70d3bbbad532eb2f3db841c4facd3efb1df30e9bf816b4f37d8a33e0
|
|
7
|
+
data.tar.gz: 6a823d728ab547b3ccab050d7a01e9825cb3764446eecb2f32b71ce1c7ff73f7da7f167e9198b9a45f4941b7ed8113c3aac3f1ca95c0a76b46a5b502dd713147
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.6.16] - 2026-04-03
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- MCP tool adapter now correctly deserializes `MCP::Tool::Response` objects instead of returning raw `#<Response:0x...>` strings
|
|
9
|
+
- Removed `is_a?(Class)` guard in executor `inject_ruby_llm_tools` that silently dropped MCP adapter instances
|
|
10
|
+
- Added `cached_mcp_tools` to inference route with lazy caching (only persists when tools are available)
|
|
11
|
+
|
|
5
12
|
## [0.6.15] - 2026-04-03
|
|
6
13
|
|
|
7
14
|
### Changed
|
|
@@ -675,7 +675,7 @@ module Legion
|
|
|
675
675
|
|
|
676
676
|
def inject_ruby_llm_tools(session)
|
|
677
677
|
(@request.tools || []).each do |tool|
|
|
678
|
-
session.with_tool(tool)
|
|
678
|
+
session.with_tool(tool)
|
|
679
679
|
end
|
|
680
680
|
|
|
681
681
|
ToolRegistry.tools.each { |tool| session.with_tool(tool) } if defined?(ToolRegistry)
|
|
@@ -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
|
data/lib/legion/llm/routes.rb
CHANGED
|
@@ -214,6 +214,34 @@ 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
|
+
|
|
217
245
|
define_method(:extract_tool_calls) do |pipeline_response|
|
|
218
246
|
tools_data = pipeline_response.tools
|
|
219
247
|
return [] unless tools_data.is_a?(Array) && !tools_data.empty?
|
|
@@ -477,6 +505,17 @@ module Legion
|
|
|
477
505
|
build_client_tool_class(ts[:name].to_s, ts[:description].to_s, ts[:parameters] || ts[:input_schema])
|
|
478
506
|
end
|
|
479
507
|
|
|
508
|
+
# Inject daemon MCP tools alongside client tools
|
|
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
|
|
518
|
+
|
|
480
519
|
streaming = body[:stream] == true && request.preferred_type.to_s.include?('text/event-stream')
|
|
481
520
|
normalized_caller = caller_context.respond_to?(:transform_keys) ? caller_context.transform_keys(&:to_sym) : {}
|
|
482
521
|
safe_caller_fields = normalized_caller.slice(:context, :session_id, :trace_id)
|
|
@@ -502,7 +541,7 @@ module Legion
|
|
|
502
541
|
messages: messages,
|
|
503
542
|
system: body[:system],
|
|
504
543
|
routing: { provider: provider, model: model },
|
|
505
|
-
tools:
|
|
544
|
+
tools: all_tools,
|
|
506
545
|
caller: effective_caller,
|
|
507
546
|
conversation_id: conversation_id,
|
|
508
547
|
metadata: { requested_tools: requested_tools },
|
data/lib/legion/llm/version.rb
CHANGED