lex-llm-gemini 0.1.5 → 0.1.7
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 +12 -0
- data/README.md +40 -6
- data/lib/legion/extensions/llm/gemini/provider.rb +16 -0
- data/lib/legion/extensions/llm/gemini/registry_event_builder.rb +75 -0
- data/lib/legion/extensions/llm/gemini/registry_publisher.rb +89 -0
- data/lib/legion/extensions/llm/gemini/transport/exchanges/llm_registry.rb +24 -0
- data/lib/legion/extensions/llm/gemini/transport/messages/registry_event.rb +42 -0
- data/lib/legion/extensions/llm/gemini/version.rb +1 -1
- data/lib/legion/extensions/llm/gemini.rb +3 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b4d2bbf521fe7cd5757553aff5a6d61c1a9e9ffbe18c683058710ab19a8a6ff
|
|
4
|
+
data.tar.gz: 98d0db7b428b68d0543682c43a27d77fde00aee8bb02377195c37224e9429fef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c40e3408f31507e4de8622e65676a2eb67849a05964dee02585545647563a4655fe808a3673782b1819bc7828a1f9fd3af900aa57ce09f6119ba28caefe01813
|
|
7
|
+
data.tar.gz: bacceead0f9edceed7da8efb605fe516f0ea7110c57f47cf8b16bad77805e74d8a1a99d37ffec056fa4affdd2c4e6a30f45c7a5812c03221182038373a45c784
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.7 - 2026-04-30
|
|
4
|
+
|
|
5
|
+
- Audit logging, rescue blocks, and README for full observability.
|
|
6
|
+
- Add `Legion::Logging::Helper` to every module and class in lib/.
|
|
7
|
+
- Replace all bare rescue blocks and custom `log_publish_failure` with `handle_exception(e, level:, handled:, operation:)`.
|
|
8
|
+
- Add info-level action logging for model listing and registry publishing.
|
|
9
|
+
- Update README to reflect registry event publishing and observability patterns.
|
|
10
|
+
|
|
11
|
+
## 0.1.6 - 2026-04-28
|
|
12
|
+
|
|
13
|
+
- Publish best-effort `llm.registry` discovered-model availability events when transport is already loaded.
|
|
14
|
+
|
|
3
15
|
## 0.1.5 - 2026-04-28
|
|
4
16
|
|
|
5
17
|
- Require current shared Legion JSON, logging, settings, and `lex-llm >= 0.1.5` runtime dependencies.
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# lex-llm-gemini
|
|
2
2
|
|
|
3
|
-
LegionIO LLM provider extension for Gemini.
|
|
3
|
+
LegionIO LLM provider extension for Google Gemini.
|
|
4
4
|
|
|
5
5
|
This gem lives under `Legion::Extensions::Llm::Gemini` and depends on `lex-llm` for shared provider-neutral routing, fleet, and schema primitives.
|
|
6
6
|
|
|
@@ -10,11 +10,24 @@ Load it with `require 'legion/extensions/llm/gemini'`.
|
|
|
10
10
|
|
|
11
11
|
- `Legion::Extensions::Llm::Provider` registration as `:gemini`
|
|
12
12
|
- Gemini-native chat requests through `POST /v1beta/{model=models/*}:generateContent`
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
13
|
+
- Streaming chat support through `POST /v1beta/{model=models/*}:streamGenerateContent?alt=sse`
|
|
14
|
+
- Model discovery through `GET /v1beta/models`
|
|
15
|
+
- Embeddings through `POST /v1beta/{model=models/*}:embedContent`
|
|
16
|
+
- Normalized chat, streaming, vision, function calling, and embedding capability mapping from `supportedGenerationMethods`
|
|
17
|
+
- Best-effort `llm.registry` availability events published to AMQP when transport is loaded
|
|
18
|
+
- Shared fleet/default settings via `Legion::Extensions::Llm.provider_settings`
|
|
19
|
+
|
|
20
|
+
## File Map
|
|
21
|
+
|
|
22
|
+
| Path | Purpose |
|
|
23
|
+
|------|---------|
|
|
24
|
+
| `lib/legion/extensions/llm/gemini.rb` | Entry point; provider registration |
|
|
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 |
|
|
30
|
+
| `lib/legion/extensions/llm/gemini/version.rb` | `VERSION` constant |
|
|
18
31
|
|
|
19
32
|
## Defaults
|
|
20
33
|
|
|
@@ -45,3 +58,24 @@ Legion::Extensions::Llm.configure do |config|
|
|
|
45
58
|
config.default_embedding_model = "gemini-embedding-001"
|
|
46
59
|
end
|
|
47
60
|
```
|
|
61
|
+
|
|
62
|
+
## Observability
|
|
63
|
+
|
|
64
|
+
Every module and class includes or extends `Legion::Logging::Helper`:
|
|
65
|
+
|
|
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.
|
|
69
|
+
|
|
70
|
+
## Development
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
bundle install
|
|
74
|
+
bundle exec rspec # 0 failures
|
|
75
|
+
bundle exec rubocop -A # auto-fix
|
|
76
|
+
bundle exec rubocop # lint check
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
Apache-2.0
|
|
@@ -8,11 +8,19 @@ module Legion
|
|
|
8
8
|
module Gemini
|
|
9
9
|
# Gemini provider implementation for the Legion::Extensions::Llm base provider contract.
|
|
10
10
|
class Provider < Legion::Extensions::Llm::Provider # rubocop:disable Metrics/ClassLength
|
|
11
|
+
include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
|
|
12
|
+
|
|
11
13
|
class << self
|
|
14
|
+
attr_writer :registry_publisher
|
|
15
|
+
|
|
12
16
|
def slug = 'gemini'
|
|
13
17
|
def configuration_options = %i[gemini_api_key gemini_api_base]
|
|
14
18
|
def configuration_requirements = %i[gemini_api_key]
|
|
15
19
|
def capabilities = Capabilities
|
|
20
|
+
|
|
21
|
+
def registry_publisher
|
|
22
|
+
@registry_publisher ||= RegistryPublisher.new
|
|
23
|
+
end
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
# Capability predicates for Gemini API models.
|
|
@@ -87,6 +95,14 @@ module Legion
|
|
|
87
95
|
"#{model_path(model)}:embedContent"
|
|
88
96
|
end
|
|
89
97
|
|
|
98
|
+
def list_models
|
|
99
|
+
log.info { 'listing available Gemini models' }
|
|
100
|
+
super.tap do |models|
|
|
101
|
+
log.info { "discovered #{models.size} Gemini model(s); publishing to registry" }
|
|
102
|
+
self.class.registry_publisher.publish_models_async(models, readiness: readiness(live: false))
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
90
106
|
private
|
|
91
107
|
|
|
92
108
|
def model_path(model)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Llm
|
|
6
|
+
module Gemini
|
|
7
|
+
# Builds sanitized lex-llm registry envelopes for Gemini provider state.
|
|
8
|
+
class RegistryEventBuilder
|
|
9
|
+
include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
|
|
10
|
+
|
|
11
|
+
def model_available(model, readiness:)
|
|
12
|
+
registry_event_class.available(
|
|
13
|
+
model_offering(model),
|
|
14
|
+
runtime: runtime_metadata,
|
|
15
|
+
health: model_health(readiness),
|
|
16
|
+
metadata: model_metadata(model)
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def model_offering(model)
|
|
23
|
+
{
|
|
24
|
+
provider_family: :gemini,
|
|
25
|
+
provider_instance: provider_instance,
|
|
26
|
+
transport: :http,
|
|
27
|
+
model: model.id,
|
|
28
|
+
usage_type: usage_type_for(model),
|
|
29
|
+
capabilities: Array(model.capabilities).map(&:to_sym),
|
|
30
|
+
limits: model_limits(model),
|
|
31
|
+
metadata: { lex: :llm_gemini, model_name: model.name }.compact
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def model_health(readiness)
|
|
36
|
+
ready = readiness.fetch(:ready, true) == true
|
|
37
|
+
{ ready:, status: ready ? :available : :degraded }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def model_metadata(model)
|
|
41
|
+
{ extension: :lex_llm_gemini, provider: :gemini, model_type: model.type }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def runtime_metadata
|
|
45
|
+
{ node: provider_instance }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def model_limits(model)
|
|
49
|
+
{
|
|
50
|
+
context_window: model.context_window,
|
|
51
|
+
max_output_tokens: model.max_output_tokens
|
|
52
|
+
}.compact
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def usage_type_for(model)
|
|
56
|
+
model.type == 'embedding' ? :embedding : :inference
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def provider_instance
|
|
60
|
+
configured_node = (::Legion::Settings.dig(:node, :canonical_name) if defined?(::Legion::Settings))
|
|
61
|
+
value = configured_node.to_s.strip
|
|
62
|
+
value.empty? ? :gemini : value.to_sym
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.registry.provider_instance')
|
|
65
|
+
:gemini
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def registry_event_class
|
|
69
|
+
::Legion::Extensions::Llm::Routing::RegistryEvent
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Llm
|
|
6
|
+
module Gemini
|
|
7
|
+
# Best-effort publisher for Gemini provider availability events.
|
|
8
|
+
class RegistryPublisher
|
|
9
|
+
include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
|
|
10
|
+
|
|
11
|
+
APP_ID = 'lex-llm-gemini'
|
|
12
|
+
|
|
13
|
+
def initialize(builder: RegistryEventBuilder.new)
|
|
14
|
+
@builder = builder
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def publish_models_async(models, readiness:)
|
|
18
|
+
log.info { "publishing #{Array(models).size} model event(s) to llm.registry" }
|
|
19
|
+
schedule do
|
|
20
|
+
Array(models).each do |model|
|
|
21
|
+
publish_event(@builder.model_available(model, readiness:))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def schedule(&)
|
|
29
|
+
return false unless publishing_available?
|
|
30
|
+
|
|
31
|
+
Thread.new do
|
|
32
|
+
Thread.current.abort_on_exception = false
|
|
33
|
+
yield
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.registry.schedule_thread')
|
|
36
|
+
end
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.registry.schedule')
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def publish_event(event)
|
|
43
|
+
return false unless publishing_available?
|
|
44
|
+
|
|
45
|
+
message_class.new(event:, app_id: APP_ID).publish(spool: false)
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
handle_exception(e, level: :warn, handled: true, operation: 'gemini.registry.publish_event')
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def publishing_available?
|
|
52
|
+
return false unless registry_event_available?
|
|
53
|
+
return false unless transport_message_available?
|
|
54
|
+
return true unless defined?(::Legion::Transport::Connection)
|
|
55
|
+
return true unless ::Legion::Transport::Connection.respond_to?(:session_open?)
|
|
56
|
+
|
|
57
|
+
::Legion::Transport::Connection.session_open?
|
|
58
|
+
rescue StandardError => e
|
|
59
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.registry.publishing_available?')
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def registry_event_available?
|
|
64
|
+
defined?(::Legion::Extensions::Llm::Routing::RegistryEvent)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def transport_message_available?
|
|
68
|
+
return true if message_class_defined?
|
|
69
|
+
return false unless defined?(::Legion::Transport::Message) && defined?(::Legion::Transport::Exchange)
|
|
70
|
+
|
|
71
|
+
require 'legion/extensions/llm/gemini/transport/messages/registry_event'
|
|
72
|
+
message_class_defined?
|
|
73
|
+
rescue LoadError => e
|
|
74
|
+
handle_exception(e, level: :debug, handled: true, operation: 'gemini.registry.transport_load')
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def message_class_defined?
|
|
79
|
+
defined?(::Legion::Extensions::Llm::Gemini::Transport::Messages::RegistryEvent)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def message_class
|
|
83
|
+
::Legion::Extensions::Llm::Gemini::Transport::Messages::RegistryEvent
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Llm
|
|
6
|
+
module Gemini
|
|
7
|
+
module Transport
|
|
8
|
+
module Exchanges
|
|
9
|
+
# Topic exchange for Gemini provider availability events.
|
|
10
|
+
class LlmRegistry < ::Legion::Transport::Exchange
|
|
11
|
+
def exchange_name
|
|
12
|
+
'llm.registry'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def default_type
|
|
16
|
+
'topic'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/llm/gemini/transport/exchanges/llm_registry'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Llm
|
|
8
|
+
module Gemini
|
|
9
|
+
module Transport
|
|
10
|
+
module Messages
|
|
11
|
+
# Publishes lex-llm RegistryEvent envelopes to the llm.registry exchange.
|
|
12
|
+
class RegistryEvent < ::Legion::Transport::Message
|
|
13
|
+
def initialize(event:, **options)
|
|
14
|
+
super(**event.to_h.merge(options))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def exchange
|
|
18
|
+
Transport::Exchanges::LlmRegistry
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def routing_key
|
|
22
|
+
@options[:routing_key] || "llm.registry.#{@options.fetch(:event_type)}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def type
|
|
26
|
+
'llm.registry.event'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def app_id
|
|
30
|
+
@options[:app_id] || RegistryPublisher::APP_ID
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def persistent # rubocop:disable Naming/PredicateMethod
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'legion/extensions/llm'
|
|
4
|
+
require 'legion/extensions/llm/gemini/registry_event_builder'
|
|
5
|
+
require 'legion/extensions/llm/gemini/registry_publisher'
|
|
4
6
|
require 'legion/extensions/llm/gemini/provider'
|
|
5
7
|
require 'legion/extensions/llm/gemini/version'
|
|
6
8
|
|
|
@@ -10,6 +12,7 @@ module Legion
|
|
|
10
12
|
# Gemini provider extension namespace.
|
|
11
13
|
module Gemini
|
|
12
14
|
extend ::Legion::Extensions::Core if ::Legion::Extensions.const_defined?(:Core, false)
|
|
15
|
+
extend Legion::Logging::Helper if defined?(Legion::Logging::Helper)
|
|
13
16
|
|
|
14
17
|
PROVIDER_FAMILY = :gemini
|
|
15
18
|
|
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.1.
|
|
4
|
+
version: 0.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LegionIO
|
|
@@ -84,6 +84,10 @@ files:
|
|
|
84
84
|
- lex-llm-gemini.gemspec
|
|
85
85
|
- lib/legion/extensions/llm/gemini.rb
|
|
86
86
|
- lib/legion/extensions/llm/gemini/provider.rb
|
|
87
|
+
- lib/legion/extensions/llm/gemini/registry_event_builder.rb
|
|
88
|
+
- lib/legion/extensions/llm/gemini/registry_publisher.rb
|
|
89
|
+
- lib/legion/extensions/llm/gemini/transport/exchanges/llm_registry.rb
|
|
90
|
+
- lib/legion/extensions/llm/gemini/transport/messages/registry_event.rb
|
|
87
91
|
- lib/legion/extensions/llm/gemini/version.rb
|
|
88
92
|
homepage: https://github.com/LegionIO/lex-llm-gemini
|
|
89
93
|
licenses:
|