legionio 1.9.33 → 1.9.34

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0e7ab0c576dcf1950fb2dd7d38d1113dfd5f584883cd30286cd990f851ce6a3
4
- data.tar.gz: a4dc69a591dd00dbb757f5e1bc5b8913005e374fed607b63d5f28088e51018a1
3
+ metadata.gz: e0fb2242e4fffe902c79cac15713bb57d8b2dd6388f122a9a6f14271faa3b3b2
4
+ data.tar.gz: c70d462ff6369c61dd5ae9bd786b325e4e53789eddc78d10d97441793eec1360
5
5
  SHA512:
6
- metadata.gz: ef50ae89f614aeec8385558444afb27f57aa1797e415ce25361ec57dec5d87ecf1181fdaf9e59bf0e696cc4ec8d68c0aa9c641bb30b1c01c08a72dd5792d0e6e
7
- data.tar.gz: e9049722257ccdc3415ec4e33af0100d692dbf85806cd2c1fb1f4094c1189364d575943e0f39907bcc295ec7fecabfd8065aae57c0857997a22dd0904ea958ea
6
+ metadata.gz: d7f43d17ba3a681ea09e82678831ba5694a50af90d508eb27acdcc6743d47c74bfec7da597b6d2fe6805e968d8ba247be571f6e26e60d1cfa86d6814974eb9ec
7
+ data.tar.gz: 198d3a7b98bb187f23f0e5cfedacabd41983dd52b0ae238650197d2ce9a4888016d211123579cd287e5a2b05f496b0dba6fb627b6280124cf39ca92b11917a18
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.9.34] - 2026-05-18
6
+
7
+ ### Added
8
+ - API: `GET /api/extensions/tools` endpoint with extension, runner, deferred, and triggered filters
9
+ - Tools::Discovery: writes to `Legion::Settings::Extensions.register_tool` (bridges discovery to LLM pipeline)
10
+
11
+ ### Fixed
12
+ - Extensions: `extension_parts_from_const` no longer converts underscores to dashes (fixes lex-microsoft_teams filtering)
13
+ - Core: `generate_runner_messages` strips `?` and `!` from method names before creating constants
14
+
5
15
  ## [1.9.33] - 2026-05-15
6
16
 
7
17
  ### Added
@@ -6,6 +6,7 @@ module Legion
6
6
  module Extensions
7
7
  def self.registered(app)
8
8
  register_loaded_summary_route(app)
9
+ register_tools_route(app)
9
10
  register_available_route(app)
10
11
  register_extension_routes(app)
11
12
  register_runner_routes(app)
@@ -29,6 +30,14 @@ module Legion
29
30
  end
30
31
  end
31
32
 
33
+ def self.register_tools_route(app)
34
+ app.get '/api/extensions/tools' do
35
+ entries = filter_tool_entries(Array(Legion::Settings::Extensions.tools), params)
36
+ tools = entries.map { |e| serialize_tool_entry(e) }
37
+ json_response({ total: tools.size, tools: tools })
38
+ end
39
+ end
40
+
32
41
  def self.register_available_route(app)
33
42
  app.get '/api/extension_catalog/available' do
34
43
  entries = Legion::Extensions::Catalog::Available.all
@@ -205,8 +214,30 @@ module Legion
205
214
  started_at: entry[:started_at]&.iso8601 }
206
215
  end
207
216
 
208
- private :register_loaded_summary_route, :register_available_route, :register_extension_routes,
209
- :register_runner_routes, :register_function_routes, :register_invoke_route
217
+ def filter_tool_entries(entries, params)
218
+ entries = entries.select { |e| e[:extension].to_s == params[:extension] } if params[:extension]
219
+ entries = entries.select { |e| e[:runner].to_s == params[:runner] } if params[:runner]
220
+ entries = entries.select { |e| e[:deferred] == (params[:deferred] == 'true') } if params.key?(:deferred)
221
+ entries = entries.select { |e| Array(e[:trigger_words]).any? } if params[:triggered] == 'true'
222
+ entries
223
+ end
224
+
225
+ def serialize_tool_entry(entry)
226
+ {
227
+ name: entry[:name],
228
+ description: entry[:description],
229
+ extension: entry[:extension],
230
+ runner: entry[:runner],
231
+ deferred: entry[:deferred],
232
+ trigger_words: entry[:trigger_words],
233
+ source: entry[:source],
234
+ sticky: entry[:sticky]
235
+ }.compact
236
+ end
237
+
238
+ private :register_loaded_summary_route, :register_tools_route, :register_available_route,
239
+ :register_extension_routes, :register_runner_routes, :register_function_routes,
240
+ :register_invoke_route
210
241
  end
