lex-llm-gemini 0.3.0 → 0.3.6

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: c5809a1fe2d0614ca09803118c54d0bf53d86253c5877a60e9e8607974f9ba09
4
- data.tar.gz: 51b3697e7ecd2f87e030b180878fe23052e22a67b20e7f89ab635e503db2d019
3
+ metadata.gz: dc50ce20a2bc5b62e79854004feee5aa14ee1d26a8dfee8698a37f387d72392c
4
+ data.tar.gz: ef401f8e9fa5a521a3b5930e835a6aa11b707ed2dd7c304e51115a27b1ba1732
5
5
  SHA512:
6
- metadata.gz: 155271bed61b4a5daf51c364721350f4f58f4c9bf1277e1d889f0a19996772af855f75d63ecd26b99b1ea3f4a2a9fc65092508c612d1f0ec88792f0eaa8789ae
7
- data.tar.gz: 2f52cc4ef38d97f53709ef9222e89b60b16487a5fa7b76e070d11a3eff7c8e5bb6b50b75bd03ee15997ea9d7c54232137202364d40d03c3448a2400aa8f222fa
6
+ metadata.gz: 03bb48c71874f80bcad9739a59e0d7d0377aa935bee79e8fe0eb3a2dff8f700537ac480a406a86b1f21f3e35a1dc3401c1443e3004ecec3de6aa9c044f8b89ce
7
+ data.tar.gz: 3c650b57f45a6cc93f1634595dc0fc14926526bd666ab57e7c824e11e889fc0ce44b4494b8b95729303170b8a29e98e31221d1d4afc3953957ae3095c91d6543
@@ -8,8 +8,20 @@ jobs:
8
8
  ci:
9
9
  uses: LegionIO/.github/.github/workflows/ci.yml@main
10
10
 
11
+ excluded-files:
12
+ uses: LegionIO/.github/.github/workflows/excluded-files.yml@main
13
+
14
+ security:
15
+ uses: LegionIO/.github/.github/workflows/security-scan.yml@main
16
+
17
+ version-changelog:
18
+ uses: LegionIO/.github/.github/workflows/version-changelog.yml@main
19
+
20
+ dependency-review:
21
+ uses: LegionIO/.github/.github/workflows/dependency-review.yml@main
22
+
11
23
  release:
12
- needs: ci
24
+ needs: [ci, excluded-files, security]
13
25
  if: github.event_name == 'push' && github.ref == 'refs/heads/main'
14
26
  uses: LegionIO/.github/.github/workflows/release.yml@main
15
27
  secrets:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.6 - 2026-05-06
4
+
5
+ - Load provider-owned fleet actors through the LegionIO subscription base and the canonical Gemini provider root.
6
+ - Keep fleet runners anchored on the provider root namespace so provider constants and instance discovery are always loaded.
7
+ - Strip temporary generic API key fields from discovered Gemini instance configs after credential deduplication.
8
+ - Gate release publishing on the shared security workflow.
9
+
10
+ ## 0.3.5 - 2026-05-06
11
+
12
+ - Keep the default Gemini endpoint on the versioned `v1beta` API base when instance settings are normalized.
13
+ - Refresh the README for the current `lex-llm >= 0.4.3` provider registry and fleet responder boundary.
14
+
15
+ ## 0.3.4 - 2026-05-06
16
+
17
+ - Use the shared `lex-llm` fleet provider responder helper for provider-owned fleet workers.
18
+ - Remove the runtime `legion-llm` dependency and require `lex-llm >= 0.4.3` for responder-side fleet execution.
19
+
20
+ ## 0.3.3 - 2026-05-06
21
+
22
+ - Remove require-time provider self-registration; `legion-llm` now owns adapter creation and registry writes from loaded provider discovery metadata.
23
+ - Bump dependency floors to `lex-llm >= 0.4.1` and `legion-llm >= 0.9.1`.
24
+
25
+ ## 0.3.2 - 2026-05-06
26
+
27
+ - Add provider contract specs for the shared keyword-only `lex-llm` provider API.
28
+ - Move Gemini defaults back to `Legion::Extensions::Llm.provider_settings` with credentials and instance-level fleet responder settings.
29
+ - Add provider-owned fleet responder actor and runner backed by `legion-llm` fleet policy execution.
30
+ - Bump the transport dependency floor to `legion-transport >= 1.4.14`.
31
+
32
+ ## 0.3.1 - 2026-05-03
33
+
34
+ - Normalize generic settings keys to Gemini provider config keys during instance discovery.
35
+
3
36
  ## 0.3.0 - 2026-05-01
4
37
 
5
38
  - Add auto-discovery via CredentialSources and AutoRegistration from lex-llm 0.3.0
data/Gemfile CHANGED
@@ -4,6 +4,8 @@ source 'https://rubygems.org'
4
4
 
5
5
  group :test do
6
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)
7
9
  gem 'lex-llm', path: llm_base_path if File.directory?(llm_base_path)
8
10
  end
9
11
 
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  LegionIO LLM provider extension for Google Gemini.
4
4
 
5
- This gem lives under `Legion::Extensions::Llm::Gemini` and depends on `lex-llm` for shared provider-neutral routing, fleet, and schema primitives.
5
+ This gem lives under `Legion::Extensions::Llm::Gemini` and depends on `lex-llm >= 0.4.3` for shared provider-neutral routing, response normalization, fleet responder execution, and schema primitives. It does not require or call `legion-llm` at runtime; `legion-llm` owns adapter creation, routing, and registry writes after discovering loaded `lex-llm-*` provider gems.
6
6
 
7
7
  Load it with `require 'legion/extensions/llm/gemini'`.
8
8
 
@@ -21,12 +21,10 @@ Load it with `require 'legion/extensions/llm/gemini'`.
21
21
 
22
22
  | Path | Purpose |
23
23
  |------|---------|
24
- | `lib/legion/extensions/llm/gemini.rb` | Entry point; provider registration |
24
+ | `lib/legion/extensions/llm/gemini.rb` | Entry point; provider discovery metadata and defaults |
25
25
  | `lib/legion/extensions/llm/gemini/provider.rb` | Gemini provider (chat, streaming, models, embeddings) |
26
- | `lib/legion/extensions/llm/gemini/registry_event_builder.rb` | Builds sanitized lex-llm registry event envelopes |
27
- | `lib/legion/extensions/llm/gemini/registry_publisher.rb` | Best-effort async publisher for model availability events |
28
- | `lib/legion/extensions/llm/gemini/transport/exchanges/llm_registry.rb` | `llm.registry` AMQP topic exchange |
29
- | `lib/legion/extensions/llm/gemini/transport/messages/registry_event.rb` | AMQP message wrapper for registry events |
26
+ | `lib/legion/extensions/llm/gemini/actors/fleet_worker.rb` | Provider-owned fleet subscription actor |
27
+ | `lib/legion/extensions/llm/gemini/runners/fleet_worker.rb` | Fleet runner delegating to `Legion::Extensions::Llm::Fleet::ProviderResponder` |
30
28
  | `lib/legion/extensions/llm/gemini/version.rb` | `VERSION` constant |
31
29
 
32
30
  ## Defaults
@@ -59,21 +57,39 @@ Legion::Extensions::Llm.configure do |config|
59
57
  end
60
58
  ```
61
59
 
60
+ ## Fleet Responder
61
+
62
+ Provider instances can opt in to consuming Legion LLM fleet requests. The provider-owned fleet actor only starts when at least one discovered instance enables `fleet.respond_to_requests`, and execution delegates to `Legion::Extensions::Llm::Fleet::ProviderResponder` from `lex-llm`.
63
+
64
+ ```yaml
65
+ extensions:
66
+ llm:
67
+ gemini:
68
+ instances:
69
+ local:
70
+ fleet:
71
+ enabled: true
72
+ respond_to_requests: true
73
+ capabilities:
74
+ - chat
75
+ - stream_chat
76
+ - embed
77
+ ```
78
+
62
79
  ## Observability
63
80
 
64
- Every module and class includes or extends `Legion::Logging::Helper`:
81
+ The Gemini entry point and provider use `Legion::Logging::Helper`:
65
82
 
66
- - **Info-level logging** on `list_models` and registry event publishing.
67
- - **All rescue blocks** call `handle_exception(e, level:, handled:, operation:)` for structured exception telemetry.
68
- - Registry publishing is best-effort; failures are handled at `:debug` or `:warn` level and never block the caller.
83
+ - `list_models` logs model discovery activity and publishes availability through the shared `lex-llm` registry publisher.
84
+ - Fleet request execution is delegated to the shared responder helper so acking, response publishing, and responder failures stay inside the provider-neutral fleet boundary.
85
+ - Registry publishing is best-effort and must not block provider calls when transport is unavailable.
69
86
 
70
87
  ## Development
71
88
 
72
89
  ```bash
73
90
  bundle install
74
- bundle exec rspec # 0 failures
75
- bundle exec rubocop -A # auto-fix
76
- bundle exec rubocop # lint check
91
+ bundle exec rspec --format json --out tmp/rspec_results.json --format progress --out tmp/rspec_progress.txt
92
+ bundle exec rubocop -A
77
93
  ```
78
94
 
79
95
  ## License
@@ -26,5 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'legion-json', '>= 1.2.1'
27
27
  spec.add_dependency 'legion-logging', '>= 1.3.2'
28
28
  spec.add_dependency 'legion-settings', '>= 1.3.14'
29
- spec.add_dependency 'lex-llm', '>= 0.3.0'
29
+ spec.add_dependency 'legion-transport', '>= 1.4.14'
30
+ spec.add_dependency 'lex-llm', '>= 0.4.3'
30
31
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'legion/extensions/actors/subscription'
5
+ rescue LoadError => e
6
+ warn(e.message) if $VERBOSE
7
+ end
8
+
9
+ unless defined?(Legion::Extensions::Actors::Subscription)
10
+ raise LoadError, 'LegionIO actor runtime is required for Gemini fleet worker'
11
+ end
12
+
13
+ require 'legion/extensions/llm/gemini'
14
+ require 'legion/extensions/llm/fleet/provider_responder'
15
+
16
+ module Legion
17
+ module Extensions
18
+ module Llm
19
+ module Gemini
20
+ module Actor
21
+ # Subscription actor for Gemini fleet request consumption.
22
+ class FleetWorker < Legion::Extensions::Actors::Subscription
23
+ def runner_class
24
+ 'Legion::Extensions::Llm::Gemini::Runners::FleetWorker'
25
+ end
26
+
27
+ def runner_function
28
+ 'handle_fleet_request'
29
+ end
30
+
31
+ def use_runner?
32
+ false
33
+ end
34
+
35
+ def enabled?
36
+ Legion::Extensions::Llm::Fleet::ProviderResponder.enabled_for?(Gemini.discover_instances)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/llm/fleet/provider_responder'
4
+ require 'legion/extensions/llm/gemini'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Llm
9
+ module Gemini
10
+ module Runners
11
+ # Runner entrypoint for Gemini fleet request execution.
12
+ module FleetWorker
13
+ module_function
14
+
15
+ def handle_fleet_request(payload, delivery: nil, properties: nil)
16
+ Legion::Extensions::Llm::Fleet::ProviderResponder.call(
17
+ payload: payload,
18
+ provider_family: Gemini::PROVIDER_FAMILY,
19
+ provider_class: Gemini::Provider,
20
+ provider_instances: -> { Gemini.discover_instances },
21
+ delivery: delivery,
22
+ properties: properties
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Llm
6
6
  module Gemini
7
- VERSION = '0.3.0'
7
+ VERSION = '0.3.6'
8
8
  end
9
9
  end
10
10
  end
@@ -17,16 +17,26 @@ module Legion
17
17
  PROVIDER_FAMILY = :gemini
18
18
 
19
19
  def self.default_settings
20
- {
21
- enabled: false,
22
- default_model: 'gemini-2.0-flash',
23
- api_key: nil,
24
- model_whitelist: [],
25
- model_blacklist: [],
26
- model_cache_ttl: 3600,
27
- tls: { enabled: false, verify: :peer },
28
- instances: {}
29
- }
20
+ ::Legion::Extensions::Llm.provider_settings(
21
+ family: PROVIDER_FAMILY,
22
+ instance: {
23
+ endpoint: 'https://generativelanguage.googleapis.com/v1beta',
24
+ default_model: 'gemini-2.0-flash',
25
+ tier: :frontier,
26
+ transport: :http,
27
+ credentials: { api_key: 'env://GEMINI_API_KEY' },
28
+ usage: { inference: true, embedding: true, image: false },
29
+ limits: { concurrency: 4 },
30
+ fleet: {
31
+ enabled: false,
32
+ respond_to_requests: false,
33
+ capabilities: %i[chat stream_chat embed],
34
+ lanes: [],
35
+ concurrency: 4,
36
+ queue_suffix: nil
37
+ }
38
+ }
39
+ )
30
40
  end
31
41
 
32
42
  def self.provider_class
@@ -37,7 +47,7 @@ module Legion
37
47
  candidates = {}
38
48
  discover_from_env(candidates)
39
49
  discover_from_settings(candidates)
40
- CredentialSources.dedup_credentials(candidates)
50
+ CredentialSources.dedup_credentials(candidates).transform_values { |config| sanitize_instance_config(config) }
41
51
  end
42
52
 
43
53
  def self.discover_from_env(candidates)
@@ -59,23 +69,46 @@ module Legion
59
69
  api_key = cfg[:api_key] || cfg['api_key']
60
70
  return if api_key.nil? || api_key.to_s.strip.empty?
61
71
 
62
- candidates[:settings] = { api_key: api_key, gemini_api_key: api_key, tier: :cloud }
72
+ candidates[:settings] = normalize_instance_config(cfg).merge(api_key: api_key,
73
+ gemini_api_key: api_key,
74
+ tier: :cloud)
63
75
  end
64
76
 
65
77
  def self.add_settings_instances(candidates, cfg)
66
78
  instances = cfg[:instances] || cfg['instances']
67
79
  return unless instances.is_a?(Hash)
68
80
 
69
- instances.each { |name, config| candidates[name.to_sym] = config.merge(tier: :cloud) }
81
+ instances.each do |name, config|
82
+ next unless config.is_a?(Hash)
83
+
84
+ normalized = normalize_instance_config(config)
85
+ next unless normalized[:gemini_api_key]
86
+
87
+ normalized[:api_key] = normalized[:gemini_api_key]
88
+ candidates[name.to_sym] = normalized.merge(tier: :cloud)
89
+ end
90
+ end
91
+
92
+ def self.normalize_instance_config(config) # rubocop:disable Metrics/AbcSize
93
+ normalized = config.to_h.transform_keys { |key| key.respond_to?(:to_sym) ? key.to_sym : key }
94
+ normalized[:gemini_api_key] ||= normalized.delete(:api_key)
95
+ normalized[:gemini_api_base] ||= normalized.delete(:base_url)
96
+ normalized[:gemini_api_base] ||= normalized.delete(:api_base)
97
+ normalized[:gemini_api_base] ||= normalized.delete(:endpoint)
98
+ normalized.compact.except(:instances)
99
+ end
100
+
101
+ def self.sanitize_instance_config(config)
102
+ config.except(:api_key)
70
103
  end
71
104
 
72
105
  private_class_method :discover_from_env, :discover_from_settings,
73
- :add_settings_api_key, :add_settings_instances
74
- end
106
+ :add_settings_api_key, :add_settings_instances, :normalize_instance_config,
107
+ :sanitize_instance_config
75
108
 
76
- Configuration.register_provider_options(Gemini::Provider.configuration_options)
109
+ Legion::Extensions::Llm::Configuration.register_provider_options(Provider.configuration_options) if
110
+ Legion::Extensions::Llm::Configuration.respond_to?(:register_provider_options)
111
+ end
77
112
  end
78
113
  end
79
114
  end
80
-
81
- Legion::Extensions::Llm::Gemini.register_discovered_instances
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.0
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO
@@ -51,20 +51,34 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: 1.3.14
54
+ - !ruby/object:Gem::Dependency
55
+ name: legion-transport
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.4.14
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.4.14
54
68
  - !ruby/object:Gem::Dependency
55
69
  name: lex-llm
56
70
  requirement: !ruby/object:Gem::Requirement
57
71
  requirements:
58
72
  - - ">="
59
73
  - !ruby/object:Gem::Version
60
- version: 0.3.0
74
+ version: 0.4.3
61
75
  type: :runtime
62
76
  prerelease: false
63
77
  version_requirements: !ruby/object:Gem::Requirement
64
78
  requirements:
65
79
  - - ">="
66
80
  - !ruby/object:Gem::Version
67
- version: 0.3.0
81
+ version: 0.4.3
68
82
  description: Gemini provider integration for the LegionIO LLM routing framework.
69
83
  email:
70
84
  - matthewdiverson@gmail.com
@@ -83,7 +97,9 @@ files:
83
97
  - README.md
84
98
  - lex-llm-gemini.gemspec
85
99
  - lib/legion/extensions/llm/gemini.rb
100
+ - lib/legion/extensions/llm/gemini/actors/fleet_worker.rb
86
101
  - lib/legion/extensions/llm/gemini/provider.rb
102
+ - lib/legion/extensions/llm/gemini/runners/fleet_worker.rb
87
103
  - lib/legion/extensions/llm/gemini/version.rb
88
104
  homepage: https://github.com/LegionIO/lex-llm-gemini
89
105
  licenses: