lex-llm-gemini 0.3.9 → 0.3.13
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/Gemfile +0 -7
- data/lex-llm-gemini.gemspec +1 -1
- data/lib/legion/extensions/llm/gemini/actors/discovery_refresh.rb +54 -0
- data/lib/legion/extensions/llm/gemini/provider.rb +98 -4
- data/lib/legion/extensions/llm/gemini/version.rb +1 -1
- data/lib/legion/extensions/llm/gemini.rb +3 -6
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d81052fa4455e1c73b7567864422ae494442f0fce0d9206fb0634bc238c939eb
|
|
4
|
+
data.tar.gz: 9f56e59676cc93aa0b55e4d8958975ce3e0a2c02308daaaeecb40c46c8535564
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0fe88e33de1fa4575867f35ffe717528a3759aa1b0e3c15fe42a9cfe99ff8e00826b0a8069f1d4788091b17448c307cf8e4ad694684c166249b9a57360c8dccc
|
|
7
|
+
data.tar.gz: 999f873f14e211211232b72ba3f5d5dd6dd31560de9e44081a1e2355c6574baa7a4a169701492a00803fcb9fb1bc6b9d73de37f399cb2439505a7c3c970717a7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.13 - 2026-06-16
|
|
4
|
+
|
|
5
|
+
- Dependency updates, code quality improvements.
|
|
6
|
+
|
|
7
|
+
## 0.3.12 - 2026-06-15
|
|
8
|
+
|
|
9
|
+
- **CapabilityPolicy integration** — `supportedGenerationMethods` mapped to `:model_metadata`. Settings overrides at provider/instance/model level supported.
|
|
10
|
+
|
|
11
|
+
## 0.3.11 - 2026-06-13
|
|
12
|
+
|
|
13
|
+
- **Gemfile cleanup** — Remove local path overrides; dependencies resolve from gemspec via rubygems.
|
|
14
|
+
- **Dependency bump** — Require `lex-llm >= 0.5.0` for canonical types support.
|
|
15
|
+
- **Canonical tool support** — Use `ToolSchema.extract` and add `:tools` capability.
|
|
16
|
+
- **Bug fix** — Handle Array tool_calls in `tool_call_parts`.
|
|
17
|
+
- 22 examples, 0 failures; 13 files, 0 rubocop offenses.
|
|
18
|
+
|
|
19
|
+
## 0.3.10 - 2026-06-02
|
|
20
|
+
|
|
21
|
+
- Add per-provider scoped discovery refresh actor
|
|
22
|
+
|
|
3
23
|
## 0.3.9 - 2026-05-21
|
|
4
24
|
|
|
5
25
|
- api_base reads from settings[:endpoint] fallback
|
data/Gemfile
CHANGED
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
group :test do
|
|
6
|
-
llm_base_path = ENV.fetch('LEX_LLM_PATH', File.expand_path('../lex-llm', __dir__))
|
|
7
|
-
transport_path = ENV.fetch('LEGION_TRANSPORT_PATH', File.expand_path('../../legion-transport', __dir__))
|
|
8
|
-
gem 'legion-transport', path: transport_path if File.directory?(transport_path)
|
|
9
|
-
gem 'lex-llm', path: llm_base_path if File.directory?(llm_base_path)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
5
|
gemspec
|
|
13
6
|
|
|
14
7
|
group :development do
|
data/lex-llm-gemini.gemspec
CHANGED
|
@@ -27,5 +27,5 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.add_dependency 'legion-logging', '>= 1.3.2'
|
|
28
28
|
spec.add_dependency 'legion-settings', '>= 1.3.14'
|
|
29
29
|
spec.add_dependency 'legion-transport', '>= 1.4.14'
|
|
30
|
-
spec.add_dependency 'lex-llm', '>= 0.
|
|
30
|
+
spec.add_dependency 'lex-llm', '>= 0.5.0'
|
|
31
31
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'legion/extensions/actors/every'
|
|
5
|
+
rescue LoadError => e
|
|
6
|
+
warn(e.message) if $VERBOSE
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
return unless defined?(Legion::Extensions::Actors::Every)
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module Extensions
|
|
13
|
+
module Llm
|
|
14
|
+
module Gemini
|
|
15
|
+
module Actor
|
|
16
|
+
class DiscoveryRefresh < Legion::Extensions::Actors::Every # rubocop:disable Style/Documentation
|
|
17
|
+
include Legion::Logging::Helper
|
|
18
|
+
|
|
19
|
+
REFRESH_INTERVAL = 1800
|
|
20
|
+
|
|
21
|
+
def runner_class = self.class
|
|
22
|
+
def runner_function = 'manual'
|
|
23
|
+
def run_now? = true
|
|
24
|
+
def use_runner? = false
|
|
25
|
+
def check_subtask? = false
|
|
26
|
+
def generate_task? = false
|
|
27
|
+
|
|
28
|
+
def time
|
|
29
|
+
return REFRESH_INTERVAL unless defined?(Legion::Settings)
|
|
30
|
+
|
|
31
|
+
Legion::Settings.dig(:extensions, :llm, :gemini, :discovery_interval) || REFRESH_INTERVAL
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def manual
|
|
35
|
+
log.debug('[gemini][discovery_refresh] refreshing model list')
|
|
36
|
+
return unless defined?(Legion::LLM::Discovery)
|
|
37
|
+
|
|
38
|
+
Legion::LLM::Discovery.refresh_discovered_models!(provider: :gemini)
|
|
39
|
+
|
|
40
|
+
if defined?(Legion::LLM::Router) && Legion::LLM::Router.respond_to?(:populate_auto_rules)
|
|
41
|
+
Legion::LLM::Router.populate_auto_rules(Legion::LLM::Discovery.discovered_instances)
|
|
42
|
+
end
|
|
43
|
+
if defined?(Legion::LLM::Inventory) && Legion::LLM::Inventory.respond_to?(:invalidate_offerings_cache!)
|
|
44
|
+
Legion::LLM::Inventory.invalidate_offerings_cache!
|
|
45
|
+
end
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
handle_exception(e, level: :warn, handled: true, operation: 'gemini.actor.discovery_refresh')
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -187,7 +187,9 @@ module Legion
|
|
|
187
187
|
end
|
|
188
188
|
|
|
189
189
|
def tool_call_parts(message)
|
|
190
|
-
|
|
190
|
+
# Array is canonical (name-keyed hashes dropped parallel same-name calls)
|
|
191
|
+
calls = message.tool_calls.is_a?(Hash) ? message.tool_calls.values : Array(message.tool_calls)
|
|
192
|
+
calls.map do |tool_call|
|
|
191
193
|
{ functionCall: { name: tool_call.name, args: tool_call.arguments } }
|
|
192
194
|
end
|
|
193
195
|
end
|
|
@@ -204,9 +206,12 @@ module Legion
|
|
|
204
206
|
def format_tools(tools)
|
|
205
207
|
[{
|
|
206
208
|
functionDeclarations: tools.values.map do |tool|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
schema = Legion::Extensions::Llm::Canonical::ToolSchema.extract(tool)
|
|
210
|
+
{
|
|
211
|
+
name: Legion::Extensions::Llm::Canonical::ToolSchema.tool_name(tool),
|
|
212
|
+
description: Legion::Extensions::Llm::Canonical::ToolSchema.tool_description(tool),
|
|
213
|
+
parameters: schema
|
|
214
|
+
}
|
|
210
215
|
end
|
|
211
216
|
}]
|
|
212
217
|
end
|
|
@@ -307,6 +312,95 @@ module Legion
|
|
|
307
312
|
end
|
|
308
313
|
end
|
|
309
314
|
|
|
315
|
+
# -- policy resolution requires many sources
|
|
316
|
+
def offering_from_model(model, health: {})
|
|
317
|
+
policy = Legion::Extensions::Llm::CapabilityPolicy.resolve(
|
|
318
|
+
real: real_capabilities_from(model),
|
|
319
|
+
provider_catalog: {},
|
|
320
|
+
probe: {},
|
|
321
|
+
provider_envelope: {},
|
|
322
|
+
provider_config: provider_capability_config,
|
|
323
|
+
instance_config: instance_capability_config,
|
|
324
|
+
model_config: model_capability_config(model.id)
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
build_model_offering(model, policy, health)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def build_model_offering(model, policy, health)
|
|
331
|
+
Routing::ModelOffering.new(
|
|
332
|
+
provider_family: slug.to_sym,
|
|
333
|
+
provider_instance: model.instance || provider_instance_id,
|
|
334
|
+
transport: offering_transport,
|
|
335
|
+
tier: offering_tier,
|
|
336
|
+
model: model.id,
|
|
337
|
+
canonical_model_alias: model.name,
|
|
338
|
+
model_family: model.family,
|
|
339
|
+
usage_type: offering_usage_type(model),
|
|
340
|
+
capabilities: policy[:capabilities],
|
|
341
|
+
capability_sources: policy[:sources],
|
|
342
|
+
limits: offering_limits(model),
|
|
343
|
+
health:,
|
|
344
|
+
metadata: offering_metadata(model)
|
|
345
|
+
)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def real_capabilities_from(model)
|
|
349
|
+
meta = model.respond_to?(:metadata) ? (model.metadata || {}) : {}
|
|
350
|
+
methods = Array(meta[:supported_generation_methods] || meta['supported_generation_methods'])
|
|
351
|
+
{
|
|
352
|
+
streaming: methods.include?('streamGenerateContent'),
|
|
353
|
+
embeddings: methods.include?('embedContent'),
|
|
354
|
+
vision: Capabilities.vision?(meta.merge('name' => "models/#{model.id}"))
|
|
355
|
+
}.compact
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def provider_capability_config
|
|
359
|
+
return {} unless defined?(Legion::Extensions::Llm::CredentialSources)
|
|
360
|
+
|
|
361
|
+
conf = Legion::Extensions::Llm::CredentialSources.setting(:extensions, :llm, :gemini)
|
|
362
|
+
conf.is_a?(Hash) ? conf.to_h.except(:instances, 'instances') : {}
|
|
363
|
+
rescue StandardError => e
|
|
364
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.provider_capability_config')
|
|
365
|
+
{}
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def instance_capability_config
|
|
369
|
+
cfg = config
|
|
370
|
+
result = {}
|
|
371
|
+
%i[capabilities enable_streaming enable_tools enable_thinking enable_vision enable_embeddings
|
|
372
|
+
thinking_flag tools_flag streaming_flag vision_flag embedding_flag embeddings_flag
|
|
373
|
+
tool_flag images_flag image_flag].each do |key|
|
|
374
|
+
next unless cfg.respond_to?(key)
|
|
375
|
+
|
|
376
|
+
val = cfg.send(key)
|
|
377
|
+
result[key] = val unless val.nil?
|
|
378
|
+
rescue StandardError
|
|
379
|
+
next
|
|
380
|
+
end
|
|
381
|
+
result
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def model_capability_config(model_id)
|
|
385
|
+
models_conf = resolve_models_config
|
|
386
|
+
return {} unless models_conf.respond_to?(:to_h)
|
|
387
|
+
|
|
388
|
+
hash = models_conf.to_h
|
|
389
|
+
hash[model_id.to_s] || hash[model_id.to_sym] || {}
|
|
390
|
+
rescue StandardError => e
|
|
391
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.model_capability_config')
|
|
392
|
+
{}
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
def resolve_models_config
|
|
396
|
+
return config.models if config.respond_to?(:models)
|
|
397
|
+
return config[:models] if config.respond_to?(:[])
|
|
398
|
+
|
|
399
|
+
nil
|
|
400
|
+
rescue StandardError
|
|
401
|
+
nil
|
|
402
|
+
end
|
|
403
|
+
|
|
310
404
|
def modalities_for(methods)
|
|
311
405
|
return [%w[text], %w[embeddings]] if methods.include?('embedContent')
|
|
312
406
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'legion/extensions/llm'
|
|
4
4
|
require 'legion/extensions/llm/gemini/provider'
|
|
5
5
|
require 'legion/extensions/llm/gemini/version'
|
|
6
|
+
require_relative 'gemini/actors/discovery_refresh'
|
|
6
7
|
|
|
7
8
|
module Legion
|
|
8
9
|
module Extensions
|
|
@@ -30,10 +31,7 @@ module Legion
|
|
|
30
31
|
fleet: {
|
|
31
32
|
enabled: false,
|
|
32
33
|
respond_to_requests: false,
|
|
33
|
-
capabilities: %i[chat stream_chat embed]
|
|
34
|
-
lanes: [],
|
|
35
|
-
concurrency: 4,
|
|
36
|
-
queue_suffix: nil
|
|
34
|
+
capabilities: %i[chat stream_chat embed tools]
|
|
37
35
|
}
|
|
38
36
|
}
|
|
39
37
|
)
|
|
@@ -106,8 +104,7 @@ module Legion
|
|
|
106
104
|
:add_settings_api_key, :add_settings_instances, :normalize_instance_config,
|
|
107
105
|
:sanitize_instance_config
|
|
108
106
|
|
|
109
|
-
Legion::Extensions::Llm::Configuration.register_provider_options(Provider.configuration_options)
|
|
110
|
-
Legion::Extensions::Llm::Configuration.respond_to?(:register_provider_options)
|
|
107
|
+
Legion::Extensions::Llm::Configuration.register_provider_options(Provider.configuration_options)
|
|
111
108
|
end
|
|
112
109
|
end
|
|
113
110
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-llm-gemini
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LegionIO
|
|
@@ -71,14 +71,14 @@ dependencies:
|
|
|
71
71
|
requirements:
|
|
72
72
|
- - ">="
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 0.
|
|
74
|
+
version: 0.5.0
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 0.
|
|
81
|
+
version: 0.5.0
|
|
82
82
|
description: Gemini provider integration for the LegionIO LLM routing framework.
|
|
83
83
|
email:
|
|
84
84
|
- matthewdiverson@gmail.com
|
|
@@ -97,6 +97,7 @@ files:
|
|
|
97
97
|
- README.md
|
|
98
98
|
- lex-llm-gemini.gemspec
|
|
99
99
|
- lib/legion/extensions/llm/gemini.rb
|
|
100
|
+
- lib/legion/extensions/llm/gemini/actors/discovery_refresh.rb
|
|
100
101
|
- lib/legion/extensions/llm/gemini/actors/fleet_worker.rb
|
|
101
102
|
- lib/legion/extensions/llm/gemini/provider.rb
|
|
102
103
|
- lib/legion/extensions/llm/gemini/runners/fleet_worker.rb
|