211
242
  end
212
243
  end
@@ -198,7 +198,7 @@ module Legion
198
198
  end
199
199
 
200
200
  def build_chunk_payload(chunk, tags, opts)
201
- {
201
+ payload = {
202
202
  content: chunk[:content],
203
203
  content_type: opts[:content_type] || 'absorbed_chunk',
204
204
  content_hash: chunk[:content_hash],
@@ -211,6 +211,8 @@ module Legion
211
211
  token_count: chunk[:token_count]
212
212
  }.merge(opts.fetch(:metadata, {}))
213
213
  }
214
+ payload[:access_scope] = opts[:access_scope] if opts.key?(:access_scope)
215
+ payload
214
216
  end
215
217
  end
216
218
  end
@@ -174,7 +174,8 @@ module Legion
174
174
  return unless runner_module.respond_to?(:definitions)
175
175
 
176
176
  runner_module.definitions.each_key do |method_name|
177
- const_name = "#{camelize(runner_name)}#{camelize(method_name)}"
177
+ sanitized = method_name.to_s.delete('?!')
178
+ const_name = "#{camelize(runner_name)}#{camelize(sanitized)}"
178
179
  next if ctx[:messages_mod].const_defined?(const_name, false)
179
180
 
180
181
  rk_value = "#{ctx[:prefix]}.runners.#{runner_name}.#{method_name}"
@@ -1061,7 +1061,7 @@ module Legion
1061
1061
  parts[(idx + 1)..].to_a.each_with_object([]) do |part, extension_parts|
1062
1062
  break extension_parts if %w[Actor Actors Runners Helpers Transport Data Hooks Skills].include?(part)
1063
1063
 
1064
- extension_parts << camel_to_snake(part).tr('_', '-')
1064
+ extension_parts << camel_to_snake(part)
1065
1065
  end
1066
1066
  end
1067
1067
 
@@ -125,6 +125,7 @@ module Legion
125
125
  )
126
126
  return unless Legion::Tools::Registry.register(tool_class)
127
127
 
128
+ register_in_settings_extensions(tool_class, ext, runner_mod, is_deferred)
128
129
  record_tool_owner(ext, tool_class)
129
130
  end
130
131
 
@@ -216,6 +217,28 @@ module Legion
216
217
  end
217
218
  end
218
219
 
220
+ def register_in_settings_extensions(tool_class, ext, runner_mod, is_deferred)
221
+ return unless defined?(Legion::Settings::Extensions) &&
222
+ Legion::Settings::Extensions.respond_to?(:register_tool)
223
+
224
+ ext_name = derive_extension_name(ext)
225
+ Legion::Settings::Extensions.register_tool(tool_class.tool_name, {
226
+ description: tool_class.respond_to?(:description) ? tool_class.description : nil,
227
+ input_schema: tool_class.respond_to?(:input_schema) ? tool_class.input_schema : {},
228
+ tool_class: tool_class,
229
+ dispatch_type: :class_call,
230
+ extension: "lex-#{ext_name}",
231
+ runner: derive_runner_snake(runner_mod),
232
+ source: :tools_discovery,
233
+ deferred: is_deferred,
234
+ trigger_words: tool_class.respond_to?(:trigger_words) ? tool_class.trigger_words : [],
235
+ sticky: tool_class.respond_to?(:sticky?) ? tool_class.sticky? : true,
236
+ mcp_tier: tool_class.respond_to?(:mcp_tier) ? tool_class.mcp_tier : nil
237
+ })
238
+ rescue StandardError => e
239
+ handle_exception(e, level: :warn, handled: true, operation: :register_in_settings_extensions)
240
+ end
241
+
219
242
  def record_tool_owner(ext, tool_class)
220
243
  return unless defined?(Legion::Extensions) && Legion::Extensions.respond_to?(:record_extension_resource)
221
244
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.9.33'
4
+ VERSION = '1.9.34'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legionio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.33
4
+ version: 1.9.34
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity